Skip to content
Advertisement

expression evaluation using stack in java

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.

Advertisement