void execIfStatement(void) { getCodeToken(); PSTR falseLocation = getCodeAddressMarker(); //------------------------------- // Eval the boolean expression. Note that, unlike C/C++, the expression // must be true(1) or false(0). In C/C++, an expression is true if it's // non-zero. Not the case in ABL using this current implementation. Do we // want to change this? getCodeToken(); execExpression(); bool test = (tos->integer == 1); pop(); if(test) { //--------------------------- // execute the TRUE branch... getCodeToken(); if((codeToken != TKN_END_IF) && (codeToken != TKN_ELSE)) do { execStatement(); if(ExitWithReturn) return; } while((codeToken != TKN_END_IF) && (codeToken != TKN_ELSE)); if(codeToken == TKN_ELSE) { getCodeToken(); codeSegmentPtr = getCodeAddressMarker(); getCodeToken(); } } else { //---------------------------- // Execute the FALSE branch... codeSegmentPtr = falseLocation; getCodeToken(); if(codeToken == TKN_ELSE) { getCodeToken(); getCodeAddressMarker(); getCodeToken(); if(codeToken != TKN_END_IF) do { execStatement(); if(ExitWithReturn) return; } while(codeToken != TKN_END_IF); } } getCodeToken(); }
void execRepeatStatement(void) { PSTR loopStartLocation = codeSegmentPtr; int32_t iterations = 0; do { getCodeToken(); if(codeToken != TKN_UNTIL) do { execStatement(); if(ExitWithReturn) return; } while(codeToken != TKN_UNTIL); //--------------------------- // Check for infinite loop... iterations++; if(iterations == MaxLoopIterations) runtimeError(ABL_ERR_RUNTIME_INFINITE_LOOP); //------------------------------- // Eval the boolean expression... getCodeToken(); execExpression(); if(tos->integer == 0) codeSegmentPtr = loopStartLocation; //-------------------------- // Grab the boolean value... pop(); } while(codeSegmentPtr == loopStartLocation); }
void execSwitchStatement (void) { getCodeToken(); char* branchTableLocation = getCodeAddressMarker(); getCodeToken(); TypePtr switchExpressionTypePtr = execExpression(); long switchExpressionValue; if ((switchExpressionTypePtr == IntegerTypePtr) || (switchExpressionTypePtr->form == FRM_ENUM)) switchExpressionValue = tos->integer; else switchExpressionValue = tos->byte; pop(); //--------------------------------------------------------- // Now, search the branch table for the expression value... codeSegmentPtr = branchTableLocation; getCodeToken(); long caseLabelCount = getCodeInteger(); bool done = false; char* caseBranchLocation = NULL; while (!done && caseLabelCount--) { long caseLabelValue = getCodeInteger(); caseBranchLocation = getCodeAddress(); done = (caseLabelValue == switchExpressionValue); } //----------------------------------------------- // If found, go to the aprropriate branch code... if (caseLabelCount >= 0) { codeSegmentPtr = caseBranchLocation; getCodeToken(); if (codeToken != TKN_END_CASE) do { execStatement(); if (ExitWithReturn) return; } while (codeToken != TKN_END_CASE); //---------------------------------- // Grab the end case and semi-colon... getCodeToken(); getCodeToken(); codeSegmentPtr = getCodeAddressMarker(); getCodeToken(); } else { //----------------------------------------------------------------- // Since the branch table is located at the end of the case blocks, // the code directly after the switch statement follows our // current code location, already. Just grab the endswitch // and semi-colon... getCodeToken(); getCodeToken(); } }
void execWhileStatement (void) { getCodeToken(); char* loopEndLocation = getCodeAddressMarker(); char* testLocation = codeSegmentPtr; bool loopDone = false; long iterations = 0; do { //------------------------------- // Eval the boolean expression... getCodeToken(); execExpression(); if (tos->integer == 0) { codeSegmentPtr = loopEndLocation; loopDone = true; } //------------------------- // Get the boolean value... pop(); //---------------------------------- // If TRUE, execute the statement... if (!loopDone) { getCodeToken(); if (codeToken != TKN_END_WHILE) do { execStatement(); if (ExitWithReturn) return; } while (codeToken != TKN_END_WHILE); codeSegmentPtr = testLocation; //--------------------------- // Check for infinite loop... iterations++; if (iterations == MaxLoopIterations) runtimeError(ABL_ERR_RUNTIME_INFINITE_LOOP); } } while (!loopDone); getCodeToken(); }
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) { int32_t 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(size_t 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: nullptr 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 execStatement(void) { if(codeToken == TKN_STATEMENT_MARKER) { execLineNumber = getCodeStatementMarker(); execStatementCount++; statementStartPtr = codeSegmentPtr; if(debugger) debugger->traceStatementExecution(); getCodeToken(); } switch(codeToken) { case TKN_IDENTIFIER: { SymTableNodePtr idPtr = getCodeSymTableNodePtr(); ABL_Assert(idPtr != nullptr, 0, " oops "); if(idPtr->defn.key == DFN_FUNCTION) { bool skipOrder = false; uint8_t orderDWord = 0; uint8_t orderBitMask = 0; if((idPtr->defn.info.routine.flags & ROUTINE_FLAG_ORDER) && CurModule->getOrderCallFlags()) { orderDWord = getCodeByte(); orderBitMask = getCodeByte(); skipOrder = !CurModule->isLibrary() && CurModule->getOrderCallFlag(orderDWord, orderBitMask); } TypePtr returnType = execRoutineCall(idPtr, skipOrder); if(idPtr->defn.info.routine.flags & ROUTINE_FLAG_ORDER) { if(AutoReturnFromOrders) { //----------------------------------------------------------------- // We called an Order function, and we're in an Orders/State block, // so do we continue the flow of orders or stop here? int32_t returnVal = tos->integer; pop(); if(returnVal == 0) execOrderReturn(returnVal); else if(CurModule->getOrderCallFlags()) { CurModule->setOrderCallFlag(orderDWord, orderBitMask); } } } else if(returnType) { //------------------------------------------ // In case this routine returns a value, pop // the return value off the stack... pop(); } } else execAssignmentStatement(idPtr); } break; case TKN_CODE: { bool wasAutoReturnFromOrders = AutoReturnFromOrders; AutoReturnFromOrders = ((CurRoutineIdPtr->defn.info.routine.flags & (ROUTINE_FLAG_ORDER + ROUTINE_FLAG_STATE)) != 0); getCodeToken(); TokenCodeType endToken = TKN_END_FUNCTION; if(CurRoutineIdPtr->defn.info.routine.flags & ROUTINE_FLAG_ORDER) endToken = TKN_END_ORDER; else if(CurRoutineIdPtr->defn.info.routine.flags & ROUTINE_FLAG_STATE) endToken = TKN_END_STATE; TokenCodeType endTokenFinal = TKN_END_MODULE; if(CurLibrary) endTokenFinal = TKN_END_LIBRARY; else if(CurRoutineIdPtr->defn.info.routine.flags & ROUTINE_FLAG_FSM) endTokenFinal = TKN_END_FSM; while((codeToken != endToken) && (codeToken != endTokenFinal) && !NewStateSet) execStatement(); if(NewStateSet) return; getCodeToken(); AutoReturnFromOrders = wasAutoReturnFromOrders; } break; case TKN_FOR: execForStatement(); break; case TKN_IF: execIfStatement(); break; case TKN_REPEAT: execRepeatStatement(); break; case TKN_WHILE: execWhileStatement(); break; case TKN_SWITCH: execSwitchStatement(); break; case TKN_TRANS: execTransStatement(); break; case TKN_TRANS_BACK: execTransBackStatement(); break; case TKN_SEMICOLON: case TKN_ELSE: case TKN_UNTIL: break; default: //runtimeError(ABL_ERR_RUNTIME_UNIMPLEMENTED_FEATURE); NODEFAULT; } while(codeToken == TKN_SEMICOLON) getCodeToken(); }
void execForStatement(void) { getCodeToken(); //--------------------------------------- // Grab address of the end of the loop... PSTR loopEndLocation = getCodeAddressMarker(); //-------------------------------------------------------- // Get the address of the control variable's stack item... getCodeToken(); SymTableNodePtr controlIdPtr = getCodeSymTableNodePtr(); TypePtr controlTypePtr = execVariable(controlIdPtr, USE_TARGET); StackItemPtr targetPtr = (StackItemPtr)tos->address; //------------------------------------ // Control variable address... pop(); //------------------------------- // Eval the initial expression... getCodeToken(); execExpression(); int32_t initialValue; if(controlTypePtr == IntegerTypePtr) initialValue = tos->integer; else initialValue = tos->byte; //--------------------- // The initial value... pop(); int32_t deltaValue; if(codeToken == TKN_TO) deltaValue = 1; else deltaValue = -1; //---------------------------------- // Now, eval the final expression... getCodeToken(); execExpression(); int32_t finalValue; if(controlTypePtr == IntegerTypePtr) finalValue = tos->integer; else finalValue = tos->byte; //------------------- // The final value... pop(); //---------------------------- // Address of start of loop... PSTR loopStartLocation = codeSegmentPtr; int32_t controlValue = initialValue; //----------------------------- // Now, execute the FOR loop... int32_t iterations = 0; if(deltaValue == 1) while(controlValue <= finalValue) { if(controlTypePtr == IntegerTypePtr) targetPtr->integer = controlValue; else targetPtr->byte = (uint8_t)controlValue; getCodeToken(); if(codeToken != TKN_END_FOR) do { execStatement(); if(ExitWithReturn) return; } while(codeToken != TKN_END_FOR); //--------------------------- // Check for infinite loop... if(++iterations == MaxLoopIterations) runtimeError(ABL_ERR_RUNTIME_INFINITE_LOOP); controlValue++; codeSegmentPtr = loopStartLocation; } else while(controlValue >= finalValue) { if(controlTypePtr == IntegerTypePtr) targetPtr->integer = controlValue; else targetPtr->byte = (uint8_t)controlValue; getCodeToken(); if(codeToken != TKN_END_FOR) do { execStatement(); if(ExitWithReturn) return; } while(codeToken != TKN_END_FOR); //--------------------------- // Check for infinite loop... if(++iterations == MaxLoopIterations) runtimeError(ABL_ERR_RUNTIME_INFINITE_LOOP); controlValue--; codeSegmentPtr = loopStartLocation; } codeSegmentPtr = loopEndLocation; getCodeToken(); }