// The MIT License (MIT) // // Copyright (C) 2026 Scott Duensing // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // opcodes.h -- DVX BASIC bytecode instruction definitions // // Stack-based p-code for the DVX BASIC virtual machine. // Embeddable: no DVX dependencies, pure C. #ifndef DVXBASIC_OPCODES_H #define DVXBASIC_OPCODES_H #include #include // ============================================================ // Variable scope tags // Emitted in bytecode (e.g. OP_FOR scopeTag byte) and consumed // by the VM to choose between globals, call-frame locals, and // form-scoped variables. Numeric values are part of the bytecode // ABI -- do not reorder. // ============================================================ typedef enum { SCOPE_GLOBAL = 0, SCOPE_LOCAL = 1, SCOPE_FORM = 2 // per-form variable (persists while form is loaded) } BasScopeE; // ============================================================ // File channel modes (BasFileChannelT.mode and OP_FILE_OPEN arg). // Numeric values are part of the bytecode ABI -- do not reorder. // ============================================================ typedef enum { BAS_FILE_MODE_CLOSED = 0, BAS_FILE_MODE_INPUT = 1, BAS_FILE_MODE_OUTPUT = 2, BAS_FILE_MODE_APPEND = 3, BAS_FILE_MODE_RANDOM = 4, BAS_FILE_MODE_BINARY = 5 } BasFileModeE; // ============================================================ // Data type tags (used in Value representation) // ============================================================ #define BAS_TYPE_INTEGER 0 // 16-bit signed #define BAS_TYPE_LONG 1 // 32-bit signed #define BAS_TYPE_SINGLE 2 // 32-bit float #define BAS_TYPE_DOUBLE 3 // 64-bit float #define BAS_TYPE_STRING 4 // ref-counted dynamic string #define BAS_TYPE_BOOLEAN 5 // True (-1) or False (0) #define BAS_TYPE_ARRAY 6 // ref-counted array #define BAS_TYPE_UDT 7 // ref-counted user-defined type #define BAS_TYPE_OBJECT 8 // opaque host object (form, control, etc.) #define BAS_TYPE_REF 9 // ByRef pointer to a BasValueT slot #define BAS_TYPE_ELEM_REF 10 // ByRef array element: counted BasArrayT* + flat index // ============================================================ // Stack operations // ============================================================ #define OP_NOP 0x00 #define OP_PUSH_INT16 0x01 // [int16] push 16-bit integer #define OP_PUSH_INT32 0x02 // [int32] push 32-bit integer #define OP_PUSH_FLT64 0x04 // [float64] push 64-bit float #define OP_PUSH_STR 0x05 // [uint16 idx] push string from constant pool #define OP_PUSH_TRUE 0x06 // push boolean True (-1) #define OP_PUSH_FALSE 0x07 // push boolean False (0) #define OP_POP 0x08 // discard top of stack #define OP_DUP 0x09 // duplicate top of stack #define OP_STMT 0x0A // statement boundary without a line number (release builds that keep ON ERROR/RESUME semantics) // ============================================================ // Variable access // ============================================================ #define OP_LOAD_LOCAL 0x10 // [uint16 idx] push local variable #define OP_STORE_LOCAL 0x11 // [uint16 idx] pop to local variable #define OP_LOAD_GLOBAL 0x12 // [uint16 idx] push global variable #define OP_STORE_GLOBAL 0x13 // [uint16 idx] pop to global variable #define OP_LOAD_ARRAY 0x16 // [uint8 dims] indices on stack, array ref below #define OP_STORE_ARRAY 0x17 // [uint8 dims] value, indices, array ref on stack #define OP_LOAD_FIELD 0x18 // [uint16 fieldIdx] load UDT field #define OP_STORE_FIELD 0x19 // [uint16 fieldIdx] store UDT field #define OP_PUSH_LOCAL_ADDR 0x1A // [uint16 idx] push address of local (for ByRef) #define OP_PUSH_GLOBAL_ADDR 0x1B // [uint16 idx] push address of global (for ByRef) #define OP_STORE_ARRAY_FIELD 0x1C // [uint8 dims, uint16 fieldIdx] value, indices, array on stack // ============================================================ // Arithmetic (integer) // ============================================================ #define OP_ADD_INT 0x20 #define OP_SUB_INT 0x21 #define OP_MUL_INT 0x22 #define OP_IDIV_INT 0x23 // integer divide (\) #define OP_MOD_INT 0x24 #define OP_NEG_INT 0x25 // ============================================================ // Arithmetic (float) // ============================================================ #define OP_DIV_FLT 0x29 // float divide (/) #define OP_POW 0x2B // exponentiation (^) // ============================================================ // String operations // ============================================================ #define OP_STR_CONCAT 0x30 #define OP_STR_LEFT 0x31 #define OP_STR_RIGHT 0x32 #define OP_STR_MID 0x33 // 3 args: str, start, len #define OP_STR_MID2 0x34 // 2 args: str, start (to end) #define OP_STR_LEN 0x35 #define OP_STR_INSTR 0x36 // 2 args: str, find #define OP_STR_INSTR3 0x37 // 3 args: start, str, find #define OP_STR_UCASE 0x38 #define OP_STR_LCASE 0x39 #define OP_STR_TRIM 0x3A #define OP_STR_LTRIM 0x3B #define OP_STR_RTRIM 0x3C #define OP_STR_CHR 0x3D #define OP_STR_ASC 0x3E #define OP_STR_SPACE 0x3F // ============================================================ // Comparison (push boolean result) // ============================================================ #define OP_CMP_EQ 0x40 #define OP_CMP_NE 0x41 #define OP_CMP_LT 0x42 #define OP_CMP_GT 0x43 #define OP_CMP_LE 0x44 #define OP_CMP_GE 0x45 // ============================================================ // Logical / bitwise // ============================================================ #define OP_AND 0x48 #define OP_OR 0x49 #define OP_NOT 0x4A #define OP_XOR 0x4B #define OP_EQV 0x4C #define OP_IMP 0x4D // ============================================================ // Control flow // ============================================================ #define OP_JMP 0x50 // [int16 offset] unconditional jump #define OP_JMP_TRUE 0x51 // [int16 offset] jump if TOS is true #define OP_JMP_FALSE 0x52 // [int16 offset] jump if TOS is false #define OP_CALL 0x53 // [uint16 addr] [uint8 argc] [uint8 baseSlot] #define OP_GOSUB_RET 0x54 // pop the current frame's latest GOSUB return address and jump there (error 3 if none) #define OP_RET 0x55 // return from subroutine #define OP_RET_VAL 0x56 // return from function (value on stack) #define OP_FOR_INIT 0x57 // [uint16 varIdx] [uint8 scope] [int16 skipOffset] init FOR, skip body if range empty #define OP_FOR_NEXT 0x58 // [uint16 varIdx] [uint8 scope] [int16 loopTop] #define OP_FOR_POP 0x59 // pop top FOR stack entry (for EXIT FOR) #define OP_GOSUB 0x5A // [int16 offset] push the next instruction's address on the GOSUB stack, jump // ============================================================ // Type conversion // ============================================================ #define OP_CONV_INT_FLT 0x60 // int -> float #define OP_CONV_FLT_INT 0x61 // float -> int (banker's rounding) #define OP_CONV_INT_STR 0x62 // int -> string #define OP_CONV_STR_INT 0x63 // string -> int (VAL) #define OP_CONV_STR_FLT 0x65 // any -> double (VAL, CDBL) #define OP_CONV_INT_LONG 0x66 // int16 -> int32 // ============================================================ // I/O // ============================================================ #define OP_PRINT 0x70 // print TOS to current output #define OP_PRINT_NL 0x71 // print newline #define OP_PRINT_TAB 0x72 // print tab (14-column zones) #define OP_LPRINT 0x73 // [uint8 BAS_LPRINT_BEGIN / BAS_LPRINT_END] route PRINT output to the printer for one LPRINT statement #define OP_INPUT 0x74 // read line into string on stack #define OP_FILE_OPEN 0x75 // [uint8 mode] filename, channel#, record length on stack #define OP_FILE_CLOSE 0x76 // channel# on stack #define OP_FILE_PRINT 0x77 // channel#, value on stack #define OP_FILE_INPUT 0x78 // channel# on stack, push string #define OP_FILE_EOF 0x79 // channel# on stack, push boolean #define OP_FILE_LINE_INPUT 0x7A // channel# on stack, push string // ============================================================ // UI / Event (used when form system is active) // ============================================================ // // All UI opcodes are name-based: control references, property names, // method names, and form names are strings resolved at runtime. // This allows third-party widget DXEs and new properties to work // without recompiling the BASIC runtime. // // Stack convention: // LOAD_PROP: ... controlRef propNameStr -> ... value // STORE_PROP: ... controlRef propNameStr value -> ... // CALL_METHOD: ... controlRef methodNameStr [args] -> ... [result] // LOAD_FORM: ... formNameStr -> ... formRef // CREATE_CTRL: ... formRef typeNameStr nameStr -> ... controlRef #define OP_LOAD_PROP 0x80 // pop propName, pop ctrlRef, push property value #define OP_STORE_PROP 0x81 // pop value, pop propName, pop ctrlRef, set property #define OP_CALL_METHOD 0x82 // [uint8 argc] pop methodName, pop ctrlRef, pop args, push result #define OP_LOAD_FORM 0x83 // pop formName string, push form reference #define OP_UNLOAD_FORM 0x84 // pop formRef, unload it #define OP_SHOW_FORM 0x85 // [uint8 modal] pop formRef, show it #define OP_HIDE_FORM 0x86 // pop formRef, hide it #define OP_DO_EVENTS 0x87 #define OP_MSGBOX 0x88 // pop flags, pop message string, push result #define OP_INPUTBOX 0x89 // pop default, pop title, pop prompt, push result string #define OP_ME_REF 0x8A // push current form reference #define OP_CREATE_CTRL 0x8B // pop name, pop typeName, pop formRef, push controlRef #define OP_FIND_CTRL 0x8C // pop ctrlName, pop formRef, push controlRef #define OP_FIND_CTRL_IDX 0x8E // pop index, pop ctrlName, pop formRef, push ctrlRef #define OP_LOAD_FORM_VAR 0x8F // [uint16 idx] push currentFormVars[idx] // ============================================================ // Array / misc // ============================================================ #define OP_DIM_ARRAY 0x90 // [uint8 dims] [uint8 type] bounds on stack #define OP_REDIM 0x91 // [uint8 dims] [uint8 preserve] [uint8 type] bounds on stack (UDT: typeId, fieldCount after bounds) #define OP_ERASE 0x92 // [uint8 mode] pop array ref, push replacement (BAS_ERASE_ZERO keeps the shape, BAS_ERASE_FREE undimensions) #define OP_LBOUND 0x93 // [uint8 dim] array ref on stack #define OP_UBOUND 0x94 // [uint8 dim] array ref on stack #define OP_ON_ERROR 0x95 // [int16 handler] set error handler (0 = disable) #define OP_RESUME 0x96 // resume after error #define OP_RESUME_NEXT 0x97 // resume at next statement #define OP_RAISE_ERR 0x98 // error number on stack #define OP_ERR_NUM 0x99 // push current error number #define OP_ERL 0x9A // push the source line of the current error (0 when none) #define OP_STORE_FORM_VAR 0x9B // [uint16 idx] pop, store to currentFormVars[idx] #define OP_PUSH_FORM_ADDR 0x9C // [uint16 idx] push ¤tFormVars[idx] (ByRef) #define OP_CREATE_CTRL_EX 0x9D // pop parentRef, pop name, pop type, pop formRef, push ctrlRef // ============================================================ // Math built-ins (single opcode each for common functions) // ============================================================ #define OP_MATH_ABS 0xA0 #define OP_MATH_INT 0xA1 // floor #define OP_MATH_FIX 0xA2 // truncate toward zero #define OP_MATH_SGN 0xA3 #define OP_MATH_SQR 0xA4 #define OP_MATH_SIN 0xA5 #define OP_MATH_COS 0xA6 #define OP_MATH_TAN 0xA7 #define OP_MATH_ATN 0xA8 #define OP_MATH_LOG 0xA9 #define OP_MATH_EXP 0xAA #define OP_MATH_RND 0xAB #define OP_MATH_RANDOMIZE 0xAC // seed on stack (BAS_RANDOMIZE_TIMER_SEED = seed from the clock) #define OP_RGB 0xAD // pop b, g, r; push LONG = (r<<16)|(g<<8)|b #define OP_GET_RED 0xAE // pop LONG color; push (color>>16) & 0xFF #define OP_GET_GREEN 0xAF // pop LONG color; push (color>>8) & 0xFF // ============================================================ // Conversion built-ins // ============================================================ #define OP_STR_VAL 0xB0 // VAL(s$) -> number #define OP_STR_STRF 0xB1 // STR$(n) -> string #define OP_STR_HEX 0xB2 // HEX$(n) -> string #define OP_STR_STRING 0xB3 // STRING$(n, char) -> string #define OP_STR_OCT 0xF3 // OCT$(n) -> string #define OP_CONV_BOOL 0xF4 // CBOOL(n) -> -1 (true) or 0 (false) #define OP_PUSH_ARR_ADDR 0xF5 // [uint8 dims] pop dims indices, pop array ref, push REF to element // ============================================================ // Extended built-ins // ============================================================ #define OP_MATH_TIMER 0xB4 // push seconds since midnight as DOUBLE #define OP_DATE_STR 0xB5 // push DATE$ string "MM-DD-YYYY" #define OP_TIME_STR 0xB6 // push TIME$ string "HH:MM:SS" #define OP_SLEEP 0xB7 // pop seconds, sleep #define OP_ENVIRON 0xB8 // pop env var name, push value string #define OP_COMMAND 0xDC // pop argument index, push COMMAND$ (0 = every argument) // ============================================================ // DATA/READ/RESTORE // ============================================================ #define OP_READ_DATA 0xB9 // push next value from data pool #define OP_RESTORE 0xBA // reset data pointer to 0 // ============================================================ // WRITE # (comma-delimited with quoted strings) // ============================================================ #define OP_FILE_WRITE 0xBB // pop channel + value, write in WRITE format #define OP_FILE_WRITE_SEP 0xBC // pop channel, write comma separator #define OP_FILE_WRITE_NL 0xBD // pop channel, write newline // ============================================================ // Random/Binary file I/O // ============================================================ #define OP_FILE_GET 0xBE // pop type (+ current string value for STRING) + recno + channel, read record, push value #define OP_FILE_PUT 0xBF // pop channel + recno + value, write record #define OP_FILE_SEEK 0xC0 // pop channel + position, seek #define OP_FILE_LOF 0xC1 // pop channel, push file length #define OP_FILE_LOC 0xC2 // pop channel, push LOC (last byte / record / block, by mode) #define OP_FILE_FREEFILE 0xC3 // push next free channel number #define OP_FILE_INPUT_N 0xC4 // pop channel + n, read n chars, push string // ============================================================ // Fixed-length strings and MID$ assignment // ============================================================ #define OP_STR_FIXLEN 0xC5 // [uint16 len] pop string, pad/truncate, push #define OP_STR_MID_ASGN 0xC6 // pop replacement, len, start, str; push modified // Length pushed for a MID$ statement without one: replace as much of the // replacement as fits (an explicit 0 replaces nothing). #define BAS_MID_LEN_OMITTED (-1) // ============================================================ // String append: var = var + x / var = var & x // ============================================================ // [uint8 flags] [uint8 scope] [uint16 varIdx] pop x, store var + x (or // var & x with BAS_APPEND_AMP) into the variable, appending in place // when the variable's string is not shared. #define OP_STR_APPEND 0xCE #define BAS_APPEND_AMP 0x01 // flags: '&' semantics (both sides as strings) instead of '+' // ============================================================ // PRINT USING // ============================================================ #define OP_PRINT_USING 0xC7 // [uint8 flags] pop format + value, push format + formatted string (BAS_USING_FIRST / BAS_USING_LAST) // ============================================================ // SPC(n) and TAB(n) with stack-based argument // ============================================================ #define OP_PRINT_TAB_N 0xC8 // pop column count, print spaces to reach column #define OP_PRINT_SPC_N 0xC9 // pop count, print that many spaces #define OP_FORMAT 0xCA // pop format string + value, push formatted string #define OP_SHELL 0xCB // pop command string, call system(), push return value #define OP_COMPARE_MODE 0xCC // [uint8 mode] set string compare mode (BAS_COMPARE_MODE_*) // ============================================================ // External library calls (DECLARE LIBRARY) // ============================================================ // // Calls native functions exported by dynamically loaded libraries. // The VM resolves library + function name on first call via a host // callback, caches the result, and marshals arguments through a // second callback. This allows BASIC programs to use any library // (serial, security, third-party) without recompiling the runtime. #define OP_CALL_EXTERN 0xCD // [uint16 libNameIdx] [uint16 funcNameIdx] [uint8 argc] [uint8 retType] #define OP_GET_BLUE 0xD0 // pop LONG color; push color & 0xFF // App object #define OP_APP_PATH 0xDD // push App.Path string #define OP_APP_CONFIG 0xDE // push App.Config string #define OP_APP_DATA 0xDF // push App.Data string // INI file operations #define OP_INI_READ 0xE0 // pop default, pop key, pop section, pop file, push string #define OP_INI_WRITE 0xE1 // pop value, pop key, pop section, pop file // Filesystem operations #define OP_FS_KILL 0xE2 // pop filename, delete file #define OP_FS_NAME 0xE3 // pop newname, pop oldname, rename #define OP_FS_FILECOPY 0xE4 // pop dst, pop src, copy file #define OP_FS_MKDIR 0xE5 // pop path, create directory #define OP_FS_RMDIR 0xE6 // pop path, remove directory #define OP_FS_CHDIR 0xE7 // pop path, change directory #define OP_FS_CHDRIVE 0xE8 // pop drive, change drive #define OP_FS_CURDIR 0xE9 // push current directory string #define OP_FS_DIR 0xEA // pop pattern, push first matching filename #define OP_FS_DIR_NEXT 0xEB // push next matching filename (no args) #define OP_FS_FILELEN 0xEC // pop filename, push file length #define OP_FS_GETATTR 0xED // pop filename, push attributes integer #define OP_FS_SETATTR 0xEE // pop attrs, pop filename, set attributes // Debug #define OP_LINE 0xEF // [uint16 lineNum] set current source line for debugger // Dynamic form construction #define OP_CREATE_FORM 0xF0 // pop height, pop width, pop nameStr, push formRef #define OP_SET_EVENT 0xF1 // pop handlerNameStr, pop eventNameStr, pop ctrlRef #define OP_REMOVE_CTRL 0xF2 // pop ctrlNameStr, pop formRef #define OP_FILE_PUT_UDT 0xF6 // pop layoutStr, pop udt, pop recno, pop channel; write packed fields #define OP_FILE_SEEK_GET 0xF7 // pop channel, push 1-based file position (SEEK function) // ============================================================ // Sound, joysticks and frame pacing (BasDeviceCallbacksT) // ============================================================ #define OP_BEEP 0xD1 // beep; waits in foreground music mode #define OP_SOUND 0xD2 // pop ticks, pop hz; play a tone (waits in foreground mode) #define OP_PLAY 0xD3 // pop macro string; play it (waits in foreground mode) #define OP_PLAY_COUNT 0xD4 // pop n (ignored), push notes waiting in the background (PLAY(n)) #define OP_STICK 0xD5 // pop n, push joystick position (STICK(n)) #define OP_STRIG 0xD6 // pop n, push joystick button state (STRIG(n)) #define OP_FRAME_WAIT 0xD7 // pop frames per second; wait for the next frame // ============================================================ // Halt // ============================================================ #define OP_END 0xFE // explicit END statement -- terminates program #define OP_HALT 0xFF // implicit end of module // OP_PRINT_USING flag bits: FIRST rewinds the format scan to the start // of the format string, LAST appends the literal text that follows the // consumed field. #define BAS_USING_FIRST 0x01 #define BAS_USING_LAST 0x02 // OP_LPRINT operand: BEGIN sends the PRINT opcodes that follow to the // printer, END sends the statement's output and goes back to the screen. #define BAS_LPRINT_END 0 #define BAS_LPRINT_BEGIN 1 // OP_ERASE modes. #define BAS_ERASE_ZERO 0 // fixed array: reset every element, keep the bounds #define BAS_ERASE_FREE 1 // dynamic array: release the storage (undimensioned until REDIM) // TYPE layout descriptors (built by the compiler as a string constant, // walked by the VM): one BAS_TYPE_* byte per field in declaration order. // A STRING entry is followed by a little-endian uint16 fixed length (0 = // variable length); a BAS_TYPE_UDT entry by the nested type's uint16 // typeId and uint16 fieldCount and then its own entries. DIM/REDIM use // the layout to build fully initialised instances, GET/PUT to pack and // unpack the fields (variable strings carry an int16 length prefix). #define BAS_LAYOUT_MAX_ENTRY_LEN 5 #define BAS_LAYOUT_MAX_LEN 1024 #define BAS_LAYOUT_MAX_DEPTH 16 // nesting cap for TYPE fields inside a layout // OP_COMPARE_MODE operand values (OPTION COMPARE BINARY / TEXT). #define BAS_COMPARE_MODE_BINARY 0 #define BAS_COMPARE_MODE_TEXT 1 // Seed value pushed by RANDOMIZE TIMER: OP_MATH_RANDOMIZE seeds from the // clock when it pops this value. #define BAS_RANDOMIZE_TIMER_SEED (-1) // ============================================================ // Operand-size table and bytecode pattern helpers // ============================================================ // // Single machine-readable source of truth for the operand byte count of // every opcode (the trailing comments above are human hints). Shared by // the VM (RESUME NEXT statement walk) and the release compactor. // // The BAS_OPERAND_* names give the operand SIZE in bytes, not its layout: // OP_DIM_ARRAY's two uint8 operands are BAS_OPERAND_U16 (2 bytes), OP_REDIM's // three uint8 operands BAS_OPERAND_U8_U16 (3 bytes), and OP_CALL's // [uint16 addr][uint8 argc][uint8 baseSlot] BAS_OPERAND_I32 (4 bytes). The // per-opcode comments above describe the real layout. // Operand widths (bytes after the 1-byte opcode). #define BAS_OPERAND_NONE 0 #define BAS_OPERAND_U8 1 #define BAS_OPERAND_U16 2 #define BAS_OPERAND_U8_U16 3 #define BAS_OPERAND_I32 4 #define BAS_OPERAND_FOR 5 // [uint16 varIdx] [uint8 scope] [int16 offset] #define BAS_OPERAND_CALL_EXTERN 6 // [uint16 lib] [uint16 func] [uint8 argc] [uint8 retType] #define BAS_OPERAND_F64 8 #define BAS_OPERAND_UNKNOWN (-1) // Byte offsets inside the FOR opcodes' BAS_OPERAND_FOR operand. #define BAS_FOR_OFFSET_OPERAND (1 + BAS_OPERAND_U16 + BAS_OPERAND_U8) // opcode-relative position of the int16 jump offset static inline int32_t basOpcodeOperandSize(uint8_t op); static inline int16_t basReadI16LE(const uint8_t *p); static inline int32_t basReadI32LE(const uint8_t *p); static inline uint16_t basReadU16LE(const uint8_t *p); static inline void basWriteI16LE(uint8_t *p, int16_t v); static inline void basWriteI32LE(uint8_t *p, int32_t v); static inline void basWriteU16LE(uint8_t *p, uint16_t v); // Returns operand byte count for op, or BAS_OPERAND_UNKNOWN. static inline int32_t basOpcodeOperandSize(uint8_t op) { switch (op) { case OP_NOP: case OP_PUSH_TRUE: case OP_PUSH_FALSE: case OP_POP: case OP_DUP: case OP_STMT: case OP_ADD_INT: case OP_SUB_INT: case OP_MUL_INT: case OP_IDIV_INT: case OP_MOD_INT: case OP_NEG_INT: case OP_DIV_FLT: case OP_POW: case OP_STR_CONCAT: case OP_STR_LEFT: case OP_STR_RIGHT: case OP_STR_MID: case OP_STR_MID2: case OP_STR_LEN: case OP_STR_INSTR: case OP_STR_INSTR3: case OP_STR_UCASE: case OP_STR_LCASE: case OP_STR_TRIM: case OP_STR_LTRIM: case OP_STR_RTRIM: case OP_STR_CHR: case OP_STR_ASC: case OP_STR_SPACE: case OP_CMP_EQ: case OP_CMP_NE: case OP_CMP_LT: case OP_CMP_GT: case OP_CMP_LE: case OP_CMP_GE: case OP_AND: case OP_OR: case OP_NOT: case OP_XOR: case OP_EQV: case OP_IMP: case OP_GOSUB_RET: case OP_RET: case OP_RET_VAL: case OP_FOR_POP: case OP_CONV_INT_FLT: case OP_CONV_FLT_INT: case OP_CONV_INT_STR: case OP_CONV_STR_INT: case OP_CONV_STR_FLT: case OP_CONV_INT_LONG: case OP_PRINT: case OP_PRINT_NL: case OP_PRINT_TAB: case OP_INPUT: case OP_FILE_CLOSE: case OP_FILE_PRINT: case OP_FILE_INPUT: case OP_FILE_EOF: case OP_FILE_LINE_INPUT: case OP_LOAD_PROP: case OP_STORE_PROP: case OP_LOAD_FORM: case OP_UNLOAD_FORM: case OP_HIDE_FORM: case OP_DO_EVENTS: case OP_MSGBOX: case OP_INPUTBOX: case OP_ME_REF: case OP_CREATE_CTRL: case OP_FIND_CTRL: case OP_FIND_CTRL_IDX: case OP_CREATE_CTRL_EX: case OP_RESUME: case OP_RESUME_NEXT: case OP_RAISE_ERR: case OP_ERR_NUM: case OP_MATH_ABS: case OP_MATH_INT: case OP_MATH_FIX: case OP_MATH_SGN: case OP_MATH_SQR: case OP_MATH_SIN: case OP_MATH_COS: case OP_MATH_TAN: case OP_MATH_ATN: case OP_MATH_LOG: case OP_MATH_EXP: case OP_MATH_RND: case OP_MATH_RANDOMIZE: case OP_RGB: case OP_GET_RED: case OP_GET_GREEN: case OP_GET_BLUE: case OP_STR_VAL: case OP_STR_STRF: case OP_STR_HEX: case OP_STR_STRING: case OP_STR_OCT: case OP_CONV_BOOL: case OP_MATH_TIMER: case OP_DATE_STR: case OP_TIME_STR: case OP_SLEEP: case OP_ENVIRON: case OP_COMMAND: case OP_READ_DATA: case OP_RESTORE: case OP_FILE_WRITE: case OP_FILE_WRITE_SEP: case OP_FILE_WRITE_NL: case OP_FILE_GET: case OP_FILE_PUT: case OP_FILE_SEEK: case OP_FILE_LOF: case OP_FILE_LOC: case OP_FILE_FREEFILE: case OP_FILE_INPUT_N: case OP_STR_MID_ASGN: case OP_PRINT_TAB_N: case OP_PRINT_SPC_N: case OP_FORMAT: case OP_SHELL: case OP_APP_PATH: case OP_APP_CONFIG: case OP_APP_DATA: case OP_INI_READ: case OP_INI_WRITE: case OP_FS_KILL: case OP_FS_NAME: case OP_FS_FILECOPY: case OP_FS_MKDIR: case OP_FS_RMDIR: case OP_FS_CHDIR: case OP_FS_CHDRIVE: case OP_FS_CURDIR: case OP_FS_DIR: case OP_FS_DIR_NEXT: case OP_FS_FILELEN: case OP_FS_GETATTR: case OP_FS_SETATTR: case OP_CREATE_FORM: case OP_SET_EVENT: case OP_REMOVE_CTRL: case OP_FILE_PUT_UDT: case OP_ERL: case OP_FILE_SEEK_GET: case OP_BEEP: case OP_SOUND: case OP_PLAY: case OP_PLAY_COUNT: case OP_STICK: case OP_STRIG: case OP_FRAME_WAIT: case OP_END: case OP_HALT: return BAS_OPERAND_NONE; case OP_LOAD_ARRAY: case OP_STORE_ARRAY: case OP_PUSH_ARR_ADDR: case OP_FILE_OPEN: case OP_CALL_METHOD: case OP_SHOW_FORM: case OP_LBOUND: case OP_UBOUND: case OP_COMPARE_MODE: case OP_PRINT_USING: case OP_ERASE: case OP_LPRINT: return BAS_OPERAND_U8; case OP_PUSH_INT16: case OP_PUSH_STR: case OP_LOAD_LOCAL: case OP_STORE_LOCAL: case OP_LOAD_GLOBAL: case OP_STORE_GLOBAL: case OP_LOAD_FIELD: case OP_STORE_FIELD: case OP_PUSH_LOCAL_ADDR: case OP_PUSH_GLOBAL_ADDR: case OP_JMP: case OP_JMP_TRUE: case OP_JMP_FALSE: case OP_GOSUB: case OP_LOAD_FORM_VAR: case OP_STORE_FORM_VAR: case OP_PUSH_FORM_ADDR: case OP_DIM_ARRAY: case OP_ON_ERROR: case OP_STR_FIXLEN: case OP_LINE: return BAS_OPERAND_U16; case OP_STORE_ARRAY_FIELD: case OP_REDIM: return BAS_OPERAND_U8_U16; case OP_PUSH_INT32: case OP_CALL: case OP_STR_APPEND: return BAS_OPERAND_I32; case OP_FOR_INIT: case OP_FOR_NEXT: return BAS_OPERAND_FOR; case OP_CALL_EXTERN: return BAS_OPERAND_CALL_EXTERN; case OP_PUSH_FLT64: return BAS_OPERAND_F64; default: return BAS_OPERAND_UNKNOWN; } } // ============================================================ // Little-endian operand access // ============================================================ // // Bytecode is always little-endian regardless of the host; the compiler, // the compactor and the serializer all go through these. static inline int16_t basReadI16LE(const uint8_t *p) { return (int16_t)basReadU16LE(p); } static inline int32_t basReadI32LE(const uint8_t *p) { return (int32_t)((uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24)); } static inline uint16_t basReadU16LE(const uint8_t *p) { return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } static inline void basWriteI16LE(uint8_t *p, int16_t v) { basWriteU16LE(p, (uint16_t)v); } static inline void basWriteI32LE(uint8_t *p, int32_t v) { uint32_t u = (uint32_t)v; p[0] = (uint8_t)(u & 0xFF); p[1] = (uint8_t)((u >> 8) & 0xFF); p[2] = (uint8_t)((u >> 16) & 0xFF); p[3] = (uint8_t)((u >> 24) & 0xFF); } static inline void basWriteU16LE(uint8_t *p, uint16_t v) { p[0] = (uint8_t)(v & 0xFF); p[1] = (uint8_t)((v >> 8) & 0xFF); } #endif // DVXBASIC_OPCODES_H