package cmmCompiler;

public class CmmAbstractSyntaxTree {
/*
 * You can extend this class to keep the AST separate from the parsing code. 
 * just move main and the sample parsing routines into a new class file 
 * class Expression (18) is left as an Exercise
 */
	

	
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 
 *  			AST CLASS DEFINITIONS
 *  
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
			
			
			
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 1. program := declaration-list | empty
 * 		 notes: this is the rare place I allow epsilon
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Program {
	DeclarationList declarationList ;
	Program ( DeclarationList declarationList)
	{
		this . declarationList = declarationList;
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 2. declaration-list := declaration-list declaration | declaration
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class DeclarationList {
	DeclarationList declarationList ;
	Declaration declaration ;
	DeclarationList ( DeclarationList declarationList, Declaration declaration)
	{
		this . declarationList = declarationList ;				
		this . declaration = declaration ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 3. declaration := var-declaration | fun-declaration
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Declaration {
	VarDeclaration varDeclaration = null;
	FunDeclaration funDeclaration = null;
	Declaration( VarDeclaration varDeclaration )
	{
		this . varDeclaration = varDeclaration ;
	}
	Declaration( FunDeclaration funDeclaration )
	{
		this . funDeclaration = funDeclaration ;
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 4. var-declaration := type-specifier ID ; | type-specifier ID [ NUM ] ;
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */				  

static class VarDeclaration {
	TypeSpecifier typeSpecifier ;
	Token ID;
	Token NUM = null;
	VarDeclaration ( TypeSpecifier typeSpecifier, Token ID, Token NUM)
	{
		this . typeSpecifier = typeSpecifier ;				
		this . ID = ID ;				
		this . NUM = NUM ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 5. type-specifier := int | void 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class TypeSpecifier {
	Token type ;
	TypeSpecifier ( Token type)
	{
		this . type = type ;				
	}
}
		
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 6. fun-declaration := type-specifier ID ( params ) compound-stmt
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */				  				  

static class FunDeclaration {
	TypeSpecifier typeSpecifier;
	Token ID;
	Params params;
	CompoundStmt compoundStmt;
	FunDeclaration ( TypeSpecifier typeSpecifier, Token ID, Params params, CompoundStmt compoundStmt)
	{
		this . typeSpecifier = typeSpecifier ;				
		this . ID = ID ;				
		this . params = params ;				
		this . compoundStmt = compoundStmt ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 7. params := param-list | void | empty
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */		  

static class Params {
	ParamList paramList = null ;
	Params ( ParamList paramList)
	{
		this . paramList = paramList ;				
	}
	Params ( )
	{
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 8. param-list := param-list , param | param
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */		  

static class ParamList {
	ParamList paramList ;
	Param param ;
	ParamList ( ParamList paramList, Param param)
	{
		this . paramList = paramList ;				
		this . param = param ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 9. Param := type-specifier ID | type-specifier ID []
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Param {
	TypeSpecifier typeSpecifier ;
	Token ID ;
	boolean array = false;
	Param ( TypeSpecifier typeSpecifier, Token ID)
	{
		this . typeSpecifier = typeSpecifier ;				
		this . ID = ID ;				
	}
	Param ( TypeSpecifier typeSpecifier, Token ID, boolean array)
	{
		this . typeSpecifier = typeSpecifier ;				
		this . ID = ID ;		
		this . array = array ;		
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 10. compound-stmt := { local-declarations statement-list }
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class CompoundStmt {
	LocalDeclarations localDeclarations ;
	StatementList statementList ;
	CompoundStmt(){}
	CompoundStmt ( LocalDeclarations localDeclarations, StatementList statementList )
	{
		this . localDeclarations = localDeclarations ;				
		this . statementList = statementList ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 11. local-declarations := local-declarations var-declaration | var-declaration
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class LocalDeclarations {
	LocalDeclarations localDeclarations ;
	VarDeclaration varDeclaration ;
	LocalDeclarations(){}
	LocalDeclarations ( LocalDeclarations localDeclarations, VarDeclaration varDeclaration)
	{
		this . localDeclarations = localDeclarations ;				
		this . varDeclaration = varDeclaration ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 12. statement-list := statement-list statement | statement
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class StatementList {
	StatementList statementList ;
	Statement statement ;
	StatementList ( StatementList statementList, Statement statement)
	{
		this . statementList = statementList ;				
		this . statement = statement ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 13. statement := expression-stmt 
 * 				| compound-stmt 
 * 				| selection-stmt 
 * 				| iteration-stmt 
 * 				| return-stmt 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Statement {
	ExpressionStmt expressionStmt =null;
	CompoundStmt compoundStmt =null;
	SelectionStmt selectionStmt =null;
	IterationStmt iterationStmt =null;
	ReturnStmt returnStmt =null;
	Statement( ExpressionStmt expressionStmt )
	{
		this . expressionStmt = expressionStmt ;				
	}
	Statement( CompoundStmt compoundStmt )
	{
		this . compoundStmt = compoundStmt ;				
	}
	Statement( SelectionStmt selectionStmt )
	{
		this . selectionStmt = selectionStmt ;				
	}
	Statement( IterationStmt iterationStmt )
	{
		this . iterationStmt = iterationStmt ;				
	}
	Statement( ReturnStmt returnStmt )
	{
		this . returnStmt = returnStmt ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 14. expression-stmt := expression ; | ;
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class ExpressionStmt {
	Expression expression;
	ExpressionStmt (Expression expression)
	{
		this . expression = expression;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 15. selection-stmt := if ( expression ) statement 
 * 				| if ( expression ) statement else statement
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class SelectionStmt {
	Expression expression;
	Statement thenStatement ;
	Statement elseStatement ;
	SelectionStmt ( Expression expression, Statement thenStatement, Statement elseStatement)
	{
		this . expression = expression ;				
		this . thenStatement = thenStatement ;				
		this . elseStatement = elseStatement ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 16. iteration-stmt := while ( expression ) statement 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class IterationStmt {
	Expression expression ;
	Statement statement ;
	IterationStmt ( Expression expression, Statement statement)
	{
		this . expression = expression ;				
		this . statement = statement ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 17. return-stmt := return ; | return expression ; 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class ReturnStmt {
	Expression expression ;
	ReturnStmt ( Expression expression)
	{
		this . expression = expression ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 18. expression  := var = expression | simple-expression
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Expression {
	//left as an exercise
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 19. var := ID | ID [ expression ] 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Var {
	Token ID ;
	Expression expression ;
	Var ( Token ID, Expression expression)
	{
		this . ID = ID ;				
		this . expression = expression ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 20. simple-expression := additive-expression relop additive-expression 
 * 				| additive-expression
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */		

static class SimpleExpression {
	AdditiveExpression left ;
	AdditiveExpression right = null ;
	OPERATOR OP = null;
	SimpleExpression ( AdditiveExpression left, OPERATOR OP, AdditiveExpression right)
	{
		this . left = left ;				
		this . OP = OP ;				
		this . right = right ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 notes: merged all operators into single class (see 25 mulop)
 * 			21. relop := <= | < | > | >= | == | !=
 * 			23. add-op := + | -
 * 			25. mulop := * | /
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 22. additive-expression := additive-expression addop term | term
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static 	class AdditiveExpression {
	AdditiveExpression left =null;
	Term term =null;
	OPERATOR OP = null;
	AdditiveExpression ( AdditiveExpression left, OPERATOR OP, Term term)
	{
		this . left = left ;				
		this . OP = OP ;				
		this . term = term ;				
	}
	AdditiveExpression ( Term term)
	{
		this . term = term ;				
	}	
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 notes: merged all operators into single class (see 25 mulop)
 * 			21. relop := <= | < | > | >= | == | !=
 * 			23. add-op := + | -
 * 			25. mulop := * | /
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */		


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 24. term := term mulop factor | factor
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Term {
	Term left = null;
	Factor factor = null;
	OPERATOR OP = null;
	Term ( Term left, OPERATOR OP, Factor factor)
	{
		this . left = left ;				
		this . OP = OP ;				
		this . factor = factor ;				
	}
	Term ( Factor factor)
	{
		this . factor = factor ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 notes: merged all operators into single class (see 25 mulop)
 * 			21. relop := <= | < | > | >= | == | !=
 * 			23. add-op := + | -
 * 			25. mulop := * | /
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class OPERATOR {
	Token OP;
	OPERATOR ( Token OP )
	{
		this . OP = OP ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 26. factor := ( expression ) | var | call | NUM
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Factor {
	Expression expression = null;
	Var var = null;
	Call call = null;
	Token NUM = null;
	Factor(Expression expression)
	{
		this . expression = expression ;				
	}
	Factor(Var var)
	{
		this . var = var ;				
	}
	Factor(Call call)
	{
		this . call = call ;				
	}
	Factor(Token NUM)
	{
		this . NUM = NUM ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 27. call := ID ( args ) 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Call {
	Token ID ;
	Args args ;
	Call ( Token ID, Args args )
	{
		this . ID = ID ;				
		this . args = args ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 28. args := arg-list | empty
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class Args {
	ArgList argList ;
	Args(){}
	Args ( ArgList argList )
	{
		this . argList = argList ;				
	}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 		 29.  arg-list := arg-list , expression | expression
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

static class ArgList {
	ArgList argList;
	Expression expression;
	ArgList ( ArgList argList, Expression expression)
	{
		this . argList = argList ;				
		this . expression = expression ;				
	}
}

}
