Interpreter Pattern: Calculator
/*
Software Architecture Design Patterns in Java
by Partha Kuchana
Auerbach Publications
*/
import java.util.HashMap;
import java.util.Stack;
public class Calculator {
private String expression;
private HashMap operators;
private Context ctx;
public static void main(String[] args) {
Calculator calc = new Calculator();
//instantiate the context
Context ctx = new Context();
//set the expression to evaluate
calc.setExpression("(a+b)*(c-d)");
//configure the calculator with the
// Context
calc.setContext(ctx);
//Display the result
System.out.println(" Variable Values: " + "a=" + ctx.getValue("a")
+ ", b=" + ctx.getValue("b") + ", c=" + ctx.getValue("c")
+ ", d=" + ctx.getValue("d"));
System.out.println(" Expression = (a+b)*(c-d)");
System.out.println(" Result = " + calc.evaluate());
}
public Calculator() {
operators = new HashMap();
operators.put("+", "1");
operators.put("-", "1");
operators.put("/", "2");
operators.put("*", "2");
operators.put("(", "0");
}
public void setContext(Context c) {
ctx = c;
}
public void setExpression(String expr) {
expression = expr;
}
public int evaluate() {
//infix to Postfix
String pfExpr = infixToPostFix(expression);
//build the Binary Tree
Expression rootNode = buildTree(pfExpr);
//Evaluate the tree
return rootNode.evaluate(ctx);
}
private NonTerminalExpression getNonTerminalExpression(String operation,
Expression l, Expression r) {
if (operation.trim().equals("+")) {
return new AddExpression(l, r);
}
if (operation.trim().equals("-")) {
return new SubtractExpression(l, r);
}
if (operation.trim().equals("*")) {
return new MultiplyExpression(l, r);
}
return null;
}
private Expression buildTree(String expr) {
Stack s = new Stack();
for (int i = 0; i < expr.length(); i++) {
String currChar = expr.substring(i, i + 1);
if (isOperator(currChar) == false) {
Expression e = new TerminalExpression(currChar);
s.push(e);
} else {
Expression r = (Expression) s.pop();
Expression l = (Expression) s.pop();
Expression n = getNonTerminalExpression(currChar, l, r);
s.push(n);
}
}//for
return (Expression) s.pop();
}
private String infixToPostFix(String str) {
Stack s = new Stack();
String pfExpr = "";
String tempStr = "";
String expr = str.trim();
for (int i = 0; i < str.length(); i++) {
String currChar = str.substring(i, i + 1);
if ((isOperator(currChar) == false) && (!currChar.equals("("))
&& (!currChar.equals(")"))) {
pfExpr = pfExpr + currChar;
}
if (currChar.equals("(")) {
s.push(currChar);
}
//for ')' pop all stack contents until '('
if (currChar.equals(")")) {
tempStr = (String) s.pop();
while (!tempStr.equals("(")) {
pfExpr = pfExpr + tempStr;
tempStr = (String) s.pop();
}
tempStr = "";
}
//if the current character is an
// operator
if (isOperator(currChar)) {
if (s.isEmpty() == false) {
tempStr = (String) s.pop();
String strVal1 = (String) operators.get(tempStr);
int val1 = new Integer(strVal1).intValue();
String strVal2 = (String) operators.get(currChar);
int val2 = new Integer(strVal2).intValue();
while ((val1 >= val2)) {
pfExpr = pfExpr + tempStr;
val1 = -100;
if (s.isEmpty() == false) {
tempStr = (String) s.pop();
strVal1 = (String) operators.get(tempStr);
val1 = new Integer(strVal1).intValue();
}
}
if ((val1 < val2) && (val1 != -100))
s.push(tempStr);
}
s.push(currChar);
}//if
}// for
while (s.isEmpty() == false) {
tempStr = (String) s.pop();
pfExpr = pfExpr + tempStr;
}
return pfExpr;
}
private boolean isOperator(String str) {
if ((str.equals("+")) || (str.equals("-")) || (str.equals("*"))
|| (str.equals("/")))
return true;
return false;
}
} // End of class
class Context {
private HashMap varList = new HashMap();
public void assign(String var, int value) {
varList.put(var, new Integer(value));
}
public int getValue(String var) {
Integer objInt = (Integer) varList.get(var);
return objInt.intValue();
}
public Context() {
initialize();
}
//Values are hardcoded to keep the example simple
private void initialize() {
assign("a", 20);
assign("b", 40);
assign("c", 30);
assign("d", 10);
}
}
class TerminalExpression implements Expression {
private String var;
public TerminalExpression(String v) {
var = v;
}
public int evaluate(Context c) {
return c.getValue(var);
}
}
interface Expression {
public int evaluate(Context c);
}
abstract class NonTerminalExpression implements Expression {
private Expression leftNode;
private Expression rightNode;
public NonTerminalExpression(Expression l, Expression r) {
setLeftNode(l);
setRightNode(r);
}
public void setLeftNode(Expression node) {
leftNode = node;
}
public void setRightNode(Expression node) {
rightNode = node;
}
public Expression getLeftNode() {
return leftNode;
}
public Expression getRightNode() {
return rightNode;
}
}// NonTerminalExpression
class AddExpression extends NonTerminalExpression {
public int evaluate(Context c) {
return getLeftNode().evaluate(c) + getRightNode().evaluate(c);
}
public AddExpression(Expression l, Expression r) {
super(l, r);
}
}// AddExpression
class SubtractExpression extends NonTerminalExpression {
public int evaluate(Context c) {
return getLeftNode().evaluate(c) - getRightNode().evaluate(c);
}
public SubtractExpression(Expression l, Expression r) {
super(l, r);
}
}// SubtractExpression
class MultiplyExpression extends NonTerminalExpression {
public int evaluate(Context c) {
return getLeftNode().evaluate(c) * getRightNode().evaluate(c);
}
public MultiplyExpression(Expression l, Expression r) {
super(l, r);
}
}// MultiplyExpression
//File: Interprepter.properties
/*
a=10
b=20
c=30
d=40
*/
Related examples in the same category