/** class Expr, our internal representation of an expression * in the L0 language. * See http://www.radford.edu/itec380/2008fall/Hw06/hw06.html * * @author Ian Barland * @version 2008.Nov.30 */ public abstract class Expr { /** Return (our internal representation of) the expression s. * @param s The source code for exactly one Expr. Must by syntactically correct. * @return (our internal representation of) the expression s. */ public static Expr parse(String s) { return Expr.parse(new java.util.Scanner(s)); } /** Return (our internal representation of) the expression s. * @param s A scanner reading the source code for exactly one Expr. * Must by syntactically correct. * @return (our internal representation of) the expression s. */ public static Expr parse(java.util.Scanner s) { final String PUNCTUATION = "{}"; if (UtilIan.hasNextDoubleSplittingBy(s,PUNCTUATION)) { return new Num( UtilIan.nextDoubleSplittingBy(s,PUNCTUATION) ); } else { assert UtilIan.hasNextChar(s,'{') : "Expected a '{' to start an Expr"; UtilIan.nextChar(s,'{'); // Consume the opening "{" and continue. Expr theNewExpr; if (UtilIan.hasNextSplittingBy(s, Sum.TOKEN, PUNCTUATION)) { UtilIan.nextSplittingBy(s,PUNCTUATION); // Consume next token, stopping on "{" or "}" (if any). theNewExpr = new Sum( parse(s), parse(s) ); } else if (UtilIan.hasNextSplittingBy(s, Prod.TOKEN, PUNCTUATION)) { UtilIan.nextSplittingBy(s,PUNCTUATION); // Consume next token, stopping "{" or "}" (if any). theNewExpr = new Prod( parse(s), parse(s) ); } else if (UtilIan.hasNextSplittingBy(s, IfZero.TOKEN, PUNCTUATION)) { UtilIan.nextSplittingBy(s, PUNCTUATION); // Consume next token, stopping "{" or "}" (if any). theNewExpr = new IfZero( parse(s), parse(s), parse(s) ); } else { /* Unknown syntax! */ String tokens = ""; while (s.hasNext()) { tokens += s.next(); } throw new IllegalArgumentException( "Couldn't parse " + tokens ); } assert UtilIan.hasNextChar(s,'}') : "Expected a '}' to finish the Expr " + theNewExpr.toString(); UtilIan.nextChar(s,'}'); // Consume the trailing '}'. return theNewExpr; } } /** Evaluate a given Expr. * @return the Value this Expr evaluates to. * (In L0, all values are numbers (doubles), but * in L3 that will change, which is why we have * pre-emptively made the return type 'Value'.) */ abstract public Value eval(); /** Return a String representation of this Expr. * The result will be something which can be * passed into 'parse(String)' to get the same * Expr back. That is, toString and parse are * inverses of each other. * @return a String representation of this Expr. */ abstract public String toString(); }