//  File: parse.C
//
//  Parse arithmetic expressions involving +, -, *, / and ().

#include <stdio.h>
#include <stdlib.h>
#include "token.h"
#include "tokenizer.h"
#include "etree.h"

#include "parse.h"


// Global Variable
char *error_msg ;


// Everything -> Expression EOL 

ETree *ParseEverything(Tokenizer *T) {
   ETree *all ;
   token_t next ;

   all = ParseExpression(T) ;
   if (all == NULL) {
	  T->PrintError() ;
	  printf("%s\n", error_msg) ;
	  return NULL ;
   }

   next = T->LookAhead() ;

   if (next.kind != EOL) {
	  T->PrintError() ;
      error_msg = "Garbage at the end" ;
	  fprintf(stderr, "%s\n", error_msg) ;
	  delete all ;
      return NULL ;
   } 
   
   return all ;
}



// Expression -> Expression + Term
//            -> Expression - Term

ETree *ParseExpression(Tokenizer *T) {
   ETree *expr, *term, *temp ;
   token_t  op ;

   expr = ParseTerm(T) ;
   if (expr == NULL) return NULL ;

   while(1) {

      op = T->LookAhead() ;

      switch(op.kind) {

         case UNDEF : 		// Bogus, bogus
	        fprintf(stderr,"Oops, caught internal error\n") ;
	        exit(1) ;
            
	 	 case PLUS :
	    	T->EatToken() ; // consume the '+'
	    	break ;

		 case MINUS :
		    T->EatToken() ; // consume the '-'
	   		break ;

		 default :
	    	return expr ;
      }
      
      term = ParseTerm(T) ;

      if (term == NULL) {
		 delete expr ;
		 return NULL ;
	  }

      temp = new ETree(&op, expr, term) ;
	  if (temp == NULL) {
		 delete expr ;
		 delete term ;
		 error_msg = "Memory full !!!" ;
		 return NULL ;
	  }
	  expr = temp ;
   }
}



// Term -> Term * Factor
//	    -> Term / Factor

ETree *ParseTerm(Tokenizer *T) {
   ETree *term, *factor, *temp ; 
   token_t op ;

   term = ParseFactor(T) ;
   if (term == NULL) return NULL ;

   while(1) {

      op = T->LookAhead() ;

      switch(op.kind) {

	 	 case UNDEF : 		// Bogus, bogus
	   	    fprintf(stderr,"Yikes, caught internal error\n") ;
	    	exit(1) ;
            
	 	 case TIMES :
	    	T->EatToken() ;	// consume the '*'
	    	break ;

	 	 case DIVIDE :
	    	T->EatToken() ; // consume the '/' 
	    	break ;

		 default :
	    	return term ;
      }

      factor = ParseFactor(T) ;

      if (factor == NULL) {
		 delete term ;
		 return NULL ;
      } 

	  temp = new ETree(&op, term, factor) ;
	  if (temp == NULL) {
		 delete term ;
		 delete factor ;
		 error_msg = "No more memory!!!" ;
		 return NULL ; 
	  }
	  term = temp ;
   }
}



// Factor -> ( Expression )
//	      -> Number

ETree *ParseFactor(Tokenizer *T) {
   ETree *temp ;
   token_t next ;

   next = T->LookAhead() ;

   if (next.kind == NUMBER) {
      T->EatToken() ; // consume the number
      temp = new ETree(&next) ; 
	  if (temp == NULL) {
		 error_msg = "Out of memory" ;
		 return NULL ;
	  }
	  return temp ;
   }

   if (next.kind != L_PAREN) {
      error_msg = "Expecting a number or '('" ;
      return NULL ;
   }

   T->EatToken() ; /* consume the '(' */

   temp = ParseExpression(T) ;
   if (temp == NULL) return NULL ;

   next = T->LookAhead() ;

   if (next.kind != R_PAREN) {
      error_msg = "Expecting ')'" ;
      return NULL ;
   }

   T->EatToken() ; /* consume ')' */

   return temp ;
}
