Проблема с приоритизацией операций и скобками при вычислении мат. выражения
Пытаюсь создать парсер математических формул на Джаве.
Но возникли 2 проблемы - мой код неправильно вычисляет сложные выражения.
Прошу помочь с нахождением решения следующих 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;
}
}