Help me stackoverflow, you're my only hope. I have been trying to make a simple calculator, and finally I've gotten it to WORK! The problem is that only simply expressions are evaluated. For example: 4*5 would give 20.0. (Awesome!)
Whenever I give it a more complicated expression like 4*(2+3), the program crashes due to an EmptyStackException. I understand the exception, but I am unable to recreate the problem in my mind when I run through the code manually with my brain and a sheet of paper.
Can anyone figure out why it's crashing? Here is the full code. I marked where the code crashes with some bold, all-caps words. (i.e. PROGRAM CRASHES HERE)
/**
* Human
* Project 3: SUPER-DUPER JAVA CALCULATOR
*/
import java.util.*;
import java.util.Stack;
import java.lang.String;
import java.util.ArrayList;
import java.lang.StringBuilder;
import java.util.HashSet;
import java.lang.Exception;
import java.lang.Math;
public class InfixEvaluator {
public static class SyntaxErrorException extends Exception {
/**
* Construct a SyntaxErrorException with the specified message.
*
* @param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/**
* This is the stack of operands:
* i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/**
* This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/**
* These are the possible operators
*/
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
private static final int[] PRECEDENCE = {1, 1, 2, 2, 2, -1, -1, -1, -1, -1, -1};
/**
* This is an ArrayList of all the discrete
* things (operators/operands) making up an input.
* This is really just getting rid of the spaces,
* and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
public static ArrayList inputCleaner(String postfix) {
StringBuilder sb = new StringBuilder();
String noSpaces = postfix.replace(" ", "");
try {
for (int i = 0; i < noSpaces.length(); i++) {
char c = noSpaces.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
sb.append(c);
if (i == noSpaces.length() - 1) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
} else if (c == '.') {
for (int j = 0; j < sb.length(); j++) {
if (sb.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == sb.length() - 1) {
sb.append(c);
j = (sb.length() + 1);
}
}
if (sb.length() == 0) {
sb.append(c);
}
if (i == noSpaces.length() - 1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c) != -1) {
if (sb.length() != 0) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
sb.append(c);
input.add(sb.toString());
sb.delete(0, sb.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
String trololol = input.get(f);
switch (trololol) {
case "(":
numLP++;
break;
case "[":
numLB++;
break;
case "{":
numLBr++;
break;
case ")":
numRP++;
break;
case "]":
numRB++;
break;
case "}":
numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(":
doop++;
break;
case "[":
scoop++;
break;
case "{":
foop++;
break;
case ")":
doop--;
break;
case "]":
scoop--;
break;
case "}":
foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size() - 1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**
* Method to process operators
*
* @param op The operator
* @throws EmptyStackException
*/
private static void processOperator(String op) {
if (operatorStack.empty() || op == "(" || op == "[" || op == "{") {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
operatorStack.push(op);
} else {
//Pop all stacked operators with equal
// or higher precedence than op.
while (!operatorStack.empty() && precedence(op) <= precedence(topOp)) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+":
operandStack.push(l + r);
break;
case "-":
operandStack.push(l - r);
break;
case "*":
operandStack.push(l * r);
break;
case "/":
operandStack.push(l / r);
break;
case "%":
operandStack.push(l % r);
break;
case "^":
operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
if (topOp == "(" || topOp == "[" || topOp == "{") {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
if (op != ")" || op != "]" || op != "}") {
operatorStack.push(op);
}
}
}
}
public static String infixCalculator(ArrayList<String> puke) {
int p;
for (p = 0; p < puke.size(); p++) {
if (OPERATORS.indexOf(puke.get(p)) == -1) {
double herp = Double.parseDouble(puke.get(p));
operandStack.push(herp);
} else {
processOperator(puke.get(p));
}
}
if (p == puke.size()) {
while (!operatorStack.empty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+":
operandStack.push(l + r);
break;
case "-":
operandStack.push(l - r);
break;
case "*":
operandStack.push(l * r);
break;
case "/":
operandStack.push(l / r);
break;
case "%":
operandStack.push(l % r);
break;
case "^":
operandStack.push(Math.pow(l, r));
break;
default:
break;
}
}
}
return String.valueOf(operandStack.pop());
}
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
public static void main(String[] args) {
do {
try {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
System.out.println("Please insert an argument: \n");
String g = f.nextLine();
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
test.clear();
} catch (EmptyStackException e) {
System.out.println("Make sure you only put in operators and operands.");
}
} while (true);
}
}
Stack trace:
java.util.EmptyStackException at
java.util.Stack.peek(Stack.java:102) at
java.util.Stack.pop(Stack.java:84) at
InfixEvaluator.processOperator(InfixEvaluator.java:177) at
InfixEvaluator.infixCalculator(InfixEvaluator.java:225) at
InfixEvaluator.main(InfixEvaluator.java:276)