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)); }
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); }