import java.io.*; import java.util.*; // ********************************************************************** // The ASTnode class defines the nodes of the abstract-syntax tree that // represents a C-- program. // // Internal nodes of the tree contain pointers to children, organized // either in a sequence (for nodes that may have a variable number of children) // or as a fixed set of fields. // // The nodes for literals and ids contain line and character number // information; for string literals and identifiers, they also contain a // string; for integer literals, they also contain an integer value. // // Here are all the different kinds of AST nodes and what kinds of children // they have. All of these kinds of AST nodes are subclasses of "ASTnode". // Indentation indicates further subclassing: // // Subclass Kids // -------- ---- // ProgramNode DeclListNode // DeclListNode linked list of DeclNode // DeclNode: // VarDeclNode TypeNode, IdNode, int // FnDeclNode TypeNode, IdNode, FormalsListNode, FnBodyNode // FormalDeclNode TypeNode, IdNode // // FormalsListNode linked list of FormalDeclNode // FnBodyNode DeclListNode, StmtListNode // StmtListNode linked list of StmtNode // ExpListNode linked list of ExpNode // // TypeNode: // IntNode -- none -- // BoolNode -- none -- // VoidNode -- none -- // // StmtNode: // ReadStmtNode ExpNode // WriteStmtNode ExpNode // AssignStmtNode ExpNode, ExpNode // IfStmtNode ExpNode, DeclListNode, StmtListNode // IfElseStmtNode ExpNode, DeclListNode, StmtListNode, // DeclListNode, StmtListNode // WhileStmtNode ExpNode, DeclListNode, StmtListNode // CallStmtNode CallExpNode // ReturnStmtNode ExpNode // // ExpNode: // IntLitNode -- none -- // StrLitNode -- none -- // TrueNode -- none -- // FalseNode -- none -- // IdNode -- none -- // ArrayExpNode IdNode, ExpNode // CallExpNode IdNode, ExpListNode // UnaryExpNode ExpNode // UnaryMinusNode // NotNode // BinaryExpNode ExpNode ExpNode // ArithmeticExpNode // PlusNode // MinusNode // TimesNode // DivideNode // LogicalExpNode // AndNode // OrNode // EqualityExpNode // EqualsNode // NotEqualsNode // RelationalExpNode // LessNode // GreaterNode // LessEqNode // GreaterEqNode // // Here are the different kinds of AST nodes again, organized according to // whether they are leaves, internal nodes with sequences of kids, or internal // nodes with a fixed number of kids: // // (1) Leaf nodes: // IntNode, BoolNode, VoidNode, IntLitNode, StrLitNode, // TrueNode, FalseNode, IdNode // // (2) Internal nodes with (possibly empty) linked lists of children: // DeclListNode, FormalsListNode, StmtListNode, ExpListNode // // (3) Internal nodes with fixed numbers of kids: // ProgramNode, VarDeclNode, FnDeclNode, FormalDeclNode, // FnBodyNode, TypeNode, ReadStmtNode, WriteStmtNode // AssignStmtNode, IfStmtNode, IfElseStmtNode, WhileStmtNode, // CallStmtNode, ReturnStmtNode, ArrayExpNode, CallExpNode, // UnaryExpNode, BinaryExpNode, ArithmeticExpNode, LogicalExpNode, // EqualityExpNode,RelationalExpNode,UnaryMinusNode, NotNode, // PlusNode, MinusNode, TimesNode, DivideNode, // AndNode, OrNode, EqualsNode, NotEqualsNode, // LessNode, GreaterNode, LessEqNode, GreaterEqNode, // // ********************************************************************** // ********************************************************************** // ASTnode class (base class for all other kinds of nodes) // ********************************************************************** abstract class ASTnode { // every subclass must provide an unparse operation abstract public void unparse(PrintWriter p, int indent); // this method can be used by the unparse methods to do indenting protected void doIndent(PrintWriter p, int indent) { for (int k=0; k> "); myExp.unparse(p,0); p.println(";"); } // 1 kid (actually can only be an IdNode or an ArrayExpNode) private ExpNode myExp; } class WriteStmtNode extends StmtNode { public WriteStmtNode(ExpNode exp) { myExp = exp; } /** typeCheck **/ public void typeCheck(Type retType) { Type T = myExp.typeCheck(); if (T.isFnType()) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Attempt to write a function"); } if (T.isArrayType()) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Attempt to write an array"); } } /** processNames **/ public void processNames(SymTab S) { myExp.processNames(S); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("cout << "); myExp.unparse(p,0); p.println(";"); } // 1 kid private ExpNode myExp; } class AssignStmtNode extends StmtNode { public AssignStmtNode(ExpNode lhs, ExpNode exp) { myLhs = lhs; myExp = exp; } /** typeCheck **/ public void typeCheck(Type retType) { Type T1 = myLhs.typeCheck(); Type T2 = myExp.typeCheck(); if (T1.isFnType() && T2.isFnType()) { Errors.fatal(myLhs.linenum(), myLhs.charnum(), "Function assignment"); } if (T1.isArrayType() && T2.isArrayType()) { Errors.fatal(myLhs.linenum(), myLhs.charnum(), "Array assignment"); } if (! T1.equals(T2) && ! T1.isErrorType() && ! T2.isErrorType()) { Errors.fatal(myLhs.linenum(), myLhs.charnum(), "Type mismatch"); } } /** processNames **/ public void processNames(SymTab S) { myLhs.processNames(S); myExp.processNames(S); } // ** unparse ** public void unparse(PrintWriter p, int indent) { myLhs.unparse(p, 0); p.print(" = "); myExp.unparse(p,0); p.println(";"); } // 2 kids private ExpNode myLhs; private ExpNode myExp; } class IfStmtNode extends StmtNode { public IfStmtNode(ExpNode exp, DeclListNode dlist, StmtListNode slist) { myDeclList = dlist; myExp = exp; myStmtList = slist; } /** typeCheck **/ public void typeCheck(Type retType) { Type T = myExp.typeCheck(); if (! T.isBoolType() && ! T.isErrorType()) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Non-bool expression used as an if condition"); } myStmtList.typeCheck(retType); } /** processNames * * process the condition, then enter scope; process decls & stmts; * exit scope * **/ public void processNames(SymTab S) { myExp.processNames(S); S.addHashtab(); myDeclList.processNames(S); myStmtList.processNames(S); try { S.removeHashtab(); } catch (EmptySymTabException ex) { System.err.println("unexpected EmptySymTabException in IfStmtNode.processNames"); System.exit(-1); } } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("if ("); myExp.unparse(p,0); p.println(") {"); if (myDeclList != null) myDeclList.unparse(p,indent+2); if (myStmtList != null) myStmtList.unparse(p,indent+2); doIndent(p, indent); p.println("}"); } // 3 kids private ExpNode myExp; private DeclListNode myDeclList; private StmtListNode myStmtList; } class IfElseStmtNode extends StmtNode { public IfElseStmtNode(ExpNode exp, DeclListNode dlist1, StmtListNode slist1, DeclListNode dlist2, StmtListNode slist2) { myExp = exp; myThenDeclList = dlist1; myThenStmtList = slist1; myElseDeclList = dlist2; myElseStmtList = slist2; } /** typeCheck **/ public void typeCheck(Type retType) { Type T = myExp.typeCheck(); if (! T.isBoolType() && ! T.isErrorType()) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Non-bool expression used as an if condition"); } myThenStmtList.typeCheck(retType); myElseStmtList.typeCheck(retType); } /** processNames * * process the condition, then enter scope; process decls & stmts * in "then" part; then exit scope; enter scope; process decls & * stmts in "else" part; exit scope * **/ public void processNames(SymTab S) { myExp.processNames(S); S.addHashtab(); myThenDeclList.processNames(S); myThenStmtList.processNames(S); try { S.removeHashtab(); } catch (EmptySymTabException ex) { System.err.println("unexpected EmptySymTabException in IfElseStmtNode.processNames"); System.exit(-1); } S.addHashtab(); myElseDeclList.processNames(S); myElseStmtList.processNames(S); try { S.removeHashtab(); } catch (EmptySymTabException ex) { System.err.println("unexpected EmptySymTabException in IfElseStmtNode.processNames"); System.exit(-1); } } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("if ("); myExp.unparse(p,0); p.println(") {"); if (myThenDeclList != null) myThenDeclList.unparse(p,indent+2); if (myThenStmtList != null) myThenStmtList.unparse(p,indent+2); doIndent(p, indent); p.println("}"); doIndent(p, indent); p.println("else {"); if (myElseDeclList != null) myElseDeclList.unparse(p,indent+2); if (myElseStmtList != null) myElseStmtList.unparse(p,indent+2); doIndent(p, indent); p.println("}"); } // 5 kids private ExpNode myExp; private DeclListNode myThenDeclList; private StmtListNode myThenStmtList; private StmtListNode myElseStmtList; private DeclListNode myElseDeclList; } class WhileStmtNode extends StmtNode { public WhileStmtNode(ExpNode exp, DeclListNode dlist, StmtListNode slist) { myExp = exp; myDeclList = dlist; myStmtList = slist; } /** typeCheck **/ public void typeCheck(Type retType) { Type T = myExp.typeCheck(); if (! T.isBoolType() && ! T.isErrorType()) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Non-bool expression used as a while condition"); } myStmtList.typeCheck(retType); } /** processNames * * process the condition, then enter scope; process decls & stmts; * exit scope * **/ public void processNames(SymTab S) { myExp.processNames(S); S.addHashtab(); myDeclList.processNames(S); myStmtList.processNames(S); try { S.removeHashtab(); } catch (EmptySymTabException ex) { System.err.println("unexpected EmptySymTabException in WhileStmtNode.processNames"); System.exit(-1); } } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("while ("); myExp.unparse(p,0); p.println(") {"); if (myDeclList != null) myDeclList.unparse(p,indent+2); if (myStmtList != null) myStmtList.unparse(p,indent+2); doIndent(p, indent); p.println("}"); } // 3 kids private ExpNode myExp; private DeclListNode myDeclList; private StmtListNode myStmtList; } class CallStmtNode extends StmtNode { public CallStmtNode(CallExpNode call) { myCall = call; } /** typeCheck **/ public void typeCheck(Type retType) { myCall.typeCheck(); } /** processNames **/ public void processNames(SymTab S) { myCall.processNames(S); } // ** unparse ** public void unparse(PrintWriter p, int indent) { myCall.unparse(p,indent); p.print(";\n"); } // 1 kid private CallExpNode myCall; } class ReturnStmtNode extends StmtNode { public ReturnStmtNode(ExpNode exp) { myExp = exp; } /** typeCheck **/ public void typeCheck(Type retType) { if (myExp != null) { Type T = myExp.typeCheck(); if (retType.isVoidType()) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Return with a value in a void function"); } else if (! T.isErrorType() && ! retType.equals(T)) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Bad return value"); } } else { if (! retType.isVoidType()) { Errors.fatal(0, 0, "Missing return value"); } } } /** processNames **/ public void processNames(SymTab S) { if (myExp != null) myExp.processNames(S); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("return"); if (myExp != null) { p.print(" "); myExp.unparse(p,0); } p.print(";\n"); } // 1 kid private ExpNode myExp; } // ********************************************************************** // ExpNode and its subclasses // ********************************************************************** abstract class ExpNode extends ASTnode { // default version of processNames (for nodes with no names) public void processNames(SymTab S) {} abstract public Type typeCheck(); abstract public int linenum(); abstract public int charnum(); } class IntLitNode extends ExpNode { public IntLitNode(int lineNum, int charNum, int intVal) { myLineNum = lineNum; myCharNum = charNum; myIntVal = intVal; } /** typeCheck **/ public Type typeCheck() { return new IntType(); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print(myIntVal); } /** linenum **/ public int linenum() { return myLineNum; } /** charnum **/ public int charnum() { return myCharNum; } private int myLineNum; private int myCharNum; private int myIntVal; } class StringLitNode extends ExpNode { public StringLitNode(int lineNum, int charNum, String strVal) { myLineNum = lineNum; myCharNum = charNum; myStrVal = strVal; } /** typeCheck **/ public Type typeCheck() { return new StringType(); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print(myStrVal); } /** linenum **/ public int linenum() { return myLineNum; } /** charnum **/ public int charnum() { return myCharNum; } private int myLineNum; private int myCharNum; private String myStrVal; } class TrueNode extends ExpNode { public TrueNode(int lineNum, int charNum) { myLineNum = lineNum; myCharNum = charNum; } /** typeCheck **/ public Type typeCheck() { return new BoolType(); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("true"); } /** linenum **/ public int linenum() { return myLineNum; } /** charnum **/ public int charnum() { return myCharNum; } private int myLineNum; private int myCharNum; } class FalseNode extends ExpNode { public FalseNode(int lineNum, int charNum) { myLineNum = lineNum; myCharNum = charNum; } /** typeCheck **/ public Type typeCheck() { return new BoolType(); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("false"); } /** linenum **/ public int linenum() { return myLineNum; } /** charnum **/ public int charnum() { return myCharNum; } // 2 fields private int myLineNum; private int myCharNum; } class IdNode extends ExpNode { public IdNode(int lineNum, int charNum, String strVal) { myLineNum = lineNum; myCharNum = charNum; myStrVal = strVal; } /** typeCheck **/ public Type typeCheck() { if (mySym != null) return mySym.type(); else { System.err.println("ID with null sym field in IdNode.typeCheck"); System.exit(-1); } return null; } /** processNames * * check for use of an undeclared name * if OK, link to symtab entry * **/ public void processNames(SymTab S) { Sym sym = S.globalLookup(myStrVal); if (sym == null) { Errors.fatal(myLineNum, myCharNum, "Undeclared identifier"); } else link(sym); } /** link **/ public void link(Sym sym) { mySym = sym; } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print(myStrVal); if (mySym != null) { p.print("(" + mySym.type() + ")"); } } /** name **/ public String name() { return myStrVal; } /** type **/ public Type type() { if (mySym != null) return mySym.type(); else { System.err.println("ID with null sym field"); System.exit(-1); } return null; } /** symbol-table entry */ public Sym sym() { return mySym; } /** line num **/ public int linenum() { return myLineNum; } /** char num **/ public int charnum() { return myCharNum; } // fields private int myLineNum; private int myCharNum; private String myStrVal; private Sym mySym; } class ArrayExpNode extends ExpNode { public ArrayExpNode(IdNode id, ExpNode exp) { myId = id; myExp = exp; } /** typeCheck **/ public Type typeCheck() { Type T = myId.type(); if (! T.isArrayType()) { Errors.fatal(myId.linenum(), myId.charnum(), "Index applied to non-array operand"); } Type expT = myExp.typeCheck(); if (! expT.isIntType() && ! expT.isErrorType()) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Non-int expression used as an array index"); } if (T.isArrayType()) return ((ArrayType)T).arrayToScalar(); else return new ErrorType(); } /** processNames **/ public void processNames(SymTab S) { myId.processNames(S); myExp.processNames(S); } // ** unparse ** public void unparse(PrintWriter p, int indent) { myId.unparse(p, 0); if (myExp != null) { p.print("["); myExp.unparse(p,0); p.print("]"); } } /** linenum **/ public int linenum() { return myId.linenum(); } /** charnum **/ public int charnum() { return myId.charnum(); } // 2 kids private IdNode myId; private ExpNode myExp; } class CallExpNode extends ExpNode { public CallExpNode(IdNode name, ExpListNode elist) { myId = name; myExpList = elist; } public CallExpNode(IdNode name) { myId = name; myExpList = new ExpListNode(new LinkedList()); } /** typeCheck **/ public Type typeCheck() { Type T = myId.typeCheck(); // check that ID is a fn if (! T.isFnType()) { Errors.fatal(myId.linenum(), myId.charnum(), "Attempt to call a non-function"); return new ErrorType(); } // check number of args FnSym s = (FnSym)myId.sym(); if (s == null) { System.out.println("null sym for ID in CallExpNode.typeCheck"); System.exit(-1); } int numParams = s.numparams(); if (numParams != myExpList.length()) { Errors.fatal(myId.linenum(), myId.charnum(), "Function call with wrong number of args"); return s.returnType(); } // check type of each arg myExpList.typeCheck(s.paramTypes()); return s.returnType(); } /** processNames * * process name of called fn and all actuals **/ public void processNames(SymTab S) { myId.processNames(S); myExpList.processNames(S); } // ** unparse ** public void unparse(PrintWriter p, int indent) { myId.unparse(p,0); p.print("("); if (myExpList != null) myExpList.unparse(p,0); p.print(")"); } /** linenum **/ public int linenum() { return myId.linenum(); } /** charnum **/ public int charnum() { return myId.charnum(); } // 2 kids private IdNode myId; private ExpListNode myExpList; } abstract class UnaryExpNode extends ExpNode { public UnaryExpNode(ExpNode exp) { myExp = exp; } /** processNames **/ public void processNames(SymTab S) { myExp.processNames(S); } /** linenum **/ public int linenum() { return myExp.linenum(); } /** charnum **/ public int charnum() { return myExp.charnum(); } // one kid protected ExpNode myExp; } abstract class BinaryExpNode extends ExpNode { public BinaryExpNode(ExpNode exp1, ExpNode exp2) { myExp1 = exp1; myExp2 = exp2; } /** processNames **/ public void processNames(SymTab S) { myExp1.processNames(S); myExp2.processNames(S); } /** linenum **/ public int linenum() { return myExp1.linenum(); } /** charnum **/ public int charnum() { return myExp1.charnum(); } // two kids protected ExpNode myExp1; protected ExpNode myExp2; } // ********************************************************************** // Subclasses of UnaryExpNode // ********************************************************************** class UnaryMinusNode extends UnaryExpNode { public UnaryMinusNode(ExpNode exp) { super(exp); } /** typeCheck **/ public Type typeCheck() { Type T = myExp.typeCheck(); if (! T.isIntType() && ! T.isErrorType()) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Arithmetic operator applied to non-numeric operand"); return new ErrorType(); } if (T.isErrorType()) return T; else return new IntType(); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("(-"); myExp.unparse(p, 0); p.print(")"); } } class NotNode extends UnaryExpNode { public NotNode(ExpNode exp) { super(exp); } /** typeCheck **/ public Type typeCheck() { Type T = myExp.typeCheck(); if (! T.isBoolType() && ! T.isErrorType()) { Errors.fatal(myExp.linenum(), myExp.charnum(), "Logical operator applied to non-bool operand"); return new ErrorType(); } if (T.isErrorType()) return T; else return new BoolType(); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("(!"); myExp.unparse(p, 0); p.print(")"); } } // ********************************************************************** // Subclasses of BinaryExpNode // ********************************************************************** abstract class ArithmeticExpNode extends BinaryExpNode { public ArithmeticExpNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } /** typeCheck **/ public Type typeCheck() { Type T1 = myExp1.typeCheck(); Type T2 = myExp2.typeCheck(); Type retType = new IntType(); if (! T1.isIntType() && ! T1.isErrorType()) { Errors.fatal(myExp1.linenum(), myExp1.charnum(), "Arithmetic operator applied to non-numeric operand"); retType = new ErrorType(); } if (! T2.isIntType() && ! T2.isErrorType()) { Errors.fatal(myExp2.linenum(), myExp2.charnum(), "Arithmetic operator applied to non-numeric operand"); retType = new ErrorType(); } if (T1.isErrorType() || T2.isErrorType()) return new ErrorType(); else return retType; } } abstract class LogicalExpNode extends BinaryExpNode { public LogicalExpNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } /** typeCheck **/ public Type typeCheck() { Type T1 = myExp1.typeCheck(); Type T2 = myExp2.typeCheck(); Type retType = new BoolType(); if (! T1.isBoolType() && ! T1.isErrorType()) { Errors.fatal(myExp1.linenum(), myExp1.charnum(), "Logical operator applied to non-bool operand"); retType = new ErrorType(); } if (! T2.isBoolType() && ! T2.isErrorType()) { Errors.fatal(myExp2.linenum(), myExp2.charnum(), "Logical operator applied to non-bool operand"); retType = new ErrorType(); } if (T1.isErrorType() || T2.isErrorType()) return new ErrorType(); else return retType; } } abstract class EqualityExpNode extends BinaryExpNode { public EqualityExpNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } /** typeCheck **/ public Type typeCheck() { Type T1 = myExp1.typeCheck(); Type T2 = myExp2.typeCheck(); Type retType = new BoolType(); if (T1.isArrayType() && T2.isArrayType()) { Errors.fatal(myExp1.linenum(), myExp1.charnum(), "Equality operator applied to arrays"); retType = new ErrorType(); } if (T1.isFnType() && T2.isFnType()) { Errors.fatal(myExp1.linenum(), myExp1.charnum(), "Equality operator applied to functions"); retType = new ErrorType(); } if (! T1.equals(T2) && ! T1.isErrorType() && ! T2.isErrorType()) { Errors.fatal(myExp1.linenum(), myExp1.charnum(), "Type mismatch"); retType = new ErrorType(); } if (T1.isErrorType() || T2.isErrorType()) return new ErrorType(); else return retType; } } abstract class RelationalExpNode extends BinaryExpNode { public RelationalExpNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } /** typeCheck **/ public Type typeCheck() { Type T1 = myExp1.typeCheck(); Type T2 = myExp2.typeCheck(); Type retType = new BoolType(); if (! T1.isIntType() && ! T1.isErrorType()) { Errors.fatal(myExp1.linenum(), myExp1.charnum(), "Relational operator applied to non-numeric operand"); retType = new ErrorType(); } if (! T2.isIntType() && ! T2.isErrorType()) { Errors.fatal(myExp2.linenum(), myExp2.charnum(), "Relational operator applied to non-numeric operand"); retType = new ErrorType(); } if (T1.isErrorType() || T2.isErrorType()) return new ErrorType(); else return retType; } } // ********************************************************************** // Subclasses of ArithmeticExpNode // ********************************************************************** class PlusNode extends ArithmeticExpNode { public PlusNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("+"); myExp2.unparse(p, 0); p.print(")"); } } class MinusNode extends ArithmeticExpNode { public MinusNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("-"); myExp2.unparse(p, 0); p.print(")"); } } class TimesNode extends ArithmeticExpNode { public TimesNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("*"); myExp2.unparse(p, 0); p.print(")"); } } class DivideNode extends ArithmeticExpNode { public DivideNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("/"); myExp2.unparse(p, 0); p.print(")"); } } // ********************************************************************** // Subclasses of LogicalExpNode // ********************************************************************** class AndNode extends LogicalExpNode { public AndNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("&&"); myExp2.unparse(p, 0); p.print(")"); } } class OrNode extends LogicalExpNode { public OrNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("||"); myExp2.unparse(p, 0); p.print(")"); } } // ********************************************************************** // Subclasses of EqualityExpNode // ********************************************************************** class EqualsNode extends EqualityExpNode { public EqualsNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("=="); myExp2.unparse(p, 0); p.print(")"); } } class NotEqualsNode extends EqualityExpNode { public NotEqualsNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("!="); myExp2.unparse(p, 0); p.print(")"); } } // ********************************************************************** // Subclasses of RelationalExpNode // ********************************************************************** class LessNode extends RelationalExpNode { public LessNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("<"); myExp2.unparse(p, 0); p.print(")"); } } class GreaterNode extends RelationalExpNode { public GreaterNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print(">"); myExp2.unparse(p, 0); p.print(")"); } } class LessEqNode extends RelationalExpNode { public LessEqNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print("<="); myExp2.unparse(p, 0); p.print(")"); } } class GreaterEqNode extends RelationalExpNode { public GreaterEqNode(ExpNode exp1, ExpNode exp2) { super(exp1, exp2); } // ** unparse ** public void unparse(PrintWriter p, int indent) { p.print("("); myExp1.unparse(p, 0); p.print(">="); myExp2.unparse(p, 0); p.print(")"); } }