// Abstract syntax for the language Jay, based on Tucker and Noonan Appendix B. // // One change I made in existing code was to use Java Generics, replacing plain // Vector with more specific types Vector and Vector. // (As an aside, Vector is very nearly the same as ArrayList.) // // I also fixed the buggy equals and hashCode methods that Tucker and Noonan // had in the Variable class. // // I also removed a comment from the Conditional class which expressed a // design decision that I disagree with. (If an "if" statement has no // "else" part, I do not think it is wise to use null for the missing // statement; instead, a Skip statement can be use, which will allow // the AST to be more consistently processed, without a special case. // // Finally, I added two methods to the various classes: toStringIndented and // toString. The goal of these methods is to allow creation of a // nice printed representation of an AST, in which each subtree is // indented a couple more spaces than its parent. Normally code // outside of this file will only make use of toString; the toStringIndented // methods are essentially helpers for toString. // // There are plenty of other improvements you could make if you want. import java.util.Vector; class Program { // Program = Declarations decpart ; Block body Declarations decpart; Block body; public String toStringIndented(String indent){ return indent + "Program(\n" + decpart.toStringIndented(indent + " ") + ",\n" + body.toStringIndented(indent + " ") + "\n" + indent + ")"; } public String toString(){ return toStringIndented(""); } } class Declarations extends Vector { // Declarations = Declaration * // (a Vector of declarations d1, d2, ..., dn) public String toString(){ return toStringIndented(""); } public String toStringIndented(String indent){ StringBuffer sb = new StringBuffer(); sb.append(indent); sb.append("Declarations(\n"); int i = 0; for(Declaration d : this){ sb.append(d.toStringIndented(indent + " ")); i++; if(i == size()) sb.append("\n"); else sb.append(",\n"); } sb.append(indent); sb.append(")"); return sb.toString(); } } class Declaration { // Declaration = Variable v; Type t Variable v; Type t; public String toString(){ return toStringIndented(""); } public String toStringIndented(String indent){ return indent + "Declaration(" + v + ", " + t + ")"; } } class Type { // Type = int | boolean | undefined final static String INTEGER = "int"; final static String BOOLEAN = "boolean"; final static String UNDEFINED = "undef"; String id; Type (String t) { id = t; } public boolean isBoolean ( ) { return id.equals(BOOLEAN); } public boolean isInteger ( ) { return id.equals(INTEGER); } public boolean isUndefined ( ) { return id.equals(UNDEFINED); } public String toString(){ return toStringIndented(""); } public String toStringIndented(String indent){ return indent + "Type(" + id + ")"; } } abstract class Statement { // Statement = Skip | Block | Assignment | Conditional | Loop public String toString(){ return toStringIndented(""); } abstract public String toStringIndented(String indent); } class Skip extends Statement { public String toStringIndented(String indent){ return indent + "Skip()"; } } class Block extends Statement { // Block = Statement * // (a Vector of members) public Vector members = new Vector(); public String toStringIndented(String indent){ StringBuffer sb = new StringBuffer(); sb.append(indent); sb.append("Block(\n"); int i = 0; for(Statement s : members){ sb.append(s.toStringIndented(indent + " ")); i++; if(i == members.size()) sb.append("\n"); else sb.append(",\n"); } sb.append(indent); sb.append(")"); return sb.toString(); } } class Assignment extends Statement { // Assignment = Variable target; Expression source Variable target; Expression source; public String toStringIndented(String indent){ return indent + "Assignment(" + target + ",\n" + source.toStringIndented(indent + " ") + "\n" + indent + ")"; } } class Conditional extends Statement { // Conditional = Expression test; Statement thenbranch, elsebranch Expression test; Statement thenbranch, elsebranch; public String toStringIndented(String indent){ return indent + "Conditional(\n" + test.toStringIndented(indent + " ") + ",\n" + thenbranch.toStringIndented(indent + " ") + ",\n" + elsebranch.toStringIndented(indent + " ") + "\n" + indent + ")"; } } class Loop extends Statement { // Loop = Expression test; Statement body Expression test; Statement body; public String toStringIndented(String indent){ return indent + "Loop(\n" + test.toStringIndented(indent + " ") + ",\n" + body.toStringIndented(indent + " ") + "\n" + indent + ")"; } } abstract class Expression { // Expression = Variable | Value | Binary | Unary public String toString(){ return toStringIndented(""); } abstract public String toStringIndented(String indent); } class Variable extends Expression { // Variable = String id String id; public boolean equals (Object obj) { if(obj instanceof Variable){ String s = ((Variable) obj).id; return id.equalsIgnoreCase(s); // case-insensitive identifiers } else { return false; } } public int hashCode ( ) { return id.toLowerCase().hashCode( ); } public String toStringIndented(String indent){ return indent + "Variable(" + id + ")"; } } class Value extends Expression { // Value = int intValue | boolean boolValue Type type; int intValue; boolean boolValue; Value (int i) { type = new Type(Type.INTEGER); intValue = i; } Value (boolean b) { type = new Type(Type.BOOLEAN); boolValue = b; } Value ( ) { type = new Type(Type.UNDEFINED); } public String toStringIndented(String indent){ return indent + "Value(" + (type.isUndefined() ? "" : (type.isBoolean() ? ""+boolValue : ""+intValue)) + ")"; } } class Binary extends Expression { // Binary = Operator op; Expression term1, term2 Operator op; Expression term1, term2; public String toStringIndented(String indent){ return indent + "Binary(" + op + "\n" + term1.toStringIndented(indent + " ") + ",\n" + term2.toStringIndented(indent + " ") + "\n" + indent + ")"; } } class Unary extends Expression { // Unary = Operator op; Expression term Operator op; Expression term; public String toStringIndented(String indent){ return indent + "Unary(" + op + "\n" + term.toStringIndented(indent + " ") + "\n" + indent + ")"; } } class Operator { // Operator = BooleanOp | RelationalOp | ArithmeticOp | UnaryOp // BooleanOp = && | || final static String AND = "&&"; final static String OR = "||"; // RelationalOp = < | <= | == | != | >= | > final static String LT = "<"; final static String LE = "<="; final static String EQ = "=="; final static String NE = "!="; final static String GT = ">"; final static String GE = ">="; // ArithmeticOp = + | - | * | / final static String PLUS = "+"; final static String MINUS = "-"; final static String TIMES = "*"; final static String DIV = "/"; // UnaryOp = ! final static String NOT = "!"; String val; Operator (String s) { val = s; } boolean BooleanOp ( ) { return val.equals(AND) || val.equals(OR); } boolean RelationalOp ( ) { return val.equals(LT) || val.equals(LE) || val.equals(EQ) || val.equals(NE) || val.equals(GT) || val.equals(GE); } boolean ArithmeticOp ( ) { return val.equals(PLUS) || val.equals(MINUS) || val.equals(TIMES) || val.equals(DIV); } boolean UnaryOp ( ) { return val.equals(NOT); } public String toString(){ return toStringIndented(""); } public String toStringIndented(String indent){ return indent + "Operator(" + val + ")"; } }