void execStdPrint (void) { //--------------------------- // Grab the opening LPAREN... getCodeToken(); //---------------------------- // Get parameter expression... getCodeToken(); TypePtr paramTypePtr = execExpression(); char buffer[20]; char* s = buffer; if (paramTypePtr == IntegerTypePtr) sprintf(buffer, "%d", tos->integer); else if (paramTypePtr == BooleanTypePtr) sprintf(buffer, "%s", tos->integer ? "true" : "false"); else if (paramTypePtr == CharTypePtr) sprintf(buffer, "%c", tos->byte); else if (paramTypePtr == RealTypePtr) sprintf(buffer, "%.4f", tos->real); else if ((paramTypePtr->form == FRM_ARRAY) && (paramTypePtr->info.array.elementTypePtr == CharTypePtr)) s = (char*)tos->address; pop(); if (debugger) { char message[512]; sprintf(message, "PRINT: \"%s\"", s); debugger->print(message); sprintf(message, " MODULE %s", CurModule->getName()); debugger->print(message); sprintf(message, " FILE %s", CurModule->getSourceFile(FileNumber)); debugger->print(message); sprintf(message, " LINE %d", execLineNumber); debugger->print(message); } /* else if (TACMAP) { aChatWindow* chatWin = TACMAP->getChatWindow(); if (chatWin) chatWin->processChatString(0, s, -1); else { #ifdef _DEBUG OutputDebugString(s); #endif } } */ else { #ifdef _DEBUG ABLDebugPrintCallback(s); #endif } //----------------------- // Grab closing RPAREN... getCodeToken(); }
void execOrderReturn (long returnVal) { //----------------------------- // Assignment to function id... StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr; long delta = level - CurRoutineIdPtr->level - 1; while (delta-- > 0) headerPtr = (StackFrameHeaderPtr)headerPtr->staticLink.address; if (CurRoutineIdPtr->defn.info.routine.flags & ROUTINE_FLAG_STATE) { //---------------------------------- // Return in a state function, so... if (debugger) debugger->traceDataStore(CurRoutineIdPtr, CurRoutineIdPtr->typePtr, (StackItemPtr)headerPtr, CurRoutineIdPtr->typePtr); ExitWithReturn = true; ExitFromTacOrder = true; if (returnVal == 0) { //---------------------------------------------------------- // Use the "eject" code only if called for a failed Order... codeSegmentPtr = (char*)ExitStateCodeSegment; getCodeToken(); } } else { //------------------------------------------------------------------------- // All Order functions (TacticalOrder/GeneralOrder/ActionOrder) must return // an integer error code, so we assume the return type is IntegerTypePtr... StackItemPtr targetPtr = (StackItemPtr)headerPtr; targetPtr->integer = returnVal; //---------------------------------------------------------------------- // Preserve the return value, in case we need it for the calling user... memcpy(&returnValue, targetPtr, sizeof(StackItem)); if (debugger) debugger->traceDataStore(CurRoutineIdPtr, CurRoutineIdPtr->typePtr, (StackItemPtr)headerPtr, CurRoutineIdPtr->typePtr); ExitWithReturn = true; ExitFromTacOrder = true; if (returnVal == 0) { //---------------------------------------------------------- // Use the "eject" code only if called for a failed Order... codeSegmentPtr = (char*)ExitOrderCodeSegment; getCodeToken(); } } }
void execAssignmentStatement(SymTableNodePtr idPtr) { StackItemPtr targetPtr; TypePtr targetTypePtr; TypePtr expressionTypePtr; //-------------------------- // Assignment to variable... targetTypePtr = execVariable(idPtr, USE_TARGET); targetPtr = (StackItemPtr)tos->address; //------------------------------ // Pop off the target address... pop(); //------------------------ // Pop the size, if nec... //if (targetTypePtr->form == FRM_ARRAY) // pop(); //--------------------------------------------------------------- // Routine execExpression() leaves the expression value on top of // stack... getCodeToken(); expressionTypePtr = execExpression(); //-------------------------- // Now, do the assignment... if((targetTypePtr == RealTypePtr) && (expressionTypePtr == IntegerTypePtr)) { //------------------------- // integer assigned to real targetPtr->real = (float)(tos->integer); } else if(targetTypePtr->form == FRM_ARRAY) { //------------------------- // Copy the array/record... PSTR dest = (PSTR)targetPtr; PSTR src = tos->address; int32_t size = targetTypePtr->size; memcpy(dest, src, size); } else if((targetTypePtr == IntegerTypePtr) || (targetTypePtr->form == FRM_ENUM)) { //------------------------------------------------------ // Range check assignment to integer or enum subrange... targetPtr->integer = tos->integer; } else if(targetTypePtr == CharTypePtr) targetPtr->byte = tos->byte; else { //----------------------- // Assign real to real... targetPtr->real = tos->real; } //----------------------------- // Grab the expression value... pop(); if(debugger) debugger->traceDataStore(idPtr, idPtr->typePtr, targetPtr, targetTypePtr); }
void execStdAssert (void) { //---------------------------------------------------------------------- // // ASSERT function: // // If the debugger is active, this immediately jumps into debug mode // if expression is FALSE. Otherwise, the assert statement is ignored // unless the #debug directive has been issued in the module. If // so, a fatal occurs and exits the game (displaying the // string passed in). // // PARAMS: boolean expression // // integer assert code to display // // char[] message // // RETURN: none // //---------------------------------------------------------------------- long expression = ABLi_popInteger(); long code = ABLi_popInteger(); char* s = ABLi_popCharPtr(); if (!expression) { char message[512]; if (debugger) { sprintf(message, "ASSERT: [%d] \"%s\"", code, s); debugger->print(message); sprintf(message, " MODULE (%d) %s", CurModule->getId(), CurModule->getName()); debugger->print(message); sprintf(message, " FILE %s", CurModule->getSourceFile(FileNumber)); debugger->print(message); sprintf(message, " LINE %d", execLineNumber); debugger->print(message); debugger->debugMode(); } else { sprintf(message, "ABL ASSERT: [%d] %s", code, s); ABL_Fatal(0, message); } } }
void runtimeError (long errCode) { char message[512]; if (debugger) { sprintf(message, "RUNTIME ERROR: [%d] %s", errCode, runtimeErrorMessages[errCode]); debugger->print(message); sprintf(message, "MODULE %s", CurModule->getName()); debugger->print(message); if (FileNumber > -1) sprintf(message, "FILE %s", CurModule->getSourceFile(FileNumber)); else sprintf(message, "FILE %s: unavailable"); debugger->print(message); sprintf(message, "LINE %d", execLineNumber); debugger->print(message); debugger->debugMode(); } sprintf(message, "ABL RUNTIME ERROR %s [line %d] - (type %d) %s\n", (FileNumber > -1) ? CurModule->getSourceFile(FileNumber) : "unavailable", execLineNumber, errCode, runtimeErrorMessages[errCode]); ABL_Fatal(-ABL_ERR_RUNTIME_ABORT, message); }
void execStdFatal (void) { //---------------------------------------------------------------------- // // FATAL function: // // If the debugger is active, this immediately jumps into debug mode. // Otherwise, it causes a fatal and exits the game (displaying the // string passed in). // // PARAMS: integer fatal code to display // // char[] message // // RETURN: none // //---------------------------------------------------------------------- long code = ABLi_popInteger(); char* s = ABLi_popCharPtr(); char message[512]; if (debugger) { sprintf(message, "FATAL: [%d] \"%s\"", code, s); debugger->print(message); sprintf(message, " MODULE (%d) %s", CurModule->getId(), CurModule->getName()); debugger->print(message); sprintf(message, " FILE %s", CurModule->getSourceFile(FileNumber)); debugger->print(message); sprintf(message, " LINE %d", execLineNumber); debugger->print(message); debugger->debugMode(); } else { sprintf(message, "ABL FATAL: [%d] %s", code, s); ABL_Fatal(0, s); } }
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 != nullptr; varIdPtr = varIdPtr->next) if(varIdPtr->defn.info.data.varType == VAR_TYPE_NORMAL) allocLocal((TypePtr)(varIdPtr->typePtr)); }
TypePtr execConstant(SymTableNodePtr idPtr) { TypePtr typePtr = idPtr->typePtr; if ((typePtr == IntegerTypePtr) || (typePtr->form == FRM_ENUM)) pushInteger(idPtr->defn.info.constant.value.integer); else if (typePtr == RealTypePtr) pushReal(idPtr->defn.info.constant.value.real); else if (typePtr == CharTypePtr) pushInteger(idPtr->defn.info.constant.value.character); else if (typePtr->form == FRM_ARRAY) pushAddress(idPtr->defn.info.constant.value.stringPtr); if (debugger) debugger->traceDataFetch(idPtr, typePtr, tos); getCodeToken(); return (typePtr); }
void routineExit(SymTableNodePtr routineIdPtr) { if(debugger) debugger->traceRoutineExit(routineIdPtr); //----------------------------------------- // De-alloc parameters & local variables... SymTableNodePtr idPtr; for(idPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.params); idPtr != nullptr; idPtr = idPtr->next) freeLocal(idPtr); for(idPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.locals); idPtr != nullptr; 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 == nullptr) tos = stackFrameBasePtr - 1; else tos = stackFrameBasePtr; stackFrameBasePtr = (StackItemPtr)headerPtr->dynamicLink.address; }
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(); }
TypePtr execDeclaredRoutineCall(SymTableNodePtr routineIdPtr, bool skipOrder) { if(skipOrder) { StackItemPtr curStackFrameBase = tos; //---------------------------------------- // Push parameter values onto the stack... getCodeToken(); if(codeToken == TKN_LPAREN) { execActualParams(routineIdPtr); getCodeToken(); } getCodeToken(); tos = curStackFrameBase; pushInteger(1); return((TypePtr)(routineIdPtr->typePtr)); } int32_t oldLevel = level; // level of caller int32_t newLevel = routineIdPtr->level + 1; // level of callee CallStackLevel++; //------------------------------------------- // First, set up the stack frame of callee... StackItemPtr newStackFrameBasePtr = tos + 1; bool isLibraryCall = (routineIdPtr->library && (routineIdPtr->library != CurRoutineIdPtr->library)); if(isLibraryCall) pushStackFrameHeader(-1, -1); else pushStackFrameHeader(oldLevel, newLevel); //---------------------------------------- // Push parameter values onto the stack... getCodeToken(); if(codeToken == TKN_LPAREN) { execActualParams(routineIdPtr); getCodeToken(); } //------------------------------------------------- // Set the return address in the new stack frame... level = newLevel; stackFrameBasePtr = newStackFrameBasePtr; StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr; headerPtr->returnAddress.address = codeSegmentPtr - 1; //--------------------------------------------------------- // If we're calling a library function, we need to set some // module-specific info... ABLModulePtr PrevModule = nullptr; if(isLibraryCall) { PrevModule = CurModule; CurModule = routineIdPtr->library; CurModuleHandle = CurModule->getHandle(); if(debugger) debugger->setModule(CurModule); StaticDataPtr = CurModule->getStaticData(); CallModuleInit = !CurModule->getInitCalled(); CurModule->setInitCalled(true); // routineEntry(ModuleRegistry[CurModule->getHandle()].moduleIdPtr); } if(ProfileLog) { int32_t functionStartTime = ABLGetTimeCallback(); execute(routineIdPtr); int32_t functionExecTime = ABLGetTimeCallback() - functionStartTime; if(functionExecTime > ProfileLogFunctionTimeLimit) { char s[512]; sprintf_s(s, _countof(s), "[%08d] ", NumExecutions); for(size_t i = 0; i < CallStackLevel; i++) strcat(s, " "); char s1[512]; sprintf_s(s1, _countof(s1), "%s (%d)\n", routineIdPtr->name, functionExecTime); strcat(s, s1); ABL_AddToProfileLog(s); } } else execute(routineIdPtr); //---------------------------------------------------------------- // If we're calling a library function, reset some module-specific // info... if(isLibraryCall) { // routineExit(ModuleRegistry[CurModule->getHandle()].moduleIdPtr); CurModule = PrevModule; CurModuleHandle = CurModule->getHandle(); if(debugger) debugger->setModule(CurModule); StaticDataPtr = CurModule->getStaticData(); } //------------------------------------------------------- // Return from the callee, and grab the first token after // the return... level = oldLevel; getCodeToken(); CallStackLevel--; return((TypePtr)(routineIdPtr->typePtr)); }
int32_t ABLModule::execute(ABLParamPtr moduleParamList, SymTableNodePtr functionIdPtr) { CurModule = this; if(debugger) debugger->setModule(this); //-------------------------- // Execute the ABL module... SymTableNodePtr moduleIdPtr = ModuleRegistry[handle].moduleIdPtr; if(moduleIdPtr->defn.info.routine.flags & ROUTINE_FLAG_FSM) CurFSM = this; else CurFSM = nullptr; NumStateTransitions = 0; //-------------------------------------------- // Point to this module's static data space... StaticDataPtr = staticData; OrderCompletionFlags = orderCallFlags; //--------------------------------- // Init some important variables... CurModuleIdPtr = nullptr; CurRoutineIdPtr = nullptr; FileNumber = -1; errorCount = 0; execStatementCount = 0; NumExecutions++; NewStateSet = false; //------------------ // 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(nullptr); //---------------- // Dynamic Link... pushAddress(nullptr); //------------------ // Return Address... pushAddress(nullptr); //initDebugger(); //---------- // Run it... if(moduleParamList) { //------------------------------------------------------------------------------ // NOTE: Currently, parameter passing of arrays is not functioning. This MUST be // done... int32_t curParam = 0; for(SymTableNodePtr formalIdPtr = (SymTableNodePtr)(moduleIdPtr->defn.info.routine.params); formalIdPtr != nullptr; formalIdPtr = formalIdPtr->next) { TypePtr formalTypePtr = (TypePtr)(formalIdPtr->typePtr); if(formalIdPtr->defn.key == DFN_VALPARAM) { if(formalTypePtr == RealTypePtr) { if(moduleParamList[curParam].type == ABL_PARAM_INTEGER) { //--------------------------------------------- // Real formal parameter, but integer actual... pushReal((float)(moduleParamList[curParam].integer)); } else if(moduleParamList[curParam].type == ABL_PARAM_REAL) pushReal(moduleParamList[curParam].real); } else if(formalTypePtr == IntegerTypePtr) { if(moduleParamList[curParam].type == ABL_PARAM_INTEGER) pushInteger(moduleParamList[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... int32_t size = formalTypePtr->size; PSTR dest = (PSTR)ABLStackMallocCallback((size_t)size); if(!dest) { char err[255]; sprintf(err, "ABL: Unable to AblStackHeap->malloc array parameter [Module %d]", id); ABL_Fatal(0, err); } PSTR src = tos->address; PSTR savePtr = dest; memcpy(dest, src, size); tos->address = savePtr; } } else { //------------------------------- // pass by reference parameter... if(formalTypePtr == RealTypePtr) pushAddress((Address) & (moduleParamList[curParam].real)); else if(formalTypePtr == IntegerTypePtr) pushAddress((Address) & (moduleParamList[curParam].integer)); else return(0); } curParam++; } } CurModuleHandle = handle; CallModuleInit = !initCalled; initCalled = true; ::executeChild(moduleIdPtr, functionIdPtr); memcpy(&returnVal, &returnValue, sizeof(StackItem)); //----------- // Summary... return(execStatementCount); }
TypePtr execVariable(SymTableNodePtr idPtr, UseType use) { TypePtr typePtr = (TypePtr)(idPtr->typePtr); // First, point to the variable's stack item. If the variable's scope // level is less than the current scope level, follow the static links // to the proper stack frame base... StackItemPtr dataPtr = nullptr; StackItem tempStackItem; switch (idPtr->defn.info.data.varType) { case VAR_TYPE_NORMAL: { StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr; int32_t delta = level - idPtr->level; while (delta-- > 0) headerPtr = (StackFrameHeaderPtr)headerPtr->staticLink.address; dataPtr = (StackItemPtr)headerPtr + idPtr->defn.info.data.offset; } break; case VAR_TYPE_ETERNAL: dataPtr = (StackItemPtr)stack + idPtr->defn.info.data.offset; break; case VAR_TYPE_STATIC: //--------------------------------------------------------- // If we're referencing a library's static variable, we may // need to shift to its static data space temporarily... if (idPtr->library && (idPtr->library != CurModule)) StaticDataPtr = idPtr->library->getStaticData(); dataPtr = (StackItemPtr)StaticDataPtr + idPtr->defn.info.data.offset; if (idPtr->library && (idPtr->library != CurModule)) StaticDataPtr = CurModule->getStaticData(); break; case VAR_TYPE_REGISTERED: tempStackItem.address = (PSTR)idPtr->defn.info.data.registeredData; dataPtr = &tempStackItem; break; } //--------------------------------------------------------------- // If it's a scalar or enumeration reference parameter, that item // points to the actual item... if (idPtr->defn.key == DFN_REFPARAM) if (typePtr->form != FRM_ARRAY) /* && (typePtr->form != FRM_RECORD)*/ dataPtr = (StackItemPtr)dataPtr->address; ABL_Assert(dataPtr != nullptr, 0, " ABL.execVariable(): dataPtr is nullptr "); //----------------------------------------------------- // Now, push the address of the variable's data area... if ((typePtr->form == FRM_ARRAY) /*|| (typePtr->form == FRM_RECORD)*/) { // pushInteger(typePtr->size); pushAddress((Address)dataPtr->address); } else if (idPtr->defn.info.data.varType == VAR_TYPE_REGISTERED) pushAddress((Address)dataPtr->address); else pushAddress((Address)dataPtr); //----------------------------------------------------------------------------------- // If there is a subscript (or field identifier, if records are being used // in ABL) then modify the address to point to the proper element of the // array (or record)... getCodeToken(); while ((codeToken == TKN_LBRACKET) /*|| (codeTOken == TKN_PERIOD)*/) { // if (codeToken == TKN_LBRACKET) typePtr = execSubscripts(typePtr); // else if (codeToken == TKN_PERIOD) // typePtr = execField(typePtr); } //------------------------------------------------------------ // Leave the modified address on the top of the stack if: // a) it's an assignment target; // b) it reresents a parameter passed by reference; // c) it's the address of an array or record; // Otherwise, replace the address with the value it points to. if ((use != USE_TARGET) && (use != USE_REFPARAM) && (typePtr->form != FRM_ARRAY)) { if ((typePtr == IntegerTypePtr) || (typePtr->form == FRM_ENUM)) { tos->integer = *((int32_t*)tos->address); } else if (typePtr == CharTypePtr) tos->byte = *((PSTR)tos->address); else tos->real = *((float*)tos->address); } if (debugger) { if ((use != USE_TARGET) && (use != USE_REFPARAM)) { if (typePtr->form == FRM_ARRAY) debugger->traceDataFetch(idPtr, typePtr, (StackItemPtr)tos->address); else debugger->traceDataFetch(idPtr, typePtr, tos); } } return (typePtr); }
void execStdReturn (void) { memset(&returnValue, 0, sizeof(StackItem)); if (CurRoutineIdPtr->typePtr) { //----------------------------- // Assignment to function id... StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr; long delta = level - CurRoutineIdPtr->level - 1; while (delta-- > 0) headerPtr = (StackFrameHeaderPtr)headerPtr->staticLink.address; StackItemPtr targetPtr = (StackItemPtr)headerPtr; TypePtr targetTypePtr = (TypePtr)(CurRoutineIdPtr->typePtr); getCodeToken(); //--------------------------------------------------------------- // Routine execExpression() leaves the expression value on top of // stack... getCodeToken(); TypePtr expressionTypePtr = execExpression(); //-------------------------- // Now, do the assignment... if ((targetTypePtr == RealTypePtr) && (expressionTypePtr == IntegerTypePtr)) { //------------------------- // integer assigned to real targetPtr->real = (float)(tos->integer); } else if (targetTypePtr->form == FRM_ARRAY) { //------------------------- // Copy the array/record... char* dest = (char*)targetPtr; char* src = tos->address; long size = targetTypePtr->size; memcpy(dest, src, size); } else if ((targetTypePtr == IntegerTypePtr) || (targetTypePtr->form == FRM_ENUM)) { //------------------------------------------------------ // Range check assignment to integer or enum subrange... targetPtr->integer = tos->integer; } else { //----------------------- // Assign real to real... targetPtr->real = tos->real; } //----------------------------- // Grab the expression value... pop(); //---------------------------------------------------------------------- // Preserve the return value, in case we need it for the calling user... memcpy(&returnValue, targetPtr, sizeof(StackItem)); if (debugger) debugger->traceDataStore(CurRoutineIdPtr, CurRoutineIdPtr->typePtr, targetPtr, targetTypePtr); } //----------------------- // Grab the semi-colon... getCodeToken(); if (CurRoutineIdPtr->defn.info.routine.flags & ROUTINE_FLAG_ORDER) codeSegmentPtr = (char*)ExitOrderCodeSegment; else if (CurRoutineIdPtr->defn.info.routine.flags & ROUTINE_FLAG_STATE) codeSegmentPtr = (char*)ExitStateCodeSegment; else codeSegmentPtr = (char*)ExitRoutineCodeSegment; ExitWithReturn = true; getCodeToken(); }