Problem with unary minus, in custom calculator with custom priorities

49 Views Asked by At

I tried making custom calculator with priorities - and / being greater then + and *. It works nearly perfectly in that manner but I come to problem with unary minus. When it removes (), rather then for example from 1 + (-3), removing + and adding minus. It create this 1 + -3. Which whould cause -3 to not have priority of regular - , but rather secundary position of +. With that many math problems whould had diffrent solutions. Any idea how to solve it?

package A_2;
import java.util.*;

public class SimpleExpressionEvaluator {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter an arithmetic expression:");
        String expression = scanner.nextLine();

        int result = evaluateExpression(expression);
        System.out.println("Result: " + result);
    }

    public static int evaluateExpression(String expression) {
        if (expression == null || expression.isEmpty()) {
            throw new IllegalArgumentException("Expression cannot be null or empty");
        }
        String cleanedExpression = expression.replaceAll("\\s+", "");
        List<String> tokens = tokenize(expression);
        List<String> intermediate = new ArrayList<>(tokens);

        Stack<Integer> openParenthesesIndices = new Stack<>();
        for (int i = 0; i < intermediate.size(); i++) {
            String token = intermediate.get(i);
            if (token.equals("(")) {
                openParenthesesIndices.push(i);
            } else if (token.equals(")")) {
                int openIndex = openParenthesesIndices.pop();
                int result = evaluateSubExpression(intermediate.subList(openIndex + 1, i));
                intermediate.subList(openIndex, i + 1).clear();
                intermediate.add(openIndex, String.valueOf(result));
                i = openIndex;
            }
        }

        return evaluateSubExpression(intermediate);
    }

    private static List<String> preprocessTokens(List<String> tokens) {
        List<String> processedTokens = new ArrayList<>();
        for (int i = 0; i < tokens.size(); i++) {
            String token = tokens.get(i);
            if ((i == 0 && "-".equals(token)) || (i > 0 && "(".equals(tokens.get(i - 1)) && "-".equals(token))) {
                processedTokens.add("0");
                processedTokens.add("-");
            } else {
                processedTokens.add(token);
            }
        }
        return processedTokens;
    }

    private static int evaluateSubExpression(List<String> tokens) {
        tokens = preprocessTokens(tokens);
        Stack<String> stack = new Stack<>();
        for (int i = 0; i < tokens.size(); i++) {
            String token = tokens.get(i);
            if ("/".equals(token) || "*".equals(token) || "(".equals(token)) {
                stack.push(token);
            } else if ("-".equals(token) || "+".equals(token)) {
                if (i > 0 && "+".equals(tokens.get(i - 1)) && "-".equals(token)) {
                    stack.pop(); 
                    System.out.println("Evaluating -: ");
                } else {
                    stack.push(token);
                }
            } else if (")".equals(token)) {
                int num = 0;
                while (!stack.isEmpty() && !stack.peek().equals("(")) {
                    String op = stack.pop();
                    if (!stack.isEmpty()) { // Add this check
                        int val = Integer.parseInt(stack.pop());
                        if ("-".equals(op)) {
                            num -= val;
                        } else if ("/".equals(op)) {
                            num /= val;
                        }
                    }
                }

                if (!stack.isEmpty()) {
                    stack.pop(); 
                }
                if (i + 1 < tokens.size() && "-".equals(tokens.get(i + 1))) {
                    tokens.add(i + 1, Integer.toString(num));
                    tokens.add(i + 1, "-");
                    i++; // Skip the next '-' token
                } else {
                    stack.push(Integer.toString(num));
                }
                System.out.println("Evaluating -: " + stack.toString());
            } else {
                // It's a number
                int num = Integer.parseInt(token);
                while (!stack.isEmpty() && ("/".equals(stack.peek()) || "-".equals(stack.peek()))) {
                    String op = stack.pop();
                    if ("-".equals(op)) {
                        num = Integer.parseInt(stack.pop()) - num;
                    }
                    else {
                        num = Integer.parseInt(stack.pop()) / num;
                    }
                }
                stack.push(Integer.toString(num));
                System.out.println("Evaluating /: " + stack.toString());
            }
        }

        // Second pass: Evaluate + and *
        Queue<String> queue = new LinkedList<>(stack);
        int result = Integer.parseInt(queue.poll());
        while (!queue.isEmpty()) {
            String op = queue.poll();
            int num = Integer.parseInt(queue.poll());
            if ("*".equals(op)) {
                result *= num;
                System.out.println("Evaluating *: " + result);
            }
            if ("+".equals(op)) {
                result += num;
                System.out.println("Evaluating +: " + result);
            }
        }

        return result;
    }

    private static List<String> tokenize(String expression) {
        List<String> tokens = new ArrayList<>();
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < expression.length(); i++) {
            char ch = expression.charAt(i);

            if (Character.isDigit(ch) || (ch == '-' && (i == 0 || tokens.isEmpty() || tokens.get(tokens.size() - 1).equals("(")))) {
                sb.append(ch);
            } else {
                if (sb.length() > 0) {
                    tokens.add(sb.toString());
                    sb.setLength(0);
                }

                if (ch == '-' && (i == 0 || tokens.isEmpty() || tokens.get(tokens.size() - 1).equals("("))) {
                    tokens.add(Character.toString(ch));
                } else if (ch != ' ') {
                    tokens.add(Character.toString(ch));
                }

            }
        }

        if (sb.length() > 0) {
            tokens.add(sb.toString());
        }
        return tokens;
    }

I tried making fuctions which if character + is followed with negative number it whould also get priority, but I was unable to do it.

As I said previesly I want it to get priority of -, when () are removed so for example this math problem whould solve like this.

4 + 1 - 3 / 2 + 3 * 5 + (-5)
4 + -2/2 + 3 * 5 - 5
4 - 1 + 3 * 0
3

Rathen then currently whould whould be calculated like this

4 + 1 - 3 / 2 + 3 * 5 + (-5) 
4 + -2/2 + 3 * 5 + -5
4 - 1 + 3 * 5 + -5
3 + 15 + -5
13
0

There are 0 best solutions below