// Abstract syntax for the language Jay, exactly as it appears in Appendix B.
// Use the file "Program.java" for this abstract syntax with "display" methods 
// added (this facilitates debugging and experimentation).

import java.util.Vector;

class Program {
// Program = Declarations decpart ; Block body
  Declarations decpart;
  Block body;
}

class Declarations extends Vector {
// Declarations = Declaration *
//     (a Vector of declarations d1, d2, ..., dn)
}

class Declaration {
// Declaration = Variable v; Type t
  Variable v;
  Type 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); }
}

class Statement {
// Statement = Skip | Block | Assignment | Conditional | Loop
}

class Skip extends Statement { }

class Block extends Statement {
// Block = Statement *
//         (a Vector of members)
  public Vector members = new Vector();
}

class Assignment extends Statement {
// Assignment = Variable target; Expression source
  Variable target;
  Expression source;
}

class Conditional extends Statement {
// Conditional = Expression test; Statement thenbranch, elsebranch
  Expression test;
  Statement thenbranch, elsebranch;
            // elsebranch == null means "if... then"
}

class Loop extends Statement {
// Loop = Expression test; Statement body
  Expression test;
  Statement body;
}

class Expression {
// Expression = Variable | Value | Binary | Unary
}

class Variable extends Expression {
// Variable = String id
  String id;
    
  public boolean equals (Object obj) {
    String s = ((Variable) obj).id;
    return id.equalsIgnoreCase(s); // case-insensitive identifiers
  }
    
  public int hashCode ( ) { return id.hashCode( ); }
}

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); }
}

class Binary extends Expression {
// Binary = Operator op; Expression term1, term2
  Operator op;
  Expression term1, term2;
}

class Unary extends Expression {
// Unary = Operator op; Expression term
  Operator op;
  Expression term;
}

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); }
}

