// 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) SCOPE_MEMBER = 3 // class member variable of the running procedure's Me } 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 #define BAS_TYPE_DATE 11 // Double serial date (dates.h), held in dblVal #define BAS_TYPE_EMPTY 12 // Variant that holds nothing yet (Empty) #define BAS_TYPE_NULL 13 // Variant Null (no valid data) #define BAS_TYPE_INSTANCE 14 // ref-counted class instance or Collection (BasObjectT) #define BAS_TYPE_VARIANT 15 // declared type only (AS VARIANT, array element type): holds any value, never a value's tag // ============================================================ // 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_SPECIAL 0x03 // [uint8 BasSpecialValE] push Empty, Null or Nothing #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 #define OP_LOAD_MEMBER 0x14 // [uint16 idx] push member variable idx of the running procedure's Me #define OP_STORE_MEMBER 0x15 // [uint16 idx] pop to member variable idx of Me #define OP_PUSH_MEMBER_ADDR 0x1D // [uint16 idx] push address of member variable idx of Me (for ByRef) // ============================================================ // 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 #define OP_IS 0x46 // pop b, a (objects); push a Is b (the same object) #define OP_OBJ_CHECK 0x47 // [uint16 class] TOS must be an object (BAS_OBJ_CHECK_ANY) or an instance of class (Nothing passes); else error // ============================================================ // 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 #define OP_CALL_ME 0x5B // [uint16 addr] [uint8 argc] [uint8 baseSlot] OP_CALL whose callee keeps the caller's Me (a class calling its own procedure) // ============================================================ // 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 #define OP_CONV_DATE 0x67 // any -> DATE (CDATE; a string is parsed as a date) // ============================================================ // 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] #define OP_ME_OBJ 0x8D // push the running procedure's Me (class module code) // ============================================================ // 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 #define OP_NEW_OBJ 0x9E // [uint16 class] push a new instance of class (BAS_NEW_COLLECTION: a Collection), running its initialisation #define OP_PROP_ASSIGN 0x9F // [uint8 argc] [uint8 flags] pop value, args, memberName, objRef; assign obj.member(args) = value (BAS_ASSIGN_SET: Set) // ============================================================ // 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 // ============================================================ // Library functions without an opcode of their own // ============================================================ // [uint8 BasBuiltinFnE] [uint8 argc] pop argc arguments (pushed in source // order), push the result. Optional trailing arguments are omitted from // argc and take their defaults in the VM. #define OP_BUILTIN 0xD8 // Most arguments one OP_BUILTIN call takes (CHOOSE: index + 31 choices). #define BAS_BUILTIN_MAX_ARGS 32 // OP_BUILTIN function numbers. Part of the bytecode ABI -- append only. typedef enum { BAS_FN_REPLACE = 0, // REPLACE$(s, find, repl [, start [, count [, compare]]]) BAS_FN_SPLIT = 1, // SPLIT(s [, delim [, limit [, compare]]]) -> STRING array BAS_FN_JOIN = 2, // JOIN$(array [, delim]) BAS_FN_INSTRREV = 3, // INSTRREV(s, find [, start [, compare]]) BAS_FN_STRCOMP = 4, // STRCOMP(a, b [, compare]) BAS_FN_STRREVERSE = 5, // STRREVERSE$(s) BAS_FN_FILTER = 6, // FILTER(array, match [, include [, compare]]) -> STRING array BAS_FN_LSET = 7, // LSET target = s: (current target, s) -> s left-justified in LEN(target) BAS_FN_RSET = 8, // RSET target = s: (current target, s) -> s right-justified in LEN(target) BAS_FN_IIF = 9, // IIF(cond, a, b) BAS_FN_CHOOSE = 10, // CHOOSE(index, a [, b ...]) BAS_FN_NOW = 11, // NOW BAS_FN_DATE = 12, // DATE BAS_FN_TIME = 13, // TIME BAS_FN_DATESERIAL = 14, // DATESERIAL(y, m, d) BAS_FN_TIMESERIAL = 15, // TIMESERIAL(h, m, s) BAS_FN_DATEVALUE = 16, // DATEVALUE(d) BAS_FN_TIMEVALUE = 17, // TIMEVALUE(d) BAS_FN_YEAR = 18, // YEAR(d) BAS_FN_MONTH = 19, // MONTH(d) BAS_FN_DAY = 20, // DAY(d) BAS_FN_WEEKDAY = 21, // WEEKDAY(d [, firstDayOfWeek]) BAS_FN_HOUR = 22, // HOUR(d) BAS_FN_MINUTE = 23, // MINUTE(d) BAS_FN_SECOND = 24, // SECOND(d) BAS_FN_DATEADD = 25, // DATEADD(interval, n, d) BAS_FN_DATEDIFF = 26, // DATEDIFF(interval, d1, d2 [, firstDayOfWeek [, firstWeekOfYear]]) BAS_FN_DATEPART = 27, // DATEPART(interval, d [, firstDayOfWeek [, firstWeekOfYear]]) BAS_FN_ISDATE = 28, // ISDATE(v) BAS_FN_MONTHNAME = 29, // MONTHNAME(m [, abbrev]) BAS_FN_WEEKDAYNAME = 30, // WEEKDAYNAME(w [, abbrev [, firstDayOfWeek]]) BAS_FN_PARAMARRAY = 31, // (elementType, v0, v1, ...) -> 0-based array of the values: a ParamArray argument (compiler-generated, no BASIC name) // The program screen (runtime/screen.c): statements return 0, which // the compiler pops. Omitted arguments are pushed as 0 and flagged in // a BAS_GIVEN_* / BAS_GFX_* mask pushed last. BAS_FN_CLS = 32, // CLS [n]: (n, -1 when omitted) BAS_FN_LOCATE = 33, // LOCATE [row] [, [col] [, cursor]]: (row, col, cursor, given) BAS_FN_COLOR = 34, // COLOR [fore] [, back]: (fore, back, given) BAS_FN_SCREEN = 35, // SCREEN mode BAS_FN_WIDTH = 36, // WIDTH [cols] [, rows]: (cols, rows, given) BAS_FN_PSET = 37, // PSET / PRESET [STEP](x, y) [, color]: (x, y, color, flags) BAS_FN_LINE = 38, // LINE [[STEP](x1, y1)]-[STEP](x2, y2) [, color] [, B|BF] [, style]: (x1, y1, x2, y2, color, style, flags) BAS_FN_CIRCLE = 39, // CIRCLE [STEP](x, y), r [, color [, start [, end [, aspect]]]]: (x, y, r, color, start, end, aspect, flags) BAS_FN_PAINT = 40, // PAINT [STEP](x, y) [, paint [, border]]: (x, y, paint, border, flags) BAS_FN_DRAW = 41, // DRAW macro$ BAS_FN_PALETTE = 42, // PALETTE [attr, color]: (attr, color, given) BAS_FN_PALETTE_USING = 43, // PALETTE USING array[(first)]: (array, first, given) BAS_FN_VIEW = 44, // VIEW [[SCREEN] (x1, y1)-(x2, y2) [, [fill] [, border]]]: (x1, y1, x2, y2, fill, border, flags) BAS_FN_WINDOW = 45, // WINDOW [[SCREEN] (x1, y1)-(x2, y2)]: (x1, y1, x2, y2, flags) BAS_FN_FULLSCREEN = 46, // FULLSCREEN [ON | OFF | expr]: (on) BAS_FN_INKEY = 47, // INKEY$ -> "" / one character / CHR$(0) + scan code BAS_FN_CSRLIN = 48, // CSRLIN -> cursor row BAS_FN_POS = 49, // POS(n) -> cursor column BAS_FN_POINT = 50, // POINT(x, y) -> colour (-1 outside the view); POINT(n) -> the last point BAS_FN_SCREENFN = 51, // SCREEN(row, col [, colorflag]) -> character code or colour BAS_FN_LINE_INPUT = 52, // LINE INPUT [prompt$;] v$: (prompt) -> the line typed // Variants and objects BAS_FN_VARTYPE = 53, // VARTYPE(v) -> vbEmpty .. vbArray + element type BAS_FN_TYPENAME = 54, // TYPENAME(v) -> "Integer", "Nothing", class name ... BAS_FN_ISEMPTY = 55, // ISEMPTY(v) BAS_FN_ISNULL = 56, // ISNULL(v) BAS_FN_ISNUMERIC = 57, // ISNUMERIC(v) BAS_FN_ISOBJECT = 58, // ISOBJECT(v) BAS_FN_ISARRAY = 59, // ISARRAY(v) BAS_FN_CVAR = 60, // CVAR(v) -> v as it is BAS_FN_TYPEOF = 61, // TYPEOF obj IS name: (obj, name) -> the object is of that type BAS_FN_EACH_COUNT = 62, // FOR EACH (compiler-generated): (group) -> items in the array or Collection BAS_FN_EACH_ITEM = 63 // FOR EACH (compiler-generated): (group, i) -> item i (0-based) } BasBuiltinFnE; // The Variant and object functions are numbered BAS_FN_VARTYPE through // BAS_FN_EACH_ITEM. #define BAS_FN_OBJECT_FIRST BAS_FN_VARTYPE #define BAS_FN_OBJECT_LAST BAS_FN_EACH_ITEM // OP_PUSH_SPECIAL operand. Part of the bytecode ABI. typedef enum { BAS_SPECIAL_EMPTY = 0, BAS_SPECIAL_NULL = 1, BAS_SPECIAL_NOTHING = 2 } BasSpecialValE; // OP_NEW_OBJ / OP_OBJ_CHECK class operand values besides a class index. #define BAS_NEW_COLLECTION 0xFFFF // OP_NEW_OBJ / OP_OBJ_CHECK: a Collection #define BAS_OBJ_CHECK_ANY 0xFFFE // OP_OBJ_CHECK: any object // OP_PROP_ASSIGN flags. #define BAS_ASSIGN_SET 0x01 // Set obj.member = value (Property Set) // VARTYPE results (VB's vbEmpty .. vbArray). #define BAS_VT_EMPTY 0 #define BAS_VT_NULL 1 #define BAS_VT_INTEGER 2 #define BAS_VT_LONG 3 #define BAS_VT_SINGLE 4 #define BAS_VT_DOUBLE 5 #define BAS_VT_CURRENCY 6 #define BAS_VT_DATE 7 #define BAS_VT_STRING 8 #define BAS_VT_OBJECT 9 #define BAS_VT_ERROR 10 #define BAS_VT_BOOLEAN 11 #define BAS_VT_VARIANT 12 #define BAS_VT_DATAOBJECT 13 #define BAS_VT_USERTYPE 36 #define BAS_VT_ARRAY 8192 // The program-screen functions are numbered BAS_FN_CLS through // BAS_FN_LINE_INPUT (the VM hands them to runtime/screen.c). #define BAS_FN_SCREEN_FIRST BAS_FN_CLS #define BAS_FN_SCREEN_LAST BAS_FN_LINE_INPUT // Given-argument masks of LOCATE, COLOR, WIDTH and PALETTE (bit n: the // n-th argument was written). #define BAS_GIVEN_1 0x01 #define BAS_GIVEN_2 0x02 #define BAS_GIVEN_3 0x04 // Flags of the drawing argument blocks (PSET, LINE, CIRCLE, PAINT). The // same blocks are the arguments of the Form / PictureBox PSet, Line and // Circle methods, so both compile and run through one path. #define BAS_GFX_STEP 0x01 // the (first) point is relative to the last point #define BAS_GFX_COLOR 0x02 // a colour was given #define BAS_GFX_PRESET 0x04 // PSET: PRESET (the default colour is the background) #define BAS_GFX_START 0x08 // LINE: the start point was given #define BAS_GFX_STEP2 0x10 // LINE: the end point is relative to the start point #define BAS_GFX_BOX 0x20 // LINE: ,B (a rectangle) #define BAS_GFX_BOX_FILL 0x40 // LINE: ,BF (a filled rectangle) #define BAS_GFX_STYLE 0x80 // LINE: a style mask was given #define BAS_GFX_ARC_START 0x08 // CIRCLE: a start angle was given #define BAS_GFX_ARC_END 0x10 // CIRCLE: an end angle was given #define BAS_GFX_ASPECT 0x20 // CIRCLE: an aspect was given #define BAS_GFX_BORDER 0x08 // PAINT: a border colour was given // Argument counts of the drawing blocks. #define BAS_GFX_PSET_ARGS 4 #define BAS_GFX_LINE_ARGS 7 #define BAS_GFX_CIRCLE_ARGS 8 #define BAS_GFX_PAINT_ARGS 5 // Argument counts of the other screen statements with optional parts. #define BAS_LOCATE_ARGS 4 #define BAS_COLOR_ARGS 3 #define BAS_WIDTH_ARGS 3 #define BAS_PALETTE_ARGS 3 #define BAS_VIEW_ARGS 7 #define BAS_WINDOW_ARGS 5 // VIEW / WINDOW flags. #define BAS_VIEW_COORDS 0x01 // a rectangle was given (none: reset) #define BAS_VIEW_SCREEN 0x02 // VIEW SCREEN / WINDOW SCREEN #define BAS_VIEW_FILL 0x04 // VIEW: a fill colour was given #define BAS_VIEW_BORDER 0x08 // VIEW: a border colour was given // Object Print (Form / PictureBox .Print): one method call per item with // (value, mode). #define BAS_OBJ_PRINT_TEXT 0 // the value's text #define BAS_OBJ_PRINT_NEWLINE 1 // end of the line (value unused) #define BAS_OBJ_PRINT_ZONE 2 // ',' : the next print zone (value unused) #define BAS_OBJ_PRINT_TAB 3 // TAB(n): column n #define BAS_OBJ_PRINT_SPC 4 // SPC(n): n spaces #define BAS_OBJ_PRINT_ARGS 2 // Compare argument of the string functions: OPTION COMPARE decides when // it is omitted (vbUseCompareOption). #define BAS_COMPARE_USE_OPTION (-1) // ============================================================ // 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 bool basBuiltinArity(uint8_t fn, int32_t *minArgs, int32_t *maxArgs); static inline uint8_t basConvOpForStore(uint8_t dataType); 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); // Argument counts an OP_BUILTIN function accepts (the compiler checks // calls against them, the VM checks the bytecode). False for an unknown // function number. static inline bool basBuiltinArity(uint8_t fn, int32_t *minArgs, int32_t *maxArgs) { switch (fn) { case BAS_FN_NOW: case BAS_FN_DATE: case BAS_FN_TIME: case BAS_FN_INKEY: case BAS_FN_CSRLIN: *minArgs = 0; *maxArgs = 0; return true; case BAS_FN_STRREVERSE: case BAS_FN_DATEVALUE: case BAS_FN_TIMEVALUE: case BAS_FN_YEAR: case BAS_FN_MONTH: case BAS_FN_DAY: case BAS_FN_HOUR: case BAS_FN_MINUTE: case BAS_FN_SECOND: case BAS_FN_ISDATE: case BAS_FN_CLS: case BAS_FN_SCREEN: case BAS_FN_DRAW: case BAS_FN_FULLSCREEN: case BAS_FN_POS: case BAS_FN_LINE_INPUT: case BAS_FN_VARTYPE: case BAS_FN_TYPENAME: case BAS_FN_ISEMPTY: case BAS_FN_ISNULL: case BAS_FN_ISNUMERIC: case BAS_FN_ISOBJECT: case BAS_FN_ISARRAY: case BAS_FN_CVAR: case BAS_FN_EACH_COUNT: *minArgs = 1; *maxArgs = 1; return true; case BAS_FN_POINT: *minArgs = 1; *maxArgs = 2; return true; case BAS_FN_SCREENFN: *minArgs = 2; *maxArgs = 3; return true; case BAS_FN_COLOR: *minArgs = BAS_COLOR_ARGS; *maxArgs = BAS_COLOR_ARGS; return true; case BAS_FN_WIDTH: *minArgs = BAS_WIDTH_ARGS; *maxArgs = BAS_WIDTH_ARGS; return true; case BAS_FN_PALETTE: case BAS_FN_PALETTE_USING: *minArgs = BAS_PALETTE_ARGS; *maxArgs = BAS_PALETTE_ARGS; return true; case BAS_FN_LOCATE: *minArgs = BAS_LOCATE_ARGS; *maxArgs = BAS_LOCATE_ARGS; return true; case BAS_FN_WINDOW: *minArgs = BAS_WINDOW_ARGS; *maxArgs = BAS_WINDOW_ARGS; return true; case BAS_FN_VIEW: *minArgs = BAS_VIEW_ARGS; *maxArgs = BAS_VIEW_ARGS; return true; case BAS_FN_PSET: *minArgs = BAS_GFX_PSET_ARGS; *maxArgs = BAS_GFX_PSET_ARGS; return true; case BAS_FN_LINE: *minArgs = BAS_GFX_LINE_ARGS; *maxArgs = BAS_GFX_LINE_ARGS; return true; case BAS_FN_CIRCLE: *minArgs = BAS_GFX_CIRCLE_ARGS; *maxArgs = BAS_GFX_CIRCLE_ARGS; return true; case BAS_FN_PAINT: *minArgs = BAS_GFX_PAINT_ARGS; *maxArgs = BAS_GFX_PAINT_ARGS; return true; case BAS_FN_JOIN: case BAS_FN_WEEKDAY: case BAS_FN_MONTHNAME: *minArgs = 1; *maxArgs = 2; return true; case BAS_FN_WEEKDAYNAME: *minArgs = 1; *maxArgs = 3; return true; case BAS_FN_SPLIT: *minArgs = 1; *maxArgs = 4; return true; case BAS_FN_LSET: case BAS_FN_RSET: case BAS_FN_TYPEOF: case BAS_FN_EACH_ITEM: *minArgs = 2; *maxArgs = 2; return true; case BAS_FN_STRCOMP: *minArgs = 2; *maxArgs = 3; return true; case BAS_FN_INSTRREV: case BAS_FN_FILTER: case BAS_FN_DATEPART: *minArgs = 2; *maxArgs = 4; return true; case BAS_FN_CHOOSE: *minArgs = 2; *maxArgs = BAS_BUILTIN_MAX_ARGS; return true; case BAS_FN_PARAMARRAY: *minArgs = 1; *maxArgs = BAS_BUILTIN_MAX_ARGS; return true; case BAS_FN_IIF: case BAS_FN_DATESERIAL: case BAS_FN_TIMESERIAL: case BAS_FN_DATEADD: *minArgs = 3; *maxArgs = 3; return true; case BAS_FN_DATEDIFF: *minArgs = 3; *maxArgs = 5; return true; case BAS_FN_REPLACE: *minArgs = 3; *maxArgs = 6; return true; default: return false; } } // The conversion a value goes through when it is stored where dataType // is declared: a numeric, BOOLEAN or DATE type is converted to it, every // other type (STRING, OBJECT, VARIANT, TYPE) stores the value as it is // (OP_NOP). One source for the compiler's typed stores and the VM's // stores into class member variables. static inline uint8_t basConvOpForStore(uint8_t dataType) { switch (dataType) { case BAS_TYPE_INTEGER: return OP_CONV_FLT_INT; case BAS_TYPE_LONG: return OP_CONV_INT_LONG; case BAS_TYPE_SINGLE: return OP_CONV_INT_FLT; case BAS_TYPE_BOOLEAN: return OP_CONV_BOOL; case BAS_TYPE_DATE: return OP_CONV_DATE; default: return OP_NOP; } } // 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_IS: case OP_ME_OBJ: 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_CONV_DATE: 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: case OP_PUSH_SPECIAL: 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: case OP_BUILTIN: case OP_LOAD_MEMBER: case OP_STORE_MEMBER: case OP_PUSH_MEMBER_ADDR: case OP_OBJ_CHECK: case OP_NEW_OBJ: case OP_PROP_ASSIGN: 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_CALL_ME: 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