// vm.h -- DVX BASIC virtual machine // // Stack-based p-code interpreter. Executes compiled BASIC bytecode. // Embeddable: the host provides I/O callbacks. No DVX dependencies. // // Usage: // BasVmT *vm = basVmCreate(); // basVmSetPrintCallback(vm, myPrintFn, myCtx); // basVmSetInputCallback(vm, myInputFn, myCtx); // basVmLoadModule(vm, compiledCode, codeLen, constants, numConsts); // BasVmResultE result = basVmRun(vm); // basVmDestroy(vm); #ifndef DVXBASIC_VM_H #define DVXBASIC_VM_H #include "values.h" #include #include // ============================================================ // Limits // ============================================================ #define BAS_VM_STACK_SIZE 256 // evaluation stack depth #define BAS_VM_CALL_STACK_SIZE 64 // max call nesting #define BAS_VM_MAX_GLOBALS 512 // global variable slots #define BAS_VM_MAX_LOCALS 64 // locals per stack frame #define BAS_VM_MAX_FOR_DEPTH 32 // nested FOR loops #define BAS_VM_MAX_FILES 16 // open file channels // ============================================================ // Result codes // ============================================================ typedef enum { BAS_VM_OK, // program completed normally BAS_VM_HALTED, // HALT instruction reached BAS_VM_YIELDED, // DoEvents yielded control BAS_VM_ERROR, // runtime error BAS_VM_STACK_OVERFLOW, BAS_VM_STACK_UNDERFLOW, BAS_VM_CALL_OVERFLOW, BAS_VM_DIV_BY_ZERO, BAS_VM_TYPE_MISMATCH, BAS_VM_OUT_OF_MEMORY, BAS_VM_BAD_OPCODE, BAS_VM_FILE_ERROR, BAS_VM_SUBSCRIPT_RANGE, BAS_VM_USER_ERROR // ON ERROR raised } BasVmResultE; // ============================================================ // I/O callbacks (host-provided) // ============================================================ // Print callback: called for PRINT output. // text is a null-terminated string. newline indicates whether // to advance to the next line after printing. typedef void (*BasPrintFnT)(void *ctx, const char *text, bool newline); // Input callback: called for INPUT statement. // prompt is the text to display. The callback must fill buf // (up to bufSize-1 chars, null-terminated). Returns true on // success, false on cancel/error. typedef bool (*BasInputFnT)(void *ctx, const char *prompt, char *buf, int32_t bufSize); // DoEvents callback: called for DoEvents statement. // The host should process pending events and return. Returns // true to continue execution, false to stop the program. typedef bool (*BasDoEventsFnT)(void *ctx); // ============================================================ // Call stack frame // ============================================================ typedef struct { int32_t returnPc; // instruction to return to int32_t baseSlot; // base index in locals array int32_t localCount; // number of locals in this frame BasValueT locals[BAS_VM_MAX_LOCALS]; } BasCallFrameT; // ============================================================ // FOR loop state // ============================================================ typedef struct { int32_t varIdx; // loop variable slot index bool isLocal; // true = local, false = global BasValueT limit; // upper bound BasValueT step; // step value int32_t loopTop; // PC of the loop body start } BasForStateT; // ============================================================ // File channel // ============================================================ typedef struct { void *handle; // FILE* or platform-specific int32_t mode; // 0=closed, 1=input, 2=output, 3=append, 4=random, 5=binary } BasFileChannelT; // ============================================================ // Compiled module (output of the compiler) // ============================================================ typedef struct { uint8_t *code; // p-code bytecode int32_t codeLen; BasStringT **constants; // string constant pool int32_t constCount; int32_t globalCount; // number of global variable slots needed int32_t entryPoint; // PC of the first instruction (module-level code) BasValueT *dataPool; // DATA statement value pool int32_t dataCount; // number of values in the data pool } BasModuleT; // ============================================================ // VM state // ============================================================ typedef struct { // Program BasModuleT *module; // Execution int32_t pc; // program counter bool running; bool yielded; // Evaluation stack BasValueT stack[BAS_VM_STACK_SIZE]; int32_t sp; // stack pointer (index of next free slot) // Call stack BasCallFrameT callStack[BAS_VM_CALL_STACK_SIZE]; int32_t callDepth; // FOR loop stack BasForStateT forStack[BAS_VM_MAX_FOR_DEPTH]; int32_t forDepth; // Global variables BasValueT globals[BAS_VM_MAX_GLOBALS]; // File channels (1-based, index 0 unused) BasFileChannelT files[BAS_VM_MAX_FILES]; // DATA/READ pointer int32_t dataPtr; // current READ position in data pool // String comparison mode bool compareTextMode; // true = case-insensitive comparisons // Error handling int32_t errorHandler; // PC of ON ERROR GOTO handler (0 = none) int32_t errorNumber; // current Err number int32_t errorPc; // PC of the instruction that caused the error (for RESUME) int32_t errorNextPc; // PC of the next instruction after error (for RESUME NEXT) bool inErrorHandler; // true when executing error handler code char errorMsg[256]; // current error description // I/O callbacks BasPrintFnT printFn; void *printCtx; BasInputFnT inputFn; void *inputCtx; BasDoEventsFnT doEventsFn; void *doEventsCtx; } BasVmT; // ============================================================ // API // ============================================================ // Create a new VM instance. BasVmT *basVmCreate(void); // Destroy a VM instance and free all resources. void basVmDestroy(BasVmT *vm); // Load a compiled module into the VM. void basVmLoadModule(BasVmT *vm, BasModuleT *module); // Execute the loaded module. Returns when the program ends, // halts, yields, or hits an error. BasVmResultE basVmRun(BasVmT *vm); // Execute a single instruction. Returns the result. // Useful for stepping/debugging. BasVmResultE basVmStep(BasVmT *vm); // Reset the VM to initial state (clear stack, globals, PC). void basVmReset(BasVmT *vm); // Set I/O callbacks. void basVmSetPrintCallback(BasVmT *vm, BasPrintFnT fn, void *ctx); void basVmSetInputCallback(BasVmT *vm, BasInputFnT fn, void *ctx); void basVmSetDoEventsCallback(BasVmT *vm, BasDoEventsFnT fn, void *ctx); // Push/pop values on the evaluation stack (for host integration). bool basVmPush(BasVmT *vm, BasValueT val); bool basVmPop(BasVmT *vm, BasValueT *val); // Get the current error message. const char *basVmGetError(const BasVmT *vm); #endif // DVXBASIC_VM_H