/* CompilerParser.c */
/*****************************************************************************/
/*                                                                           */
/*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
/*    Copyright (C) 1994  Thomas R. Lawrence                                 */
/*                                                                           */
/*    This program is free software; you can redistribute it and/or modify   */
/*    it under the terms of the GNU General Public License as published by   */
/*    the Free Software Foundation; either version 2 of the License, or      */
/*    (at your option) any later version.                                    */
/*                                                                           */
/*    This program is distributed in the hope that it will be useful,        */
/*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/*    GNU General Public License for more details.                           */
/*                                                                           */
/*    You should have received a copy of the GNU General Public License      */
/*    along with this program; if not, write to the Free Software            */
/*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
/*                                                                           */
/*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
/*                                                                           */
/*****************************************************************************/

#include "MiscInfo.h"
#include "Audit.h"
#include "Debug.h"
#include "Definitions.h"

#include "CompilerParser.h"
#include "CompilerScanner.h"
#include "SymbolTableEntry.h"
#include "ASTExpression.h"
#include "SymbolTable.h"
#include "TrashTracker.h"
#include "SymbolList.h"
#include "PcodeObject.h"
#include "Memory.h"
#include "ASTAssignment.h"
#include "ASTBinaryOperator.h"
#include "ASTErrorForm.h"
#include "ASTLoop.h"
#include "ASTArrayDeclaration.h"
#include "ASTVariableDeclaration.h"
#include "ASTConditional.h"
#include "ASTUnaryOperator.h"
#include "ASTOperand.h"
#include "ASTFuncCall.h"
#include "ASTExpressionList.h"
#include "ASTWaveGetter.h"
#include "ASTPrintString.h"
#include "ASTPrintExpr.h"
#include "FloatingPoint.h"


/* protoplops */
static CompileErrors	ParseFunction(SymbolRec** FunctionSymbolTableEntryOut,
												ASTExpressionRec** FunctionBodyOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParsePrototype(SymbolRec** PrototypeSymbolTableEntryOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseFormalParamStart(SymbolListRec** FormalArgListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseType(DataTypes* TypeOut, ScannerRec* Scanner,
												long* LineNumberOut);

static CompileErrors	ParseFormalParamList(SymbolListRec** FormalArgListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseVarTail(ASTExpressionRec** ExpressionOut,
												TokenRec* VariableName, long VariableDeclLine,
												DataTypes VariableType, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseIfRest(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseWhileLoop(ASTExpressionRec** ExpressionOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseLoopWhileUntil(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LoopBodyExpression, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut, long LineNumberOfLoop);

static CompileErrors	ParseUntilLoop(ASTExpressionRec** ExpressionOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseExpr2(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseFormalArg(SymbolRec** FormalArgOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseFormalArgTail(SymbolListRec** ArgListTailOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseIfTail(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* Predicate, ASTExpressionRec* Consequent,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseExpr3(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseExpr2Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LeftHandSide, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseExpr4(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseExpr3Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LeftHandSide, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseConjOper(BinaryOpType* OperatorOut, ScannerRec* Scanner,
												long* LineNumberOut);

static CompileErrors	ParseExpr5(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseExpr4Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LeftHandSide, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseRelOper(BinaryOpType* OperatorOut, ScannerRec* Scanner,
												long* LineNumberOut);

static CompileErrors	ParseExpr6(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseExpr5Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LeftHandSide, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseAddOper(BinaryOpType* OperatorOut, ScannerRec* Scanner,
												long* LineNumberOut);

static CompileErrors	ParseExpr7(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseMultOper(BinaryOpType* OperatorOut, ScannerRec* Scanner,
												long* LineNumberOut);

static CompileErrors	ParseExpr8(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseExpr7Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* TheExpr8Thing, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseFuncCall(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* FunctionGenerator, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseArraySubscript(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* ArrayGenerator, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut);

static CompileErrors	ParseExponentiation(ASTExpressionRec** ExpressionOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseActualStart(ASTExprListRec** ParamListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseActualList(ASTExprListRec** ParamListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseActualTail(ASTExprListRec** ParamListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseExprListTail(ASTExprListRec** ListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);

static CompileErrors	ParseExprListElem(ASTExpressionRec** ExpressionOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut);




/* parse a top-level form, which is either a prototype or a function.  prototypes */
/* are entered into the symbol table and return NIL in *FunctionBodyOut but returns */
/* eCompileNoError. */
/*   1:   <form>             ::= <function> ; */
/*   2:                      ::= <prototype> ; */
/* FIRST SET: */
/* <form>             : {func, proto, <function>, <prototype>} */
/* FOLLOW SET: */
/* <form>             : {$$$} */
CompileErrors					ParseForm(struct SymbolRec** FunctionSymbolTableEntryOut,
												struct ASTExpressionRec** FunctionBodyOut,
												struct ScannerRec* Scanner, struct SymbolTableRec* SymbolTable,
												struct TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;
		CompileErrors				Error;

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		/* do lookahead on "func" */
		if ((GetTokenType(Token) == eTokenKeyword)
			&& (GetTokenKeywordTag(Token) == eKeywordFunc))
			{
				/* push token back */
				UngetToken(Scanner,Token);

				/* parse function definition */
				Error = ParseFunction(FunctionSymbolTableEntryOut,FunctionBodyOut,
					Scanner,SymbolTable,TrashTracker,LineNumberOut);
				if (Error != eCompileNoError)
					{
						return Error;
					}
			}

		/* do lookahead on "proto" */
		else if ((GetTokenType(Token) == eTokenKeyword)
			&& (GetTokenKeywordTag(Token) == eKeywordProto))
			{
				/* push token back */
				UngetToken(Scanner,Token);

				/* parse prototype */
				Error = ParsePrototype(FunctionSymbolTableEntryOut,Scanner,SymbolTable,
					TrashTracker,LineNumberOut);
				*FunctionBodyOut = NIL; /* no code body for a prototype */
				if (Error != eCompileNoError)
					{
						return Error;
					}
			}

		/* otherwise, it's an error */
		else
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedFuncOrProto;
			}


		/* swallow the semicolon */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenSemicolon)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedSemicolon;
			}

		return eCompileNoError;
	}




/* this parses a function declaration, returning the symbol table entry for the */
/* function in *FunctionSymbolTableEntryOut and the expression for the function */
/* in *FunctionBodyOut. */
/*  14:   <function>         ::= func <identifier> ( <formalparamstart> ) : */
/*      <type> <expr> */
/* FIRST SET: */
/* <function>         : {func} */
/* FOLLOW SET: */
/* <function>         : {;} */
static CompileErrors	ParseFunction(SymbolRec** FunctionSymbolTableEntryOut,
												ASTExpressionRec** FunctionBodyOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;
		TokenRec*						FunctionName;
		SymbolListRec*			FormalArgumentList;
		CompileErrors				Error;
		DataTypes						ReturnType;
		long								LineNumberOfIdentifier;

		/* swallow "func" */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if ((GetTokenType(Token) != eTokenKeyword)
			|| (GetTokenKeywordTag(Token) != eKeywordFunc))
			{
				/* this is impossible -- we should be able to do some error checking here, */
				/* but it seems uncertain since we don't (formally) know whose calling us. */
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedFunc;
			}

		/* get the identifier */
		FunctionName = GetNextToken(Scanner);
		if (FunctionName == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(FunctionName) != eTokenIdentifier)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedIdentifier;
			}
		LineNumberOfIdentifier = GetCurrentLineNumber(Scanner);

		/* add the identifier to the symbol table */
		*FunctionSymbolTableEntryOut = NewSymbol(TrashTracker,
			GetTokenIdentifierString(FunctionName),
			PtrSize(GetTokenIdentifierString(FunctionName)));
		if (*FunctionSymbolTableEntryOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		switch (AddSymbolToTable(SymbolTable,*FunctionSymbolTableEntryOut))
			{
				case eAddSymbolNoErr:
					break;
				case eAddSymbolAlreadyExists:
					*LineNumberOut = LineNumberOfIdentifier;
					return eCompileMultiplyDefinedIdentifier;
				case eAddSymbolNoMemory:
					*LineNumberOut = LineNumberOfIdentifier;
					return eCompileOutOfMemory;
				default:
					EXECUTE(PRERR(ForceAbort,"ParseFunction:  bad value from AddSymbolToTable"));
					break;
			}

		/* create a new lexical level */
		if (!IncrementSymbolTableLevel(SymbolTable))
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		/* swallow the open parenthesis */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenOpenParen)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedOpenParen;
			}

		/* parse <formalparamstart> */
		Error = ParseFormalParamStart(&FormalArgumentList,Scanner,SymbolTable,
			TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* swallow the close parenthesis */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenCloseParen)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedCloseParen;
			}

		/* swallow the colon */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenColon)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedColon;
			}

		/* parse the return type of the function */
		Error = ParseType(&ReturnType,Scanner,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* store the interesting information into the symbol table entry */
		SymbolBecomeFunction(*FunctionSymbolTableEntryOut,FormalArgumentList,ReturnType);

		/* parse the body of the function */
		Error = ParseExpr(FunctionBodyOut,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* pop lexical level */
		DecrementSymbolTableLevel(SymbolTable);

		return eCompileNoError;
	}




/* this parses a prototype of a function and returns a symbol table entry in */
/* the *PrototypeSymbolTableEntryOut place. */
/*  21:   <prototype>        ::= proto <identifier> ( <formalparamstart> ) : */
/*      <type> */
/* FIRST SET: */
/* <prototype>        : {proto} */
/* FOLLOW SET: */
/*  <prototype>        : {then, else, elseif, while, until, do, to, ), CLOSEBRACKET, */
/*       ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParsePrototype(SymbolRec** PrototypeSymbolTableEntryOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;
		TokenRec*						FunctionName;
		long								LineNumberOfIdentifier;
		CompileErrors				Error;
		SymbolListRec*			FormalArgumentList;
		DataTypes						ReturnType;

		/* swallow "proto" */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if ((GetTokenType(Token) != eTokenKeyword)
			|| (GetTokenKeywordTag(Token) != eKeywordProto))
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedFunc;
			}

		/* get the identifier */
		FunctionName = GetNextToken(Scanner);
		if (FunctionName == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(FunctionName) != eTokenIdentifier)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedIdentifier;
			}
		LineNumberOfIdentifier = GetCurrentLineNumber(Scanner);

		/* add the identifier to the symbol table */
		*PrototypeSymbolTableEntryOut = NewSymbol(TrashTracker,
			GetTokenIdentifierString(FunctionName),
			PtrSize(GetTokenIdentifierString(FunctionName)));
		if (*PrototypeSymbolTableEntryOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		switch (AddSymbolToTable(SymbolTable,*PrototypeSymbolTableEntryOut))
			{
				case eAddSymbolNoErr:
					break;
				case eAddSymbolAlreadyExists:
					*LineNumberOut = LineNumberOfIdentifier;
					return eCompileMultiplyDefinedIdentifier;
				case eAddSymbolNoMemory:
					*LineNumberOut = LineNumberOfIdentifier;
					return eCompileOutOfMemory;
				default:
					EXECUTE(PRERR(ForceAbort,"ParsePrototype:  bad value from AddSymbolToTable"));
					break;
			}

		/* create a new lexical level */
		if (!IncrementSymbolTableLevel(SymbolTable))
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		/* swallow the open parenthesis */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenOpenParen)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedOpenParen;
			}

		/* parse <formalparamstart> */
		Error = ParseFormalParamStart(&FormalArgumentList,Scanner,SymbolTable,
			TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* swallow the close parenthesis */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenCloseParen)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedCloseParen;
			}

		/* swallow the colon */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenColon)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedColon;
			}

		/* parse the return type of the function */
		Error = ParseType(&ReturnType,Scanner,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* store the interesting information into the symbol table entry */
		SymbolBecomeFunction(*PrototypeSymbolTableEntryOut,FormalArgumentList,ReturnType);

		/* pop lexical level */
		DecrementSymbolTableLevel(SymbolTable);

		return eCompileNoError;
	}




/* this parses an argument list.  the argument list may be empty, in which case */
/* the empty list (NIL) is returned in *FormalArgListOut. */
/*  15:   <formalparamstart> ::= <formalparamlist> */
/*  16:                      ::=  */
/* FIRST SET: */
/* <formalparamstart> : {<identifier>, <formalparamlist>, <formalarg>} */
/* FOLLOW SET: */
/* <formalparamstart> : {)} */
static CompileErrors	ParseFormalParamStart(SymbolListRec** FormalArgListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;

		/* get a token so we can lookahead */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		/* if it's a paren, then we abort */
		if (GetTokenType(Token) == eTokenCloseParen)
			{
				/* stuff it back */
				UngetToken(Scanner,Token);

				/* we want to return the empty list since argument list is empty */
				*FormalArgListOut = NIL;

				return eCompileNoError;
			}

		/* stuff it back */
		UngetToken(Scanner,Token);

		/* it really is something, so parse it */
		return ParseFormalParamList(FormalArgListOut,Scanner,SymbolTable,TrashTracker,
			LineNumberOut);
	}




/* this function parses a type and returns the corresponding enumeration value */
/* in *TypeOut. */
/*   3:   <type>             ::= void */
/*   4:                      ::= bool */
/*   5:                      ::= int */
/*   6:                      ::= single */
/*   7:                      ::= double */
/*   8:                      ::= fixed */
/*   9:                      ::= boolarray */
/*  10:                      ::= intarray */
/*  11:                      ::= singlearray */
/*  12:                      ::= doublearray */
/*  13:                      ::= fixedarray */
/* FIRST SET: */
/* <type>             : {void, bool, int, single, double, fixed, boolarray, */
/*      intarray, singlearray, doublearray, fixedarray} */
/* FOLLOW SET: */
/*  <type>             : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, proto, var, not, sin, cos, */
/*       tan, asin, acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, if, */
/*       then, else, elseif, while, until, do, resize, to, error, true, */
/*       false, set, (, ), CLOSEBRACKET, ,, :=, ;, -, EQ, <prototype>, <expr>, */
/*       <formalargtail>, <vartail>, <expr2>, <expr3>, <expr4>, <expr5>, <expr6>, */
/*       <unary_oper>, <expr7>, <expr8>, <actualtail>, <iftail>, <whileloop>, */
/*       <loopwhileuntil>, <untilloop>, <exprlisttail>} */
static CompileErrors	ParseType(DataTypes* TypeOut, ScannerRec* Scanner,
												long* LineNumberOut)
	{
		TokenRec*						Token;

		/* get the word */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		/* make sure it's a keyword */
		if (GetTokenType(Token) != eTokenKeyword)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedTypeSpecifier;
			}

		/* do the decoding */
		switch (GetTokenKeywordTag(Token))
			{
				default:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileExpectedTypeSpecifier;
				case eKeywordVoid:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileVoidExpressionIsNotAllowed;
				case eKeywordBool:
					*TypeOut = eBoolean;
					break;
				case eKeywordInt:
					*TypeOut = eInteger;
					break;
				case eKeywordSingle:
					*TypeOut = eFloat;
					break;
				case eKeywordDouble:
					*TypeOut = eDouble;
					break;
				case eKeywordFixed:
					*TypeOut = eFixed;
					break;
				case eKeywordBoolarray:
					*TypeOut = eArrayOfBoolean;
					break;
				case eKeywordIntarray:
					*TypeOut = eArrayOfInteger;
					break;
				case eKeywordSinglearray:
					*TypeOut = eArrayOfFloat;
					break;
				case eKeywordDoublearray:
					*TypeOut = eArrayOfDouble;
					break;
				case eKeywordFixedarray:
					*TypeOut = eArrayOfFixed;
					break;
			}

		return eCompileNoError;
	}




/*   26:   <expr>             ::= <expr2> */
/*  109:   <expr>             ::= if <ifrest> */
/*  114:   <expr>             ::= <whileloop> */
/*  115:                      ::= do <expr> <loopwhileuntil> */
/*  116:                      ::= <untilloop> */
/*  121:   <expr>             ::= set <expr> := <expr> */
/*  125:   <expr>             ::= resize <expr> to <expr> */
/*  126:                      ::= error <string> resumable <expr> */
/*  XXX:                      ::= getsampleleft <string> */
/*  XXX:                      ::= getsampleright <string> */
/*  XXX:                      ::= getsample <string> */
/*  XXX:                      ::= getwavenumframes <string> */
/*  XXX:                      ::= getwavenumtables <string> */
/*  XXX:                      ::= getwavedata <string> */
/*  XXX:                      ::= print (<string> | <expr>) */
/* FIRST SET: */
/*  <expr>             : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, proto, var, not, sin, cos, */
/*       tan, asin, acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, if, */
/*       while, until, do, resize, error, true, false, set, (, -, */
/*       <prototype>, <expr2>, <expr3>, <expr4>, <expr5>, <expr6>, <unary_oper>, */
/*       <expr7>, <expr8>, <whileloop>, <untilloop>} */
/* FOLLOW SET: */
/*  <expr>             : {then, else, elseif, while, until, do, to, ), CLOSEBRACKET, */
/*       ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
CompileErrors					ParseExpr(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		long								LineNumberForFirstToken;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		/* get the first token to be gotten */
		Token = GetNextToken(Scanner);
		LineNumberForFirstToken = GetCurrentLineNumber(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = LineNumberForFirstToken;
				return eCompileOutOfMemory;
			}

		/* see what action should be taken */
		switch (GetTokenType(Token))
			{
				default:
					UngetToken(Scanner,Token);
					return ParseExpr2(ExpressionOut,Scanner,SymbolTable,TrashTracker,
						LineNumberOut);

				case eTokenKeyword:
					switch (GetTokenKeywordTag(Token))
						{
							default:
								UngetToken(Scanner,Token);
								return ParseExpr2(ExpressionOut,Scanner,SymbolTable,TrashTracker,
									LineNumberOut);

							/*  109:   <expr>             ::= if <ifrest> */
							case eKeywordIf:
								return ParseIfRest(ExpressionOut,Scanner,SymbolTable,TrashTracker,
									LineNumberOut);

							/*  114:   <expr>             ::= <whileloop> */
							/* FIRST SET: */
							/*  <whileloop>        : {while} */
							case eKeywordWhile:
								UngetToken(Scanner,Token);
								return ParseWhileLoop(ExpressionOut,Scanner,SymbolTable,TrashTracker,
									LineNumberOut);

							/*  115:                      ::= do <expr> <loopwhileuntil> */
							case eKeywordDo:
								{
									ASTExpressionRec*		BodyExpression;
									CompileErrors				Error;

									Error = ParseExpr(&BodyExpression,Scanner,SymbolTable,
										TrashTracker,LineNumberOut);
									if (Error != eCompileNoError)
										{
											return Error;
										}

									/* parse the rest of it */
									return ParseLoopWhileUntil(ExpressionOut,BodyExpression,Scanner,
										SymbolTable,TrashTracker,LineNumberOut,LineNumberForFirstToken);
								}

							/*  116:                      ::= <untilloop> */
							/* FIRST SET */
							/*  <untilloop>        : {until} */
							case eKeywordUntil:
								UngetToken(Scanner,Token);
								return ParseUntilLoop(ExpressionOut,Scanner,SymbolTable,TrashTracker,
									LineNumberOut);

							/*  121:   <expr>             ::= set <expr> := <expr> */
							case eKeywordSet:
								{
									ASTExpressionRec*		LValue;
									ASTExpressionRec*		RValue;
									CompileErrors				Error;
									ASTAssignRec*				TotalAssignment;

									Error = ParseExpr(&LValue,Scanner,SymbolTable,TrashTracker,
										LineNumberOut);
									if (Error != eCompileNoError)
										{
											return Error;
										}

									/* swallow the colon-equals */
									Token = GetNextToken(Scanner);
									if (Token == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if (GetTokenType(Token) != eTokenColonEqual)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileExpectedColonEqual;
										}

									Error = ParseExpr(&RValue,Scanner,SymbolTable,TrashTracker,
										LineNumberOut);
									if (Error != eCompileNoError)
										{
											return Error;
										}

									TotalAssignment = NewAssignment(LValue,RValue,TrashTracker,
										LineNumberForFirstToken);
									if (TotalAssignment == NIL)
										{
											*LineNumberOut = LineNumberForFirstToken;
											return eCompileOutOfMemory;
										}

									*ExpressionOut = NewExprAssignment(TotalAssignment,TrashTracker,
										LineNumberForFirstToken);
									if (*ExpressionOut == NIL)
										{
											*LineNumberOut = LineNumberForFirstToken;
											return eCompileOutOfMemory;
										}

									return eCompileNoError;
								}

							/*  125:   <expr>             ::= resize <expr> to <expr> */
							case eKeywordResize:
								{
									ASTExpressionRec*		ArrayGenerator;
									ASTExpressionRec*		NewSizeExpression;
									CompileErrors				Error;
									ASTBinaryOpRec*			BinaryOperator;

									Error = ParseExpr(&ArrayGenerator,Scanner,SymbolTable,TrashTracker,
										LineNumberOut);
									if (Error != eCompileNoError)
										{
											return Error;
										}

									/* swallow the to */
									Token = GetNextToken(Scanner);
									if (Token == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if ((GetTokenType(Token) != eTokenKeyword)
										|| (GetTokenKeywordTag(Token) != eKeywordTo))
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileExpectedTo;
										}

									Error = ParseExpr(&NewSizeExpression,Scanner,SymbolTable,TrashTracker,
										LineNumberOut);
									if (Error != eCompileNoError)
										{
											return Error;
										}

									BinaryOperator = NewBinaryOperator(eBinaryResizeArray,ArrayGenerator,
										NewSizeExpression,TrashTracker,LineNumberForFirstToken);
									if (BinaryOperator == NIL)
										{
											*LineNumberOut = LineNumberForFirstToken;
											return eCompileOutOfMemory;
										}

									*ExpressionOut = NewExprBinaryOperator(BinaryOperator,TrashTracker,
										LineNumberForFirstToken);
									if (*ExpressionOut == NIL)
										{
											*LineNumberOut = LineNumberForFirstToken;
											return eCompileOutOfMemory;
										}

									return eCompileNoError;
								}

							/*  126:                      ::= error <string> resumable <expr> */
							case eKeywordError:
								{
									TokenRec*						MessageString;
									ASTExpressionRec*		ResumableCondition;
									CompileErrors				Error;
									ASTErrorFormRec*		ErrorForm;

									MessageString = GetNextToken(Scanner);
									if (MessageString == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if (GetTokenType(MessageString) != eTokenString)
										{
											*LineNumberOut = LineNumberForFirstToken;
											return eCompileExpectedStringLiteral;
										}

									/* swallow the resumable */
									Token = GetNextToken(Scanner);
									if (Token == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if ((GetTokenType(Token) != eTokenKeyword)
										|| (GetTokenKeywordTag(Token) != eKeywordResumable))
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileExpectedResumable;
										}

									Error = ParseExpr(&ResumableCondition,Scanner,SymbolTable,
										TrashTracker,LineNumberOut);
									if (Error != eCompileNoError)
										{
											return Error;
										}

									ErrorForm = NewErrorForm(ResumableCondition,
										GetTokenStringValue(MessageString),TrashTracker,
										LineNumberForFirstToken);
									if (ErrorForm == NIL)
										{
											*LineNumberOut = LineNumberForFirstToken;
											return eCompileOutOfMemory;
										}

									*ExpressionOut = NewExprErrorForm(ErrorForm,TrashTracker,
										LineNumberForFirstToken);
									if (*ExpressionOut == NIL)
										{
											*LineNumberOut = LineNumberForFirstToken;
											return eCompileOutOfMemory;
										}

									return eCompileNoError;
								}

							/*  XXX:                      ::= getsampleleft <string> */
							case eKeywordGetsampleleft:
								{
									ASTWaveGetterRec*		WaveGetterThang;

									Token = GetNextToken(Scanner);
									if (Token == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if (GetTokenType(Token) != eTokenString)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileExpectedStringLiteral;
										}

									WaveGetterThang = NewWaveGetter(GetTokenStringValue(Token),
										eWaveGetterSampleLeft,TrashTracker,GetCurrentLineNumber(Scanner));
									if (WaveGetterThang == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									*ExpressionOut = NewExprWaveGetter(WaveGetterThang,TrashTracker,
										GetCurrentLineNumber(Scanner));
									if (*ExpressionOut == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									return eCompileNoError;
								}

							/*  XXX:                      ::= getsampleright <string> */
							case eKeywordGetsampleright:
								{
									ASTWaveGetterRec*		WaveGetterThang;

									Token = GetNextToken(Scanner);
									if (Token == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if (GetTokenType(Token) != eTokenString)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileExpectedStringLiteral;
										}

									WaveGetterThang = NewWaveGetter(GetTokenStringValue(Token),
										eWaveGetterSampleRight,TrashTracker,GetCurrentLineNumber(Scanner));
									if (WaveGetterThang == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									*ExpressionOut = NewExprWaveGetter(WaveGetterThang,TrashTracker,
										GetCurrentLineNumber(Scanner));
									if (*ExpressionOut == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									return eCompileNoError;
								}

							/*  XXX:                      ::= getsample <string> */
							case eKeywordGetsample:
								{
									ASTWaveGetterRec*		WaveGetterThang;

									Token = GetNextToken(Scanner);
									if (Token == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if (GetTokenType(Token) != eTokenString)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileExpectedStringLiteral;
										}

									WaveGetterThang = NewWaveGetter(GetTokenStringValue(Token),
										eWaveGetterSampleMono,TrashTracker,GetCurrentLineNumber(Scanner));
									if (WaveGetterThang == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									*ExpressionOut = NewExprWaveGetter(WaveGetterThang,TrashTracker,
										GetCurrentLineNumber(Scanner));
									if (*ExpressionOut == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									return eCompileNoError;
								}

							/*  XXX:                      ::= getwavenumframes <string> */
							case eKeywordGetwavenumframes:
								{
									ASTWaveGetterRec*		WaveGetterThang;

									Token = GetNextToken(Scanner);
									if (Token == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if (GetTokenType(Token) != eTokenString)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileExpectedStringLiteral;
										}

									WaveGetterThang = NewWaveGetter(GetTokenStringValue(Token),
										eWaveGetterWaveFrames,TrashTracker,GetCurrentLineNumber(Scanner));
									if (WaveGetterThang == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									*ExpressionOut = NewExprWaveGetter(WaveGetterThang,TrashTracker,
										GetCurrentLineNumber(Scanner));
									if (*ExpressionOut == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									return eCompileNoError;
								}

							/*  XXX:                      ::= getwavenumtables <string> */
							case eKeywordGetwavenumtables:
								{
									ASTWaveGetterRec*		WaveGetterThang;

									Token = GetNextToken(Scanner);
									if (Token == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if (GetTokenType(Token) != eTokenString)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileExpectedStringLiteral;
										}

									WaveGetterThang = NewWaveGetter(GetTokenStringValue(Token),
										eWaveGetterWaveTables,TrashTracker,GetCurrentLineNumber(Scanner));
									if (WaveGetterThang == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									*ExpressionOut = NewExprWaveGetter(WaveGetterThang,TrashTracker,
										GetCurrentLineNumber(Scanner));
									if (*ExpressionOut == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									return eCompileNoError;
								}

							/*  XXX:                      ::= getwavedata <string> */
							case eKeywordGetwavedata:
								{
									ASTWaveGetterRec*		WaveGetterThang;

									Token = GetNextToken(Scanner);
									if (Token == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}
									if (GetTokenType(Token) != eTokenString)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileExpectedStringLiteral;
										}

									WaveGetterThang = NewWaveGetter(GetTokenStringValue(Token),
										eWaveGetterWaveArray,TrashTracker,GetCurrentLineNumber(Scanner));
									if (WaveGetterThang == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									*ExpressionOut = NewExprWaveGetter(WaveGetterThang,TrashTracker,
										GetCurrentLineNumber(Scanner));
									if (*ExpressionOut == NIL)
										{
											*LineNumberOut = GetCurrentLineNumber(Scanner);
											return eCompileOutOfMemory;
										}

									return eCompileNoError;
								}

							/*  XXX:                      ::= print (<string> | <expr>) */
							case eKeywordPrint:
								Token = GetNextToken(Scanner);
								if (Token == NIL)
									{
										*LineNumberOut = GetCurrentLineNumber(Scanner);
										return eCompileOutOfMemory;
									}
								if (GetTokenType(Token) == eTokenString)
									{
										ASTPrintStringRec*	PrintString;

										/* print string literal part */
										PrintString = NewPrintString(GetTokenStringValue(Token),
											TrashTracker,LineNumberForFirstToken);
										if (PrintString == NIL)
											{
												*LineNumberOut = LineNumberForFirstToken;
												return eCompileOutOfMemory;
											}
										*ExpressionOut = NewExprPrintString(PrintString,TrashTracker,
											LineNumberForFirstToken);
										if (*ExpressionOut == NIL)
											{
												*LineNumberOut = LineNumberForFirstToken;
												return eCompileOutOfMemory;
											}
									}
								 else
									{
										ASTPrintExprRec*		PrintExpr;
										ASTExpressionRec*		Operand;
										CompileErrors				Error;

										/* print expression part */
										UngetToken(Scanner,Token);
										Error = ParseExpr(&Operand,Scanner,SymbolTable,
											TrashTracker,LineNumberOut);
										if (Error != eCompileNoError)
											{
												return Error;
											}
										PrintExpr = NewPrintExpr(Operand,TrashTracker,
											LineNumberForFirstToken);
										if (PrintExpr == NIL)
											{
												*LineNumberOut = LineNumberForFirstToken;
												return eCompileOutOfMemory;
											}
										*ExpressionOut = NewExprPrintExpr(PrintExpr,TrashTracker,
											LineNumberForFirstToken);
										if (*ExpressionOut == NIL)
											{
												*LineNumberOut = LineNumberForFirstToken;
												return eCompileOutOfMemory;
											}
									}
								return eCompileNoError;
						}
			}
		EXECUTE(PRERR(ForceAbort,"ParseExpr:  control reached end of function"));
	}




/*   17:   <formalparamlist>  ::= <formalarg> <formalargtail>  */
/* FIRST SET: */
/*  <formalparamlist>  : {<identifier>, <formalarg>} */
/* FOLLOW SET: */
/*  <formalparamlist>  : {)} */
static CompileErrors	ParseFormalParamList(SymbolListRec** FormalArgListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		CompileErrors				Error;
		SymbolRec*					FormalArgOut;
		SymbolListRec*			ListTail;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Error = ParseFormalArg(&FormalArgOut,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		Error = ParseFormalArgTail(&ListTail,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		*FormalArgListOut = SymbolListCons(FormalArgOut,ListTail,TrashTracker);
		if (*FormalArgListOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*  117:   <whileloop>        ::= while <expr> do <expr> */
/* FIRST SET: */
/*  <whileloop>        : {while} */
/* FOLLOW SET: */
/*  <whileloop>        : {then, else, elseif, while, until, do, to, ), CLOSEBRACKET, */
/*       ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseWhileLoop(ASTExpressionRec** ExpressionOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;
		ASTExpressionRec*		ConditionalExpr;
		ASTExpressionRec*		BodyExpr;
		CompileErrors				Error;
		ASTLoopRec*					WhileLoopThing;
		long								LineNumberOfWholeForm;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		LineNumberOfWholeForm = GetCurrentLineNumber(Scanner);

		/* munch while */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if ((GetTokenType(Token) != eTokenKeyword)
			|| (GetTokenKeywordTag(Token) != eKeywordWhile))
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedWhile;
			}

		Error = ParseExpr(&ConditionalExpr,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* munch do */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if ((GetTokenType(Token) != eTokenKeyword)
			|| (GetTokenKeywordTag(Token) != eKeywordDo))
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedDo;
			}

		Error = ParseExpr(&BodyExpr,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		WhileLoopThing = NewLoop(eLoopWhileDo,ConditionalExpr,BodyExpr,TrashTracker,
			LineNumberOfWholeForm);
		if (WhileLoopThing == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		*ExpressionOut = NewExprLoop(WhileLoopThing,TrashTracker,LineNumberOfWholeForm);
		if (*ExpressionOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*  118:   <untilloop>        ::= until <expr> do <expr> */
/* FIRST SET: */
/*  <untilloop>        : {until} */
/* FOLLOW SET: */
/*  <untilloop>        : {then, else, elseif, while, until, do, to, ), CLOSEBRACKET, */
/*       ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseUntilLoop(ASTExpressionRec** ExpressionOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;
		ASTExpressionRec*		ConditionalExpr;
		ASTExpressionRec*		BodyExpr;
		CompileErrors				Error;
		ASTLoopRec*					UntilLoopThing;
		long								LineNumberOfWholeForm;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		LineNumberOfWholeForm = GetCurrentLineNumber(Scanner);

		/* munch until */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if ((GetTokenType(Token) != eTokenKeyword)
			|| (GetTokenKeywordTag(Token) != eKeywordUntil))
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedUntil;
			}

		Error = ParseExpr(&ConditionalExpr,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* munch do */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if ((GetTokenType(Token) != eTokenKeyword)
			|| (GetTokenKeywordTag(Token) != eKeywordDo))
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedDo;
			}

		Error = ParseExpr(&BodyExpr,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		UntilLoopThing = NewLoop(eLoopUntilDo,ConditionalExpr,BodyExpr,TrashTracker,
			LineNumberOfWholeForm);
		if (UntilLoopThing == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		*ExpressionOut = NewExprLoop(UntilLoopThing,TrashTracker,LineNumberOfWholeForm);
		if (*ExpressionOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*   24:   <vartail>          ::= EQ <expr> */
/*   25:                      ::= ( <expr> ) */
/* FIRST SET: */
/*  <vartail>          : {(, EQ} */
/* FOLLOW SET: */
/*  <vartail>          : {then, else, elseif, while, until, do, to, ), CLOSEBRACKET, */
/*       ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseVarTail(ASTExpressionRec** ExpressionOut,
												TokenRec* VariableName, long VariableDeclLine,
												DataTypes VariableType, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		SymbolRec*					SymbolTableEntry;

		CheckPtrExistence(VariableName);
		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		/* create symbol table entry */
		SymbolTableEntry = NewSymbol(TrashTracker,GetTokenIdentifierString(
			VariableName),PtrSize(GetTokenIdentifierString(VariableName)));
		if (SymbolTableEntry == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		SymbolBecomeVariable(SymbolTableEntry,VariableType);

		/* see what to do */
		switch (GetTokenType(Token))
			{
				default:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileExpectedOpenParenOrEqual;

				/* array declaration */
				case eTokenOpenParen:
					{
						ASTExpressionRec*			ArraySizeExpression;
						CompileErrors					Error;
						ASTArrayDeclRec*			ArrayConstructor;

						if ((VariableType != eArrayOfBoolean) && (VariableType != eArrayOfInteger)
							&& (VariableType != eArrayOfFloat) && (VariableType != eArrayOfDouble)
							&& (VariableType != eArrayOfFixed))
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileArrayConstructionOnScalarType;
							}

						Error = ParseExpr(&ArraySizeExpression,Scanner,SymbolTable,TrashTracker,
							LineNumberOut);
						if (Error != eCompileNoError)
							{
								return Error;
							}

						/* swallow the close paren */
						Token = GetNextToken(Scanner);
						if (Token == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}
						if (GetTokenType(Token) != eTokenCloseParen)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileExpectedCloseParen;
							}

						/* build the array constructor node */
						ArrayConstructor = NewArrayConstruction(SymbolTableEntry,
							ArraySizeExpression,TrashTracker,VariableDeclLine);
						if (ArrayConstructor == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}

						/* build AST node */
						*ExpressionOut = NewExprArrayDecl(ArrayConstructor,TrashTracker,
							VariableDeclLine);
						if (*ExpressionOut == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}
					}
					break;

				/* variable construction */
				case eTokenEqual:
					{
						ASTExpressionRec*			Initializer;
						CompileErrors					Error;
						ASTVarDeclRec*				VariableConstructor;

						Error = ParseExpr(&Initializer,Scanner,SymbolTable,TrashTracker,
							LineNumberOut);
						if (Error != eCompileNoError)
							{
								return Error;
							}

						/* build variable thing */
						VariableConstructor = NewVariableDeclaration(SymbolTableEntry,
							Initializer,TrashTracker,VariableDeclLine);
						if (VariableConstructor == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}

						/* encapsulate */
						*ExpressionOut = NewExprVariableDeclaration(VariableConstructor,TrashTracker,
							VariableDeclLine);
						if (*ExpressionOut == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}
					}
					break;
			}

		/* add the identifier to the symbol table */
		switch (AddSymbolToTable(SymbolTable,SymbolTableEntry))
			{
				case eAddSymbolNoErr:
					break;
				case eAddSymbolAlreadyExists:
					*LineNumberOut = VariableDeclLine;
					return eCompileMultiplyDefinedIdentifier;
				case eAddSymbolNoMemory:
					*LineNumberOut = VariableDeclLine;
					return eCompileOutOfMemory;
				default:
					EXECUTE(PRERR(ForceAbort,"ParseVarTail:  bad value from AddSymbolToTable"));
					break;
			}

		return eCompileNoError;
	}




/*  110:   <ifrest>           ::= <expr> then <expr> <iftail> */
/* FIRST SET: */
/*  <ifrest>           : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, proto, var, not, sin, */
/*       cos, tan, asin, acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, */
/*       if, while, until, do, resize, error, true, false, set, (, -, */
/*       <prototype>, <expr>, <expr2>, <expr3>, <expr4>, <expr5>, <expr6>, */
/*       <unary_oper>, <expr7>, <expr8>, <whileloop>, <untilloop>} */
/* FOLLOW SET: */
/*  <ifrest>           : {then, else, elseif, while, until, do, to, ), CLOSEBRACKET, */
/*       ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseIfRest(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		CompileErrors				Error;
		ASTExpressionRec*		Predicate;
		ASTExpressionRec*		Consequent;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Error = ParseExpr(&Predicate,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* eat the "then" */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if ((GetTokenType(Token) != eTokenKeyword)
			|| (GetTokenKeywordTag(Token) != eKeywordThen))
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedThen;
			}

		Error = ParseExpr(&Consequent,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		return ParseIfTail(ExpressionOut,Predicate,Consequent,Scanner,SymbolTable,
			TrashTracker,LineNumberOut);
	}




/*  119:   <loopwhileuntil>   ::= while <expr> */
/*  120:                      ::= until <expr> */
/* FIRST SET: */
/*  <loopwhileuntil>   : {while, until} */
/* FOLLOW SET: */
/*  <loopwhileuntil>   : {then, else, elseif, while, until, do, to, */
/*       ), CLOSEBRACKET, ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, */
/*       <exprlisttail>} */
static CompileErrors	ParseLoopWhileUntil(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LoopBodyExpression, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut, long LineNumberOfLoop)
	{
		TokenRec*						Token;
		LoopTypes						LoopKind;
		ASTExpressionRec*		ConditionalExpression;
		CompileErrors				Error;
		ASTLoopRec*					LoopThang;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(LoopBodyExpression);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		/* see what there is to do */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenKeyword)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedWhileOrUntil;
			}

		switch (GetTokenKeywordTag(Token))
			{
				default:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileExpectedWhileOrUntil;

				case eKeywordWhile:
					LoopKind = eLoopDoWhile;
					break;

				case eKeywordUntil:
					LoopKind = eLoopDoUntil;
					break;
			}

		Error = ParseExpr(&ConditionalExpression,Scanner,SymbolTable,TrashTracker,
			LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		LoopThang = NewLoop(LoopKind,ConditionalExpression,LoopBodyExpression,
			TrashTracker,LineNumberOfLoop);
		if (LoopThang == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		*ExpressionOut = NewExprLoop(LoopThang,TrashTracker,LineNumberOfLoop);
		if (*ExpressionOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*   27:   <expr2>            ::= <expr3> <expr2prime> */
/* FIRST SET: */
/*  <expr2>            : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, not, sin, cos, tan, asin, */
/*       acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, true, */
/*       false, (, -, <expr3>, <expr4>, <expr5>, <expr6>, <unary_oper>, <expr7>, */
/*       <expr8>} */
/* FOLLOW SET: */
/*  <expr2>            : {then, else, elseif, while, until, do, to, ), CLOSEBRACKET, */
/*       ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr2(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		CompileErrors				Error;
		ASTExpressionRec*		LeftHandSide;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Error = ParseExpr3(&LeftHandSide,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		return ParseExpr2Prime(ExpressionOut,LeftHandSide,Scanner,SymbolTable,
			TrashTracker,LineNumberOut);
	}




/*   18:   <formalarg>        ::= <identifier> : <type> */
/* FIRST SET: */
/*  <formalarg>        : {<identifier>} */
/* FOLLOW SET: */
/*  <formalarg>        : {), ,, <formalargtail>} */
static CompileErrors	ParseFormalArg(SymbolRec** FormalArgOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						IdentifierName;
		TokenRec*						Token;
		DataTypes						Type;
		CompileErrors				Error;
		long								LineNumberOfIdentifier;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		LineNumberOfIdentifier = GetCurrentLineNumber(Scanner);

		IdentifierName = GetNextToken(Scanner);
		if (IdentifierName == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(IdentifierName) != eTokenIdentifier)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedIdentifier;
			}

		/* swallow the colon */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenColon)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedColon;
			}

		Error = ParseType(&Type,Scanner,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		*FormalArgOut = NewSymbol(TrashTracker,GetTokenIdentifierString(IdentifierName),
			PtrSize(GetTokenIdentifierString(IdentifierName)));
		if (*FormalArgOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		SymbolBecomeVariable(*FormalArgOut,Type);

		switch (AddSymbolToTable(SymbolTable,*FormalArgOut))
			{
				case eAddSymbolNoErr:
					break;
				case eAddSymbolAlreadyExists:
					*LineNumberOut = LineNumberOfIdentifier;
					return eCompileMultiplyDefinedIdentifier;
				case eAddSymbolNoMemory:
					*LineNumberOut = LineNumberOfIdentifier;
					return eCompileOutOfMemory;
				default:
					EXECUTE(PRERR(ForceAbort,"ParseFormalArg:  bad value from AddSymbolToTable"));
					break;
			}

		return eCompileNoError;
	}




/*   19:   <formalargtail>    ::= , <formalparamlist> */
/*   20:                      ::=  */
/* FIRST SET: */
/*  <formalargtail>    : {,} */
/* FOLLOW SET: */
/*  <formalargtail>    : {)} */
static CompileErrors	ParseFormalArgTail(SymbolListRec** ArgListTailOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileExpectedCommaOrCloseParen;

				case eTokenComma:
					return ParseFormalParamList(ArgListTailOut,Scanner,SymbolTable,TrashTracker,
						LineNumberOut);

				case eTokenCloseParen:
					UngetToken(Scanner,Token);
					*ArgListTailOut = NIL; /* end of list */
					return eCompileNoError;
			}
		EXECUTE(PRERR(ForceAbort,"ParseFormalArgTail:  control reaches end of function"));
	}




/*  111:   <iftail>           ::= else <expr> */
/*  112:                      ::= elseif <ifrest> */
/*  113:                      ::=  */
/* FIRST SET: */
/*  <iftail>           : {else, elseif} */
/* FOLLOW SET: */
/*  <iftail>           : {then, else, elseif, while, until, do, to, ), CLOSEBRACKET, */
/*       ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
/* note that 'else' and 'elseif' are in both the first and follow set.  this is */
/* because if-then-else isn't LL(1).  we handle this by binding else to the deepest */
/* if statement. */
static CompileErrors	ParseIfTail(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* Predicate, ASTExpressionRec* Consequent,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;
		ASTCondRec*					Conditional;
		ASTExpressionRec*		Alternative;
		CompileErrors				Error;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		/* see what the token is */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		/* do the operation */
		switch (GetTokenType(Token))
			{
					/*  113:                      ::=  */
				default:
				 NullificationPoint:
					UngetToken(Scanner,Token);
					Conditional = NewConditional(Predicate,Consequent,NIL,TrashTracker,
						GetCurrentLineNumber(Scanner));
					if (Conditional == NIL)
						{
							*LineNumberOut = GetCurrentLineNumber(Scanner);
							return eCompileOutOfMemory;
						}
					break;

				case eTokenKeyword:
					switch (GetTokenKeywordTag(Token))
						{
								/*  113:                      ::=  */
							default:
								goto NullificationPoint;

								/*  111:   <iftail>           ::= else <expr> */
							case eKeywordElse:
								Error = ParseExpr(&Alternative,Scanner,SymbolTable,TrashTracker,
									LineNumberOut);
								if (Error != eCompileNoError)
									{
										return Error;
									}
								Conditional = NewConditional(Predicate,Consequent,Alternative,
									TrashTracker,GetCurrentLineNumber(Scanner));
								if (Conditional == NIL)
									{
										*LineNumberOut = GetCurrentLineNumber(Scanner);
										return eCompileOutOfMemory;
									}
								break;

								/*  112:                      ::= elseif <ifrest> */
							case eKeywordElseif:
								Error = ParseIfRest(&Alternative,Scanner,SymbolTable,TrashTracker,
									LineNumberOut);
								if (Error != eCompileNoError)
									{
										return Error;
									}
								Conditional = NewConditional(Predicate,Consequent,Alternative,
									TrashTracker,GetCurrentLineNumber(Scanner));
								if (Conditional == NIL)
									{
										*LineNumberOut = GetCurrentLineNumber(Scanner);
										return eCompileOutOfMemory;
									}
								break;
						}
					break;
			}

		/* finish building expression node */
		*ExpressionOut = NewExprConditional(Conditional,TrashTracker,
			GetCurrentLineNumber(Scanner));
		if (*ExpressionOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*   33:   <expr3>            ::= <expr4> <expr3prime> */
/* FIRST SET: */
/*  <expr3>            : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, not, sin, cos, tan, asin, */
/*       acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, true, */
/*       false, (, -, <expr4>, <expr5>, <expr6>, <unary_oper>, <expr7>, <expr8>} */
/* FOLLOW SET: */
/*  <expr3>            : {and, or, xor, then, else, elseif, while, until, do, */
/*       to, ), CLOSEBRACKET, ,, :=, ;, <expr2prime>, <conj_oper>, <actualtail>, */
/*       <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr3(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		CompileErrors				Error;
		ASTExpressionRec*		LeftHandSide;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Error = ParseExpr4(&LeftHandSide,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		return ParseExpr3Prime(ExpressionOut,LeftHandSide,Scanner,SymbolTable,
			TrashTracker,LineNumberOut);
	}




/*   28:   <expr2prime>       ::= <conj_oper> <expr3> <expr2prime> */
/*   29:                      ::=  */
/* FIRST SET: */
/*  <expr2prime>       : {and, or, xor, <conj_oper>} */
/* FOLLOW SET: */
/*  <expr2prime>       : {then, else, elseif, while, until, do, to, ), */
/*       CLOSEBRACKET, ,, :=, ;, <actualtail>, <iftail>, <loopwhileuntil>, */
/*       <exprlisttail>} */
static CompileErrors	ParseExpr2Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LeftHandSide, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		BinaryOpType				OperatorType;
		CompileErrors				Error;
		ASTExpressionRec*		RightHandSide;
		ASTBinaryOpRec*			WholeOperator;
		ASTExpressionRec*		ThisWholeNode;

		CheckPtrExistence(LeftHandSide);
		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
				 NullifyPoint:
					UngetToken(Scanner,Token);
					*ExpressionOut = LeftHandSide;
					return eCompileNoError;

				case eTokenKeyword:
					switch (GetTokenKeywordTag(Token))
						{
							default:
								goto NullifyPoint;

							case eKeywordAnd:
							case eKeywordOr:
							case eKeywordXor:
								/* actually do the thing */
								UngetToken(Scanner,Token);
								Error = ParseConjOper(&OperatorType,Scanner,LineNumberOut);
								if (Error != eCompileNoError)
									{
										return Error;
									}
								Error = ParseExpr3(&RightHandSide,Scanner,SymbolTable,TrashTracker,
									LineNumberOut);
								if (Error != eCompileNoError)
									{
										return Error;
									}
								/* build the operator node */
								WholeOperator = NewBinaryOperator(OperatorType,LeftHandSide,
									RightHandSide,TrashTracker,GetCurrentLineNumber(Scanner));
								if (WholeOperator == NIL)
									{
										*LineNumberOut = GetCurrentLineNumber(Scanner);
										return eCompileOutOfMemory;
									}
								ThisWholeNode = NewExprBinaryOperator(WholeOperator,TrashTracker,
									GetCurrentLineNumber(Scanner));
								if (ThisWholeNode == NIL)
									{
										*LineNumberOut = GetCurrentLineNumber(Scanner);
										return eCompileOutOfMemory;
									}
								return ParseExpr2Prime(ExpressionOut,ThisWholeNode,Scanner,SymbolTable,
									TrashTracker,LineNumberOut);
						}
					break;
			}
		EXECUTE(PRERR(ForceAbort,"ParseExpr2Prime:  control reached end of function"));
	}




/*   42:   <expr4>            ::= <expr5> <expr4prime> */
/* FIRST SET: */
/*  <expr4>            : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, not, sin, cos, tan, asin, */
/*       acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, true, */
/*       false, (, -, <expr5>, <expr6>, <unary_oper>, <expr7>, <expr8>} */
/* FOLLOW SET: */
/*  <expr4>            : {and, or, xor, then, else, elseif, while, until, do, */
/*       to, ), CLOSEBRACKET, ,, :=, ;, EQ, NEQ, LT, LTEQ, GR, GREQ, <expr2prime>, */
/*       <conj_oper>, <expr3prime>, <rel_oper>, <actualtail>, <iftail>, */
/*       <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr4(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		CompileErrors				Error;
		ASTExpressionRec*		LeftHandSide;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Error = ParseExpr5(&LeftHandSide,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		return ParseExpr4Prime(ExpressionOut,LeftHandSide,Scanner,SymbolTable,
			TrashTracker,LineNumberOut);
	}




/*   34:   <expr3prime>       ::= <rel_oper> <expr4> <expr3prime> */
/*   35:                      ::=  */
/* FIRST SET: */
/*  <expr3prime>       : {EQ, NEQ, LT, LTEQ, GR, GREQ, <rel_oper>} */
/* FOLLOW SET: */
/*  <expr3prime>       : {and, or, xor, then, else, elseif, while, until, */
/*       do, to, ), CLOSEBRACKET, ,, :=, ;, <expr2prime>, <conj_oper>, */
/*       <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr3Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LeftHandSide, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		BinaryOpType				OperatorType;
		CompileErrors				Error;
		ASTExpressionRec*		RightHandSide;
		ASTBinaryOpRec*			WholeOperator;
		ASTExpressionRec*		ThisWholeNode;

		CheckPtrExistence(LeftHandSide);
		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
					UngetToken(Scanner,Token);
					*ExpressionOut = LeftHandSide;
					return eCompileNoError;

				case eTokenLessThan:
				case eTokenLessThanOrEqual:
				case eTokenGreaterThan:
				case eTokenGreaterThanOrEqual:
				case eTokenEqual:
				case eTokenNotEqual:
					/* actually do the thing */
					UngetToken(Scanner,Token);
					Error = ParseRelOper(&OperatorType,Scanner,LineNumberOut);
					if (Error != eCompileNoError)
						{
							return Error;
						}
					Error = ParseExpr4(&RightHandSide,Scanner,SymbolTable,TrashTracker,
						LineNumberOut);
					if (Error != eCompileNoError)
						{
							return Error;
						}
					/* build the operator node */
					WholeOperator = NewBinaryOperator(OperatorType,LeftHandSide,
						RightHandSide,TrashTracker,GetCurrentLineNumber(Scanner));
					if (WholeOperator == NIL)
						{
							*LineNumberOut = GetCurrentLineNumber(Scanner);
							return eCompileOutOfMemory;
						}
					ThisWholeNode = NewExprBinaryOperator(WholeOperator,TrashTracker,
						GetCurrentLineNumber(Scanner));
					if (ThisWholeNode == NIL)
						{
							*LineNumberOut = GetCurrentLineNumber(Scanner);
							return eCompileOutOfMemory;
						}
					return ParseExpr3Prime(ExpressionOut,ThisWholeNode,Scanner,SymbolTable,
						TrashTracker,LineNumberOut);
			}

		EXECUTE(PRERR(ForceAbort,"ParseExpr3Prime:  control reached end of function"));
	}




/*   30:   <conj_oper>        ::= and */
/*   31:                      ::= or */
/*   32:                      ::= xor */
/* FIRST SET: */
/*  <conj_oper>        : {and, or, xor} */
/* FOLLOW SET: */
/*  <conj_oper>        : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, not, sin, cos, tan, */
/*       asin, acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, */
/*       true, false, (, -, <expr3>, <expr4>, <expr5>, <expr6>, <unary_oper>, */
/*       <expr7>, <expr8>} */
static CompileErrors	ParseConjOper(BinaryOpType* OperatorOut, ScannerRec* Scanner,
												long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileExpectedOperatorOrStatement;

				case eTokenKeyword:
					switch (GetTokenKeywordTag(Token))
						{
							default:
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileExpectedOperatorOrStatement;

							case eKeywordAnd:
								*OperatorOut = eBinaryAnd;
								return eCompileNoError;

							case eKeywordOr:
								*OperatorOut = eBinaryOr;
								return eCompileNoError;

							case eKeywordXor:
								*OperatorOut = eBinaryXor;
								return eCompileNoError;
						}
					break;
			}
		EXECUTE(PRERR(ForceAbort,"ParseConjOper:  control reached end of function"));
	}




/*   47:   <expr5>            ::= <expr6> <expr5prime> */
/* FIRST SET: */
/*  <expr5>            : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, not, sin, cos, tan, asin, */
/*       acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, true, */
/*       false, (, -, <expr6>, <unary_oper>, <expr7>, <expr8>} */
/* FOLLOW SET: */
/*  <expr5>            : {and, or, xor, then, else, elseif, while, until, do, */
/*       to, ), CLOSEBRACKET, ,, :=, ;, +, -, EQ, NEQ, LT, LTEQ, GR, GREQ, */
/*       <expr2prime>, <conj_oper>, <expr3prime>, <rel_oper>, <expr4prime>, */
/*       <add_oper>, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr5(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		CompileErrors				Error;
		ASTExpressionRec*		LeftHandSide;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Error = ParseExpr6(&LeftHandSide,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		return ParseExpr5Prime(ExpressionOut,LeftHandSide,Scanner,SymbolTable,
			TrashTracker,LineNumberOut);
	}




/*   43:   <expr4prime>       ::= <add_oper> <expr5> <expr4prime> */
/*   44:                      ::=  */
/* FIRST SET: */
/*  <expr4prime>       : {+, -, <add_oper>} */
/* FOLLOW SET: */
/*  <expr4prime>       : {and, or, xor, then, else, elseif, while, until, */
/*       do, to, ), CLOSEBRACKET, ,, :=, ;, EQ, NEQ, LT, LTEQ, GR, GREQ, */
/*       <expr2prime>, <conj_oper>, <expr3prime>, <rel_oper>, <actualtail>, */
/*       <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr4Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LeftHandSide, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		BinaryOpType				OperatorType;
		CompileErrors				Error;
		ASTExpressionRec*		RightHandSide;
		ASTBinaryOpRec*			WholeOperator;
		ASTExpressionRec*		ThisWholeNode;

		CheckPtrExistence(LeftHandSide);
		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
					UngetToken(Scanner,Token);
					*ExpressionOut = LeftHandSide;
					return eCompileNoError;

				case eTokenPlus:
				case eTokenMinus:
					UngetToken(Scanner,Token);
					Error = ParseAddOper(&OperatorType,Scanner,LineNumberOut);
					if (Error != eCompileNoError)
						{
							return Error;
						}
					Error = ParseExpr5(&RightHandSide,Scanner,SymbolTable,TrashTracker,
						LineNumberOut);
					if (Error != eCompileNoError)
						{
							return Error;
						}
					/* create the node */
					WholeOperator = NewBinaryOperator(OperatorType,LeftHandSide,RightHandSide,
						TrashTracker,GetCurrentLineNumber(Scanner));
					if (WholeOperator == NIL)
						{
							*LineNumberOut = GetCurrentLineNumber(Scanner);
							return eCompileOutOfMemory;
						}
					ThisWholeNode = NewExprBinaryOperator(WholeOperator,TrashTracker,
						GetCurrentLineNumber(Scanner));
					if (ThisWholeNode == NIL)
						{
							*LineNumberOut = GetCurrentLineNumber(Scanner);
							return eCompileOutOfMemory;
						}
					return ParseExpr4Prime(ExpressionOut,ThisWholeNode,Scanner,SymbolTable,
						TrashTracker,LineNumberOut);
			}
		EXECUTE(PRERR(ForceAbort,"ParseConjOper:  control reached end of function"));
	}




/*   36:   <rel_oper>         ::= LT */
/*   37:                      ::= LTEQ */
/*   38:                      ::= GR */
/*   39:                      ::= GREQ */
/*   40:                      ::= EQ */
/*   41:                      ::= NEQ */
/* FIRST SET: */
/*  <rel_oper>         : {EQ, NEQ, LT, LTEQ, GR, GREQ} */
/* FOLLOW SET: */
/*  <rel_oper>         : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, not, sin, cos, tan, */
/*       asin, acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, */
/*       true, false, (, -, <expr4>, <expr5>, <expr6>, <unary_oper>, <expr7>, */
/*       <expr8>} */
static CompileErrors	ParseRelOper(BinaryOpType* OperatorOut, ScannerRec* Scanner,
												long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileExpectedOperatorOrStatement;

				case eTokenEqual:
					*OperatorOut = eBinaryEqual;
					return eCompileNoError;

				case eTokenNotEqual:
					*OperatorOut = eBinaryNotEqual;
					return eCompileNoError;

				case eTokenLessThan:
					*OperatorOut = eBinaryLessThan;
					return eCompileNoError;

				case eTokenLessThanOrEqual:
					*OperatorOut = eBinaryLessThanOrEqual;
					return eCompileNoError;

				case eTokenGreaterThan:
					*OperatorOut = eBinaryGreaterThan;
					return eCompileNoError;

				case eTokenGreaterThanOrEqual:
					*OperatorOut = eBinaryGreaterThanOrEqual;
					return eCompileNoError;
			}
		EXECUTE(PRERR(ForceAbort,"ParseRelOper:  control reached end of function"));
	}




/*   56:   <expr6>            ::= <unary_oper> <expr6> */
/*   57:                      ::= <expr7> */
/* FIRST SET: */
/*  <expr6>            : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, not, sin, cos, tan, asin, */
/*       acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, true, */
/*       false, (, -, <unary_oper>, <expr7>, <expr8>} */
/* FOLLOW SET: */
/*  <expr6>            : {and, or, xor, div, mod, SHR, SHL, then, else, elseif, */
/*       while, until, do, to, ), CLOSEBRACKET, ,, :=, ;, *, /, +, -, EQ, NEQ, */
/*       LT, LTEQ, GR, GREQ, <expr2prime>, <conj_oper>, <expr3prime>, <rel_oper>, */
/*       <expr4prime>, <add_oper>, <expr5prime>, <mult_oper>, <actualtail>, */
/*       <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr6(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		UnaryOpType					UnaryOperatorThing;
		ASTExpressionRec*		UnaryArgument;
		CompileErrors				Error;
		ASTUnaryOpRec*			UnaryOpNode;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
				 OtherPoint:
					UngetToken(Scanner,Token);
					return ParseExpr7(ExpressionOut,Scanner,SymbolTable,TrashTracker,LineNumberOut);

				case eTokenMinus:
					UnaryOperatorThing = eUnaryNegation;
					break;

				case eTokenKeyword:
					switch (GetTokenKeywordTag(Token))
						{
							default:
								goto OtherPoint;

							case eKeywordNot:
								UnaryOperatorThing = eUnaryNot;
								break;

							case eKeywordSin:
								UnaryOperatorThing = eUnarySine;
								break;

							case eKeywordCos:
								UnaryOperatorThing = eUnaryCosine;
								break;

							case eKeywordTan:
								UnaryOperatorThing = eUnaryTangent;
								break;

							case eKeywordAsin:
								UnaryOperatorThing = eUnaryArcSine;
								break;

							case eKeywordAcos:
								UnaryOperatorThing = eUnaryArcCosine;
								break;

							case eKeywordAtan:
								UnaryOperatorThing = eUnaryArcTangent;
								break;

							case eKeywordLn:
								UnaryOperatorThing = eUnaryLogarithm;
								break;

							case eKeywordExp:
								UnaryOperatorThing = eUnaryExponentiation;
								break;

							case eKeywordBool:
								UnaryOperatorThing = eUnaryCastToBoolean;
								break;

							case eKeywordInt:
								UnaryOperatorThing = eUnaryCastToInteger;
								break;

							case eKeywordSingle:
								UnaryOperatorThing = eUnaryCastToSingle;
								break;

							case eKeywordDouble:
								UnaryOperatorThing = eUnaryCastToDouble;
								break;

							case eKeywordFixed:
								UnaryOperatorThing = eUnaryCastToFixed;
								break;

							case eKeywordSqr:
								UnaryOperatorThing = eUnarySquare;
								break;

							case eKeywordSqrt:
								UnaryOperatorThing = eUnarySquareRoot;
								break;

							case eKeywordAbs:
								UnaryOperatorThing = eUnaryAbsoluteValue;
								break;

							case eKeywordNeg:
								UnaryOperatorThing = eUnaryTestNegative;
								break;

							case eKeywordSign:
								UnaryOperatorThing = eUnaryGetSign;
								break;

							case eKeywordLength:
								UnaryOperatorThing = eUnaryGetArrayLength;
								break;
						}
					break;
			}

		/* build argument */
		Error = ParseExpr6(&UnaryArgument,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* build node */
		UnaryOpNode = NewUnaryOperator(UnaryOperatorThing,UnaryArgument,TrashTracker,
			GetCurrentLineNumber(Scanner));
		if (UnaryOpNode == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		*ExpressionOut = NewExprUnaryOperator(UnaryOpNode,TrashTracker,
			GetCurrentLineNumber(Scanner));
		if (*ExpressionOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*   48:   <expr5prime>       ::= <mult_oper> <expr6> <expr5prime> */
/*   49:                      ::=  */
/* FIRST SET: */
/*  <expr5prime>       : {div, mod, SHR, SHL, *, /, <mult_oper>} */
/* FOLLOW SET: */
/*  <expr5prime>       : {and, or, xor, then, else, elseif, while, until, */
/*       do, to, ), CLOSEBRACKET, ,, :=, ;, +, -, EQ, NEQ, LT, LTEQ, GR, */
/*       GREQ, <expr2prime>, <conj_oper>, <expr3prime>, <rel_oper>, <expr4prime>, */
/*       <add_oper>, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr5Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* LeftHandSide, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		ASTExpressionRec*		RightHandSide;
		BinaryOpType				OperatorThing;
		CompileErrors				Error;
		ASTBinaryOpRec*			BinaryOperator;
		ASTExpressionRec*		WholeThingThing;

		CheckPtrExistence(LeftHandSide);
		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
				 NullifyPoint:
					*ExpressionOut = LeftHandSide;
					UngetToken(Scanner,Token);
					return eCompileNoError;

				case eTokenKeyword:
					switch (GetTokenKeywordTag(Token))
						{
							default:
								goto NullifyPoint;

							case eKeywordDiv:
							case eKeywordMod:
							 DoTheStuffPoint:
								UngetToken(Scanner,Token);
								Error = ParseMultOper(&OperatorThing,Scanner,LineNumberOut);
								if (Error != eCompileNoError)
									{
										return Error;
									}
								Error = ParseExpr6(&RightHandSide,Scanner,SymbolTable,TrashTracker,
									LineNumberOut);
								if (Error != eCompileNoError)
									{
										return Error;
									}
								/* create the node */
								BinaryOperator = NewBinaryOperator(OperatorThing,LeftHandSide,
									RightHandSide,TrashTracker,GetCurrentLineNumber(Scanner));
								if (BinaryOperator == NIL)
									{
										*LineNumberOut = GetCurrentLineNumber(Scanner);
										return eCompileOutOfMemory;
									}
								WholeThingThing = NewExprBinaryOperator(BinaryOperator,TrashTracker,
									GetCurrentLineNumber(Scanner));
								if (WholeThingThing == NIL)
									{
										*LineNumberOut = GetCurrentLineNumber(Scanner);
										return eCompileOutOfMemory;
									}
								return ParseExpr5Prime(ExpressionOut,WholeThingThing,Scanner,
									SymbolTable,TrashTracker,LineNumberOut);
						}
					break;

				case eTokenShiftLeft:
				case eTokenShiftRight:
				case eTokenStar:
				case eTokenSlash:
					goto DoTheStuffPoint;
			}
		EXECUTE(PRERR(ForceAbort,"ParseExpr5Prime:  control reached end of function"));
	}




/*   45:   <add_oper>         ::= + */
/*   46:                      ::= - */
/*  <add_oper>         : {+, -} */
/*  <add_oper>         : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, not, sin, cos, tan, */
/*       asin, acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, */
/*       true, false, (, -, <expr5>, <expr6>, <unary_oper>, <expr7>, <expr8>} */
static CompileErrors	ParseAddOper(BinaryOpType* OperatorOut, ScannerRec* Scanner,
												long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileExpectedOperatorOrStatement;

				case eTokenPlus:
					*OperatorOut = eBinaryPlus;
					return eCompileNoError;

				case eTokenMinus:
					*OperatorOut = eBinaryMinus;
					return eCompileNoError;
			}
		EXECUTE(PRERR(ForceAbort,"ParseAddOper:  control reached end of function"));
	}




/*   79:   <expr7>            ::= <expr8> <expr7prime> */
/* FIRST SET: */
/*  <expr7>            : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, true, false, (, <expr8>} */
/* FOLLOW SET: */
/*  <expr7>            : {and, or, xor, div, mod, SHR, SHL, then, else, elseif, */
/*       while, until, do, to, ), CLOSEBRACKET, ,, :=, ;, *, /, +, -, EQ, NEQ, */
/*       LT, LTEQ, GR, GREQ, <expr2prime>, <conj_oper>, <expr3prime>, <rel_oper>, */
/*       <expr4prime>, <add_oper>, <expr5prime>, <mult_oper>, <actualtail>, */
/*       <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr7(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		ASTExpressionRec*		ResultOfExpr8;
		CompileErrors				Error;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Error = ParseExpr8(&ResultOfExpr8,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		return ParseExpr7Prime(ExpressionOut,ResultOfExpr8,Scanner,SymbolTable,TrashTracker,
			LineNumberOut);
	}




/*   50:   <mult_oper>        ::= * */
/*   51:                      ::= / */
/*   52:                      ::= div */
/*   53:                      ::= mod */
/*   54:                      ::= SHL */
/*   55:                      ::= SHR */
/*  <mult_oper>        : {div, mod, SHR, SHL, *, /} */
/*  <mult_oper>        : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, not, sin, cos, tan, */
/*       asin, acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, length, */
/*       true, false, (, -, <expr6>, <unary_oper>, <expr7>, <expr8>} */
static CompileErrors	ParseMultOper(BinaryOpType* OperatorOut, ScannerRec* Scanner,
												long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileExpectedOperatorOrStatement;

				case eTokenStar:
					*OperatorOut = eBinaryMultiplication;
					return eCompileNoError;

				case eTokenSlash:
					*OperatorOut = eBinaryImpreciseDivision;
					return eCompileNoError;

				case eTokenShiftLeft:
					*OperatorOut = eBinaryShiftLeft;
					return eCompileNoError;

				case eTokenShiftRight:
					*OperatorOut = eBinaryShiftRight;
					return eCompileNoError;

				case eTokenKeyword:
					switch (GetTokenKeywordTag(Token))
						{
							default:
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileExpectedOperatorOrStatement;

							case eKeywordDiv:
								*OperatorOut = eBinaryIntegerDivision;
								return eCompileNoError;

							case eKeywordMod:
								*OperatorOut = eBinaryIntegerRemainder;
								return eCompileNoError;
						}
					break;
			}
		EXECUTE(PRERR(ForceAbort,"ParseMultOper:  control reached end of function"));
	}




/*   92:   <expr8>            ::= <identifier> */
/*   93:                      ::= <integer> */
/*   94:                      ::= <single> */
/*   95:                      ::= <double> */
/*   96:                      ::= <fixed> */
/*   97:                      ::= <string> */
/*   98:                      ::= true */
/*   99:                      ::= false */
/*  108:                      ::= ( <exprlist> ) */
/*  <expr8>            : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, true, false, (} */
/*  <expr8>            : {and, or, xor, div, mod, SHR, SHL, then, else, elseif, */
/*       while, until, do, to, (, ), OPENBRACKET, CLOSEBRACKET, ,, :=, ;, *, */
/*       /, +, -, ^, EQ, NEQ, LT, LTEQ, GR, GREQ, <expr2prime>, <conj_oper>, */
/*       <expr3prime>, <rel_oper>, <expr4prime>, <add_oper>, <expr5prime>, */
/*       <mult_oper>, <expr7prime>, <arraysubscript>, <funccall>, <exponentiation>, */
/*       <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr8(ASTExpressionRec** ExpressionOut, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		ASTOperandRec*			TheOperand;
		TokenRec*						Token;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileExpectedOperand;

					/*   92:   <expr8>            ::= <identifier> */
				case eTokenIdentifier:
					{
						SymbolRec*				TheSymbolTableEntry;

						TheSymbolTableEntry = GetSymbolFromTable(SymbolTable,
							GetTokenIdentifierString(Token),PtrSize(GetTokenIdentifierString(Token)));
						if (TheSymbolTableEntry == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileIdentifierNotDeclared;
							}
						TheOperand = NewSymbolReference(TrashTracker,TheSymbolTableEntry,
							GetCurrentLineNumber(Scanner));
					}
					break;

					/*   93:                      ::= <integer> */
				case eTokenInteger:
					TheOperand = NewIntegerLiteral(TrashTracker,GetTokenIntegerValue(Token),
						GetCurrentLineNumber(Scanner));
					break;

					/*   94:                      ::= <single> */
				case eTokenSingle:
					TheOperand = NewSingleLiteral(TrashTracker,GetTokenSingleValue(Token),
						GetCurrentLineNumber(Scanner));
					break;

					/*   95:                      ::= <double> */
				case eTokenDouble:
					TheOperand = NewDoubleLiteral(TrashTracker,GetTokenDoubleValue(Token),
						GetCurrentLineNumber(Scanner));
					break;

					/*   96:                      ::= <fixed> */
				case eTokenFixed:
					TheOperand = NewFixedLiteral(TrashTracker,GetTokenFixedValue(Token),
						GetCurrentLineNumber(Scanner));
					break;

					/*   97:                      ::= <string> */
				case eTokenString:
					/* this was here, but I took it out */
					*LineNumberOut = GetCurrentLineNumber(Scanner);
					return eCompileCantHaveStringLiteralThere;
#if 0
					TheOperand = NewStringLiteral(TrashTracker,GetTokenStringValue(Token),
						GetCurrentLineNumber(Scanner));
#endif

					/*  108:                      ::= ( <exprlist> ) */
				case eTokenOpenParen:
					{
						CompileErrors			Error;
						ASTExprListRec*		ListOfExpressions;

						/* open a new scope */
						if (!IncrementSymbolTableLevel(SymbolTable))
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}

						/* parse the expression sequence */
						Error = ParseExprList(&ListOfExpressions,Scanner,SymbolTable,TrashTracker,
							LineNumberOut);
						if (Error != eCompileNoError)
							{
								return Error;
							}

						/* dispose of the current scope */
						DecrementSymbolTableLevel(SymbolTable);

						/* build the thing */
						*ExpressionOut = NewExprSequence(ListOfExpressions,TrashTracker,
							GetCurrentLineNumber(Scanner));
						if (*ExpressionOut == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}

						/* clean up by getting rid of the close paren */
						Token = GetNextToken(Scanner);
						if (Token == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}
						if (GetTokenType(Token) != eTokenCloseParen)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileExpectedCloseParen;
							}
					}
					return eCompileNoError;

				case eTokenKeyword:
					switch (GetTokenKeywordTag(Token))
						{
							default:
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileExpectedOperand;

								/*   98:                      ::= true */
							case eKeywordTrue:
								TheOperand = NewBooleanLiteral(TrashTracker,True,
									GetCurrentLineNumber(Scanner));
								break;

								/*   99:                      ::= false */
							case eKeywordFalse:
								TheOperand = NewBooleanLiteral(TrashTracker,False,
									GetCurrentLineNumber(Scanner));
								break;

								/* this was added later. */
							case eKeywordPi:
								TheOperand = NewDoubleLiteral(TrashTracker,DGETPI(),
									GetCurrentLineNumber(Scanner));
								break;
						}
					break;
			}

		if (TheOperand == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		*ExpressionOut = NewExprOperand(TheOperand,TrashTracker,
			GetCurrentLineNumber(Scanner));
		if (*ExpressionOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*   80:   <expr7prime>       ::= <arraysubscript> */
/*   81:                      ::= <funccall> */
/*   82:                      ::= <exponentiation> */
/*   83:                      ::=  */
/*  <expr7prime>       : {(, OPENBRACKET, ^, <arraysubscript>, <funccall>, */
/*       <exponentiation>} */
/*  <expr7prime>       : {and, or, xor, div, mod, SHR, SHL, then, else, */
/*       elseif, while, until, do, to, ), CLOSEBRACKET, ,, :=, ;, *, /, */
/*       +, -, EQ, NEQ, LT, LTEQ, GR, GREQ, <expr2prime>, <conj_oper>, */
/*       <expr3prime>, <rel_oper>, <expr4prime>, <add_oper>, <expr5prime>, */
/*       <mult_oper>, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExpr7Prime(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* TheExpr8Thing, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(TheExpr8Thing);
		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		switch (GetTokenType(Token))
			{
				default:
					UngetToken(Scanner,Token);
					*ExpressionOut = TheExpr8Thing;
					return eCompileNoError;

					/*   81:                      ::= <funccall> */
				case eTokenOpenParen:
					UngetToken(Scanner,Token);
					return ParseFuncCall(ExpressionOut,TheExpr8Thing,Scanner,SymbolTable,
						TrashTracker,LineNumberOut);

					/*   80:   <expr7prime>       ::= <arraysubscript> */
				case eTokenOpenBracket:
					UngetToken(Scanner,Token);
					return ParseArraySubscript(ExpressionOut,TheExpr8Thing,Scanner,SymbolTable,
						TrashTracker,LineNumberOut);

					/*   82:                      ::= <exponentiation> */
				case eTokenCircumflex:
					{
						ASTExpressionRec*			RightHandSide;
						ASTBinaryOpRec*				TheOperator;
						CompileErrors					Error;

						UngetToken(Scanner,Token);
						Error = ParseExponentiation(&RightHandSide,Scanner,SymbolTable,
							TrashTracker,LineNumberOut);
						if (Error != eCompileNoError)
							{
								return Error;
							}
						TheOperator = NewBinaryOperator(eBinaryExponentiation,TheExpr8Thing,
							RightHandSide,TrashTracker,GetCurrentLineNumber(Scanner));
						if (TheOperator == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}
						*ExpressionOut = NewExprBinaryOperator(TheOperator,TrashTracker,
							GetCurrentLineNumber(Scanner));
						if (*ExpressionOut == NIL)
							{
								*LineNumberOut = GetCurrentLineNumber(Scanner);
								return eCompileOutOfMemory;
							}
						return eCompileNoError;
					}
			}
		EXECUTE(PRERR(ForceAbort,"ParseExpr7Prime:  control reached end of function"));
	}




/*   85:   <funccall>         ::= ( <actualstart> ) */
/* FIRST SET: */
/*  <funccall>         : {(} */
/* FOLLOW SET: */
/*  <funccall>         : {and, or, xor, div, mod, SHR, SHL, then, else, elseif, */
/*       while, until, do, to, ), CLOSEBRACKET, ,, :=, ;, *, /, +, -, EQ, */
/*       NEQ, LT, LTEQ, GR, GREQ, <expr2prime>, <conj_oper>, <expr3prime>, */
/*       <rel_oper>, <expr4prime>, <add_oper>, <expr5prime>, <mult_oper>, */
/*       <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseFuncCall(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* FunctionGenerator, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		ASTExprListRec*			ListOfParameters;
		CompileErrors				Error;
		ASTFuncCallRec*			TheFunctionCall;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		/* swallow open parenthesis */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenOpenParen)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedOpenParen;
			}

		/* parse the argument list */
		Error = ParseActualStart(&ListOfParameters,Scanner,SymbolTable,TrashTracker,
			LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* swallow close parenthesis */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenCloseParen)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedCommaOrCloseParen;
			}

		TheFunctionCall = NewFunctionCall(ListOfParameters,FunctionGenerator,
			TrashTracker,GetCurrentLineNumber(Scanner));
		if (TheFunctionCall == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		*ExpressionOut = NewExprFunctionCall(TheFunctionCall,TrashTracker,
			GetCurrentLineNumber(Scanner));
		if (*ExpressionOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*   84:   <arraysubscript>   ::= OPENBRACKET <exprlist> CLOSEBRACKET */
/* FIRST SET: */
/*  <arraysubscript>   : {OPENBRACKET} */
/* FOLLOW SET: */
/*  <arraysubscript>   : {and, or, xor, div, mod, SHR, SHL, then, else, */
/*       elseif, while, until, do, to, ), CLOSEBRACKET, ,, :=, ;, *, */
/*       /, +, -, EQ, NEQ, LT, LTEQ, GR, GREQ, <expr2prime>, <conj_oper>, */
/*       <expr3prime>, <rel_oper>, <expr4prime>, <add_oper>, <expr5prime>, */
/*       <mult_oper>, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseArraySubscript(ASTExpressionRec** ExpressionOut,
												ASTExpressionRec* ArrayGenerator, ScannerRec* Scanner,
												SymbolTableRec* SymbolTable, TrashTrackRec* TrashTracker,
												long* LineNumberOut)
	{
		TokenRec*						Token;
		ASTExpressionRec*		Subscript;
		CompileErrors				Error;
		ASTBinaryOpRec*			ArraySubsOperation;
		ASTExprListRec*			SubscriptRaw;

		CheckPtrExistence(ArrayGenerator);
		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenOpenBracket)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedOpenBracket;
			}

		Error = ParseExprList(&SubscriptRaw,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}
		Subscript = NewExprSequence(SubscriptRaw,TrashTracker,GetCurrentLineNumber(Scanner));
		if (Subscript == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenCloseBracket)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedCloseBracket;
			}

		ArraySubsOperation = NewBinaryOperator(eBinaryArraySubscripting,ArrayGenerator,
			Subscript,TrashTracker,GetCurrentLineNumber(Scanner));
		if (ArraySubsOperation == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		*ExpressionOut = NewExprBinaryOperator(ArraySubsOperation,TrashTracker,
			GetCurrentLineNumber(Scanner));
		if (*ExpressionOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*  124:   <exprlist>         ::= <exprlistelem> <exprlisttail> */
/* FIRST SET: */
/*  <exprlist>         : {<identifier>, <integer>, <single>, <double>, <fixed>, */
/*       <string>, bool, int, single, double, fixed, proto, var, not, sin, */
/*       cos, tan, asin, acos, atan, ln, exp, sqr, sqrt, abs, neg, sign, */
/*       length, if, while, until, do, resize, error, true, false, */
/*       set, (, -, <prototype>, <expr>, <expr2>, <expr3>, <expr4>, <expr5>, */
/*       <expr6>, <unary_oper>, <expr7>, <expr8>, <whileloop>, <untilloop>} */
/* FOLLOW SET: */
/*  <exprlist>         : {), CLOSEBRACKET, EOF} */
CompileErrors					ParseExprList(ASTExprListRec** ExpressionOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		CompileErrors				Error;
		ASTExpressionRec*		FirstExpression;
		TokenRec*						Token;
		ASTExprListRec*			RestOfList;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		if ((GetTokenType(Token) == eTokenCloseParen)
			|| (GetTokenType(Token) == eTokenCloseBracket)
			|| (GetTokenType(Token) == eTokenEndOfInput))
			{
				UngetToken(Scanner,Token);
				*ExpressionOut = NIL; /* empty list */
				return eCompileNoError;
			}

		/* see if we should parse a non-existent element (prototype) which */
		/* generates no code */
		if ((GetTokenType(Token) == eTokenKeyword)
			&& (GetTokenKeywordTag(Token) == eKeywordProto))
			{
				SymbolRec*					ProtoSymbolOut;
				CompileErrors				Error;

				UngetToken(Scanner,Token);
				Error = ParsePrototype(&ProtoSymbolOut,Scanner,SymbolTable,
					TrashTracker,LineNumberOut);
				if (Error != eCompileNoError)
					{
						return Error;
					}
				/* this is declarative and generates no code */
				/* as a hack to get this to work, we'll expect a semicolon and */
				/* another expression list */
				Token = GetNextToken(Scanner);
				if (Token == NIL)
					{
						*LineNumberOut = GetCurrentLineNumber(Scanner);
						return eCompileOutOfMemory;
					}
				/* eat up the semicolon */
				if (GetTokenType(Token) != eTokenSemicolon)
					{
						*LineNumberOut = GetCurrentLineNumber(Scanner);
						return eCompilePrototypeCantBeLastThingInExprList;
					}
				/* now just parse the rest of the expression list */
				return ParseExprList(ExpressionOut,Scanner,SymbolTable,TrashTracker,
					LineNumberOut);
			}

		/* get first part of list */
		UngetToken(Scanner,Token);
		Error = ParseExprListElem(&FirstExpression,Scanner,SymbolTable,TrashTracker,
			LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		/* get the rest of the list */
		Error = ParseExprListTail(&RestOfList,Scanner,SymbolTable,TrashTracker,
			LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		*ExpressionOut = ASTExprListCons(FirstExpression,RestOfList,TrashTracker);
		if (*ExpressionOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*   91:   <exponentiation>   ::= ^ <expr7> */
/* FIRST SET: */
/*  <exponentiation>   : {^} */
/* FOLLOW SET: */
/*  <exponentiation>   : {and, or, xor, div, mod, SHR, SHL, then, else, */
/*       elseif, while, until, do, to, ), CLOSEBRACKET, ,, :=, ;, *, */
/*       /, +, -, EQ, NEQ, LT, LTEQ, GR, GREQ, <expr2prime>, <conj_oper>, */
/*       <expr3prime>, <rel_oper>, <expr4prime>, <add_oper>, <expr5prime>, */
/*       <mult_oper>, <actualtail>, <iftail>, <loopwhileuntil>, <exprlisttail>} */
static CompileErrors	ParseExponentiation(ASTExpressionRec** ExpressionOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if (GetTokenType(Token) != eTokenCircumflex)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedRightAssociativeOperator;
			}

		return ParseExpr7(ExpressionOut,Scanner,SymbolTable,TrashTracker,LineNumberOut);
	}




/*   86:   <actualstart>      ::= <actuallist> */
/*   87:                      ::=  */
/* FIRST SET: */
/*  <actualstart>      : {<identifier>, <integer>, <single>, <double>, */
/*       <fixed>, <string>, bool, int, single, double, fixed, proto, var, */
/*       not, sin, cos, tan, asin, acos, atan, ln, exp, sqr, sqrt, abs, */
/*       neg, sign, length, if, while, until, do, resize, error, */
/*       true, false, set, (, -, <prototype>, <expr>, <expr2>, */
/*       <expr3>, <expr4>, <expr5>, <expr6>, <unary_oper>, <expr7>, <expr8>, */
/*       <actuallist>, <whileloop>, <untilloop>} */
/* FOLLOW SET: */
/*  <actualstart>      : {)} */
static CompileErrors	ParseActualStart(ASTExprListRec** ParamListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		/* handle the nullification */
		if (GetTokenType(Token) == eTokenCloseParen)
			{
				UngetToken(Scanner,Token);
				*ParamListOut = NIL; /* empty list is NIL */
				return eCompileNoError;
			}

		UngetToken(Scanner,Token);
		return ParseActualList(ParamListOut,Scanner,SymbolTable,TrashTracker,LineNumberOut);
	}




/*   88:   <actuallist>       ::= <expr> <actualtail> */
/* FIRST SET: */
/*  <actuallist>       : {<identifier>, <integer>, <single>, <double>, */
/*       <fixed>, <string>, bool, int, single, double, fixed, proto, var, */
/*       not, sin, cos, tan, asin, acos, atan, ln, exp, sqr, sqrt, abs, */
/*       neg, sign, length, if, while, until, do, resize, error, */
/*       true, false, set, (, -, <prototype>, <expr>, <expr2>, */
/*       <expr3>, <expr4>, <expr5>, <expr6>, <unary_oper>, <expr7>, <expr8>, */
/*       <whileloop>, <untilloop>} */
/* FOLLOW SET: */
/*  <actuallist>       : {)} */
static CompileErrors	ParseActualList(ASTExprListRec** ParamListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		ASTExpressionRec*		FirstExpression;
		CompileErrors				Error;
		ASTExprListRec*			RestOfList;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Error = ParseExpr(&FirstExpression,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		Error = ParseActualTail(&RestOfList,Scanner,SymbolTable,TrashTracker,LineNumberOut);
		if (Error != eCompileNoError)
			{
				return Error;
			}

		*ParamListOut = ASTExprListCons(FirstExpression,RestOfList,TrashTracker);
		if (*ParamListOut == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		return eCompileNoError;
	}




/*   89:   <actualtail>       ::= , <actuallist> */
/*   90:                      ::=  */
/* FIRST SET: */
/*  <actualtail>       : {,} */
/* FOLLOW SET: */
/*  <actualtail>       : {)} */
static CompileErrors	ParseActualTail(ASTExprListRec** ParamListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}
		if ((GetTokenType(Token) != eTokenComma)
			&& (GetTokenType(Token) != eTokenCloseParen))
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedCommaOrCloseParen;
			}

		/* handle nullification */
		if (GetTokenType(Token) == eTokenCloseParen)
			{
				UngetToken(Scanner,Token);
				*ParamListOut = NIL; /* empty list */
				return eCompileNoError;
			}

		return ParseActualList(ParamListOut,Scanner,SymbolTable,TrashTracker,LineNumberOut);
	}




/*  125:   <exprlisttail>     ::= ; <exprlist> */
/*  126:                      ::=  */
/* FIRST SET: */
/*  <exprlisttail>     : {;} */
/* FOLLOW SET: */
/*  <exprlisttail>     : {), CLOSEBRACKET, EOF} */
static CompileErrors	ParseExprListTail(ASTExprListRec** ListOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		/* find out if we should continue or not */
		if ((GetTokenType(Token) == eTokenCloseParen)
			|| (GetTokenType(Token) == eTokenCloseBracket)
			|| (GetTokenType(Token) == eTokenEndOfInput))
			{
				UngetToken(Scanner,Token);
				*ListOut = NIL; /* empty list */
				return eCompileNoError;
			}

		if (GetTokenType(Token) != eTokenSemicolon)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileExpectedSemicolon;
			}

		return ParseExprList(ListOut,Scanner,SymbolTable,TrashTracker,LineNumberOut);
	}




/*  124:   <exprlistelem>     ::= <expr> */
/*  125:                      ::= var <identifier> : <type> <vartail> */
/*   22:   <exprlistelem>     ::= <prototype> */
/* FIRST SET: */
/*  <exprlistelem>     : {<identifier>, <integer>, <single>, <double>, */
/*       <fixed>, <string>, bool, int, single, double, fixed, proto, */
/*       var, not, sin, cos, tan, asin, acos, atan, ln, exp, sqr, sqrt, */
/*       abs, neg, sign, length, if, while, until, do, resize, error, */
/*       true, false, set, (, -, <prototype>, <expr>, */
/*       <expr2>, <expr3>, <expr4>, <expr5>, <expr6>, <unary_oper>, <expr7>, */
/*       <expr8>, <whileloop>, <untilloop>} */
/* FOLLOW SET: */
/*  <exprlistelem>     : {), CLOSEBRACKET, ;, <exprlisttail>} */
static CompileErrors	ParseExprListElem(ASTExpressionRec** ExpressionOut,
												ScannerRec* Scanner, SymbolTableRec* SymbolTable,
												TrashTrackRec* TrashTracker, long* LineNumberOut)
	{
		TokenRec*						Token;

		CheckPtrExistence(Scanner);
		CheckPtrExistence(SymbolTable);
		CheckPtrExistence(TrashTracker);

		/* lookahead to see what to do */
		Token = GetNextToken(Scanner);
		if (Token == NIL)
			{
				*LineNumberOut = GetCurrentLineNumber(Scanner);
				return eCompileOutOfMemory;
			}

		if ((GetTokenType(Token) == eTokenKeyword)
			&& (GetTokenKeywordTag(Token) == eKeywordVar))
			{
				TokenRec*						VariableName;
				DataTypes						ReturnType;
				CompileErrors				Error;
				long								LineNumberForFirstToken;

				/* get the identifier */
				VariableName = GetNextToken(Scanner);
				if (VariableName == NIL)
					{
						*LineNumberOut = GetCurrentLineNumber(Scanner);
						return eCompileOutOfMemory;
					}
				if (GetTokenType(VariableName) != eTokenIdentifier)
					{
						*LineNumberOut = GetCurrentLineNumber(Scanner);
						return eCompileExpectedIdentifier;
					}
				LineNumberForFirstToken = GetCurrentLineNumber(Scanner);

				/* get the colon */
				Token = GetNextToken(Scanner);
				if (Token == NIL)
					{
						*LineNumberOut = GetCurrentLineNumber(Scanner);
						return eCompileOutOfMemory;
					}
				if (GetTokenType(Token) != eTokenColon)
					{
						*LineNumberOut = GetCurrentLineNumber(Scanner);
						return eCompileExpectedColon;
					}

				/* get the variable's type */
				Error = ParseType(&ReturnType,Scanner,LineNumberOut);
				if (Error != eCompileNoError)
					{
						return Error;
					}

				/* finish up the declaration of the variable */
				return ParseVarTail(ExpressionOut,VariableName,LineNumberForFirstToken,
					ReturnType,Scanner,SymbolTable,TrashTracker,LineNumberOut);
			}
		else
			{
				/* do the other thing */
				UngetToken(Scanner,Token);
				return ParseExpr(ExpressionOut,Scanner,SymbolTable,TrashTracker,LineNumberOut);
			}
	}
