/* Abstract syntax trees for online calculator - Visitor Pattern Version. You should read chapter 4 of the compiler text for an introduction or review of the Visitor design pattern. However, the version I'm writing belong uses parametric types, which were not available when your text book was written. That's why the code that the textbook provides have two visitors : one that returns void and one that returns an arbitrary "Type". But parametric types (generics) clearly offer a better solution. */ interface Exp // interface for visitees { public R accept(Expvisitor v); } interface Expvisitor // interface for visitors that return type T { public T visit(dlit d); public T visit(plusexp e); public T visit(minusexp e); public T visit(multexp e); public T visit(divexp e); public T visit(negexp e); } class dlit implements Exp // class for simple double expressions { double value; public dlit(double x) {value=x;} public R accept(Expvisitor v) { return v.visit(this); } } class opexp // superclass for all binary operator expressions { Exp left, right; // left and right subtrees public opexp(Exp l, Exp r) {left=l; right=r;} } class plusexp extends opexp implements Exp { public plusexp(Exp l, Exp r) { super(l,r); } public R accept(Expvisitor v) { return v.visit(this); } } class minusexp extends opexp implements Exp { public minusexp(Exp l, Exp r) { super(l,r); } public R accept(Expvisitor v) { return v.visit(this); } } class multexp extends opexp implements Exp { public multexp(Exp l, Exp r) { super(l,r); } public R accept(Expvisitor v) { return v.visit(this); } } class divexp extends opexp implements Exp { public divexp(Exp l, Exp r) { super(l,r); } public R accept(Expvisitor v) { return v.visit(this); } } class negexp implements Exp // negative values { Exp sub; // subexpression public negexp(Exp s) { sub=s; } public R accept(Expvisitor v) { return v.visit(this); } } //////////////////////////// // Concrete visitors: //////////////////////////// // The eval operation is just a visitor that returns doubles class evaluator implements Expvisitor { public Double visit(dlit d) { return d.value; } public Double visit(plusexp e) { return e.left.accept(this) + e.right.accept(this); } public Double visit(minusexp e) { return e.left.accept(this) - e.right.accept(this); } public Double visit(multexp e) { return e.left.accept(this) * e.right.accept(this); } public Double visit(divexp e) { return e.left.accept(this) / e.right.accept(this); } public Double visit(negexp e) { return -1 * e.sub.accept(this); } } // evaluation visitor /// The following visitor transforms the expression to prefix (scheme) syntax class schemer implements Expvisitor { // utility method: private String format(String op, String a, String b) { return "("+op+" "+a+" "+b+")"; } public String visit(dlit d) { return d.value+""; } public String visit(plusexp e) { return format("+",e.left.accept(this), e.right.accept(this)); } public String visit(minusexp e) { return format("-",e.left.accept(this), e.right.accept(this)); } public String visit(multexp e) { return format("*",e.left.accept(this), e.right.accept(this)); } public String visit(divexp e) { return format("/",e.left.accept(this), e.right.accept(this)); } public String visit(negexp e) { return "(- "+e.sub.accept(this)+")"; } } ////////////////////////// // interface public class calcvp { public static void main(String[] args) throws Exception { parser P = new parser(); System.out.print("Enter expression: "); Exp E = (Exp)P.parse().value; String S = E.accept(new schemer()); System.out.println("in scheme syntax: "+S); double v = E.accept(new evaluator()); System.out.println("value is "+v); } } /* This program requires the following minor modifications of the grammar file: The start symbol's (Line) smantic action should just be: RESULT = v1; That is, the act of invoking the visitors is nolonger up to the parser. The rule for division should just be {: RESULT = new divexp(v1,v2); :} This means that error checking will be moved from the parsing stage to a latter stage. */