123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722 |
- //===========================================================================//
- // Copyright (C) Microsoft Corporation. All rights reserved. //
- //===========================================================================//
- //***************************************************************************
- //
- // ABLEXEC.CPP
- //
- //***************************************************************************
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #ifndef ABLGEN_H
- #include "ablgen.h"
- #endif
- #ifndef ABLERR_H
- #include "ablerr.h"
- #endif
- #ifndef ABLSCAN_H
- #include "ablscan.h"
- #endif
- #ifndef ABLEXEC_H
- #include "ablexec.h"
- #endif
- #ifndef ABLDBUG_H
- #include "abldbug.h"
- #endif
- //***************************************************************************
- //--------
- // GLOBALS
- char* codeBuffer = NULL;
- char* codeBufferPtr = NULL;
- char* codeSegmentPtr = NULL;
- char* codeSegmentLimit = NULL;
- char* statementStartPtr = NULL;
- TokenCodeType codeToken;
- long execLineNumber;
- long execStatementCount = 0;
- StackItem* stack = NULL;
- StackItemPtr tos = NULL;
- StackItemPtr stackFrameBasePtr = NULL;
- StackItemPtr StaticDataPtr = NULL;
- long* StaticVariablesSizes = NULL;
- long* EternalVariablesSizes = NULL;
- long eternalOffset = 0;
- long MaxStaticVariables = 0;
- long MaxEternalVariables = 0;
- long NumStaticVariables = 0;
- long NumOrderCalls = 1;
- long NumStateHandles = 0;
- StateHandleInfo StateHandleList[MAX_STATE_HANDLES_PER_MODULE];
- long CurModuleHandle = 0;
- long MaxCodeBufferSize = 0;
- bool CallModuleInit = false;
- bool AutoReturnFromOrders = false;
- long MaxLoopIterations = 100001;
- bool AssertEnabled = false;
- bool PrintEnabled = true;
- bool StringFunctionsEnabled = true;
- bool DebugCodeEnabled = false;
- bool IncludeDebugInfo = true;
- bool ProfileABL = false;
- bool Crunch = true;
- char SetStateDebugStr[256];
- //----------
- // EXTERNALS
- extern SymTableNodePtr CurRoutineIdPtr;
- extern ModuleEntryPtr ModuleRegistry;
- extern ABLModulePtr* ModuleInstanceRegistry;
- extern ABLModulePtr CurModule;
- extern ABLModulePtr CurLibrary;
- extern long NumStateTransitions;
- extern TokenCodeType curToken;
- extern long lineNumber;
- extern long FileNumber;
- extern long level;
- extern TypePtr IntegerTypePtr;
- extern TypePtr CharTypePtr;
- extern TypePtr RealTypePtr;
- extern TypePtr BooleanTypePtr;
- extern StackItem returnValue;
- extern bool ExitWithReturn;
- extern bool ExitFromTacOrder;
- extern DebuggerPtr debugger;
- extern bool NewStateSet;
- extern void (*ABLEndlessStateCallback) (UserFile* log);
- //***************************************************************************
- // CRUNCH/DECRUNCH routines
- //***************************************************************************
- void crunchToken (void) {
- if (!Crunch)
- return;
- if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
- syntaxError(ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW);
- else {
- *codeBufferPtr = curToken;
- codeBufferPtr++;
- }
- }
- //***************************************************************************
- void crunchSymTableNodePtr (SymTableNodePtr nodePtr) {
- if (!Crunch)
- return;
- if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
- syntaxError(ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW);
- else {
- SymTableNodePtr* nodePtrPtr = (SymTableNodePtr*)codeBufferPtr;
- *nodePtrPtr = nodePtr;
- codeBufferPtr += sizeof(SymTableNodePtr);
- }
- }
- //***************************************************************************
- void crunchStatementMarker (void) {
- if (!Crunch)
- return;
- if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
- syntaxError(ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW);
- else {
- char saveCode = *(--codeBufferPtr);
- *codeBufferPtr = (char)TKN_STATEMENT_MARKER;
- codeBufferPtr++;
- if (IncludeDebugInfo) {
- *((unsigned char*)codeBufferPtr) = (unsigned char)FileNumber;
- codeBufferPtr += sizeof(unsigned char);
- *((long*)codeBufferPtr) = lineNumber;
- codeBufferPtr += sizeof(long);
- }
- *codeBufferPtr = saveCode;
- codeBufferPtr++;
- }
- }
- //***************************************************************************
- void uncrunchStatementMarker (void) {
- //-------------------------
- // Pull code off the buffer
- codeBufferPtr--;
- //-------------------------------
- // Pull debug info off the buffer
- if (IncludeDebugInfo)
- codeBufferPtr -= (sizeof(unsigned char) + sizeof(long));
- //-------------------------------------
- // Pull statement marker off the buffer
- codeBufferPtr--;
- }
- //***************************************************************************
- char* crunchAddressMarker (Address address) {
- if (!Crunch)
- return(NULL);
- char* saveCodeBufferPtr = NULL;
- if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
- syntaxError(ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW);
- else {
- char saveCode = *(--codeBufferPtr);
- *codeBufferPtr = (char)TKN_ADDRESS_MARKER;
- codeBufferPtr++;
- saveCodeBufferPtr = codeBufferPtr;
- *((Address*)codeBufferPtr) = address;
- codeBufferPtr += sizeof(Address);
- *codeBufferPtr = saveCode;
- codeBufferPtr++;
- }
- return(saveCodeBufferPtr);
- }
- //***************************************************************************
- char* fixupAddressMarker (Address address) {
- if (!Crunch)
- return(NULL);
- char* oldAddress = *((Address*)address);
- *((long*)address) = codeBufferPtr - address;
- return(oldAddress);
- }
- //***************************************************************************
- void crunchInteger (long value) {
- if (!Crunch)
- return;
- if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
- syntaxError(ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW);
- else {
- *((long*)codeBufferPtr) = value;
- codeBufferPtr += sizeof(long);
- }
- }
- //***************************************************************************
- void crunchByte (unsigned char value) {
- if (!Crunch)
- return;
- if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
- syntaxError(ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW);
- else {
- *((unsigned char*)codeBufferPtr) = value;
- codeBufferPtr += sizeof(unsigned char);
- }
- }
- //***************************************************************************
- void crunchOffset (Address address) {
- if (!Crunch)
- return;
- if (codeBufferPtr >= (codeBuffer + MaxCodeBufferSize - 100))
- syntaxError(ABL_ERR_SYNTAX_CODE_SEGMENT_OVERFLOW);
- else {
- *((long*)codeBufferPtr) = address - codeBufferPtr;
- codeBufferPtr += sizeof(long);
- }
- }
- //***************************************************************************
- char* createCodeSegment (long& codeSegmentSize) {
- codeSegmentSize = codeBufferPtr - codeBuffer + 1;
- char* codeSegment = (char*)ABLCodeMallocCallback(codeSegmentSize);
- if (!codeSegment)
- ABL_Fatal(0, " ABL: Unable to AblCodeHeap->malloc code segment ");
- for (long i = 0; i < codeSegmentSize; i++)
- codeSegment[i] = codeBuffer[i];
- codeBufferPtr = codeBuffer;
- return(codeSegment);
- }
- //***************************************************************************
- SymTableNodePtr getCodeSymTableNodePtr (void) {
- SymTableNodePtr* nodePtrPtr = (SymTableNodePtr*)codeSegmentPtr;
- SymTableNodePtr nodePtr = *nodePtrPtr;
- codeSegmentPtr += sizeof(SymTableNodePtr);
- return(nodePtr);
- }
- //***************************************************************************
- long getCodeStatementMarker (void) {
- //------------------------------------------
- // NOTE: If there's a problem, we return -1.
- long lineNum = -1;
- if (codeToken == TKN_STATEMENT_MARKER) {
- if (IncludeDebugInfo) {
- FileNumber = *((unsigned char*)codeSegmentPtr);
- codeSegmentPtr += sizeof(unsigned char);
- lineNum = *((long*)codeSegmentPtr);
- codeSegmentPtr += sizeof(long);
- }
- }
- return(lineNum);
- }
- //***************************************************************************
- char* getCodeAddressMarker (void) {
- Address address = NULL;
- if (codeToken == TKN_ADDRESS_MARKER) {
- address = *((long*)codeSegmentPtr) + codeSegmentPtr - 1;
- codeSegmentPtr += sizeof(Address);
- }
- return(address);
- }
- //***************************************************************************
- long getCodeInteger (void) {
- long value = *((long*)codeSegmentPtr);
- codeSegmentPtr += sizeof(long);
- return(value);
- }
- //***************************************************************************
- unsigned char getCodeByte (void) {
- unsigned char value = *((unsigned char*)codeSegmentPtr);
- codeSegmentPtr += sizeof(unsigned char);
- return(value);
- }
- //***************************************************************************
- char* getCodeAddress (void) {
- Address address = *((long*)codeSegmentPtr) + codeSegmentPtr - 1;
- codeSegmentPtr += sizeof(long);
- return(address);
- }
- //***************************************************************************
- // STACK routines
- //***************************************************************************
- void pop (void) {
- --tos;
- }
- //***************************************************************************
- void getCodeToken (void) {
- codeToken = (TokenCodeType)*codeSegmentPtr;
- codeSegmentPtr++;
- }
- //***************************************************************************
- void pushInteger (long value) {
- StackItemPtr valuePtr = ++tos;
- if (valuePtr >= &stack[MAXSIZE_STACK])
- runtimeError(ABL_ERR_RUNTIME_STACK_OVERFLOW);
- valuePtr->integer = value;
- }
- //***************************************************************************
- void pushReal (float value) {
- StackItemPtr valuePtr = ++tos;
- if (valuePtr >= &stack[MAXSIZE_STACK])
- runtimeError(ABL_ERR_RUNTIME_STACK_OVERFLOW);
- valuePtr->real = value;
- }
- //***************************************************************************
- void pushByte (char value) {
- StackItemPtr valuePtr = ++tos;
- if (valuePtr >= &stack[MAXSIZE_STACK])
- runtimeError(ABL_ERR_RUNTIME_STACK_OVERFLOW);
- valuePtr->byte = value;
- }
- //***************************************************************************
- void pushAddress (Address address) {
- StackItemPtr valuePtr = ++tos;
- if (valuePtr >= &stack[MAXSIZE_STACK])
- runtimeError(ABL_ERR_RUNTIME_STACK_OVERFLOW);
- valuePtr->address = address;
- }
- //***************************************************************************
- void pushBoolean (bool value) {
- StackItemPtr valuePtr = ++tos;
- if (valuePtr >= &stack[MAXSIZE_STACK])
- runtimeError(ABL_ERR_RUNTIME_STACK_OVERFLOW);
- valuePtr->integer = (value ? 1 : 0);
- }
- //***************************************************************************
- void pushStackFrameHeader (long oldLevel, long newLevel) {
- //-----------------------------------
- // Make space for the return value...
- pushInteger(0);
- StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr;
- //----------------------------------------------------------------------
- // STATIC LINK
- // Currently, let's not allow functions defined within functions. Assume
- // the old scope level equals the new scope level, for now.
- if (newLevel == -1) {
- //--------------------------------------------------------------------
- // Calling a library function, so push a NULL static link since
- // it's scope is in a different module than the calling function.
- // Note that global variables in libraries should be STATIC, otherwise
- // they're never in scope! Weird "feature" which we may want
- // to fix later...
- pushAddress(NULL);
- }
- else if (newLevel == oldLevel + 1) {
- //----------------------------------------------------------------
- // Calling a routine nested within the caller, so push the pointer
- // to the caller's stack frame. In ABL, as currently defined
- // (2/22/96), this should only be when a module's code section is
- // calling a function...
- pushAddress((Address)headerPtr);
- }
- else if (newLevel == oldLevel) {
- //---------------------------------------------------------------
- // Calling a function at the same scope level. We like that! Push
- // pointer to stack frame of their common parent...
- pushAddress(headerPtr->staticLink.address);
- }
- else {
- //-------------------------------------------------------
- // Oops. We don't want nested functions, for now, in ABL.
- runtimeError(ABL_ERR_RUNTIME_NESTED_FUNCTION_CALL);
- }
- pushAddress((Address)stackFrameBasePtr);
- //---------------------------
- // Push the return address...
- pushAddress(0);
- }
- //***************************************************************************
- void allocLocal (TypePtr typePtr) {
- if (typePtr == IntegerTypePtr)
- pushInteger(0);
- else if (typePtr == RealTypePtr)
- pushReal((float)0.0);
- else if (typePtr == BooleanTypePtr)
- pushByte(0);
- else if (typePtr == CharTypePtr)
- pushByte(0);
- else
- switch (typePtr->form) {
- case FRM_ENUM:
- pushInteger(0);
- break;
- // NOTE: We currently are not supporting sub ranges, until
- // we really want 'em...
- // case FRM_SUBRANGE:
- // allocLocal(typePtr->info.subrange.rangeTypePtr);
- // break;
- case FRM_ARRAY:
- char* ptr = (char*)ABLStackMallocCallback(typePtr->size);
- if (!ptr)
- ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc local array ");
- pushAddress((Address)ptr);
- break;
- }
- }
- //***************************************************************************
- void freeLocal (SymTableNodePtr idPtr) {
- //---------------------------------------
- // Frees data allocated on local stack...
- TypePtr typePtr = (TypePtr)(idPtr->typePtr);
- StackItemPtr itemPtr = NULL;
- if (((typePtr->form == FRM_ARRAY) /* || (typePtr->form == FRM_RECORD)*/) &&
- (idPtr->defn.key != DFN_REFPARAM)) {
- switch (idPtr->defn.info.data.varType) {
- case VAR_TYPE_NORMAL:
- itemPtr = stackFrameBasePtr + idPtr->defn.info.data.offset;
- break;
- // case VAR_TYPE_ETERNAL:
- // itemPtr = stack + idPtr->defn.info.data.offset;
- // break;
- // case VAR_TYPE_STATIC:
- // itemPtr = StaticDataPtr + idPtr->defn.info.data.offset;
- // break;
- }
- if (!itemPtr)
- runtimeError(0);
- else
- ABLStackFreeCallback(itemPtr->address);
- }
- }
- //***************************************************************************
- // FUNCTION ENTRY/EXIT routines
- //***************************************************************************
- void routineEntry (SymTableNodePtr routineIdPtr) {
- if (debugger)
- debugger->traceRoutineEntry(routineIdPtr);
- memset(&returnValue, 0, sizeof(StackItem));
- //------------------------------
- // Switch to new code segment...
- codeSegmentPtr = routineIdPtr->defn.info.routine.codeSegment;
- //----------------------------------------------
- // Allocate local variables onto system stack...
- for (SymTableNodePtr varIdPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.locals);
- varIdPtr != NULL;
- varIdPtr = varIdPtr->next)
- if (varIdPtr->defn.info.data.varType == VAR_TYPE_NORMAL)
- allocLocal((TypePtr)(varIdPtr->typePtr));
- }
- //***************************************************************************
- void routineExit (SymTableNodePtr routineIdPtr) {
- if (debugger)
- debugger->traceRoutineExit(routineIdPtr);
- //-----------------------------------------
- // De-alloc parameters & local variables...
- for (SymTableNodePtr idPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.params);
- idPtr != NULL;
- idPtr = idPtr->next)
- freeLocal(idPtr);
- for (idPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.locals);
- idPtr != NULL;
- idPtr = idPtr->next)
- if (idPtr->defn.info.data.varType == VAR_TYPE_NORMAL)
- freeLocal(idPtr);
- StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr;
- codeSegmentPtr = headerPtr->returnAddress.address;
- if (routineIdPtr->typePtr == NULL)
- tos = stackFrameBasePtr - 1;
- else
- tos = stackFrameBasePtr;
- stackFrameBasePtr = (StackItemPtr)headerPtr->dynamicLink.address;
- }
- //***************************************************************************
- void execute (SymTableNodePtr routineIdPtr) {
- SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr;
- CurRoutineIdPtr = routineIdPtr;
- routineEntry(routineIdPtr);
- //----------------------------------------------------
- // Now, search this module for the function we want...
- if (CallModuleInit) {
- CallModuleInit = false;
- SymTableNodePtr initFunctionIdPtr = searchSymTable("init", ModuleRegistry[CurModule->getHandle()].moduleIdPtr->defn.info.routine.localSymTable);
- if (initFunctionIdPtr) {
- execRoutineCall(initFunctionIdPtr, false);
- //-------------------------------------------------------------------------
- // Since we're calling the function directly, we need to compensate for the
- // codeSegmentPtr being incremented by 1 in the normal execRoutineCall...
- codeSegmentPtr--;
- }
- }
- if (routineIdPtr->defn.info.routine.flags & ROUTINE_FLAG_FSM) {
- NewStateSet = true;
- static char stateList[60][256];
- strcpy(SetStateDebugStr, "--");
- while (NewStateSet) {
- NumStateTransitions++;
- sprintf(stateList[NumStateTransitions], "%s (%s)", CurModule->getState()->name, SetStateDebugStr);
- if (NumStateTransitions == 50) {
- UserFile* userFile = UserFile::getNewFile();
- char errStr[512];
- if (userFile) {
- long err = userFile->open("endless.log");
- if (!err) {
- //char s[1024];
- //sprintf(s, "Current Date: %s\n", GetTime());
- //userFile->write(s);
- userFile->write(ModuleRegistry[CurModule->getHandle()].fileName);
- for (long i = 1; i < 51; i++)
- userFile->write(stateList[i]);
- userFile->write(" ");
- if (ABLEndlessStateCallback)
- (*ABLEndlessStateCallback)(userFile);
- userFile->close();
- }
- }
- sprintf(errStr, " ABL endless state loop in %s [%s:%s] ", ModuleRegistry[CurModule->getHandle()].fileName, CurModule->getState()->name, CurModule->getPrevState()->name);
- #if 0
- ABL_Fatal(NumStateTransitions, errStr);
- #else
- NewStateSet = false;
- #endif
- }
- else {
- NewStateSet = false;
- SymTableNodePtr curState = CurModule->getState();
- if (!curState)
- ABL_Fatal(0, " ABL.execute: NULL state in FSM ");
- execRoutineCall(curState, false);
- codeSegmentPtr--;
- }
- //---------------------------------------------
- // In case we exited with a return statement...
- ExitWithReturn = false;
- ExitFromTacOrder = false;
- }
- }
- else {
- getCodeToken();
- execStatement();
- //---------------------------------------------
- // In case we exited with a return statement...
- ExitWithReturn = false;
- ExitFromTacOrder = false;
- }
- routineExit(routineIdPtr);
- CurRoutineIdPtr = thisRoutineIdPtr;
- }
- //***************************************************************************
- void executeChild (SymTableNodePtr routineIdPtr, SymTableNodePtr childRoutineIdPtr) {
- // THIS DOES NOT SUPPORT CALLING FUNCTIONS WITH PARAMETERS YET!
- SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr;
- CurRoutineIdPtr = routineIdPtr;
- routineEntry(routineIdPtr);
- //----------------------------------------------------
- // Now, search this module for the function we want...
- SymTableNodePtr initFunctionIdPtr = NULL;
- if (CallModuleInit) {
- CallModuleInit = false;
- initFunctionIdPtr = searchSymTable("init", routineIdPtr->defn.info.routine.localSymTable);
- if (initFunctionIdPtr) {
- execRoutineCall(initFunctionIdPtr, false);
- //-------------------------------------------------------------------------
- // Since we're calling the function directly, we need to compensate for the
- // codeSegmentPtr being incremented by 1 in the normal execRoutineCall...
- codeSegmentPtr--;
- }
- }
- if (initFunctionIdPtr != childRoutineIdPtr) {
- //-----------------------------------------------------------------------
- // If we're calling the module's init function, and we just did above,
- // don't call it again! That's why we make the check on the above line...
- execRoutineCall(childRoutineIdPtr, false);
- //-------------------------------------------------------------------------
- // Since we're calling the function directly, we need to compensate for the
- // codeSegmentPtr being incremented by 1 in the normal execRoutineCall...
- codeSegmentPtr--;
- }
- //---------------------------------------------
- // In case we exited with a return statement...
- ExitWithReturn = false;
- ExitFromTacOrder = false;
- routineExit(routineIdPtr);
- CurRoutineIdPtr = thisRoutineIdPtr;
- }
- //***************************************************************************
- // MISC routines
- //***************************************************************************
|