//*************************************************************************** // // ABLRTN.CPP // //*************************************************************************** #include "MW4Headers.hpp" #include #include #include #include #pragma warning (disable:4284) #pragma warning (push) #include #pragma warning (pop) #ifndef ABLGEN_H #include "ablgen.h" #endif #ifndef ABLERR_H #include "ablerr.h" #endif #ifndef ABLSCAN_H #include "ablscan.h" #endif #ifndef ABLSYMT_H #include "ablsymt.h" #endif #ifndef ABLPARSE_H #include "ablparse.h" #endif #ifndef ABLEXEC_H #include "ablexec.h" #endif #ifndef ABLENV_H #include "ablenv.h" #endif #ifndef ABL_H #include "abl.h" #endif #ifndef ABLDBUG_H #include "abldbug.h" #endif #ifndef ABLHEAP_H #include "ablheap.h" #endif #include "AblProfiler.hpp" #include "ablfuncs.hpp" #include "ABLFile.h" // MC-specific... #ifdef USE_OBJECTS #ifndef GROUP_H #include "group.h" #endif #endif //#ifndef IFACE_H //#include "iface.h" //#endif //*************************************************************************** namespace ABL { extern ABLError *ablError; extern jmp_buf abl_jmp_buf; extern long MaxBreaks; extern long MaxWatches; extern DebuggerPtr debugger; extern long NumModules; extern ModuleEntryPtr ModuleRegistry; extern ABLModulePtr* ModuleInstanceRegistry; extern long MaxModules; extern ABLModulePtr* LibraryInstanceRegistry; extern long MaxLibraries; extern long NumModulesRegistered; extern long NumModuleInstances; extern long MaxWatchesPerModule; extern long MaxBreakPointsPerModule; extern long MaxCodeBufferSize; extern ABLModulePtr CurModule; extern ABLModulePtr CurLibrary; extern char* codeBuffer; extern char* codeBufferPtr; extern char* codeSegmentPtr; extern char* codeSegmentLimit; extern char* statementStartPtr; extern StackItem* stack; extern StackItemPtr tos; extern StackItemPtr stackFrameBasePtr; extern StackItemPtr StaticDataPtr; extern long* StaticVariablesSizes; extern long* EternalVariablesSizes; extern long MaxEternalVariables; extern long eternalOffset; extern long MaxStaticVariables; extern long NumStaticVariables; extern long CurModuleHandle; extern bool CallModuleInit; extern bool InOrdersBlock; extern long MaxLoopIterations; extern bool AssertEnabled; extern bool IncludeDebugInfo; extern bool ProfileABL; extern bool Crunch; extern long level; extern long FSMLevel; extern long lineNumber; extern long FileNumber; extern FilePtr sourceFile; extern bool printFlag; extern bool blockFlag; extern BlockType blockType; extern SymTableNodePtr CurModuleIdPtr; extern SymTableNodePtr CurRoutineIdPtr; extern bool DumbGetCharOn; extern long NumOpenFiles; extern long NumSourceFiles; extern long NumLibrariesUsed; extern ABLModulePtr LibrariesUsed[MAX_LIBRARIES_USED]; extern long bufferOffset; extern char* bufferp; extern char* tokenp; extern long digitCount; extern bool countError; extern long pageNumber; extern long lineCount; // std::string currentParamList; // TODO: use this implementation or remove it // std::string currentScriptSuffix; #ifdef USE_OBJECTS extern bool IsUnitOrder; #else bool IsUnitOrder = false; #endif #ifdef USE_OBJECTS extern bool TacOrderOrigin; extern MoverGroupPtr CurGroup; extern GameObjectPtr CurObject; extern long CurObjectClass; extern MechWarriorPtr CurWarrior; extern GameObjectPtr CurContact; #endif extern long CurAlarm; extern bool eofFlag; extern bool ExitWithReturn; extern bool ExitFromTacOrder; extern long dummyCount; extern long lineNumber; extern long FileNumber; extern long errorCount; extern long execStatementCount; extern long NumSourceFiles; extern char SourceFiles[MAX_SOURCE_FILES][MAXLEN_FILENAME]; extern TokenCodeType curToken; extern char wordString[]; extern SymTableNodePtr symTableDisplay[]; extern long level; extern bool blockFlag; extern BlockType blockType; extern bool printFlag; extern SymTableNodePtr CurRoutineIdPtr; extern Type DummyType; extern StackItem* stack; //extern StackItem* eternalStack; extern StackItemPtr tos; extern StackItemPtr stackFrameBasePtr; extern long eternalOffset; extern TokenCodeType statementStartList[]; extern TokenCodeType statementEndList[]; extern TokenCodeType declarationStartList[]; extern char tokenString[MAXLEN_TOKENSTRING]; extern CharCodeType charTable[256]; extern char sourceBuffer[MAXLEN_SOURCELINE]; extern long bufferOffset; extern char* bufferp; extern char* tokenp; extern long digitCount; extern bool countError; extern bool eofFlag; extern long pageNumber; extern UserHeapPtr systemHeap; extern UserHeapPtr AblSymTableHeap; extern UserHeapPtr AblStackHeap; extern UserHeapPtr AblCodeHeap; extern SymTableNodePtr SymTableDisplay[MAX_NESTING_LEVEL]; extern TypePtr IntegerTypePtr; extern TypePtr RealTypePtr; extern TypePtr BooleanTypePtr; extern StackItemPtr StaticDataPtr; extern StackItem returnValue; extern ModuleEntryPtr ModuleRegistry; extern long MaxModules; extern long NumModulesRegistered; extern long* StaticVariablesSizes; extern long MaxStaticVariables; extern long NumStaticVariables; extern long NumSourceFiles; extern bool IncludeDebugInfo; extern bool AssertEnabled; extern bool PrintEnabled; extern bool StringFunctionsEnabled; extern bool DebugCodeEnabled; extern DebuggerPtr debugger; extern bool parsingFSM; bool ABLenabled = false; bool g_ABLCreated = false; char buffer[MAXLEN_PRINTLINE]; extern long CallStackLevel; long numLibrariesLoaded = 0; long NumExecutions = 0; Profiler* g_Profiler = 0; //*************************************************************************** TokenCodeType followHeaderList[] = { TKN_SEMICOLON, TKN_EOF, TKN_NONE }; TokenCodeType followModuleIdList[] = { TKN_LPAREN, TKN_COLON, TKN_SEMICOLON, TKN_EOF, TKN_NONE }; TokenCodeType followFunctionIdList[] = { TKN_LPAREN, TKN_COLON, TKN_SEMICOLON, TKN_EOF, TKN_NONE }; TokenCodeType followParamsList[] = { TKN_RPAREN, TKN_COMMA, //TKN_SEMICOLON, TKN_EOF, TKN_NONE }; TokenCodeType followParamList[] = { TKN_COMMA, TKN_RPAREN, TKN_NONE }; TokenCodeType followModuleDeclsList[] = { TKN_SEMICOLON, TKN_CODE, TKN_EOF, TKN_NONE }; TokenCodeType followRoutineDeclsList[] = { TKN_SEMICOLON, TKN_CODE, TKN_EOF, TKN_NONE }; TokenCodeType followDeclsList[] = { TKN_SEMICOLON, //TKN_BEGIN, TKN_EOF, TKN_NONE }; void ABL_CloseProfileLog (void); void ABL_OpenProfileLog (void); void ABL_AddToProfileLog (char* profileString); //*************************************************************************** // ABL library interface routines //*************************************************************************** void ABLi_init (unsigned long symTableHeapSize, unsigned long stackHeapSize, unsigned long codeHeapSize, unsigned long runtimeStackSize, unsigned long maxCodeBufferSize, unsigned long maxRegisteredModules, unsigned long maxStaticVariables, void (*callback)(char* s), bool debugInfo, bool debug, bool profile) { // HACK, for testing... #ifdef _DEBUG profile = true; #endif // //------------------------------------------------------------------- // Let's make sure we have not created too many built-in ABL routines // for the lovely user... g_ABLFunctions = new stlport::vector; g_ABLFunctions->assign (NUM_ABL_ROUTINES,NULL); // if (NUM_ABL_ROUTINES > 254) // ABL_Fatal(0, " MAJOR ABL ERROR: Too Many ABL Routines "); ablError = NULL; ABLenabled = true; MaxBreaks = 50; MaxWatches = 50; debugger = NULL; NumModules = 0; ModuleRegistry = NULL; ModuleInstanceRegistry = NULL; LibraryInstanceRegistry = NULL; MaxModules = 0; MaxLibraries = 0; NumModulesRegistered = 0; NumModuleInstances = 0; MaxWatchesPerModule = 20; MaxBreakPointsPerModule = 20; CurModule = NULL; errorCount = 0; codeBuffer = NULL; codeBufferPtr = NULL; codeSegmentPtr = NULL; codeSegmentLimit = NULL; statementStartPtr = NULL; execStatementCount = 0; stack = NULL; tos = NULL; stackFrameBasePtr = NULL; StaticDataPtr = NULL; StaticVariablesSizes = NULL; EternalVariablesSizes = NULL; MaxEternalVariables = 5000; eternalOffset = 0; MaxStaticVariables = 0; NumStaticVariables = 0; CurModuleHandle = 0; CallModuleInit = false; InOrdersBlock = false; MaxLoopIterations = 100001; AssertEnabled = false; PrintEnabled = false; StringFunctionsEnabled = true; IncludeDebugInfo = true; ProfileABL = profile; Crunch = true; AblSymTableHeap = NULL; AblStackHeap = NULL; AblCodeHeap = NULL; level = 0; lineNumber = 0; FileNumber = 0; sourceFile = NULL; printFlag = true; blockFlag = false; blockType = BLOCK_MODULE; CurModuleIdPtr = NULL; CurRoutineIdPtr = NULL; DumbGetCharOn = false; NumOpenFiles = 0; NumSourceFiles = 0; bufferOffset = 0; bufferp = sourceBuffer; tokenp = tokenString; digitCount = 0; countError = false; pageNumber = 0; lineCount = MAX_LINES_PER_PAGE; IsUnitOrder = false; #ifdef USE_OBJECTS TacOrderOrigin = ORDER_ORIGIN_COMMANDER; #endif eofFlag = false; ExitWithReturn = false; ExitFromTacOrder = false; dummyCount = 0; numLibrariesLoaded = 0; AblSymTableHeap = new UserHeap; long heapErr = AblSymTableHeap->init(symTableHeapSize,"ABL symbol table"); if (heapErr != NO_ERR) { //systemHeap->MemoryDump(); STOP(("unable to create ABL symbol table heap")); } AblStackHeap = new UserHeap; heapErr = AblStackHeap->init(stackHeapSize,"ABL stack"); if (heapErr != NO_ERR) { //systemHeap->MemoryDump(); STOP(("unable to create ABL stack heap")); } AblCodeHeap = new UserHeap; heapErr = AblCodeHeap->init(codeHeapSize,"ABL code"); if (heapErr != NO_ERR) { //systemHeap->MemoryDump(); STOP(("unable to create ABL code heap")); } //---------------------------------- // Initialize the character table... for (long curCh = 0; curCh < 256; curCh++) charTable[curCh] = CHR_SPECIAL; for (curCh = '0'; curCh <= '9'; curCh++) charTable[curCh] = CHR_DIGIT; for (curCh = 'A'; curCh <= 'Z'; curCh++) charTable[curCh] = CHR_LETTER; for (curCh = 'a'; curCh <= 'z'; curCh++) charTable[curCh] = CHR_LETTER; charTable['\"'] = CHR_DQUOTE; charTable[CHAR_EOF] = CHR_EOF; //-------------------------------------------------------------------- // Allocate the code buffer used during pre-processing/interpreting... MaxCodeBufferSize = maxCodeBufferSize; codeBuffer = (char*)AblCodeHeap->Malloc(maxCodeBufferSize); if (!codeBuffer) ABL_Fatal(0, " ABL: Unable to AblCodeHeap->malloc preprocess code buffer "); //---------------------------------------------------------------------- // Alloc the static variable data block. Ultimately, we may want to just // implement the static data construction with a linked list, rather // than a set max size... MaxStaticVariables = maxStaticVariables; NumStaticVariables = 0; StaticDataPtr = NULL; StaticVariablesSizes = NULL; if (MaxStaticVariables > 0) { StaticVariablesSizes = (long*)AblStackHeap->Malloc(sizeof(long) * MaxStaticVariables); if (!StaticVariablesSizes) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc StaticVariablesSizes "); } //------------------------------ // Allocate the runtime stack... stack = (StackItemPtr)AblStackHeap->Malloc(sizeof(StackItem) * (runtimeStackSize / sizeof(StackItem))); if (!stack) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc stack "); //----------------------------------- // Allocate Eternal Vars Size List... if (MaxEternalVariables > 0) { EternalVariablesSizes = (long*)AblStackHeap->Malloc(sizeof(long) * MaxEternalVariables); if (!EternalVariablesSizes) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc EternalVariablesSizes "); } //------------------------- // Prep the symbol table... initSymTable(); initModuleRegistry(maxRegisteredModules); initLibraryRegistry(10); //-------------------------------- // Init the debugger, if needed... IncludeDebugInfo = debugInfo; if (debug) { IncludeDebugInfo = true; debugger = new Debugger; if (!debugger) ABL_Fatal(0, " Unable to initialize ABL Debugger. "); debugger->init(callback, NULL); } //blurt UserFile::setup(); if (ProfileABL) ABL_OpenProfileLog(); if (g_Profiler == 0) { g_Profiler = new Profiler; } g_ABLCreated = true; //--------------------- // MC-specific stuff... #ifdef USE_OBJECTS CurGroup = NULL; CurObject = NULL; CurObjectClass = 0; CurWarrior = NULL; CurContact = NULL; #endif } //*************************************************************************** void ABLi_VerifyStates (SymTableNodePtr node) { if (!node) return; ABLi_VerifyStates (node->left); if ((node->defn.key == DFN_STATE) && (node->defn.info.routine.key==RTN_FORWARD)) syntaxError (ABL_ERR_SYNTAX_FORWARDED_STATE_NOT_DECLARED); ABLi_VerifyStates (node->right); } //*************************************************************************** long ABLi_preProcess (char* sourceFileName, ABLError *err,long* numErrors, long* numLinesProcessed, long* numFilesProcessed, bool printLines) { //-------------------------------------------------------------------------------- // First, check if this module has already been registered into the environment... for (long i = 0; i < NumModulesRegistered; i++) if (strcmp(strlwr(sourceFileName), ModuleRegistry[i].fileName) == 0) return(i); ablError = err; //--------------------------------- // Init some important variables... parsingFSM = false; level = 0; lineNumber = 0; FileNumber = 0; AssertEnabled = (debugger != NULL); PrintEnabled = (debugger != NULL); StringFunctionsEnabled = true; DebugCodeEnabled = (debugger != NULL); NumSourceFiles = 0; NumLibrariesUsed = 0; sourceFile = NULL; printFlag = printLines; blockFlag = false; blockType = BLOCK_MODULE; bufferOffset = 0; bufferp = sourceBuffer; tokenp = tokenString; digitCount = 0; countError = false; pageNumber = 0; errorCount = 0; execStatementCount = 0; eofFlag = false; NumStaticVariables = 0; if (numErrors) *numErrors = 0; if (numLinesProcessed) *numLinesProcessed = 0; //--------------------------------------- // Now, let's open the ABL source file... long openErr = NO_ERR; if ((openErr = openSourceFile(sourceFileName)) != NO_ERR) { if (ablError) { ablError->String ("Unable to open file"); ablError->File (sourceFileName); ablError->Line (0); ablError->Code (openErr); } ablError = NULL; return(openErr); } #pragma warning (disable:4611) if (ablError) { if (setjmp (abl_jmp_buf)) { closeSourceFile (); ablError = NULL; return -1; } } #pragma warning (default:4611) //------------------------ // Set up the code buffer. codeBufferPtr = codeBuffer; //------------------ // Get it rolling... getToken(); SymTableNodePtr moduleIdPtr = moduleHeader(); CurModuleIdPtr = moduleIdPtr; CurRoutineIdPtr = moduleIdPtr; //--------------------- // Error synchronize... synchronize(followHeaderList, declarationStartList, statementStartList); if (curToken == TKN_SEMICOLON) getToken(); else if (tokenIn(declarationStartList) || tokenIn(statementStartList)) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); //------------------------------------------------------------- // Parse the module's block. Use to call block(), now we do the // stuff right here... //block(moduleIdPtr); declarations(moduleIdPtr, 1,parsingFSM ? 1: 0); if (!parsingFSM) { synchronize(followModuleDeclsList, NULL, NULL); if ((curToken != TKN_CODE) && (parsingFSM == false)) syntaxError(ABL_ERR_SYNTAX_MISSING_CODE); else if ((curToken != TKN_STATE) && (parsingFSM == true)) syntaxError(ABL_ERR_SYNTAX_CODE_OUTSIDE_STATE_BLOCK); crunchToken(); blockType = BLOCK_MODULE; blockFlag = true; getToken(); } TokenCodeType endToken; if (parsingFSM) endToken = TKN_END_FSM; else endToken = ((CurLibrary == NULL) ? TKN_END_MODULE : TKN_END_LIBRARY); if (curToken != endToken) do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if (curToken == endToken) break; //------------------------------------ // Synchronize after possible error... synchronize(statementStartList, NULL, NULL); } while (tokenIn(statementStartList)); if (CurLibrary) ifTokenGetElseError(TKN_END_LIBRARY, ABL_ERR_SYNTAX_MISSING_END_LIBRARY); else if (parsingFSM) ifTokenGetElseError(TKN_END_FSM, ABL_ERR_SYNTAX_MISSING_END_MODULE); else ifTokenGetElseError(TKN_END_MODULE, ABL_ERR_SYNTAX_MISSING_END_MODULE); blockFlag = false; moduleIdPtr->defn.info.routine.localSymTable = exitScope(); moduleIdPtr->defn.info.routine.codeSegment = createCodeSegment(moduleIdPtr->defn.info.routine.codeSegmentSize); analyzeBlock(moduleIdPtr->defn.info.routine.codeSegment); ifTokenGetElseError(TKN_PERIOD, ABL_ERR_SYNTAX_MISSING_PERIOD); while (curToken != TKN_EOF) { syntaxError(ABL_ERR_SYNTAX_UNEXPECTED_TOKEN); getToken(); } //------------------------------------------ // Done with the source file, so close it... closeSourceFile(); //------------------------------------------ // Verify that all states were declared if (parsingFSM) ABLi_VerifyStates (moduleIdPtr->defn.info.routine.localSymTable); //extractSymTable(&SymTableDisplay[0], moduleIdPtr); //-------------------------------------------------- // Register the new module in the ABL environment... ModuleRegistry[NumModulesRegistered].fileName = (char*)AblStackHeap->Malloc(strlen(sourceFileName) + 1); if (!ModuleRegistry[NumModulesRegistered].fileName) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module filename "); strcpy(ModuleRegistry[NumModulesRegistered].fileName, strlwr(sourceFileName)); ModuleRegistry[NumModulesRegistered].moduleIdPtr = moduleIdPtr; ModuleRegistry[NumModulesRegistered].numSourceFiles = NumSourceFiles; ModuleRegistry[NumModulesRegistered].sourceFiles = (char**)AblStackHeap->Malloc(NumSourceFiles * sizeof(char*)); if (!ModuleRegistry[NumModulesRegistered].sourceFiles) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc sourceFiles "); for (i = 0; i < NumSourceFiles; i++) { ModuleRegistry[NumModulesRegistered].sourceFiles[i] = (char*)AblStackHeap->Malloc(strlen(SourceFiles[i]) + 1); strcpy(ModuleRegistry[NumModulesRegistered].sourceFiles[i], SourceFiles[i]); } if (NumLibrariesUsed > 0) { ModuleRegistry[NumModulesRegistered].numLibrariesUsed = NumLibrariesUsed; ModuleRegistry[NumModulesRegistered].librariesUsed = (ABLModulePtr*)AblStackHeap->Malloc(NumLibrariesUsed * sizeof(SymTableNodePtr)); if (!ModuleRegistry[NumModulesRegistered].librariesUsed) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc librariesUsed "); for (i = 0; i < NumLibrariesUsed; i++) ModuleRegistry[NumModulesRegistered].librariesUsed[i] = LibrariesUsed[i]; } ModuleRegistry[NumModulesRegistered].numStaticVars = NumStaticVariables; ModuleRegistry[NumModulesRegistered].sizeStaticVars = NULL; ModuleRegistry[NumModulesRegistered].totalSizeStaticVars = 0; if (NumStaticVariables) { ModuleRegistry[NumModulesRegistered].sizeStaticVars = (long*)AblStackHeap->Malloc(sizeof(long) * NumStaticVariables); if (!ModuleRegistry[NumModulesRegistered].sizeStaticVars) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module sizeStaticVars "); memcpy(ModuleRegistry[NumModulesRegistered].sizeStaticVars, StaticVariablesSizes, sizeof(long) * NumStaticVariables); ModuleRegistry[NumModulesRegistered].totalSizeStaticVars = sizeof(long) * NumStaticVariables; for (long i = 0; i < ModuleRegistry[NumModulesRegistered].numStaticVars; i++) ModuleRegistry[NumModulesRegistered].totalSizeStaticVars += ModuleRegistry[NumModulesRegistered].sizeStaticVars[i]; } ModuleRegistry[NumModulesRegistered].numInstances = 0; NumModulesRegistered++; //--------------------------------------------------------------- // Now, exit with the number of source lines processed, if any... if (numLinesProcessed) *numLinesProcessed = lineNumber; if (numFilesProcessed) *numFilesProcessed = FileNumber; if (numErrors) *numErrors = errorCount; ablError = NULL; return(NumModulesRegistered - 1); } //*************************************************************************** /* long ABLi_preProcessFromParams(const std::string& params, const std::string& script_suffix) { ablError = 0; //--------------------------------- // Init some important variables... parsingFSM = false; level = 0; lineNumber = 0; FileNumber = 0; AssertEnabled = (debugger != NULL); PrintEnabled = (debugger != NULL); StringFunctionsEnabled = true; DebugCodeEnabled = (debugger != NULL); NumSourceFiles = 0; NumLibrariesUsed = 0; sourceFile = NULL; blockFlag = false; blockType = BLOCK_MODULE; bufferOffset = 0; bufferp = sourceBuffer; tokenp = tokenString; digitCount = 0; countError = false; pageNumber = 0; errorCount = 0; execStatementCount = 0; eofFlag = false; NumStaticVariables = 0; std::string params_copy(params); std::string source_file_name("Content\\ABLScripts\\GenericScripts\\"); while (params_copy[0] != ',') { source_file_name += params_copy[0]; params_copy.erase(0,1); } params_copy.erase(0,1); //--------------------------------------- // Now, let's open the ABL source file... long openErr = NO_ERR; currentParamList = params_copy; currentScriptSuffix = script_suffix; if ((openErr = openSourceFile((char*)source_file_name.c_str())) != NO_ERR) { if (ablError) { ablError->String ("Unable to open file"); ablError->File (source_file_name.c_str()); ablError->Line (0); ablError->Code (openErr); } ablError = NULL; currentParamList.erase(currentParamList.begin(),currentParamList.end()); currentScriptSuffix.erase(currentScriptSuffix.begin(),currentScriptSuffix.end()); return(openErr); } currentParamList.erase(currentParamList.begin(),currentParamList.end()); currentScriptSuffix.erase(currentScriptSuffix.begin(),currentScriptSuffix.end()); #pragma warning (disable:4611) if (ablError) { if (setjmp (abl_jmp_buf)) { closeSourceFile (); ablError = NULL; return -1; } } #pragma warning (default:4611) //------------------------ // Set up the code buffer. codeBufferPtr = codeBuffer; //------------------ // Get it rolling... getToken(); SymTableNodePtr moduleIdPtr = moduleHeader(); CurModuleIdPtr = moduleIdPtr; CurRoutineIdPtr = moduleIdPtr; //--------------------- // Error synchronize... synchronize(followHeaderList, declarationStartList, statementStartList); if (curToken == TKN_SEMICOLON) getToken(); else if (tokenIn(declarationStartList) || tokenIn(statementStartList)) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); //------------------------------------------------------------- // Parse the module's block. Use to call block(), now we do the // stuff right here... //block(moduleIdPtr); declarations(moduleIdPtr, 1,parsingFSM ? 1: 0); if (!parsingFSM) { synchronize(followModuleDeclsList, NULL, NULL); if ((curToken != TKN_CODE) && (parsingFSM == false)) syntaxError(ABL_ERR_SYNTAX_MISSING_CODE); else if ((curToken != TKN_STATE) && (parsingFSM == true)) syntaxError(ABL_ERR_SYNTAX_CODE_OUTSIDE_STATE_BLOCK); crunchToken(); blockType = BLOCK_MODULE; blockFlag = true; getToken(); } TokenCodeType endToken; if (parsingFSM) endToken = TKN_END_FSM; else endToken = ((CurLibrary == NULL) ? TKN_END_MODULE : TKN_END_LIBRARY); if (curToken != endToken) do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if (curToken == endToken) break; //------------------------------------ // Synchronize after possible error... synchronize(statementStartList, NULL, NULL); } while (tokenIn(statementStartList)); if (CurLibrary) ifTokenGetElseError(TKN_END_LIBRARY, ABL_ERR_SYNTAX_MISSING_END_LIBRARY); else if (parsingFSM) ifTokenGetElseError(TKN_END_FSM, ABL_ERR_SYNTAX_MISSING_END_MODULE); else ifTokenGetElseError(TKN_END_MODULE, ABL_ERR_SYNTAX_MISSING_END_MODULE); blockFlag = false; moduleIdPtr->defn.info.routine.localSymTable = exitScope(); moduleIdPtr->defn.info.routine.codeSegment = createCodeSegment(moduleIdPtr->defn.info.routine.codeSegmentSize); analyzeBlock(moduleIdPtr->defn.info.routine.codeSegment); ifTokenGetElseError(TKN_PERIOD, ABL_ERR_SYNTAX_MISSING_PERIOD); // while (curToken != TKN_EOF) // { // syntaxError(ABL_ERR_SYNTAX_UNEXPECTED_TOKEN); // getToken(); // } //------------------------------------------ // Done with the source file, so close it... closeSourceFile(); //------------------------------------------ // Verify that all states were declared if (parsingFSM) ABLi_VerifyStates (moduleIdPtr->defn.info.routine.localSymTable); //extractSymTable(&SymTableDisplay[0], moduleIdPtr); //-------------------------------------------------- // Register the new module in the ABL environment... ModuleRegistry[NumModulesRegistered].fileName = (char*)AblStackHeap->Malloc(strlen((char*)source_file_name.c_str()) + 1); if (!ModuleRegistry[NumModulesRegistered].fileName) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module filename "); strcpy(ModuleRegistry[NumModulesRegistered].fileName, strlwr((char*)source_file_name.c_str())); ModuleRegistry[NumModulesRegistered].moduleIdPtr = moduleIdPtr; ModuleRegistry[NumModulesRegistered].numSourceFiles = NumSourceFiles; ModuleRegistry[NumModulesRegistered].sourceFiles = (char**)AblStackHeap->Malloc(NumSourceFiles * sizeof(char*)); if (!ModuleRegistry[NumModulesRegistered].sourceFiles) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc sourceFiles "); for (long i = 0; i < NumSourceFiles; i++) { ModuleRegistry[NumModulesRegistered].sourceFiles[i] = (char*)AblStackHeap->Malloc(strlen(SourceFiles[i]) + 1); strcpy(ModuleRegistry[NumModulesRegistered].sourceFiles[i], SourceFiles[i]); } if (NumLibrariesUsed > 0) { ModuleRegistry[NumModulesRegistered].numLibrariesUsed = NumLibrariesUsed; ModuleRegistry[NumModulesRegistered].librariesUsed = (ABLModulePtr*)AblStackHeap->Malloc(NumLibrariesUsed * sizeof(SymTableNodePtr)); if (!ModuleRegistry[NumModulesRegistered].librariesUsed) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc librariesUsed "); for (i = 0; i < NumLibrariesUsed; i++) ModuleRegistry[NumModulesRegistered].librariesUsed[i] = LibrariesUsed[i]; } ModuleRegistry[NumModulesRegistered].numStaticVars = NumStaticVariables; ModuleRegistry[NumModulesRegistered].sizeStaticVars = NULL; ModuleRegistry[NumModulesRegistered].totalSizeStaticVars = 0; if (NumStaticVariables) { ModuleRegistry[NumModulesRegistered].sizeStaticVars = (long*)AblStackHeap->Malloc(sizeof(long) * NumStaticVariables); if (!ModuleRegistry[NumModulesRegistered].sizeStaticVars) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module sizeStaticVars "); memcpy(ModuleRegistry[NumModulesRegistered].sizeStaticVars, StaticVariablesSizes, sizeof(long) * NumStaticVariables); ModuleRegistry[NumModulesRegistered].totalSizeStaticVars = sizeof(long) * NumStaticVariables; for (long i = 0; i < ModuleRegistry[NumModulesRegistered].numStaticVars; i++) ModuleRegistry[NumModulesRegistered].totalSizeStaticVars += ModuleRegistry[NumModulesRegistered].sizeStaticVars[i]; } ModuleRegistry[NumModulesRegistered].numInstances = 0; NumModulesRegistered++; ablError = NULL; return(NumModulesRegistered - 1); } */ //*************************************************************************** long ABLi_execute (SymTableNodePtr moduleIdPtr, SymTableNodePtr functionIdPtr, ABLParamPtr paramList, StackItemPtr returnVal) { //insertSymTable(&SymTableDisplay[0], moduleIdPtr); //-------------------------- // Execute the ABL module... //---------------------------------------------------------------------------------- // NOTE: Ultimately, we want the ABL virtual machine to be set up once, and then // ABL modules/routines can be called multiple times from within a program. For now, // to test, let's just assume every time we run a module, it is a self-contained // ABL program. //--------------------------------- // Init some important variables... //lineNumber = 0; //printFlag = true; //blockFlag = false; //blockType = BLOCK_MODULE; CurModuleIdPtr = NULL; CurRoutineIdPtr = NULL; //bufferOffset = 0; //bufferp = sourceBuffer; //tokenp = tokenString; //digitCount = 0; //countError = false; errorCount = 0; execStatementCount = 0; NumExecutions++; //------------------ // Init the stack... stackFrameBasePtr = tos = (stack + eternalOffset); //--------------------------------------- // Initialize the module's stack frame... level = 1; CallStackLevel = 0; stackFrameBasePtr = tos + 1; //------------------------- // Function return value... pushInteger(0); //--------------- // Static Link... pushAddress(NULL); //---------------- // Dynamic Link... pushAddress(NULL); //------------------ // Return Address... pushAddress(NULL); //initDebugger(); //---------- // Run it... if (paramList) { //------------------------------------------------------------------------------ // NOTE: Currently, parameter passing of arrays is not functioning. This MUST be // done... long curParam = 0; for (SymTableNodePtr formalIdPtr = (SymTableNodePtr)(moduleIdPtr->defn.info.routine.params); formalIdPtr != NULL; formalIdPtr = formalIdPtr->next) { TypePtr formalTypePtr = (TypePtr)(formalIdPtr->typePtr); if (formalIdPtr->defn.key == DFN_VALPARAM) { if (formalTypePtr == RealTypePtr) { if (paramList[curParam].type == ABL_PARAM_INTEGER) { //--------------------------------------------- // Real formal parameter, but integer actual... pushReal((float)(paramList[curParam].integer)); } else if (paramList[curParam].type == ABL_PARAM_REAL) pushReal(paramList[curParam].real); } else if (formalTypePtr == IntegerTypePtr) { if (paramList[curParam].type== ABL_PARAM_INTEGER) pushInteger(paramList[curParam].integer); else return(0); } //---------------------------------------------------------- // Formal parameter is an array or record, so make a copy... if ((formalTypePtr->form == FRM_ARRAY)/* || (formalTypePtr->form == FRM_RECORD)*/) { //------------------------------------------------------------------------------ // The following is a little inefficient, but is kept this way to keep it clear. // Once it's verified to work, optimize... long size = formalTypePtr->size; char* dest = (char*)AblStackHeap->Malloc((size_t)size); if (!dest) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module formal array param "); char* src = tos->address; char* savePtr = dest; memcpy(dest, src, size); tos->address = savePtr; } } else { //------------------------------- // pass by reference parameter... if (formalTypePtr == RealTypePtr) pushAddress((Address)&(paramList[curParam].real)); else if (formalTypePtr == IntegerTypePtr) pushAddress((Address)&(paramList[curParam].integer)); else return(0); //SymTableNodePtr idPtr = getCodeSymTableNodePtr(); //execVariable(idPtr, USE_REFPARAM); } curParam++; } } execute(moduleIdPtr); if (returnVal) memcpy(returnVal, &returnValue, sizeof(StackItem)); //extractSymTable(&SymTableDisplay[0], moduleIdPtr); //----------- // Summary... return(execStatementCount); } //*************************************************************************** long ABLi_deleteModule (SymTableNodePtr moduleIdPtr) { return(NO_ERR); } //*************************************************************************** void ABLi_close (void) { if (!g_ABLCreated) return; if (g_Profiler != 0) { delete g_Profiler; g_Profiler = 0; } //blurt UserFile::cleanup(); destroyModuleRegistry(); destroyLibraryRegistry(); stlport::vector::iterator iter; for (iter = g_ABLFunctions->begin ();iter < g_ABLFunctions->end ();iter++) { delete (*iter); } delete g_ABLFunctions; if (StaticVariablesSizes) { AblStackHeap->Free(StaticVariablesSizes); StaticVariablesSizes = NULL; } if (EternalVariablesSizes) { AblStackHeap->Free(EternalVariablesSizes); EternalVariablesSizes = NULL; } if (codeBuffer) { AblCodeHeap->Free(codeBuffer); codeBuffer = NULL; } if (stack) { AblStackHeap->Free(stack); stack = NULL; } if (debugger) { delete debugger; debugger = NULL; } if (AblSymTableHeap) { delete AblSymTableHeap; AblSymTableHeap = NULL; } if (AblStackHeap) { delete AblStackHeap; AblStackHeap = NULL; } if (AblCodeHeap) { delete AblCodeHeap; AblCodeHeap = NULL; } ABL_CloseProfileLog(); ABLenabled = false; g_ABLCreated = false; } //*************************************************************************** long ABLi_loadLibrary (char* sourceFileName, ABLError *ablerr, long* numErrors, long* numLinesProcessed, long* numFilesProcessed, bool printLines) { //-------------------------------------------------------------------- // Create an instance of it so it may be used from other modules. Note // that we need this when preprocessing since all identifiers in the // library should point to this module... ABLModulePtr library = new ABLModule; if (!library) return(-2/*NO_RAM_FOR_ABL*/); CurLibrary = library; //------------------------------------------------------------- // Preprocess the library. Note that a library should be loaded // just once. long libraryHandle = ABLi_preProcess(sourceFileName, ablerr,numErrors, numLinesProcessed, numFilesProcessed, printLines); if (libraryHandle < (NumModulesRegistered - 1)) { //------------------ // Already loaded... delete library; library = NULL; CurLibrary = NULL; return(-1); } long err = library->init(libraryHandle); ABL_Assert(err == NO_ERR, err, " Error Loading ABL Library "); library->setName(sourceFileName); CurLibrary = NULL; LibraryInstanceRegistry[numLibrariesLoaded] = library; numLibrariesLoaded++; ablError = NULL; return(NO_ERR); } //*************************************************************************** ABLParamPtr ABLi_createParamList (long numParameters) { if (numParameters) { ABLParamPtr paramList = (ABLParamPtr)AblStackHeap->Malloc(sizeof(ABLParam) * (numParameters + 1)); if (!paramList) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc paramList "); memset(paramList, 0, sizeof(ABLParam) * (numParameters + 1)); return(paramList); } return(NULL); } //*************************************************************************** void ABLi_setIntegerParam (ABLParamPtr paramList, long index, long value) { if (paramList) { paramList[index].type = ABL_PARAM_INTEGER; paramList[index].integer = value; } } //*************************************************************************** void ABLi_setRealParam (ABLParamPtr paramList, long index, float value) { if (paramList) { paramList[index].type = ABL_PARAM_REAL; paramList[index].real = value; } } //*************************************************************************** void ABLi_deleteParamList (ABLParamPtr paramList) { if (paramList) AblStackHeap->Free(paramList); } //*************************************************************************** ABLModulePtr ABLi_getModule (long id) { if ((id >= 0) && (id < NumModules)) return(ModuleInstanceRegistry[id]); return(NULL); } //*************************************************************************** bool ABLi_enabled (void) { return(ABLenabled); } //*************************************************************************** // MODULE routines //*************************************************************************** SymTableNodePtr moduleHeader (void) { SymTableNodePtr moduleIdPtr = NULL; if (CurLibrary) ifTokenGetElseError(TKN_LIBRARY, ABL_ERR_SYNTAX_MISSING_LIBRARY); else { if (curToken == TKN_MODULE) { parsingFSM = false; getToken (); } else if (curToken == TKN_FSM) { parsingFSM = true; getToken (); } else { syntaxError(ABL_ERR_SYNTAX_MISSING_MODULE); } } //------------------------------------------------------------ // NOTE: If a module is a library, its library pointer will be // non-NULL. if (curToken == TKN_IDENTIFIER) { searchAndEnterLocalSymTable(moduleIdPtr); if (parsingFSM) moduleIdPtr->defn.key = DFN_FSM; else moduleIdPtr->defn.key = DFN_MODULE; moduleIdPtr->defn.info.routine.key = RTN_DECLARED; moduleIdPtr->defn.info.routine.paramCount = 0; moduleIdPtr->defn.info.routine.totalParamSize = 0; moduleIdPtr->defn.info.routine.totalLocalSize = 0; moduleIdPtr->defn.info.routine.params = NULL; moduleIdPtr->defn.info.routine.locals = NULL; moduleIdPtr->defn.info.routine.localSymTable = NULL; moduleIdPtr->defn.info.routine.codeSegment = NULL; moduleIdPtr->library = CurLibrary; moduleIdPtr->typePtr = &DummyType; moduleIdPtr->labelIndex = 0; getToken(); } else syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER); //-------------------------------------------- // For now, modules do not have param lists... synchronize(followModuleIdList, declarationStartList, statementStartList); enterScope(NULL); if (parsingFSM) { FSMLevel = level; } if (curToken == TKN_LPAREN) { long paramCount; long totalParamSize; SymTableNodePtr paramListPtr = formalParamList(¶mCount, &totalParamSize); //if (forwardFlag) // syntaxError(ABL_ERR_SYNTAX_ALREADY_FORWARDED); //else { moduleIdPtr->defn.info.routine.paramCount = (unsigned char) paramCount; moduleIdPtr->defn.info.routine.totalParamSize = (unsigned char) totalParamSize; moduleIdPtr->defn.info.routine.params = paramListPtr; //} } //else if (!forwardFlag) { // functionIdPtr->defn.info.routine.paramCount = 0; // functionIdPtr->defn.info.routine.totalParamSize = 0; // functionIdPtr->defn.info.routine.params = NULL; //} //----------------------------- // Now, check if return type... moduleIdPtr->typePtr = NULL; SymTableNodePtr typeIdPtr = NULL; if (curToken == TKN_COLON) { getToken(); if (curToken == TKN_IDENTIFIER) { searchAndFindAllSymTables(typeIdPtr); if (typeIdPtr->defn.key != DFN_TYPE) syntaxError(ABL_ERR_SYNTAX_INVALID_TYPE); //if (!forwardFlag) moduleIdPtr->typePtr = typeIdPtr->typePtr; getToken(); } else { syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER); moduleIdPtr->typePtr = &DummyType; } //if (forwardFlag) // syntaxError(ABL_ERR_SYNTAX_ALREADY_FORWARDED); } return(moduleIdPtr); } //*************************************************************************** // ROUTINE/FUNCTION routines //*************************************************************************** void routine (void) { SymTableNodePtr routineIdPtr = NULL; //------------------------------------------------------------------------ // Do we want to have "procedures", or do functions handle both cases (with // and without return values)? For now, functions handle both... routineIdPtr = functionHeader(); //------------------------------------------------------------------ // We need to save a pointer to the current routine we're parsing... SymTableNodePtr prevRoutineIdPtr = CurRoutineIdPtr; CurRoutineIdPtr = routineIdPtr; //--------------------- // Error synchronize... synchronize(followHeaderList, declarationStartList, statementStartList); if (curToken == TKN_SEMICOLON) getToken(); else if (tokenIn(declarationStartList) || tokenIn(statementStartList)) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); if ((strcmp(wordString, "forward") != 0) && (strcmp(wordString, "extern") != 0)) { routineIdPtr->defn.info.routine.key = RTN_DECLARED; //analyzeRoutineHeader(routineIdPtr); routineIdPtr->defn.info.routine.locals = NULL; //-------------------------------------------------------------- // Parse the routine's block. Use to call block(), now we do the // stuff right here... //block(routineIdPtr); declarations(routineIdPtr, 0, 0); synchronize(followRoutineDeclsList, NULL, NULL); if (curToken != TKN_CODE) syntaxError(ABL_ERR_SYNTAX_MISSING_CODE); crunchToken(); blockType = BLOCK_ROUTINE; blockFlag = true; //compoundStatement(); getToken(); if (curToken != TKN_END_FUNCTION) do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if (curToken == TKN_END_FUNCTION) break; //------------------------------------ // Synchronize after possible error... synchronize(statementStartList, NULL, NULL); } while (tokenIn(statementStartList)); ifTokenGetElseError(TKN_END_FUNCTION, ABL_ERR_SYNTAX_MISSING_END_FUNCTION); blockFlag = false; ABL::TokenCodeType ttoken = curToken; curToken = TKN_NONE; crunchToken (); curToken = ttoken; routineIdPtr->defn.info.routine.codeSegment = createCodeSegment(routineIdPtr->defn.info.routine.codeSegmentSize); analyzeBlock(routineIdPtr->defn.info.routine.codeSegment); } else if (strcmp (wordString,"forward") == 0) { getToken(); routineIdPtr->defn.info.routine.key = RTN_FORWARD; analyzeRoutineHeader(routineIdPtr); } else { getToken(); routineIdPtr->defn.info.routine.key = RTN_EXTERN; analyzeRoutineHeader(routineIdPtr); } routineIdPtr->defn.info.routine.localSymTable = exitScope(); CurRoutineIdPtr = prevRoutineIdPtr; } //*************************************************************************** SymTableNodePtr functionHeader (void) { getToken(); SymTableNodePtr functionIdPtr = NULL; SymTableNodePtr typeIdPtr = NULL; bool forwardFlag = false; if (curToken == TKN_IDENTIFIER) { searchLocalSymTable(functionIdPtr); if (!functionIdPtr) { enterLocalSymTable(functionIdPtr); functionIdPtr->defn.key = DFN_FUNCTION; functionIdPtr->defn.info.routine.key = RTN_DECLARED; functionIdPtr->defn.info.routine.paramCount = 0; functionIdPtr->defn.info.routine.totalParamSize = 0; functionIdPtr->defn.info.routine.totalLocalSize = 0; functionIdPtr->defn.info.routine.params = NULL; functionIdPtr->defn.info.routine.locals = NULL; functionIdPtr->defn.info.routine.localSymTable = NULL; functionIdPtr->defn.info.routine.codeSegment = NULL; functionIdPtr->library = CurLibrary; functionIdPtr->typePtr = &DummyType; functionIdPtr->labelIndex = 0; } else if ((functionIdPtr->defn.key == DFN_FUNCTION) && (functionIdPtr->defn.info.routine.key == RTN_FORWARD)) forwardFlag = true; else if ((functionIdPtr->defn.key == DFN_FUNCTION) && (functionIdPtr->defn.info.routine.key == RTN_EXTERN)) syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER); else syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER); getToken(); } //--------------------- // Error synchronize... synchronize(followFunctionIdList, declarationStartList, statementStartList); enterScope(NULL); if (curToken == TKN_LPAREN) { long paramCount; long totalParamSize; SymTableNodePtr paramListPtr = formalParamList(¶mCount, &totalParamSize); if (forwardFlag) syntaxError(ABL_ERR_SYNTAX_ALREADY_FORWARDED); else { functionIdPtr->defn.info.routine.paramCount = (unsigned char) paramCount; functionIdPtr->defn.info.routine.totalParamSize = (unsigned char) totalParamSize; functionIdPtr->defn.info.routine.params = paramListPtr; } } else if (!forwardFlag) { functionIdPtr->defn.info.routine.paramCount = 0; functionIdPtr->defn.info.routine.totalParamSize = 0; functionIdPtr->defn.info.routine.params = NULL; } //-------------------------------------------- // Now, check if return type and/or forward... functionIdPtr->typePtr = NULL; if (curToken == TKN_COLON) { getToken(); if (curToken == TKN_IDENTIFIER) { searchAndFindAllSymTables(typeIdPtr); if (typeIdPtr->defn.key != DFN_TYPE) syntaxError(ABL_ERR_SYNTAX_INVALID_TYPE); if (!forwardFlag) functionIdPtr->typePtr = typeIdPtr->typePtr; getToken(); } else { syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER); functionIdPtr->typePtr = &DummyType; } if (forwardFlag) syntaxError(ABL_ERR_SYNTAX_ALREADY_FORWARDED); } return(functionIdPtr); } //*************************************************************************** SymTableNodePtr formalParamList (long* count, long* totalSize) { SymTableNodePtr paramIdPtr; SymTableNodePtr firstIdPtr; SymTableNodePtr lastIdPtr = NULL; SymTableNodePtr paramListPtr = NULL; SymTableNodePtr typeIdPtr; TypePtr paramTypePtr; DefinitionType paramDefn; long paramCount = 0; long paramOffset = STACK_FRAME_HEADER_SIZE; getToken(); while ((curToken == TKN_IDENTIFIER) || (curToken == TKN_REF)) { firstIdPtr = NULL; if (curToken == TKN_REF) { paramDefn = DFN_REFPARAM; getToken(); } else paramDefn = DFN_VALPARAM; //----------------------------------- // Grab the type of this parameter... if (curToken == TKN_IDENTIFIER) { searchAndFindAllSymTables(typeIdPtr); if (typeIdPtr->defn.key != DFN_TYPE) syntaxError(ABL_ERR_SYNTAX_INVALID_TYPE); paramTypePtr = (TypePtr)(typeIdPtr->typePtr); getToken(); } else { syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER); paramTypePtr = &DummyType; } //------------------------------------------------------------ // Is this an array parameter? If so, parse the dimensions and // whether it's an open array... if (curToken == TKN_LBRACKET) { } //----------------------------------------------- // Now grab the variable id for this parameter... if (curToken == TKN_IDENTIFIER) { searchAndEnterLocalSymTable(paramIdPtr); paramIdPtr->defn.key = paramDefn; paramIdPtr->labelIndex = 0; paramIdPtr->typePtr = paramTypePtr; paramIdPtr->defn.info.data.offset = paramOffset++; paramCount++; if (paramListPtr == NULL) paramListPtr = paramIdPtr; if (lastIdPtr != NULL) lastIdPtr->next = paramIdPtr; lastIdPtr = paramIdPtr; //if (firstIdPtr == NULL) // firstIdPtr = lastIdPtr = paramIdPtr; //else { // lastIdPtr->next = paramIdPtr; // lastIdPtr = paramIdPtr; //} getToken(); //ifTokenGet(TKN_COMMA); } else { syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER); //-------------------------------- // Do we need to synchronize here? } //------------------------------------------------------------------ // Assign the offset and the type to all param ids in the sublist... //for (paramIdPtr = firstIdPtr; paramIdPtr != NULL; paramIdPtr = paramIdPtr->next) { // paramIdPtr->typePtr = paramTypePtr; // paramIdPtr->defn.info.data.offset = paramOffset++; //} //----------------------------------------------- // Link this list to the list of all param ids... //if (prevLastIdPtr != NULL) // prevLastIdPtr->next = firstIdPtr; //prevLastIdPtr = lastIdPtr; //------------------------------- // Error synch... should be ; or ) synchronize(followParamsList, NULL, NULL); ifTokenGet(TKN_COMMA); } ifTokenGetElseError(TKN_RPAREN, ABL_ERR_SYNTAX_MISSING_RPAREN); *count = paramCount; *totalSize = paramOffset - STACK_FRAME_HEADER_SIZE; if (paramCount > 255) syntaxError(ABL_ERR_SYNTAX_TOO_MANY_FORMAL_PARAMETERS); return(paramListPtr); } //*************************************************************************** TypePtr routineCall (SymTableNodePtr routineIdPtr, long paramCheckFlag) { SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr; TypePtr resultType = NULL; if ((routineIdPtr->defn.info.routine.key == RTN_DECLARED) || (routineIdPtr->defn.info.routine.key == RTN_FORWARD) || (routineIdPtr->defn.info.routine.key == RTN_EXTERN) || !paramCheckFlag) resultType = declaredRoutineCall(routineIdPtr, paramCheckFlag); else resultType = standardRoutineCall(routineIdPtr); CurRoutineIdPtr = thisRoutineIdPtr; return(resultType); } //*************************************************************************** TypePtr declaredRoutineCall (SymTableNodePtr routineIdPtr, long paramCheckFlag) { actualParamList(routineIdPtr, paramCheckFlag); return(/*routineIdPtr->defn.key == DFN_PROCEDURE ? NULL :*/ (TypePtr)(routineIdPtr->typePtr)); } //*************************************************************************** void actualParamList (SymTableNodePtr routineIdPtr, long paramCheckFlag) { SymTableNodePtr formalParamIdPtr = NULL; DefinitionType formalParamDefn = (DefinitionType)0; TypePtr formalParamTypePtr = NULL; TypePtr actualParamTypePtr = NULL; if (paramCheckFlag) formalParamIdPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.params); if (curToken == TKN_LPAREN) { //----------------------------------------------- // Loop to process actual parameter expression... do { //---------------------------------------------------- // Obtain info about the corresponding formal param... if (paramCheckFlag && (formalParamIdPtr != NULL)) { formalParamDefn = formalParamIdPtr->defn.key; formalParamTypePtr = (TypePtr)(formalParamIdPtr->typePtr); } getToken(); if ((formalParamIdPtr == NULL) || (formalParamDefn == DFN_VALPARAM) || !paramCheckFlag) { //-------------- // VAL Params... actualParamTypePtr = expression(); if (paramCheckFlag && (formalParamIdPtr != NULL) && !isAssignTypeCompatible(formalParamTypePtr, actualParamTypePtr)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); } else { //-------------- // VAR params... if (curToken == TKN_IDENTIFIER) { SymTableNodePtr idPtr; searchAndFindAllSymTables(idPtr); actualParamTypePtr = variable(idPtr); if (formalParamTypePtr != actualParamTypePtr) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); } else { //------------------------------------------------------------------ // Not a variable--parse the expression anyway for error recovery... actualParamTypePtr = expression(); syntaxError(ABL_ERR_SYNTAX_INVALID_REF_PARAM); } } //--------------------------------------- // More actual params than formal params? if (paramCheckFlag) { if (formalParamIdPtr == NULL) syntaxError(ABL_ERR_SYNTAX_WRONG_NUMBER_OF_PARAMS); else formalParamIdPtr = formalParamIdPtr->next; } //--------------- // Error synch... synchronize(followParamList, statementEndList, NULL); } while (curToken == TKN_COMMA); ifTokenGetElseError(TKN_RPAREN, ABL_ERR_SYNTAX_MISSING_RPAREN); } //---------------------------------------- // Fewer actual params than formal params? if (paramCheckFlag && (formalParamIdPtr != NULL)) syntaxError(ABL_ERR_SYNTAX_WRONG_NUMBER_OF_PARAMS); } //*************************************************************************** //*************************************************************************** // State routines //*************************************************************************** void state (void) { SymTableNodePtr routineIdPtr = NULL; //------------------------------------------------------------------------ // Do we want to have "procedures", or do functions handle both cases (with // and without return values)? For now, functions handle both... routineIdPtr = stateHeader(); //------------------------------------------------------------------ // We need to save a pointer to the current routine we're parsing... SymTableNodePtr prevRoutineIdPtr = CurRoutineIdPtr; CurRoutineIdPtr = routineIdPtr; //--------------------- // Error synchronize... synchronize(followHeaderList, declarationStartList, statementStartList); if (curToken == TKN_SEMICOLON) getToken(); else if (tokenIn(declarationStartList) || tokenIn(statementStartList)) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); if (strcmp(wordString, "forward") != 0) { routineIdPtr->defn.info.routine.key = RTN_DECLARED; //analyzeRoutineHeader(routineIdPtr); routineIdPtr->defn.info.routine.locals = NULL; //-------------------------------------------------------------- // Parse the routine's block. Use to call block(), now we do the // stuff right here... //block(routineIdPtr); declarations(routineIdPtr, 0, 0); synchronize(followRoutineDeclsList, NULL, NULL); if (curToken != TKN_CODE) syntaxError(ABL_ERR_SYNTAX_MISSING_CODE); crunchToken(); blockType = BLOCK_ROUTINE; blockFlag = true; //compoundStatement(); getToken(); if (curToken != TKN_END_STATE) do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if (curToken == TKN_END_STATE) break; //------------------------------------ // Synchronize after possible error... synchronize(statementStartList, NULL, NULL); } while (tokenIn(statementStartList)); ifTokenGetElseError(TKN_END_STATE, ABL_ERR_SYNTAX_MISSING_END_STATE); blockFlag = false; ABL::TokenCodeType ttoken = curToken; curToken = TKN_NONE; crunchToken (); curToken = ttoken; routineIdPtr->defn.info.routine.codeSegment = createCodeSegment(routineIdPtr->defn.info.routine.codeSegmentSize); analyzeBlock(routineIdPtr->defn.info.routine.codeSegment); } else { getToken(); routineIdPtr->defn.info.routine.key = RTN_FORWARD; analyzeRoutineHeader(routineIdPtr); } routineIdPtr->defn.info.routine.localSymTable = exitScope(); CurRoutineIdPtr = prevRoutineIdPtr; } //*************************************************************************** SymTableNodePtr stateHeader (void) { getToken(); SymTableNodePtr functionIdPtr = NULL; if (curToken == TKN_IDENTIFIER) { searchLocalSymTable(functionIdPtr); if (!functionIdPtr) { enterLocalSymTable(functionIdPtr); functionIdPtr->defn.key = DFN_STATE; functionIdPtr->defn.info.routine.key = RTN_DECLARED; functionIdPtr->defn.info.routine.paramCount = 0; functionIdPtr->defn.info.routine.totalParamSize = 0; functionIdPtr->defn.info.routine.totalLocalSize = 0; functionIdPtr->defn.info.routine.params = NULL; functionIdPtr->defn.info.routine.locals = NULL; functionIdPtr->defn.info.routine.localSymTable = NULL; functionIdPtr->defn.info.routine.codeSegment = NULL; functionIdPtr->library = CurLibrary; functionIdPtr->typePtr = &DummyType; functionIdPtr->labelIndex = 0; } else if ((functionIdPtr->defn.key == DFN_STATE) && (functionIdPtr->defn.info.routine.key == RTN_FORWARD)) { } else syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER); getToken(); } //--------------------- // Error synchronize... synchronize(followFunctionIdList, declarationStartList, statementStartList); enterScope(NULL); return(functionIdPtr); } }