Проблема с приоритизацией операций и скобками при вычислении мат. выражения

Пытаюсь создать парсер математических формул на Джаве.

Но возникли 2 проблемы - мой код неправильно вычисляет сложные выражения.

Прошу помочь с нахождением решения следующих 2 проблем:

  1. Как добавить приоритизацию по мат.операциям (например, чтобы сначала выполнялось умножение, а потом вычитание и т.п.),
  2. Как в существующем коде сделать проверку по скобкам -- если пользователь ввел в выражении много скобок,-- чтобы это тоже влияло на приоритизацию вычислений.

Код на данный момент:

package com.javacourse;
    
import java.util.Scanner;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
    
public class Task20 {
    
    private static Map<String, String> variables = new HashMap<>();
    private static ArrayList<Lexem> tokens = new ArrayList<>();
    
    public static void main(String[] args) {
        Scanner sc;
        String expr;
        sc = new Scanner(System.in);
        System.out.println("Formula to be calculated: ");
        expr = sc.nextLine();
        tokeniser(expr);
        System.out.println(evaluateFormula());
    }
    
    private enum Expressions { 
        EOT, LEFT_BRACKET, RIGHT_BRACKET, VAR, NUM, MULT, DIV, MNS, PLS, RISE;
    }
    
    static class Lexem {
        Expressions type; String name; String val;
    
        Lexem (Expressions type, String name, String value) {
            this.val = value; this.type = type; this.name = name;
        }
    }
    
    private static void tokeniser(String expr) {
        int pos = 0; int newPos = 0;
    
        while (pos < expr.length()) {
            char character = expr.charAt(pos);
    
            switch (character) {
            case '+':
                tokens.add(new Lexem(Expressions.PLS, "",  ""));
                pos++;
                break;
            case '(':
                tokens.add(new Lexem(Expressions.LBR, "",  ""));
                pos++;
                break;
            case ')':
                tokens.add(new Lexem(Expressions.RBR, "",  ""));
                pos++;
                break;
            case '/':
                tokens.add(new Lexem(Expressions.DIV, "",  ""));
                pos++;
                break;
            case '*':
                tokens.add(new Lexem(Expressions.MULT, "",  ""));
                pos++;
                break;
            case '-':
                tokens.add(new Lexem(Expressions.MNS, "",  ""));
                pos++;
                break;
            case '^':
                tokens.add(new Lexem(Expressions.RISE, "",  ""));
                pos++;
                break;
            case ' ':
                pos++;
                break;
            default:
                if (character >= '0' && character <= '9') {
                    StringBuilder number = new StringBuilder();
    
                    while (character >= '0' && character <= '9') {
                        number.append(character);
    
                        pos++;
                        if ((pos + 1) >= expr.length()) {
                            break;
                        }
                        character = expr.charAt(pos);
    
                        if ((character <= '0' || character >= '9')) {
                            pos--;
                            break;
                        }
                    }
                    tokens.add(new Lexem(Expressions.NUM,  "", number.toString()));
                    pos++;
                } else if (character <= 'z' && character >= 'a') {
                    if (variables.containsKey("" + character) && pos == expr.lastIndexOf(character) ) {
                        newPos = expr.lastIndexOf(character, pos + 1);

                        char newcharacteraracter = ' ';
                        int i = 1;
                        while ((newPos + i) < expr.length()) {
                            newcharacteraracter = expr.charAt(newPos+ i);
    
                            if (newcharacteraracter == ' ' || newcharacteraracter == '=') {
                                i++;
                            } else if (newcharacteraracter >= '0' && newcharacteraracter <= '9') {

                                StringBuilder value = new StringBuilder();
                                pos = newPos + i;
                                newcharacteraracter = expr.charAt(pos);
    
                                while(newcharacteraracter <= '9' && newcharacteraracter >= '0') {
                                    value.append(newcharacteraracter);
    
                                    if ((pos + 1) < expr.length()) {
                                        pos++;
                                        newcharacteraracter = expr.charAt(pos);
                                    } else {
                                        break;
                                    }
                                }
    

                                for (int j = 0; j < tokens.size(); j++) {
    
                                    if (tokens.get(j).type == Expressions.VAR && tokens.get(j).val == null) {
    
                                        if (("" + character).equals(tokens.get(j).name)) {
                                            tokens.get(j).val = value.toString();
                                        }
                                    }
                                }
                                pos++;
                                break;
                            }
                        }
                    } else {
                        variables.put("" + character, "");
                        tokens.add(new Lexem(Expressions.VAR, "" + character, null));
                        pos++;
                    }
                }
            }
        }
        tokens.add(new Lexem(Expressions.EOT, "", ""));
    }
    
    private static double evaluateFormula() {
        double res = 0;
    
        int i = 0;
        while (i < tokens.size()) {
            switch (tokens.get(i).type) {
            case MNS:
                if ((i + 1) < tokens.size()) {
                    res -= Double.parseDouble(tokens.get(i + 1).val);
                }
                i++;
                i++;
                break;
            case DIV:
                if ((i + 1) < tokens.size()) {
                    res /= Double.parseDouble(tokens.get(i + 1).val);
                }
                i++;
                i++;
                break;
            case RISE:
                if ((i + 1) < tokens.size()) {
                    res = Math.pow(res, Double.parseDouble(tokens.get(i + 1).val));
                }
                i++;
                i++;
                break;
            case NUM:
                res = Double.parseDouble(tokens.get(i).val);
                i++;
                break;
            case MULT:
                if ((i + 1) < tokens.size()) {
                    res *= Double.parseDouble(tokens.get(i + 1).val);
                }
                i++;
                i++;
                break;
            case PLS:
                if ((i + 1) < tokens.size()) {
                    res += Double.parseDouble(tokens.get(i + 1).val);
                }
                i++;
                i++;
                break;
            case VAR:
                res = Double.parseDouble(tokens.get(i).val);
                i++;
            case LEFT_BRACKET: ...............................................
            //case RIGHT_BRACKET: ...............................................
            case EOT:
                i++;
                break;
            }
        }
    
        return res;
    }
}

Ответы (0 шт):