package cmmCompiler;

public class CmmAbstractSyntaxTreeBuilder extends CmmAbstractSyntaxTree {
	/*
	 * Extending CmmAbstractSyntaxTree class to keep 
	 * the AST separate from the parsing code. 
	 */
	
	/*
	 * The purpose of this file is to give you an idea of where to start.
	 * No assumption regarding the correctness of any of this code should be made
	 * I've tried to highlight obvious problems but I've intentionally incorporated
	 * some parsing problems
	 */
	
	/*
	 * A simple testing routine 
	 * it might be wise to point it at a cmm program
	 */
	public static void main(String[] args)
	{
		lex = new LexScan("src/cmmCompiler/Recognizer.java");
		Program program = program();
		if ( program != null && !ErrorsFound )
			System.out.println("\nACCEPT");/* later we'll add add emit() */
		else 
			System.out.println("\nERRORS FOUND\n"+ErrorMessages);
	}
	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	 * 
	 * 		 UTILITY METHODS
	 * 
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
	
	/*
	 * Some errors may not prevent AST construction (example, missing semi)
	 * I used Some ErrorsFound to distinguish fatal errors
	 */
	static boolean ErrorsFound = false;
	/*
	 * Any errors, fatal or otherwise, were appended to ErrorMessages
	 */
	static String ErrorMessages = "";
	/*
	 * my scanner
	 */
	static LexScan lex;
	

	/*
	 * the token of interest
	 */
	static Token currentToken = null;
	/*
	 * eats the token and reports success if matches
	 */
	static public boolean accept (int TokenType)
	{
		if (currentToken == null) 
			currentToken = lex.nextToken();
		if (currentToken.type != TokenType)
			return false; 
		currentToken = null;
		return true;
	}
	/*
	 * eats the token and reports error if fails to matche
	 */
	static public boolean expect (int tokenType)
	{
		if (accept(tokenType))
			return true;
		ErrorsFound = true;
		String ErrorMessage = 
			"\nError at line: "+currentToken.lineNo +
			" column: "+currentToken.column +
			"\n\tExpected: "+Token.tokenName(tokenType)+
			"\n\t   Found: "+Token.tokenName(currentToken.type) + 
			"\t("+currentToken.text+")";	
		ErrorMessages = ErrorMessages + ErrorMessage;
		return false;
	}
	/* 
	 * require is identical to accept except that it returns the token if found
	 */
	static public Token require (int tokenType)
	{
		Token keeper = currentToken;
		if (accept(tokenType))
			return keeper;
		return null;
	}
	/* 
	 * keep is identical to expect except that it returns the token if found 
	 */
	static public Token keep (int tokenType)
	{
		Token keeper = currentToken;
		if (expect(tokenType))
			return keeper;
		return null;
	}
	
	
	
	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	 * 
	 * 		 SAMPLE PARSING METHODS
	 * 
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

		
	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	 * 		 1. program := declaration-list | empty
	 * 		 notes: this is the rare place I allow epsilon
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

	static public Program program()
	{	/* even empty is a program */
		return new Program(declarationList());
	}

	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	 * 		 2. declaration-list := declaration-list declaration | declaration
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

	static public DeclarationList declarationList()
	{
		DeclarationList declarationList = null;
		Declaration declaration = declaration();
		while( declaration != null )
		{
			declarationList = new DeclarationList(declarationList, declaration);
			declaration = declaration();
		}
		return declarationList;
	}	
	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	 * 		 3. declaration := var-declaration | fun-declaration
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

	//incomplete
	static public Declaration declaration()
	{
		VarDeclaration vd = varDeclaration();
		if (vd == null) return null;
		else return new Declaration (vd) ;
	}
	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
	 * 		 4. var-declaration := type-specifier ID ; | type-specifier ID [ NUM] ;
	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */				  

	//incomplete
	static public VarDeclaration varDeclaration()
	{
		TypeSpecifier typeSpecifier = typeSpecifier() ;
		if (typeSpecifier == null) 
			return null;
		Token ID = keep (Token.ID);
		Token NUM = null;
		
		if (accept(Token.SEMI) )
			return new VarDeclaration(typeSpecifier, ID, NUM);				
		else if ( accept(Token.OPEN_BRACKET) )
		{
			NUM  = keep (Token.NUMBER);
			expect(Token.CLOSE_BRACKET);
			expect(Token.SEMI);
			return new VarDeclaration(typeSpecifier, ID, NUM);
		}
		//problem here as we may have eaten tokens 
		//(type & id) of a FunDeclaration
		return null;
	}
	//incomplete
	static TypeSpecifier typeSpecifier(){
		return null;
	}
}
