My program is working with expression like 12 + 3 * 45.But Its not working expression like 12*4+(7/2). please give correction in my code.I am attaching my code:
import java.util.Stack; public class EvaluateString { public static int evaluate(String expression) { char[] tokens = expression.toCharArray(); // Stack for numbers: 'values' Stack<Integer> values = new Stack<Integer>(); // Stack for Operators: 'ops' Stack<Character> ops = new Stack<Character>(); for (int i = 0; i < tokens.length; i++) { // Current token is a whitespace, skip it if (tokens[i] == ' ') continue; // Current token is a number, push it to stack for numbers if (tokens[i] >= '0' && tokens[i] <= '9') { StringBuffer sbuf = new StringBuffer(); // There may be more than one digits in number while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9') sbuf.append(tokens[i++]); values.push(Integer.parseInt(sbuf.toString())); } // Current token is an opening brace, push it to 'ops' else if (tokens[i] == '(') ops.push(tokens[i]); // Closing brace encountered, solve entire brace else if (tokens[i] == ')') { while (ops.peek() != '(') values.push(applyOp(ops.pop(), values.pop(), values.pop())); ops.pop(); } // Current token is an operator. else if (tokens[i] == '+' || tokens[i] == '-' || tokens[i] == '*' || tokens[i] == '/') { // While top of 'ops' has same or greater precedence to current // token, which is an operator. Apply operator on top of 'ops' // to top two elements in values stack while (!ops.empty() && hasPrecedence(tokens[i], ops.peek())) values.push(applyOp(ops.pop(), values.pop(), values.pop())); // Push current token to 'ops'. ops.push(tokens[i]); } } // Entire expression has been parsed at this point, apply remaining // ops to remaining values while (!ops.empty()) values.push(applyOp(ops.pop(), values.pop(), values.pop())); // Top of 'values' contains result, return it return values.pop(); } // Returns true if 'op2' has higher or same precedence as 'op1', // otherwise returns false. public static boolean hasPrecedence(char op1, char op2) { if (op2 == '(' || op2 == ')') return false; if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) return false; else return true; } // A utility method to apply an operator 'op' on operands 'a' // and 'b'. Return the result. public static int applyOp(char op, int b, int a) { switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': if (b == 0) throw new UnsupportedOperationException("Cannot divide by zero"); return a / b; } return 0; } // Driver method to test above methods public static void main(String[] args) { System.out.println(EvaluateString.evaluate("10 + 2 * 6")); } }
Advertisement
Answer
Let’s take a look at your block which parses digits:
for (int i = 0; i < tokens.length; i++) { // ... if (tokens[i] >= '0' && tokens[i] <= '9') { StringBuffer sbuf = new StringBuffer(); // There may be more than one digits in number while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9') sbuf.append(tokens[i++]); values.push(Integer.parseInt(sbuf.toString())); } // ... }
Let’s assume our tokens are {‘1’, ‘+’, ‘2’} and your initial i
value is 0. We’re entering the if
-body (as tokens[0] == 1
), declare an sbuf
variable and again make exactly the same check for that i
(but we’re inside the if
-block with the same check as your while
condition). So, we’re going inside while loop, append tokens[0]
to sbuf
and increase our i
. So now i
is 1 and points to +
, while condition is false
, we parse "1"
into 1 and add it to values
. But now the next iteration of outer for-loop begins and the i
value will be 2
. So, we totally missed +
as we incremented it’s value inside while-loop but haven’t processed it in any way.
Now let’s find an alternative approach:
for (int i = 0; i < tokens.length; i++) { // ... if (tokens[i] >= '0' && tokens[i] <= '9') { StringBuilder sb = new StringBuilder(); sb.append(tokens[i]); // There may be more than one digits in number while (i + 1 < tokens.length && tokens[i + 1] >= '0' && tokens[i + 1] <= '9') { sb.append(tokens[++i]); } values.push(Integer.parseInt(sb.toString())); } // ... }
This approach adds the current value right after declaring sb
(I changed StringBuffer
to StringBuilder
as there is no need to use thread-safe StringBuffer
implementation). Next we’re checking the next value of i
without incrementing. If it is also a number we’re incrementing i
and appending it to sb
. Otherwise no changes to i
happens and it will still point to the same value (1 in our case). Now your outer for-loop will increment it and you’ll correctly process +
.
By the way, if you’re writing parser it’s better not only return values.pop()
but also check that values.size() == 1
. If the size is not one then the expression either is not correct or has not been parsed correctly.