Krolyxon
Commit d134acd

Branches

Refs →

jcalParser.java

154 lines · 4.4 KB · Java

1/* Todo
2* - Fix this:
3* when expression = 5+10*(10), it misses +
4* - Add support for trigonometric functions
5* - Remove all edge cases
6*/
7
8import java.util.Stack;
9import java.util.StringJoiner;
10
11public class Parser {
12 private String expr;
13 private Stack<Character> operatorStack;
14
15 public Parser(String infixExpr) {
16 expr = infixExpr.trim().replaceAll("\\s", ""); // remove whitespaces
17 }
18
19 public static boolean isOperand(char c) {
20 switch (c) {
21 case '0':
22 case '1':
23 case '2':
24 case '3':
25 case '4':
26 case '5':
27 case '6':
28 case '7':
29 case '8':
30 case '9':
31 return true;
32 default:
33 return false;
34 }
35 }
36
37 public static boolean isOperand(String c) {
38 return isOperand(c.charAt(0));
39 }
40
41 public int getPresedence(char c) {
42 switch (c) {
43 case '^':
44 return 3;
45 case '/':
46 return 2;
47 case '*':
48 return 2;
49 case '+':
50 return 1;
51 case '-':
52 return 1;
53 default:
54 return -1;
55 }
56 }
57
58 public boolean hasLeftAssociativity(char c) {
59 if (c == '^') {
60 return false;
61 } else {
62 return true;
63 }
64 }
65
66 public String toPostFix() {
67 operatorStack = new Stack<>();
68 StringJoiner output = new StringJoiner(" ");
69 StringBuilder operand = new StringBuilder();
70 char[] infix = expr.replaceAll(" ", "").toCharArray();
71
72 // Main Expression Iteration
73 for (int i = 0; i < infix.length; i++) {
74 char c = infix[i];
75
76 // Keep appending digits to the operand StringBuilder and skip iterations till
77 // we find a operator.
78 if (isOperand(c)) {
79 operand.append(infix[i]);
80 if (i < infix.length - 1) {
81 continue;
82 }
83 }
84
85 if (operand.length() > 0) {
86 output.add(operand.toString());
87 operand = new StringBuilder();
88 }
89
90 if (c == '(') {
91 operatorStack.push(c);
92 } else if (c == ')') {
93 while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
94 output.add(operatorStack.pop().toString());
95 }
96 operatorStack.pop();
97 } else {
98 // Manage precedence order of operatorStack operators
99 while (!operatorStack.isEmpty() && getPresedence(c) <= getPresedence((char) operatorStack.peek())
100 && hasLeftAssociativity(c)) {
101 output.add(operatorStack.pop().toString());
102 }
103
104 // For whatever reason, the last digit gets added to the operatorStack, leading
105 // to a duplicate of last digit in the expression
106 // To fix this, we again make sure that the current char is not a operand.
107 if (!isOperand(c)) {
108 operatorStack.push(c);
109 }
110 }
111 }
112
113 // pop all the operators left in the operatorStack after the loop is done.
114 while (!operatorStack.isEmpty()) {
115 if (operatorStack.peek() == '(') {
116 return "This expression is invalid";
117 }
118 output.add(operatorStack.pop().toString());
119 }
120
121 return output.toString();
122 }
123
124 private Double evaluate(String operator, Double op1, Double op2) {
125 switch (operator.charAt(0)) {
126 case '+':
127 return op2 + op1;
128 case '-':
129 return op1 - op2;
130 case '*':
131 return op2 * op1;
132 case '/':
133 return op1 / op2;
134 case '^':
135 return (Math.pow(op2, op1));
136 default:
137 return 0.0;
138 }
139 }
140
141 public double evalExpr(String postfix) {
142 Stack<Double> stack = new Stack<Double>();
143 for (String c : postfix.split(" ")) {
144 if (isOperand(c)) {
145 stack.push(Double.parseDouble(c));
146 } else {
147 Double op1 = (Double) (stack.pop());
148 Double op2 = (Double) (stack.pop());
149 stack.push(evaluate(c, op2, op1));
150 }
151 }
152 return stack.pop();
153 }
154}