001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
|
package algs13;
import stdlib.*;
import java.util.TreeMap;
/* ***********************************************************************
* Compilation: javac EvaluateDeluxe.java
* Execution: java EvaluateDeluxe
* Dependencies: Stack.java
*
* Evaluates arithmetic expressions using Dijkstra's two-stack algorithm.
* Handles the following binary operators: +, -, *, / and parentheses.
*
* % echo "3 + 5 * 6 - 7 * ( 8 + 5 )" | java EvaluateDeluxe
* -58.0
*
*
* Limitiations
* --------------
* - can easily add additional operators and precedence orders, but they
* must be left associative (exponentiation is right associative)
* - assumes whitespace between operators (including parentheses)
*
* Remarks
* --------------
* - can eliminate second phase if we enclose input expression
* in parentheses (and, then, could also remove the test
* for whether the operator stack is empty in the inner while loop)
* - see http://introcs.cs.princeton.edu/java/11precedence/ for
* operator precedence in Java
*
*************************************************************************/
public class XEvaluateDeluxe {
// result of applying binary operator op to two operands val1 and val2
public static double eval(String op, double val1, double val2) {
if (op.equals("+")) return val1 + val2;
if (op.equals("-")) return val1 - val2;
if (op.equals("/")) return val1 / val2;
if (op.equals("*")) return val1 * val2;
throw new Error("Invalid operator");
}
public static void main(String[] args) {
StdIn.fromString ("1 + 2 + 3");
// precedence order of operators
TreeMap<String, Integer> precedence = new TreeMap<>();
precedence.put("(", 0); // for convenience with algorithm
precedence.put(")", 0);
precedence.put("+", 1); // + and - have lower precedence than * and /
precedence.put("-", 1);
precedence.put("*", 2);
precedence.put("/", 2);
Stack<String> ops = new Stack<>();
Stack<Double> vals = new Stack<>();
while (!StdIn.isEmpty()) {
// read in next token (operator or value)
String s = StdIn.readString();
// token is a value
if (!precedence.containsKey(s)) {
vals.push(Double.parseDouble(s));
continue;
}
// token is an operator
while (true) {
// the last condition ensures that the operator with higher precedence is evaluated first
if (ops.isEmpty() || s.equals("(") || (precedence.get(s) > precedence.get(ops.peek()))) {
ops.push(s);
break;
}
// evaluate expression
String op = ops.pop();
// but ignore left parentheses
if (op.equals("(")) {
if (!s.equals(")")) throw new Error ();
break;
}
// evaluate operator and two operands and push result onto value stack
else {
double val2 = vals.pop();
double val1 = vals.pop();
vals.push(eval(op, val1, val2));
}
}
}
// finished parsing string - evaluate operator and operands remaining on two stacks
while (!ops.isEmpty()) {
String op = ops.pop();
double val2 = vals.pop();
double val1 = vals.pop();
vals.push(eval(op, val1, val2));
}
// last value on stack is value of expression
StdOut.println(vals.pop());
if (!vals.isEmpty()) throw new Error ();
if (!ops.isEmpty()) throw new Error ();
}
}
|