int32_t Debugger::sprintSimpleValue(PSTR dest, SymTableNodePtr symbol) { //-------------------------------------------------------------------- // This code is adapted from execVariable(). If that function changes, // this better too! TypePtr typePtr = (TypePtr)(symbol->typePtr); if(symbol->defn.key == DFN_CONST) { if(typePtr == IntegerTypePtr) sprintf(dest, "%d", symbol->defn.info.constant.value.integer); else if(typePtr == CharTypePtr) sprintf(dest, "%c", symbol->defn.info.constant.value.character); else sprintf(dest, "%.4f", symbol->defn.info.constant.value.real); } else { //-------------------------------------------------------------------- // 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; switch(symbol->defn.info.data.varType) { case VAR_TYPE_NORMAL: { StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr; int32_t delta = level - symbol->level; while(delta-- > 0) headerPtr = (StackFrameHeaderPtr)headerPtr->staticLink.address; dataPtr = (StackItemPtr)headerPtr + symbol->defn.info.data.offset; } break; case VAR_TYPE_ETERNAL: dataPtr = (StackItemPtr)stack + symbol->defn.info.data.offset; break; case VAR_TYPE_STATIC: dataPtr = (StackItemPtr)StaticDataPtr + symbol->defn.info.data.offset; break; } //--------------------------------------------------------------- // If it's a scalar or enumeration reference parameter, that item // points to the actual item... if((symbol->defn.key == DFN_REFPARAM) && (typePtr->form != FRM_ARRAY)/* && (typePtr->form != FRM_RECORD)*/) dataPtr = (StackItemPtr)dataPtr->address; if((typePtr->form != FRM_ARRAY) /*&& (typePtr->form != FRM_RECORD)*/) { ABL_Assert(dataPtr != nullptr, 0, " Debugger.sprintSimpleValue(): dataPtr is nullptr "); if((typePtr == IntegerTypePtr) || (typePtr->form == FRM_ENUM)) sprintf(dest, "%d", *((int32_t*)dataPtr)); else if(typePtr == CharTypePtr) sprintf(dest, "\"%c\"", *((PSTR)dataPtr)); else sprintf(dest, "%.4f", *((float*)dataPtr)); } else sprintf(dest, "ARRAY"); } return(ABL_NO_ERR); }
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(); }
int32_t Debugger::sprintArrayValue(PSTR dest, SymTableNodePtr symbol, PSTR subscriptString) { //-------------------------------------------------------------------- // This code is adapted from execVariable(). If that function changes, // this better too! //-------------------------------------------------------------------- // 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... if(symbol->defn.key == DFN_CONST) sprintf(dest, "\"%s\"", symbol->defn.info.constant.value.stringPtr); else { StackItemPtr dataPtr = nullptr; switch(symbol->defn.info.data.varType) { case VAR_TYPE_NORMAL: { StackFrameHeaderPtr headerPtr = (StackFrameHeaderPtr)stackFrameBasePtr; int32_t delta = level - symbol->level; while(delta-- > 0) headerPtr = (StackFrameHeaderPtr)headerPtr->staticLink.address; dataPtr = (StackItemPtr)headerPtr + symbol->defn.info.data.offset; } break; case VAR_TYPE_ETERNAL: dataPtr = (StackItemPtr)stack + symbol->defn.info.data.offset; break; case VAR_TYPE_STATIC: dataPtr = (StackItemPtr)StaticDataPtr + symbol->defn.info.data.offset; break; } TypePtr typePtr = (TypePtr)(symbol->typePtr); ABL_Assert(dataPtr != nullptr, 0, " Debugger.sprintArrayValue(): dataPtr is nullptr "); Address elementAddress = (Address)dataPtr->address; if(subscriptString) { PSTR cp = subscriptString; //----------------------------- // Get past the open bracket... cp++; PSTR token = strtok(&subscriptString[1], ",]"); while(token) { //---------------- // Read integer... int32_t index = atoi(token); //------------------------- // Range check the index... if((index < 0) || (index >= typePtr->info.array.elementCount)) return(1); elementAddress += (index * typePtr->info.array.elementTypePtr->size); typePtr = typePtr->info.array.elementTypePtr; token = strtok(nullptr, ",]"); } } if((typePtr->form != FRM_ARRAY)) { if((typePtr == IntegerTypePtr) || (typePtr->form == FRM_ENUM)) sprintf(dest, "%d", *((int32_t*)elementAddress)); else if(typePtr == CharTypePtr) sprintf(dest, "\"%c\"", *((PSTR)elementAddress)); else sprintf(dest, "%.4f", *((float*)elementAddress)); } else if(typePtr->info.array.elementTypePtr == CharTypePtr) sprintf(dest, "\"%s\"", (PSTR)elementAddress); else sprintf(dest, "Could you be more specific?"); } return(ABL_NO_ERR); }
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); }