This repository has been archived on 2026-01-13. You can view files and clone it, but cannot push or open issues or pull requests.
jcal/Parser.java

155 lines
4.4 KiB
Java

/* Todo
* - Fix this:
* when expression = 5+10*(10), it misses +
* - Add support for trigonometric functions
* - Remove all edge cases
*/
import java.util.Stack;
import java.util.StringJoiner;
public class Parser {
private String expr;
private Stack<Character> operatorStack;
public Parser(String infixExpr) {
expr = infixExpr.trim().replaceAll("\\s", ""); // remove whitespaces
}
public static boolean isOperand(char c) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return true;
default:
return false;
}
}
public static boolean isOperand(String c) {
return isOperand(c.charAt(0));
}
public int getPresedence(char c) {
switch (c) {
case '^':
return 3;
case '/':
return 2;
case '*':
return 2;
case '+':
return 1;
case '-':
return 1;
default:
return -1;
}
}
public boolean hasLeftAssociativity(char c) {
if (c == '^') {
return false;
} else {
return true;
}
}
public String toPostFix() {
operatorStack = new Stack<>();
StringJoiner output = new StringJoiner(" ");
StringBuilder operand = new StringBuilder();
char[] infix = expr.replaceAll(" ", "").toCharArray();
// Main Expression Iteration
for (int i = 0; i < infix.length; i++) {
char c = infix[i];
// Keep appending digits to the operand StringBuilder and skip iterations till
// we find a operator.
if (isOperand(c)) {
operand.append(infix[i]);
if (i < infix.length - 1) {
continue;
}
}
if (operand.length() > 0) {
output.add(operand.toString());
operand = new StringBuilder();
}
if (c == '(') {
operatorStack.push(c);
} else if (c == ')') {
while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
output.add(operatorStack.pop().toString());
}
operatorStack.pop();
} else {
// Manage precedence order of operatorStack operators
while (!operatorStack.isEmpty() && getPresedence(c) <= getPresedence((char) operatorStack.peek())
&& hasLeftAssociativity(c)) {
output.add(operatorStack.pop().toString());
}
// For whatever reason, the last digit gets added to the operatorStack, leading
// to a duplicate of last digit in the expression
// To fix this, we again make sure that the current char is not a operand.
if (!isOperand(c)) {
operatorStack.push(c);
}
}
}
// pop all the operators left in the operatorStack after the loop is done.
while (!operatorStack.isEmpty()) {
if (operatorStack.peek() == '(') {
return "This expression is invalid";
}
output.add(operatorStack.pop().toString());
}
return output.toString();
}
private Double evaluate(String operator, Double op1, Double op2) {
switch (operator.charAt(0)) {
case '+':
return op2 + op1;
case '-':
return op1 - op2;
case '*':
return op2 * op1;
case '/':
return op1 / op2;
case '^':
return (Math.pow(op2, op1));
default:
return 0.0;
}
}
public double evalExpr(String postfix) {
Stack<Double> stack = new Stack<Double>();
for (String c : postfix.split(" ")) {
if (isOperand(c)) {
stack.push(Double.parseDouble(c));
} else {
Double op1 = (Double) (stack.pop());
Double op2 = (Double) (stack.pop());
stack.push(evaluate(c, op2, op1));
}
}
return stack.pop();
}
}