/* Implementation file for semantic functions
	by Jason Plumb */

#include <stdio.h>
#include "defines.h"
#include "lex.h"
#include "semantics.h"
#include "syntax.h"

/* Globally defined symbols */
extern TOKEN SymTable[SYM_TABLE_SIZE];	//The symbol table
extern int iCurrLine;					//Indicates the current line
extern int iLineOffset;					//Maintains offset into current line
extern int iNT;
extern int iTokenIndexTrue;
extern int iTokenIndexFalse;

int iException;
int declares[255];						//Indices to declared variables
int decct;								//Count of declared variables

bool sf_program(){

	sas_init();							//Init the semantic action stack
	qt_init();							//Init the quad table

	iException = 0;
	decct = 0;
	sf_getNT();
	if(iNT > 0){
		if(SymTable[iNT].iTokenType == findTokenType("procedure")){
			sf_getNT();
			if(SymTable[iNT].iTokenType == TOKEN_TYPE_ID){
				sf_getNT();
				if(SymTable[iNT].iTokenType == findTokenType("is")){
					sf_getNT();
					if(sf_declare_part()){
						if(SymTable[iNT].iTokenType == findTokenType("begin")){
							sf_getNT();
							if(sf_seq_of_statements()){
								if(SymTable[iNT].iTokenType == findTokenType("end")){
									sf_getNT();
									if(SymTable[iNT].iTokenType == findTokenType(";")){
										sf_getNT();
										if(iNT == ERR_EOF){
											qt_debug_print();			//Show symbol table
											return true;
										}//if
										else{
											sf_error("Expecting EOF");
											return false;
										}
									}//if
									else{
										sf_error("Expecting ; after 'end'");
										return false;	//ERROR: Expecting ";" after "end"
									}//else
								}
								else{
									sf_error("Expecting 'end' keyword");
									return false;		//ERROR: Expecting "end" keyword
								}//else
							}//if
							else
								return false;
						}//if
						else{
							sf_error("Expecting 'begin' keyword");
							return false;			//ERROR: Expecting "begin"
						}//else
					}//if
					else
						return false;
				}//if
				else{
					sf_error("Expecting keyword 'is'");
					return false;
				}
			}//if
			else{
				sf_error("Expecting identifier");
				return false;
			}//else
		}//if
		else{
			sf_error("Expecting keyword 'procedure'");
			return false;
		}//else
	}//if
	else
		return false;
}//sf_program

bool sf_declare_part(){

	if(SymTable[iNT].iTokenType == TOKEN_TYPE_ID){
		if(sf_declaration()){
			if(sf_declare_part())
				return true;
			else
				return false;
		}//if
		else
			return false;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("begin")){
		return true;
	}
	else{
		sf_error("Expecting identifier or 'begin' keyword");
		return false;
	}
}//sf_declare_part

bool sf_declaration(){
	if(sf_id_list()){
		if(SymTable[iNT].iTokenType == findTokenType(":")){
			sf_getNT();
			if(SymTable[iNT].iTokenType == findTokenType("integer")){
				sf_getNT();
				if(SymTable[iNT].iTokenType == findTokenType(";")){
					sf_getNT();
					return true;
				}
				else{
					sf_error("Expecting ;");
					return false;
				}
			}//if
			else{		
				sf_error("Expecting keyword 'integer'");
				return false;			//Expecting "integer"
			}//else
		}
		else{
			sf_error("Expecting :");
			return false;
		}//else
	}//if
	else
		return false;
}//sf_declaration

bool sf_id_list(){
	if(sf_idz()){
		if(sf_more_idz())
			return true;
		else
			return false;
	}
	else
		return false;
}//sf_id_list

bool sf_idz(){
	if(SymTable[iNT].iTokenType == TOKEN_TYPE_ID){
		declares[decct++] = iNT;
		SymTable[iNT].bVarDeclared = true;				//Set declared flag
		sf_getNT();
		if(sf_idz1())
			return true;
		else{
			SymTable[declares[--decct]].bVarDeclared = false;		//Declare failed...take it back
			declares[decct] = -1;
			return false;
		}
	}
	else{
		sf_error("Expecting identifier");
		return false;			//Not in selection set...expecting Identifier
	}

}//sf_idz

bool sf_idz1(){
	if(SymTable[iNT].iTokenType == findTokenType("[")){
		sf_getNT();
		if(SymTable[iNT].iTokenType == TOKEN_TYPE_CONST){
			sf_getNT();
			if(SymTable[iNT].iTokenType == findTokenType("]")){
				sf_getNT();
				return true;
			}
			else{
				sf_error("Expecting [");
				return false;			//Expecting closing ]
			}
		}
		else{
			sf_error("Expecting integer value");
			return false;		//Expecting integer value for array dimension
		}
	}
	else if((SymTable[iNT].iTokenType == findTokenType(",")) ||
			(SymTable[iNT].iTokenType == findTokenType(":"))){
		return true;
	}
	else{
		sf_error("Expecting one of: [, ,, or :");
		return false;
	}
}//sf_idz

bool sf_more_idz(){
	if(SymTable[iNT].iTokenType == findTokenType(",")){
		sf_getNT();
		if(sf_idz()){
			if(sf_more_idz())
				return true;
			else
				return false;
		}
		else
			return false;
	}
	else if(SymTable[iNT].iTokenType == findTokenType(":"))
		return true;
	else{
		sf_error("Expecting , or :");
		return false;
	}//else
}//sf_more_idz

bool sf_seq_of_statements(){

	if( (SymTable[iNT].iTokenType == TOKEN_TYPE_ID)					||
		(SymTable[iNT].iTokenType == findTokenType("null"))			||
		(SymTable[iNT].iTokenType == findTokenType("if"))			||
		(SymTable[iNT].iTokenType == findTokenType("while"))		||
		(SymTable[iNT].iTokenType == findTokenType("for"))			||
		(SymTable[iNT].iTokenType == findTokenType("read"))			||
		(SymTable[iNT].iTokenType == findTokenType("readln"))		||
		(SymTable[iNT].iTokenType == findTokenType("write"))		||
		(SymTable[iNT].iTokenType == findTokenType("writeln"))){
		
		if(sf_statement()){
			return sf_seq_of_statements();
		}//if
		else{
			//Statement failed...try to recover at next statement....
			sf_getNT();
			while((iNT != ERR_EOF) && (iNT != findTokenType(";")))
				sf_getNT();			//Keep getting tokens until new statement

			sf_getNT();
			return sf_seq_of_statements();
			//return false;
			//Note: Normally we would return false...but hopefully we have repositioned
			//on the next statement...so we'll try to continue processing...error recovery!
			//The semantics have actually failed, but we will hopefully try to continue
			//compiling...
		}//else
	}//if
	else if((SymTable[iNT].iTokenType == findTokenType("end"))		||
			(SymTable[iNT].iTokenType == findTokenType("elsif"))	||
			(SymTable[iNT].iTokenType == findTokenType("else"))){
		return true;
	}
	else{
		sf_error("Expecting one of: null, if, while, for, read, readln, write, writeln, end, else, elsif");
		return false;
	}
}//sf_seq_of_statements

bool sf_statement(){

	if(SymTable[iNT].iTokenType == findTokenType("null")){
		return sf_null_stmt();
	}
	else if(SymTable[iNT].iTokenType == TOKEN_TYPE_ID){
		return sf_assignment_stmt();
	}
	else if(SymTable[iNT].iTokenType == findTokenType("if")){
		return sf_if_stmt();
	}
	else if((SymTable[iNT].iTokenType == findTokenType("while")) ||
			(SymTable[iNT].iTokenType == findTokenType("for"))){
		return sf_loop_stmt();
	}
	else if((SymTable[iNT].iTokenType == findTokenType("read"))		||
			(SymTable[iNT].iTokenType == findTokenType("readln"))	||
			(SymTable[iNT].iTokenType == findTokenType("write"))		||
			(SymTable[iNT].iTokenType == findTokenType("writeln"))){
		return sf_io_stmt();
	}//else if
	else{
		sf_error("Expecting one of: null, identifier, if, while, for, read, readln, write, writeln");
		return false;
	}//else
}//sf_statement

bool sf_null_stmt(){
	if(SymTable[iNT].iTokenType == findTokenType("null")){
		sf_getNT();
		if(SymTable[iNT].iTokenType == findTokenType(";")){
			sf_getNT();
			return true;
		}//if
		else{
			sf_error("Expecting ;");
			return false;
		}//else
	}//if
	else{
		sf_error("Expecting 'null'");
		return false;
	}
}//sf_null_stmt


bool sf_assignment_stmt(){
	if(sf_I()){
		if(SymTable[iNT].iTokenType == findTokenType(":=")){
			sf_getNT();
			if(sf_expression()){
				
				int A, B;
				B = sas_pop();
				A = sas_pop();

				genquad(ASSIGN,  B, 0, NULLOP, 0, A, 0);

				if(SymTable[iNT].iTokenType == findTokenType(";")){
					sf_getNT();
					return true;
				}
				else{
					sf_error("Expecting ;");
					return false;
				}
			}
			else
				return false;
		}//if
		else{
			sf_error("Expecting :=");
			return false;
		}
	}//if
	else{
		return false;
	}
}//sf_assignment_stmt

bool sf_I(){
	if(SymTable[iNT].iTokenType == TOKEN_TYPE_ID){
		
		sas_push(iNT);		//Push id onto sas

		sf_getNT();
		if(sf_remid())
			return true;
		else
			return false;
	}//if
	else{
		sf_error("Expecting identifier");
		return false;
	}//else
}//sf_I

/* Cooke changed this one on us...
bool sf_assignment_stmt(){
	if(SymTable[iNT].iTokenType == TOKEN_TYPE_ID){
		sf_getNT();
		if(SymTable[iNT].iTokenType == findTokenType(":=")){
			sf_getNT();
			if(sf_expression()){
				if(SymTable[iNT].iTokenType == findTokenType(";")){
					sf_getNT();
					return true;
				}
				else{
					sf_error("Expecting ;");
					return false;
				}
			}//if
			else
				return false;
		}
		else{
			sf_error("Expecting :=");
			return false;		//Expecting :=
		}
	}
	else{
		sf_error("Expecting identifier");
		return false;			//Expecting <id>
	}
}//sf_assignment_stmt
*/

bool sf_if_stmt(){
	if(SymTable[iNT].iTokenType == findTokenType("if")){
		sf_getNT();
		if(sf_expression()){
			if(SymTable[iNT].iTokenType == findTokenType("then")){	
				
				int A;
				A = sas_pop();			//Get expression from stack
				sas_push(IFTAG);		//Push if terminating value
				sas_push(-1*qt_NQ());		//Push this quad to be filled in later
				genquad(JFALSE, A, 0, NULLOP, 0, NULLOP, 0);				

				sf_getNT();
				if(sf_seq_of_statements()){

					if(sf_else_seq()){

						//Now do the fixups for all the jump arounds if needed....
						A = sas_pop();

						if(A == ELSEIFTAG){				//Doh, we have elseifs to fix up...
							A = sas_pop();				//Get elsif jfalse quad that needs fixup
							quad(-1*A, 4, -1*qt_NQ());
							A = sas_pop();
						}//if

						while(A != IFTAG){
							quad(-1*A, 4, -1*qt_NQ());
							A = sas_pop();
						}//while

						if(SymTable[iNT].iTokenType == findTokenType("end")){
							sf_getNT();
							if(SymTable[iNT].iTokenType == findTokenType("if")){
								sf_getNT();
								if(SymTable[iNT].iTokenType == findTokenType(";")){
									sf_getNT();
									return true;
								}
								else{
									sf_error("Expecting ;");
									return false;
								}
							}
							else{
								sf_error("Expecting 'if' (as in 'end if')");
								return false;
							}
						}
						else{
							sf_error("Expecting 'end'");
							return false;
						}
					}//if(sf_else_seq())
					else						
						return false;
				}
				else
					return false;
			}
			else{
				sf_error("Expecting 'then'");
				return false;
			}
		}
		else
			return false;
	}
	else{
		sf_error("Expecting 'if'");
		return false;
	}
}//sf_if_stmt

bool sf_else_seq(){
	if(SymTable[iNT].iTokenType == findTokenType("elsif")){
		if(sf_else_if_clause()){
			if(sf_else_seq()){
				return true;
			}
			else
				return false;
		}
		else
			return false;
	}
	else if((SymTable[iNT].iTokenType == findTokenType("end")) ||
			(SymTable[iNT].iTokenType == findTokenType("else"))){
		if(sf_else_clause()){

			return true;
		}
		else
			return false;
	}
	else{
		sf_error("Expecting 'elsif', 'else', or 'end'");		
		return false;
	}

}//sf_else_seq

bool sf_else_if_clause(){
	if(SymTable[iNT].iTokenType == findTokenType("elsif")){

		/* This is the else portion of the elsif */
		int	A = sas_pop();								//Get quad number needing fixup
		if(A == ELSEIFTAG){								//Doh, we have elseifs to fix up...
			A = sas_pop();							//Get elsif quad that needs fixup
		}//if
		
		sas_push(-1*qt_NQ());							//Get current quad number
		genquad(JMP, NULLOP, 0, NULLOP, 0, NULLOP, 0);	//Generate partial jump around
		quad(-1*A, 4, -1*qt_NQ());						//Fixup for jfalse

		sf_getNT();
		if(sf_expression()){
			if(SymTable[iNT].iTokenType == findTokenType("then")){

				/* This is the if portion of the elsif */
				A = sas_pop();				//Get expression from stack
				sas_push(-1*qt_NQ());		//Push this quad to be filled in later
				sas_push(ELSEIFTAG);		//Push if terminating value
				genquad(JFALSE, A, 0, NULLOP, 0, NULLOP, 0);				

				sf_getNT();
				if(sf_seq_of_statements()){
					return true;
				}//if
				else
					return false;
			}
			else{
				sf_error("Expecting 'then'");
				return false;
			}
		}
		else
			return false;
	}
	else{
		sf_error("Expecting 'elsif'");
		return false;
	}
}//sf_else_if_clause

bool sf_else_clause(){
	if(SymTable[iNT].iTokenType == findTokenType("else")){

		int	A = sas_pop();								//Get quad number needing fixup
		if(A == ELSEIFTAG){								//Doh, we have elseifs to fix up...
			A = sas_pop();							//Get elsif quad that needs fixup
		}//if

		sas_push(-1*qt_NQ());							//Get current quad number
		genquad(JMP, NULLOP, 0, NULLOP, 0, NULLOP, 0);	//Generate partial jump around
		quad(-1*A, 4, -1*qt_NQ());						//Fixup for jfalse
		
		sf_getNT();
		if(sf_seq_of_statements()){
			return true;
		}
		else
			return false;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("end"))
		return true;
	else{
		sf_error("Expecting 'else' or 'end'");
		return false;
	}
}//sf_else_clause

bool sf_loop_stmt(){

	if(sf_iteration_rule()){
		if(sf_basic_loop()){
			if(SymTable[iNT].iTokenType == findTokenType(";")){
				sf_getNT();
				return true;
			}
			else{
				sf_error("Expecting ;");
				return false;				//Missing ';'
			}//else
		}
		else
			return false;
	}
	else
		return false;
}//sf_loop_stmt

bool sf_iteration_rule(){
	if(SymTable[iNT].iTokenType == findTokenType("while")){
		
		int A = qt_NQ();			//Get location of quad before expression evaluated
		sas_push(-1*A);
		A = iNT;

		sf_getNT();

		if(sf_expression()){
			sas_push(A);
			return true;
		}
		else
			return false;
	}//if
	else if(SymTable[iNT].iTokenType == findTokenType("for")){
		sf_getNT();
		if(SymTable[iNT].iTokenType == TOKEN_TYPE_ID){
			sas_push(iNT);			//Push <id> onto sas
			sf_getNT();
			if(SymTable[iNT].iTokenType == findTokenType("in")){
				sf_getNT();
				if(sf_range()){
					//Semantic action for 'for' loop
					int A, B, C, tmphi, tmpinc, tmp;
					B = sas_pop();	//get range high val
					A = sas_pop();	//get range low val
					C = sas_pop();	//get <id> used in loop

					tmphi = gentemp();
					tmpinc = gentemp();
					tmp = gentemp();

					genquad(ASSIGN, iTokenIndexTrue, 0, NULLOP, 0, tmpinc, 0);
					genquad(ASSIGN, B, 0, NULLOP, 0, tmphi, 0);
					genquad(ASSIGN, A, 0, NULLOP, 0, C, 0);
					genquad(GE, B, 0, A, 0, tmp, 0);
					genquad(JTRUE, tmp, 0, NULLOP, 0, -1*(qt_NQ()+3), 0);
					genquad(SUB, tmpinc, 0, iTokenIndexTrue, 0, tmpinc, 0);
					genquad(SUB, tmpinc, 0, iTokenIndexTrue, 0, tmpinc, 0);
					sas_push(-1*qt_NQ());
					genquad(EQ, C, 0, tmphi, 0, tmp, 0);
					
					sas_push(tmp);
					sas_push(tmpinc);
					sas_push(C);
					sas_push(findTokenType("for"));
					
					return true;
				}//if
				else
					return false;
			}//if
			else{
				sf_error("Expecting 'in'");
				return false;		//Expecting 'in'
			}
		}//if
		else{
			sf_error("Expecting identifier");
			return false;			//Expecting <id>
		}//else
	}
	else{
		sf_error("Expecting 'while' or 'for'");
		return false;				//Error: expecting while/for
	}//else
}//sf_iteration_rule

bool sf_basic_loop(){
	if(SymTable[iNT].iTokenType == findTokenType("loop")){
		sf_getNT();

		int A, B;

		A = sas_pop();				//Get loop type from stack
		if(A == findTokenType("while")){
			A = sas_pop();				//Get expression to evaluate from stack
			B = qt_NQ();				//Get this quad number
			genquad(JFALSE, A, 0, NULLOP, 0, NULLOP, 0);		//Generate partial quad
			sas_push(-1*B);
			sas_push(findTokenType("while"));
		}//if
		else
			sas_push(A);
		
		

		if(sf_seq_of_statements()){
			if(SymTable[iNT].iTokenType == findTokenType("end")){
				sf_getNT();
				if(SymTable[iNT].iTokenType == findTokenType("loop")){
					sf_getNT();
					
					A = sas_pop();			//Get loop type from stack
					if(A == findTokenType("for")){
						int C, tmp, tmpinc;
						C = sas_pop();
						tmpinc = sas_pop();
						tmp = sas_pop();
						A = sas_pop();

						genquad(JTRUE, tmp, 0, NULLOP, 0, -1*(qt_NQ()+3), 0);
						genquad(ADD, tmpinc, 0, C, 0, C, 0);
						genquad(JMP, NULLOP, 0, NULLOP, 0, A, 0);

					}//if
					else{						//Must be while loop
						A = qt_NQ()+1;			//Note: Probably shouldn't just add 1 because quad table might be full....but I'm too tired right now and I've decided it's worth the risk.
						int C = sas_pop();
						quad(-1*C, 4, -1*A);
						B = sas_pop();			//Get location of partial quad from above
						genquad(JMP, NULLOP, 0, NULLOP, 0, B, 0);	//Create a jump to it
					}//else

					return true;
				}
				else{
					sf_error("Expecting 'loop'");
					return false;			//Expecting 'loop'
				}
			}
			else{
				sf_error("Expecting 'end'");
				return false;				//Expecting end
			}
		}
		else
			return false;
	}
	else{
		sf_error("Expecting 'loop'");
		return false;
	}//else
}//sf_basic_loop

bool sf_range(){
	if(sf_simple_expr()){
		if(SymTable[iNT].iTokenType == findTokenType("..")){
			sf_getNT();
			return sf_simple_expr();
		}
		else{
			sf_error("Expecting ..");
			return false;			//Expecting '..'
		}//else
	}
	else
		return false;
}//sf_range

bool sf_io_stmt(){
	if(SymTable[iNT].iTokenType == findTokenType("read")){
		sf_getNT();
		if(sf_input_spec()){
			//Note: this local array mess is needed because the items are pushed in 
			//reverse order.  The array will cache all items and output them in the correct order
			int items[80];		//Should never have more than 80 output items (not even close)
			int ct = -1;
			int A = sas_pop();
			while(A != IOTAG){					//Loop for all output items
				items[++ct] = A;
				A = sas_pop();
			}//while
			while(ct >=0){
				genquad(READ, items[ct--], 0, NULLOP, 0, NULLOP, 0);
			}
			if(SymTable[iNT].iTokenType == findTokenType(";")){
				sf_getNT();
				return true;
			}
			else{
				sf_error("Expecting ;");
				return false;					//Expecting ;
			}//else
		}
		else
			return false;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("readln")){
		sf_getNT();
		if(sf_input_spec()){
			//Note: this local array mess is needed because the items are pushed in 
			//reverse order.  The array will cache all items and output them in the correct order
			int items[80];		//Should never have more than 80 output items (not even close)
			int ct = -1;
			int A = sas_pop();
			while(A != IOTAG){					//Loop for all output items
				items[++ct] = A;
				A = sas_pop();
			}//while
			while(ct >=0){
				genquad(READLN, items[ct--], 0, NULLOP, 0, NULLOP, 0);
			}
			if(SymTable[iNT].iTokenType == findTokenType(";")){
				sf_getNT();
				return true;
			}
			else{
				sf_error("Expecting ;");
				return false;			//Expecting ;
			}
		}
		else
			return false;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("write")){
		sf_getNT();
		if(sf_output_spec()){

			//Note: this local array mess is needed because the items are pushed in 
			//reverse order.  The array will cache all items and output them in the correct order
			int items[80];		//Should never have more than 80 output items (not even close)
			int ct = -1;
			int A = sas_pop();
			while(A != IOTAG){					//Loop for all output items
				items[++ct] = A;
				A = sas_pop();
			}//while
			while(ct >=0){
				genquad(WRITE, items[ct--], 0, NULLOP, 0, NULLOP, 0);
			}

			if(SymTable[iNT].iTokenType == findTokenType(";")){
				sf_getNT();
				return true;
			}
			else{
				sf_error("Expecting ;");
				return false;			//Expecting ';'
			}
		}
		else
			return false;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("writeln")){
		sf_getNT();
		if(sf_output_spec()){

			//Note: this local array mess is needed because the items are pushed in 
			//reverse order.  The array will cache all items and output them in the correct order
			int items[80];		//Should never have more than 80 output items (not even close)
			int ct = -1;
			int A = sas_pop();
			while(A != IOTAG){					//Loop for all output items
				items[++ct] = A;
				A = sas_pop();
			}//while
			while(ct >=0){
				genquad(WRITELN, items[ct--], 0, NULLOP, 0, NULLOP, 0);
			}

			if(SymTable[iNT].iTokenType == findTokenType(";")){
				sf_getNT();
				return true;
			}
			else{
				sf_error("Expecting ;");
				return false;			//Expecting ';'
			}
		}
		else
			return false;
	}
	else{
		sf_error("Expecting one of: read, readln, write, writeln");
		return false;		//Expecting read, readln, write, writeln
	}
}//sf_io_stmt

bool sf_input_spec(){
	if(SymTable[iNT].iTokenType == findTokenType("(")){
		sf_getNT();
		sas_push(IOTAG);			//Tag that indicates the end of a set of io items
		if(sf_I()){
			if(sf_more_inputs()){
				if(SymTable[iNT].iTokenType == findTokenType(")")){
					sf_getNT();
					return true;
				}
				else{
					sf_error("Expecting )");
					return false;	//Expecting ")"
				}
			}
			else
				return false;
		}
		else{
			sf_error("Expecting identifier");
			return false;			//Expecting ID
		}
	}
	else if(SymTable[iNT].iTokenType == findTokenType(";"))
		return true;
	else{
		sf_error("Expecting ( or ;");
		return false;				//Expecting ( or ;
	}
}//sf_input_spec

bool sf_more_inputs(){
	if(SymTable[iNT].iTokenType == findTokenType(",")){
		sf_getNT();
		if(SymTable[iNT].iTokenType == TOKEN_TYPE_ID){
			sas_push(iNT);
			sf_getNT();
			return sf_more_inputs();
		}
		else{
			sf_error("Expecting identifier");
			return false;			//Expecting <id>
		}//else
	}
	else if(SymTable[iNT].iTokenType == findTokenType(")"))
		return true;
	else{
		sf_error("Expecting , or )");
		return false;				//Expecting ")";
	}
}//sf_more_inputs

bool sf_output_spec(){
	if(SymTable[iNT].iTokenType == findTokenType("(")){
		sf_getNT();
		sas_push(IOTAG);			//Tag that indicates the end of a set of io items

		if(sf_output_item()){
			if(sf_more_outputs()){
				if(SymTable[iNT].iTokenType == findTokenType(")")){
					sf_getNT();
					return true;
				}
				else{
					sf_error("Expecting )");
					return false;			//Expecting )
				}//else
			}
			else
				return false;
		}
		else
			return false;
	}
	else if(SymTable[iNT].iTokenType == findTokenType(";"))
		return true;
	else{
		sf_error("Expecting ( or ;");
		return false;				//Expecting ; or (
	}
}//sf_output_spec

bool sf_output_item(){
	if( (SymTable[iNT].iTokenType == TOKEN_TYPE_ID)			|| 
		(SymTable[iNT].iTokenType == findTokenType("("))	||
		(SymTable[iNT].iTokenType == TOKEN_TYPE_CONST)		||
		(SymTable[iNT].iTokenType == findTokenType("sqrt"))	||
		(SymTable[iNT].iTokenType == findTokenType("abs"))	||
		(SymTable[iNT].iTokenType == findTokenType("+"))	||
		(SymTable[iNT].iTokenType == findTokenType("-"))){
		if(sf_simple_expr()){
			
			return true;
		}
		else
			return false;
	}
	else if(SymTable[iNT].iTokenType == TOKEN_TYPE_LITERAL){
		sas_push(iNT);			//Push string onto stack
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting one of: identifier, integer, string literal, (, sqrt, abs, +, -");
		return false;
	}

}//sf_output_item

bool sf_more_outputs(){
	if(SymTable[iNT].iTokenType == findTokenType(",")){
		sf_getNT();
		if(sf_output_item()){
			return sf_more_outputs();
		}
		else
			return false;
	}
	else if(SymTable[iNT].iTokenType == findTokenType(")"))
		return true;
	else{
		sf_error("Expecting , or )");
		return false;
	}
}//sf_more_outputs

bool sf_expression(){	
	if(sf_relation()){
		return sf_expression1();
	}
	else
		return false;
}//sf_expression

bool sf_expression1(){
	if( (SymTable[iNT].iTokenType == findTokenType("and"))		||
		(SymTable[iNT].iTokenType == findTokenType("or"))		||
		(SymTable[iNT].iTokenType == findTokenType("xor"))){
		if(sf_bool_op()){
			if(sf_relation()){
				
				int A, B, C, D;
				C = sas_pop();					//Right hand side of operator
				B = sas_pop();					//Operator
				A = sas_pop();					//Left hand side of operator
				D = gentemp();

				if(B == findTokenType("and")){
					sas_push( -1*qt_NQ());
					genquad(JFALSE, A, 0, NULLOP, 0, NULLOP, 0);
					sas_push( -1*qt_NQ());
					genquad(JFALSE, C, 0, NULLOP, 0, NULLOP, 0);
					genquad(ASSIGN, iTokenIndexTrue, 0, NULLOP, 0, D, 0);
					sas_push( -1*qt_NQ());
					genquad(JMP, NULLOP, 0, NULLOP, 0, NULLOP, 0);		//Generate partial quad
					A = sas_pop();
					genquad(ASSIGN, iTokenIndexFalse, 0, NULLOP, 0, D, 0);
					quad(-1*A, 4, -1*qt_NQ());
					A = sas_pop();
					quad(-1*A, 4, -1*(qt_NQ()-1));
					A = sas_pop();
					quad(-1*A, 4, -1*(qt_NQ()-1));
					sas_push(D);
				}//if
				else if(B == findTokenType("or")){
					sas_push( -1*qt_NQ());
					genquad(JTRUE, A, 0, NULLOP, 0, NULLOP, 0);
					sas_push( -1*qt_NQ());
					genquad(JTRUE, C, 0, NULLOP, 0, NULLOP, 0);
					genquad(ASSIGN, iTokenIndexFalse, 0, NULLOP, 0, D, 0);
					sas_push( -1*qt_NQ());
					genquad(JMP, NULLOP, 0, NULLOP, 0, NULLOP, 0);		//Generate partial quad
					A = sas_pop();
					genquad(ASSIGN, iTokenIndexTrue, 0, NULLOP, 0, D, 0);
					quad(-1*A, 4, -1*qt_NQ());
					A = sas_pop();
					quad(-1*A, 4, -1*(qt_NQ()-1));
					A = sas_pop();
					quad(-1*A, 4, -1*(qt_NQ()-1));
					sas_push(D);
				}//else if
				else if(B == findTokenType("xor")){
					genquad(JFALSE, A, 0, NULLOP, 0, -1*(qt_NQ()+4), 0);
					genquad(JFALSE, C, 0, NULLOP, 0, -1*(qt_NQ()+4), 0);
					genquad(ASSIGN, iTokenIndexFalse, 0, NULLOP, 0, D, 0);
					genquad(JMP, NULLOP, 0, NULLOP, 0, -1*(qt_NQ()+3), 0);					
					genquad(JFALSE, C, 0, NULLOP, 0, -1*(qt_NQ()-2), 0);
					genquad(ASSIGN, iTokenIndexTrue, 0, NULLOP, 0, D, 0);
					sas_push(D);
				}//else

				return sf_expression1();
			}
			else
				return false;
		}
		else
			return false;
	}
	else if((SymTable[iNT].iTokenType == findTokenType(";"))	||
			(SymTable[iNT].iTokenType == findTokenType("then"))	||
			(SymTable[iNT].iTokenType == findTokenType(")"))	||
			(SymTable[iNT].iTokenType == findTokenType("loop")))
		return true;
	else{
		sf_error("Expecting one of: and, or, xor, ;, then, loop");
		return false;
	}
}//sf_expression1

bool sf_relation(){
	if(sf_simple_expr())
		return sf_relation1();
	else
		return false;
}//sf_relation

bool sf_relation1(){
	if(	(SymTable[iNT].iTokenType == findTokenType("<"))			||
		(SymTable[iNT].iTokenType == findTokenType(">"))			||
		(SymTable[iNT].iTokenType == findTokenType(">="))			||
		(SymTable[iNT].iTokenType == findTokenType("<="))			||
		(SymTable[iNT].iTokenType == findTokenType("="))			||
		(SymTable[iNT].iTokenType == findTokenType("<>"))){
		if(sf_rel_op()){
			if(sf_simple_expr()){
				
				int A, B, C, D;
				D = gentemp();
				C = sas_pop();
				A = sas_pop();
				B = sas_pop();
				sas_push(D);
				genquad(A, B, 0, C, 0, D, 0);
				
				return true;
			}//if
			else
				return false;
		}
		else
			return false;
	}
	else if(	(SymTable[iNT].iTokenType == findTokenType(";"))	||
				(SymTable[iNT].iTokenType == findTokenType("then"))	||
				(SymTable[iNT].iTokenType == findTokenType("loop"))	||
				(SymTable[iNT].iTokenType == findTokenType(")"))	||
				(SymTable[iNT].iTokenType == findTokenType("and"))	||
				(SymTable[iNT].iTokenType == findTokenType("or"))	||
				(SymTable[iNT].iTokenType == findTokenType("xor"))){
		return true;
	}
	else{
		sf_error("Expecting one of: <, >, >=, <=, =, <>, ;, then, loop, ), and, or, xor");
		return false;
	}
}//sf_relation1

bool sf_simple_expr(){
	if(	(SymTable[iNT].iTokenType == findTokenType("+"))		||
		(SymTable[iNT].iTokenType == findTokenType("-"))){
		if(sf_unary_op())
			if(sf_term())
				return sf_simple_expr1();
			else
				return false;
		else
			return false;
	}
	else if(	(SymTable[iNT].iTokenType == TOKEN_TYPE_ID)			||
				(SymTable[iNT].iTokenType == findTokenType("("))	||
				(SymTable[iNT].iTokenType == TOKEN_TYPE_CONST)		||
				(SymTable[iNT].iTokenType == findTokenType("sqrt"))	||
				(SymTable[iNT].iTokenType == findTokenType("abs"))){
		if(sf_term())
			return sf_simple_expr1();
		else
			return false;
	}
	else{
		sf_error("Expecting one of: +, -, identifier, (, integer, sqrt, abs");
		return false;
	}
}//sf_simple_expr

bool sf_simple_expr1(){
	if(	(SymTable[iNT].iTokenType == findTokenType("+"))		||
		(SymTable[iNT].iTokenType == findTokenType("-"))){
		if(sf_add_op())
			if(sf_term()){

				int A, B, C, D;
				D = gentemp();
				C = sas_pop();
				A = sas_pop();			//This assumes the operator has been pushed onto the stack
				B = sas_pop();
				sas_push(D);
				
				genquad(A, B, 0, C, 0, D, 0);
				
				return sf_simple_expr1();
			}//if
			else
				return false;
		else
			return false;
	}
	else if(	(SymTable[iNT].iTokenType == findTokenType("<"))	||
				(SymTable[iNT].iTokenType == findTokenType(">"))	||
				(SymTable[iNT].iTokenType == findTokenType(">="))	||
				(SymTable[iNT].iTokenType == findTokenType("<="))	||
				(SymTable[iNT].iTokenType == findTokenType("="))	||
				(SymTable[iNT].iTokenType == findTokenType("<>"))	||
				(SymTable[iNT].iTokenType == findTokenType(";"))	||
				(SymTable[iNT].iTokenType == findTokenType(","))	||
				(SymTable[iNT].iTokenType == findTokenType("then"))	||
				(SymTable[iNT].iTokenType == findTokenType("loop"))	||
				(SymTable[iNT].iTokenType == findTokenType(".."))	||
				(SymTable[iNT].iTokenType == findTokenType(")"))	||
				(SymTable[iNT].iTokenType == findTokenType("]"))	||
				(SymTable[iNT].iTokenType == findTokenType("and"))	||
				(SymTable[iNT].iTokenType == findTokenType("or"))	||
				(SymTable[iNT].iTokenType == findTokenType("xor")))
		return true;
	else{
		sf_error("Expecting one of: +, -, <, >, >=, <=, =, <>, ;, ,, then, loop, .., ), and, or, xor");
		return false;
	}
}//sf_simple_expr1

bool sf_term(){
	if(sf_factor())
		return sf_term1();
	else
		return false;
}//sf_term

bool sf_term1(){

	if(	(SymTable[iNT].iTokenType == findTokenType("*"))		||
		(SymTable[iNT].iTokenType == findTokenType("/"))){
		if(sf_mul_op())
			if(sf_factor())
				if(sf_term1()){

					int A, B, C, D;
					D = gentemp();
					C = sas_pop();
					A = sas_pop();
					B = sas_pop();
					sas_push(D);
					
					genquad(A, B, 0, C, 0, D, 0);
					
					return true;
				}//if
				else
					return false;
			else
				return false;
		else
			return false;
	}
	else if(	(SymTable[iNT].iTokenType == findTokenType("<"))	||
				(SymTable[iNT].iTokenType == findTokenType(">"))	||
				(SymTable[iNT].iTokenType == findTokenType(">="))	||
				(SymTable[iNT].iTokenType == findTokenType("<="))	||
				(SymTable[iNT].iTokenType == findTokenType("="))	||
				(SymTable[iNT].iTokenType == findTokenType("<>"))	||
				(SymTable[iNT].iTokenType == findTokenType(";"))	||
				(SymTable[iNT].iTokenType == findTokenType(","))	||
				(SymTable[iNT].iTokenType == findTokenType("then"))	||
				(SymTable[iNT].iTokenType == findTokenType("loop"))	||
				(SymTable[iNT].iTokenType == findTokenType(".."))	||
				(SymTable[iNT].iTokenType == findTokenType(")"))	||
				(SymTable[iNT].iTokenType == findTokenType("and"))	||
				(SymTable[iNT].iTokenType == findTokenType("or"))	||
				(SymTable[iNT].iTokenType == findTokenType("xor"))	||
				(SymTable[iNT].iTokenType == findTokenType("+"))	||
				(SymTable[iNT].iTokenType == findTokenType("]"))	||
				(SymTable[iNT].iTokenType == findTokenType("-")))
		return true;
	else{
		sf_error("Expecting one of: *, /, <, >, >=, <=, =, <>, ;, ,, then, loop, .., ), and, or, xor, +, -");
		return false;
	}
}//sf_term1

bool sf_factor(){
	if(sf_primary())
		return sf_factor1();
	else
		return false;
}//sf_factor

bool sf_factor1(){
	if(SymTable[iNT].iTokenType == findTokenType("**")){
		
		sf_getNT();
		if(sf_primary()){
			int A, B, counter, tmp, tmp2;
			B = sas_pop();
			A = sas_pop();
			counter = gentemp();
			tmp = gentemp();
			tmp2 = gentemp();

			genquad(ASSIGN, B, 0, NULLOP, 0, counter, 0);
			genquad(ASSIGN, A, 0, NULLOP, 0, tmp, 0);

			genquad(JTRUE, B, 0, NULLOP, 0, -1*(qt_NQ()+3), 0);		//If B == 0, fall through
			genquad(ASSIGN, iTokenIndexTrue, 0, NULLOP, 0, tmp, 0);
			genquad(JMP, NULLOP, 0, NULLOP, 0, -1*(qt_NQ()+8), 0);

			genquad(EQ, B, 0, iTokenIndexTrue, 0, tmp2, 0);
			genquad(JFALSE, tmp2, 0, NULLOP, 0, -1*(qt_NQ()+2), 0);
			genquad(JMP, NULLOP, 0, NULLOP, 0, -1*(qt_NQ()+5), 0);


			genquad(SUB, counter, 0, iTokenIndexTrue, 0, counter, 0);
			
			genquad(MUL, tmp, 0, tmp, 0, tmp, 0);
			genquad(SUB, counter, 0, iTokenIndexTrue, 0, counter, 0);
			genquad(JTRUE, counter, 0, NULLOP, 0, -1*(qt_NQ()-2), 0);
			sas_push(tmp);

			return true;

		}//if
		else
			return false;
	}
	else if(	(SymTable[iNT].iTokenType == findTokenType("<"))	||
				(SymTable[iNT].iTokenType == findTokenType(">"))	||
				(SymTable[iNT].iTokenType == findTokenType(">="))	||
				(SymTable[iNT].iTokenType == findTokenType("<="))	||
				(SymTable[iNT].iTokenType == findTokenType("="))	||
				(SymTable[iNT].iTokenType == findTokenType("<>"))	||
				(SymTable[iNT].iTokenType == findTokenType(";"))	||
				(SymTable[iNT].iTokenType == findTokenType(","))	||
				(SymTable[iNT].iTokenType == findTokenType("then"))	||
				(SymTable[iNT].iTokenType == findTokenType("loop"))	||
				(SymTable[iNT].iTokenType == findTokenType(".."))	||
				(SymTable[iNT].iTokenType == findTokenType(")"))	||
				(SymTable[iNT].iTokenType == findTokenType("and"))	||
				(SymTable[iNT].iTokenType == findTokenType("or"))	||
				(SymTable[iNT].iTokenType == findTokenType("xor"))	||
				(SymTable[iNT].iTokenType == findTokenType("+"))	||
				(SymTable[iNT].iTokenType == findTokenType("-"))	||
				(SymTable[iNT].iTokenType == findTokenType("*"))	||
				(SymTable[iNT].iTokenType == findTokenType("]"))	||
				(SymTable[iNT].iTokenType == findTokenType("/")))
		return true;
	else{
		sf_error("Expected one of **, <, >, <=, >=, <>, ; , ',', then, loop, .., ), and, or, xor, +, -, *, /");
		return false;
	}
}//sf_factor1

bool sf_remid(){
	if(SymTable[iNT].iTokenType == findTokenType("[")){
		sf_getNT();
		if(sf_simple_expr()){

			if(SymTable[iNT].iTokenType == findTokenType("]")){
				sf_getNT();
				return true;
			}
			else{
				sf_error("Expecting ]");
				return false;
			}
		}
		else
			return false;
	}
	//Note: This selection set was not provided by Dr. Cooke....I think that this
	//is right, but I didn't spend too much time deciding...jjp
//	else if(	(SymTable[iNT].iTokenType == findTokenType(":="))	||
//				(SymTable[iNT].iTokenType == findTokenType(";")))
	else if(	(SymTable[iNT].iTokenType == findTokenType("**"))	||
				(SymTable[iNT].iTokenType == findTokenType(":="))	||
				(SymTable[iNT].iTokenType == findTokenType("<"))	||
				(SymTable[iNT].iTokenType == findTokenType(">"))	||
				(SymTable[iNT].iTokenType == findTokenType(">="))	||
				(SymTable[iNT].iTokenType == findTokenType("<="))	||
				(SymTable[iNT].iTokenType == findTokenType("="))	||
				(SymTable[iNT].iTokenType == findTokenType("<>"))	||
				(SymTable[iNT].iTokenType == findTokenType(";"))	||
				(SymTable[iNT].iTokenType == findTokenType(","))	||
				(SymTable[iNT].iTokenType == findTokenType("then"))	||
				(SymTable[iNT].iTokenType == findTokenType("loop"))	||
				(SymTable[iNT].iTokenType == findTokenType(".."))	||
				(SymTable[iNT].iTokenType == findTokenType(")"))	||
				(SymTable[iNT].iTokenType == findTokenType("and"))	||
				(SymTable[iNT].iTokenType == findTokenType("or"))	||
				(SymTable[iNT].iTokenType == findTokenType("xor"))	||
				(SymTable[iNT].iTokenType == findTokenType("+"))	||
				(SymTable[iNT].iTokenType == findTokenType("-"))	||
				(SymTable[iNT].iTokenType == findTokenType("*"))	||
				(SymTable[iNT].iTokenType == findTokenType("]"))	||
				(SymTable[iNT].iTokenType == findTokenType("/"))){

		//If we have a remid item that doesn't have a [, then it's not an array item
		//and we need to push 0 onto the sas
		return true;
	}//if
	else{
		sf_error("Expected one of [, **, <, >, <=, >=, <>, ; , ',', then, loop, .., ), and, or, xor, +, -, *, /");
		return false;
	}
}//sf_remid

bool sf_primary(){
	if(SymTable[iNT].iTokenType == TOKEN_TYPE_ID){
		sas_push(iNT);		//Push identifier index onto SAS
		sf_getNT();
		return sf_remid();
	}
	else if(SymTable[iNT].iTokenType == TOKEN_TYPE_CONST){
		sas_push(iNT);		//Push constant index onto SAS
		sf_getNT();
		return true;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("sqrt")){
		sf_getNT();
		if(SymTable[iNT].iTokenType == findTokenType("(")){
			sf_getNT();
			if(sf_expression()){
				if(SymTable[iNT].iTokenType == findTokenType(")")){

					int A, tmp, tmp2, tmp3;
					A = sas_pop();
					tmp = gentemp();
					tmp2 = gentemp();
					tmp3 = gentemp();

					genquad(LT, A, 0, iTokenIndexFalse, 0, tmp2, 0);
					genquad(ASSIGN, iTokenIndexFalse, 0, NULLOP, 0, tmp, 0);

					genquad(JTRUE, tmp2, 0, NULLOP, 0, -1*(qt_NQ()+5), 0);
					
					genquad(ADD, iTokenIndexTrue, 0, tmp, 0, tmp, 0);
					genquad(MUL, tmp, 0, tmp, 0, tmp2, 0);
					genquad(GT, tmp2, 0, A, 0, tmp3, 0);
					genquad(JFALSE, tmp3, 0, NULLOP, 0, -1*(qt_NQ()-3), 0);
					genquad(SUB, tmp, 0, iTokenIndexTrue, 0, tmp, 0);
					sas_push(tmp);


					sf_getNT();
					return true;
				}//if
				else{
					sf_error("Expecting )");
					return false;	//Expecting )
				}
			}//if
			else
				return false;
		}
		else{
			sf_error("Expecting (");
			return false;			//Expecting (
		}
	}
	else if(SymTable[iNT].iTokenType == findTokenType("abs")){
		sf_getNT();
		if(SymTable[iNT].iTokenType == findTokenType("(")){
			sf_getNT();
			if(sf_expression()){

				if(SymTable[iNT].iTokenType == findTokenType(")")){

					int A, tmp, tmp2, tmp3;
					A = sas_pop();
					tmp2 = gentemp();
					tmp = gentemp();
					tmp3 = gentemp();

					/* Hack to create a negative 1 */
					genquad(ASSIGN, iTokenIndexFalse, 0, NULLOP, 0, tmp3, 0);
					genquad(SUB, tmp3, 0, iTokenIndexTrue, 0, tmp3, 0);
					genquad(ASSIGN, A, 0, NULLOP, 0, tmp2, 0);
					genquad(GE, A, 0, NULLOP, 0, tmp, 0);
					genquad(JTRUE, tmp, 0, NULLOP, 0, -1*(qt_NQ()+2), 0);
					genquad(MUL, tmp3, 0, A, 0, tmp2, 0);
					sas_push(tmp2);


					sf_getNT();
					return true;
				}
				else{
					sf_error("Expecting )");
					return false;	//Expecting )
				}
			}//if
			else
				return false;
		}
		else{
			sf_error("Expecting (");
			return false;			//Expecting (
		}
	}
	else if(SymTable[iNT].iTokenType == findTokenType("(")){
		sf_getNT();
		if(sf_expression()){
			if(SymTable[iNT].iTokenType == findTokenType(")")){
				sf_getNT();
				return true;
			}
			else{
				sf_error("Expecting )");
				return false;			//Expecting )
			}
		}
		else
			return false;
	}
	else{
		sf_error("Expecting one of: identifier, integer, sqrt, abs, (");
		return false;
	}

}//sf_primary

bool sf_bool_op(){
	if(SymTable[iNT].iTokenType == findTokenType("and")){
		sas_push(findTokenType("and"));
		sf_getNT();
		return true;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("or")){
		sas_push(findTokenType("or"));
		sf_getNT();
		return true;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("xor")){
		sas_push(findTokenType("xor"));
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting one of: and, or, xor");
		return false;			//Expecting and/or/xor
	}
}//sf_bool_op

bool sf_rel_op(){
	if(SymTable[iNT].iTokenType == findTokenType("<=")){
		return sf_le();
	}
	else if(SymTable[iNT].iTokenType == findTokenType(">=")){
		return sf_ge();
	}
	else if(SymTable[iNT].iTokenType == findTokenType("<")){
		return sf_lt();
	}
	else if(SymTable[iNT].iTokenType == findTokenType(">")){
		return sf_gt();
	}
	else if(SymTable[iNT].iTokenType == findTokenType("=")){
		return sf_eq();
	}
	else if(SymTable[iNT].iTokenType == findTokenType("<>")){
		return sf_ne();
	}
	else{
		sf_error("Expecting one of: <=, >=, <, >, =, <>");
		return false;
	}
}//sf_rel_op

bool sf_le(){
	if(SymTable[iNT].iTokenType == findTokenType("<=")){
		sas_push(LE);
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting <=");
		return false;
	}//else
}//sf_le

bool sf_ge(){
	if(SymTable[iNT].iTokenType == findTokenType(">=")){
		sas_push(GE);
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting >=");
		return false;
	}
}//bool sf_ge

bool sf_lt(){
	if(SymTable[iNT].iTokenType == findTokenType("<")){
		sas_push(LT);
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting <");
		return false;
	}
}//sf_lt

bool sf_gt(){
	if(SymTable[iNT].iTokenType == findTokenType(">")){
		sas_push(GT);
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting >");
		return false;
	}//else
}//sf_gt

bool sf_eq(){
	if(SymTable[iNT].iTokenType == findTokenType("=")){
		sas_push(EQ);
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting =");
		return false;
	}//else
}//sf_eq

bool sf_ne(){
	if(SymTable[iNT].iTokenType == findTokenType("<>")){
		sas_push(NE);
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting <>");
		return false;
	}//else
}//sf_ne

bool sf_add_op(){
	if(SymTable[iNT].iTokenType == findTokenType("+")){
		sas_push(ADD);					//Push operator onto sas
		sf_getNT();
		return true;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("-")){
		sas_push(SUB);					//Push operator onto sas
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting + or -");
		return true;					//Expecting +,-
	}//else
}//sf_add_op

bool sf_mul_op(){
	if(SymTable[iNT].iTokenType == findTokenType("*")){
		sas_push(MUL);					//Push op onto sas
		sf_getNT();
		return true;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("/")){
		sas_push(DIV);					//Push op onto sas
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting * or /");
		return false;
	}
}//sf_mul_op

bool sf_unary_op(){
	if(SymTable[iNT].iTokenType == findTokenType("+")){
		sf_getNT();
		return true;
	}
	else if(SymTable[iNT].iTokenType == findTokenType("-")){
		sf_getNT();
		return true;
	}
	else{
		sf_error("Expecting + or -");
		return false;
	}
}//sf_unary_op

//This function is used to report syntax errors.
void sf_error(char *pMsg){
	
	printf("Error on line %d [%d]:\n", iCurrLine+1, iLineOffset);
	printf("    %s\n", pMsg);
	iException++;

}//sf_error

//The sf_getNT function will call the real getNT to get the next token.
//It is placed here to do some sanity checking on the return value to ensure
//that the lexical item is valid.  If it encounters an invalid lexical item,
//it will report the error and continue to consume tokens from the input
//until a real one has been found.
//This is a pretty bad hack...
void sf_getNT(){
	int i = getNT();
	if(i < 0){
		switch(i){
		case ERR_FILE_IO:
			printf("Error: Unknown file I/O error\n");
			break;
		case ERR_SYM_TABLE_FULL:
			printf("Error: The symbol table is full.\n");
			printf("       Your program is too complex for this simple compiler!\n");
			break;
		case ERR_INVALID_LEXEME:
			printf("Error: Invalid lexical element on line %d\n", iCurrLine+1);
			break;
		case ERR_STRING_NOT_TERM:
			printf("Error: String literal not terminated correctly\n");
			break;
		case ERR_EOF:
//			if(iException != 0)
//				printf("Error: Unexpected EOF\n");
			break;
		case ERR_INVALID_STRING_CHAR:
			printf("Error: Invalid character in string literal on line %d\n", iCurrLine+1);

			break;
		}//switch

		if(i != ERR_EOF)				//Dont increment errs on eof
			iException++;
		
	}//if
}//sf_getNT