123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831 |
- <P><PRE>
- **
- ** GCSx object structure and script bytecode format
- ** Revision: August 16, 2006 Alexis Janson:
- ** Added SENDT, SENDTs, QUERYT, QUERYTs (send/query when script type is known)
- ** Adding GET, GETs, GETT, GETTf, GETTs, GETTh, GETTa, GETTv
- ** Adding SET, SETs, SETT, SETTf, SETTs, SETTh, SETTa, SETTv
- **
- </PRE></P>
- <H3>GET [Stack]/[Local]/[Ptr](#) [String] [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>GET [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](c$) [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>GETs [Pop]/[Stack]/[Local]/[Ptr](c$) [String] [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>GETs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$) [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>GETs [String] [String] [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>GETs [String] [Pop]/[Stack]/[Local]/[Ptr](c$) [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>GETT [Stack]/[Local]/[Ptr](#) [Int] [Int] [Int] *@</H3>
- <H3>GETT [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](#) *@</H3>
- <H3>GETTf [Stack]/[Local]/[Ptr](#) [Int] [Int] [Float] *@</H3>
- <H3>GETTf [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](%) *@</H3>
- <H3>GETTs [Stack]/[Local]/[Ptr](#) [Int] [Int] [String] *@</H3>
- <H3>GETTs [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](c$) *@</H3>
- <H3>GETTh [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](h) *@</H3>
- <H3>GETTa [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](a) *@</H3>
- <H3>GETTv [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>SET [Stack]/[Local]/[Ptr](#) [String] [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>SET [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](c$) [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>SETs [Pop]/[Stack]/[Local]/[Ptr](c$) [String] [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>SETs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$) [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>SETs [String] [String] [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>SETs [String] [Pop]/[Stack]/[Local]/[Ptr](c$) [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H3>SETT [Stack]/[Local]/[Ptr](#) [Int] [Int] [Int] *@</H3>
- <H3>SETT [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](#) *@</H3>
- <H3>SETTf [Stack]/[Local]/[Ptr](#) [Int] [Int] [Float] *@</H3>
- <H3>SETTf [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](%) *@</H3>
- <H3>SETTs [Stack]/[Local]/[Ptr](#) [Int] [Int] [String] *@</H3>
- <H3>SETTs [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](c$) *@</H3>
- <H3>SETTh [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](h) *@</H3>
- <H3>SETTa [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack]/[Local]/[Ptr](a) *@</H3>
- <H3>SETTv [Stack]/[Local]/[Ptr](#) [Int] [Int] [Stack](S)/[Local](S)/[Global](G) *@</H3>
- <H1>0) Introduction</H1>
- <P>
- This document describes the exact internal structure of objects and code in a GCSx game. The exact structure and storage of an object script or function library is detailed from its original text (source) format, to pre-link bytecode format, (compiled when the code is saved) to fully-linked bytecode format, ready for game play.
- </P><P>
- When stored to a file, integer values are stored in Intel format (little-endian) and floating point values are stored in standard IEEE formats. Pointers are stored in whatever format and size is native to the platform being run on. Pointers are never saved to a file.
- </P>
- <H1>1) Object Structure</H1>
- <H2>1A) Global Variable Structure</H2>
- <P>
- Variables are stored as an 8-bit code that denotes the type of variable, and a 32-bit (or larger) value representing the variable. Integer and floating point values are stored as 32-bit values; strings, arrays, and hashes as pointers to more complex structures. String structures in memory are stored as either C-style NUL-terminated strings, or STL String objects, depending on circumstances. Array and hash structures include a reference count, counting the number of stack entries and variables that point to them.
- </P><P>
- The value or pointer for a variable is always in the same "place", regardless of variable type, so miscompiled code could accidentally read a pointer as an integer value, or vice-versa. Bytecode must be carefully compiled to know what value type will be present, or check this at runtime.
- </P><P>
- Variable type is 1 for integer, 2 for floating point, 4 for string, +8 for array, +16 for hash. An undefined variable will have a type of 0. This is not currently supported by the GCSx language directly, but can be used by certain bytecode constructs.
- </P>
- <H2>1B) Internal Stack Structure</H2>
- <P>
- Note that local variables of all types are stored on the stack.
- </P><P>
- An object stack can hold any number of items, accessed in a LIFO manner. An item consists of an 8-bit code denoting what that stack item contains, followed by a 32-bit value. (on platforms where pointers are larger than 32 bits, a stack value will be the size of a pointer instead.) Note that stack items and global variables have exactly the same format except for stack types 128, 129, and 130. Codes and values include-
- </P>
- <P><UL>
- <LI>0 - An undefined value (used only in very specific circumstances)
- <LI>1 - An integer value
- <LI>2 - A floating-point value
- <LI>4 - A pointer to a string, in the format of an STL String structure, which must be deallocated when removed from the stack
- <LI>+8 - A pointer to an array structure, which must be reference-checked; contains integers, floats, or strings
- <LI>+16 - A pointer to a hash structure, which must be reference-checked; contains integers, floats, or strings
- <LI>(reference-checking may result in deallocation if the stack entry was the last reference to the array or hash)
- <LI>128 - A function or code pointer, usually a return pointer; can be a NULL pointer (0) to signify stopping or no code
- <LI>129 - A pointer to an object waiting on a return value; more specifically, a pointer to a stack entry where the return value should be stored; can be a NULL pointer (0) to signify the object already got its value or does not need a value, but that this function was still called remotely and should not push the return value back to the stack. Unless NULL, will always point to a 130.
- <LI>130 - A pointer to an object that will eventually reply; more specifically, a pointer to the 129 stack entry within that object. Cannot be NULL. The eventual reply will replace this entry.
- </UL></P>
- <P>
- Most bytecode opcodes assume stack items are of a certain type, but the type of an element can be checked if necessary. This is mostly needed if you are clearing up the stack, as you must deallocate/dereference structures and release other objects waiting on return values (type 129) or objects that expect to reply (type 130).
- </P><P>
- When a function is called within an object (for whatever reason, internal or external) the stack should have an optional 129 entry defining where a return value should go if on another object, followed by zero or more parameters for the function, follwed by a 128 entry defining where the return will jump.
- </P>
- <H2>1C) Internal Object Structure</H2>
- <P>
- Internally, an object stores the following data-
- </P>
- <P><UL>
- <LI>A stack, including actual size (where to push items) and allocated size
- <LI>Amount of stack used by local variables
- <LI>Pointer to current instruction
- <LI>Object name, in string format
- <LI>Internal numeric ID
- <LI>ID of original codebase
- <LI>[link to sprite or onscreen representation]
- <LI>[other internal modes and settings as needed]
- </UL></P>
- <P>
- The actual, original code is stored elsewhere, and is not even loaded during gameplay. The bytecode is also stored elsewhere, as multiple objects can use the same bytecode.
- </P>
- <H2>1D) File Variable, Stack, Object Structures</H2>
- <P>(...notes on pointer storage/conversion...)</P>
- <H1>2) Function Library (and Codebase) Structure</H1>
- <P>
- A "function library" is used to store code that can be called from any object. A "codebase" is code that is assigned to one or more objects as their primary script. They are stored and structure almost identically.
- </P>
- <H2>2A) Internal Function Library (and Codebase) Structure</H2>
- <P>
- Internally, a function library or codebase stores the following data-
- </P>
- <P><UL>
- <LI>Library or codebase name, in string format
- <LI>Unique internal ID
- <LI>Size of bytecode
- <LI>Bytecode
- <LI>A 32-bit unsigned integer containing the count of [Ptr] links that need to be adjusted
- <LI>An array of links- (see bytecode pre-link for details on how this is used)
- <UL><LI>A 32-bit unsigned integer containing the exact offset where the 32-bit [Ptr] value is stored within the code block, with zero representing the first byte of code
- <LI>An 8-bit code, containing 0 for a global variable [Ptr], 1 for a built-in function [Ptr], 2 for a function library [Ptr]
- <LI>A string (NUL-terminated) containing the entirely-uppercase name of the global variable, internal function, or library function. Library functions can be written as the library name, followed by ::, followed by the function name, but this is not always necessary. (conflicting names will cause linking errors, however.)
- </UL>
- <LI>Original source code, during editing (this is discarded or not loaded during gameplay)
- <LI>Array of pointers, parameter lists, and names for each function within the library or codebase; these point directly into parts of the bytecode
- </UL><P>
- <H2>2B) File Function Library (and Codebase) Structure</H2>
- <P>(...notes on pointer storage/conversion...)</P>
- <H2>2C) Built-In Function Library Codebase</H2>
- <P>
- All built-in functions are C++ functions, accessed using the CALL opcode. However, QUERY, SEND, and SUBRs can only jump to bytecode- not directly to a C++ function. To allow these opcodes to call C++ functions, a special wrapper codebase is generated containing bytecode for calling each built-in function, and this bytecode is referenced during QUERY, SEND, and SUBRs opcode handling. Each wrapper is simply a PRECALL, CALL, and RET sequence.
- </P>
- <H1>3) Text Source Format</H1>
- <P>
- "Text source" is the code for a script or function in its original, human-readable format.
- </P>
- <H2>3A) Internal Text Source</H2>
- <P>
- The complete size of the text source is stored as a 32-bit integer. Text source is stored as a sequence of NUL-terminated strings. Each string is a single line of code. No newlines are stored. Nothing related to syntax coloring is stored.
- </P>
- <H2>3B) File Text Source</H2>
- <P>
- The complete size of the text source is stored as a 32-bit integer, followed immediately by the text source in the same format as internally.
- </P>
- <H1>4) Compiled Bytecode Format</H1>
- <P>
- "Bytecode" is a compiled form of code, designed to be quickly interpreted by the GCSx game engine. Whenever code for an object or function library is edited and saved, bytecode is compiled. This bytecode is kept stored in memory and as part of the world file in a "pre-link" state. This bytecode is mostly compiled, but not quite ready to be used. When the game is played, the code is "linked", which combines all loaded code and function libraries into a ready-to-use codebase. The resulting bytecode is in "post-link" format.
- </P>
- <H2>4A) Linking Process</H2>
- <P><UL>
- <LI>Load all object code and function libraries that will be used into internal structures
- <LI>If current platform uses non-32-bit pointers, scan all code and adjust [Ptr] operands to appropriate size; adjust [Offset] and [String] operand values to match; adjust function and codebase library pointers to match. This is done by actually interpreting the bytecode to know which operands to adjust, hence is relatively slow- this is only relevant on 64-bit or higher architectures, however, and is unlikely to ever matter
- <LI>Scan the link headers for all code to determine the names of all global variables used; create storage for all unique global variables and determine pointers for them
- <LI>Determine pointers for all library functions and built-in functions
- <LI>Link all object code, by inserting these pointers into the code based on the linking headers
- </UL></P>
- <H2>4B) Internal Function Library (and Codebase) Structure - Post-link</H2>
- <P>
- After linking, the array of link data is cleared, as is any original source code if present. The array of function names is kept, for dynamic function lookup during gameplay.
- </P>
- <H1>5) Bytecode</H1>
- <P>
- This section describes how the bytecode works. Note that bytecode is highly optimized for speed, and hence when not in debugging mode, few safety checks are performed.
- </P>
- <H2>5A) Registers</H2>
- <P>
- Although bytecode looks similar to assembly, there are no registers. (other than the code and stack pointers, to draw assembly parallels) All operations work via the stack.
- </P>
- <H2>5B) Operand Types</H2>
- <P>
- The following types of operands are available to bytecode commands, also known as bytecode opcodes. Operands marked with * may not have their final value determined until post-link. All operands are 32 bits wide except on platforms with pointers larger than 32 bits.
- </P>
- <H3>5B1) [Int]</H3>
- <P>
- A 32-bit signed integer value.
- </P>
- <H3>5B2) [Float]</H3>
- <P>
- A 32-bit signed floating-point value.
- </P>
- <H3>5B4) [Offset]*</H3>
- <P>
- A 32-bit signed integer value representing the number of 32-bit dwords to look or move forward or backward in the current code. Positive values move forward, negative move backward. A value of zero represents the current opcode. This value will be adjusted if the code size changes during linking- this will only occur if pointers larger than 32 bits are used by the current system.
- </P>
- <H3>5B3) [String]*</H3>
- <P>
- Same as [Offset], but contains an offset to a location containing a static string stored within the bytecode. At this location is a NUL-terminated string. Strings are typically stored at the end of bytecode. This value will be adjusted if the code size changes during linking- this will only occur if pointers larger than 32 bits are used by the current system.
- </P>
- <H3>5B5) [Ptr]*</H3>
- <P>
- A pointer to a memory location. A 32-bit placeholder is stored during pre-link, and during the linking process, an actual pointer to a memory location is stored here. This points to either a built-in (coded in C++) function, a library (bytecode) function, or a global variable. If linked on a system that uses pointers of a size other than 32 bits, this field will expand as necessary, and all [Offset] and [String] values will adjust accordingly.
- </P>
- <H3>5B6) [Local]</H3>
- <P>
- A 32-bit unsigned integer value that references a stack entry from the bottom-up. 0 references the first added stack entry; 1, the next, and so on. This is used to access non-scoped local variables.
- </P>
- <H3>5B6) [Stack]</H3>
- <P>
- A 32-bit unsigned integer value that references a stack entry from the top-down. 0 references the most recently added stack entry; 1, one entry back, and so on.
- </P>
- <H2>5C) Bytecode Command Format</H2>
- <P>
- Each bytecode command consists of-
- </P>
- <P><UL>
- <LI>A packed opcode containing addressing modes-
- <UL><LI>Lowest 8-bits represent the base opcode
- <LI>Consecutive 10-bit codes that represent opcode addressing modes for up to three operands (basically, which type of operand is present)
- <LI>Note that the third operand mode can only be 4 bits.
- </UL>
- <LI>Zero to three operands for that opcode, in order, stored per the above operand definitions and addressing modes selected. All operands are 32-bits unless on a platform with larger pointers.
- </UL></P>
- <H2>5D) Opcode Addressing Modes</H2>
- <P>
- Addressing modes allow one opcode to function in many ways; in addition, it allows the bytecode interpreter to prepare the operands before selecting a generic routine to perform. For example, although stack entries and global variables are accessed in different ways, the data itself is still the same, so a direct pointer to the data can be created and used to allow the same code to write to a stack entry or a variable. This also allows all debugging checks and assertions to be centralized.
- </P><P>
- All addressing modes return a pointer to an area of memory or structure containing the data, to be directly read or modified by the bytecode processor.
- </P><P>
- Each addressing mode is listed as the numeric value associated with it, as well as codes used to clarify which addressing modes apply to each format in the opcode reference, for [Stack], [Ptr], and [Local] operands. Also listed is what the entry is translated to at runtime before running the opcode.
- </P><P>
- Remember that [Local] mode is zero-based- 0 points to the bottom stack entry. [Stack] is also zero-based- 0 points to the top stack entry. [Offset] and [String] are zero-based- 0 points to the current opcode- and measured in 32-bit dwords.
- <P><UL>
- <LI>0 - No operand
- <LI>1 (#) - [Int] Integer literal (operand is the actual literal, should not modify) Translates to a pointer to the literal.
- <LI>2 (%) - [Float] Floating-point literal (operand is the actual literal, should not modify) Translates to a pointer to the literal.
- <LI>3 - [Offset] Offset to code location; Translates to a pointer to the code.
- <LI>4 ($) - [String] Offset to string literal (should not modify offset or literal) Translates to a pointer to the NUL-terminated string.
- <LI>5 (B) - [Ptr] Pointer to built-in function
- <LI>6 (F) - [Ptr] Pointer to library function
- <LI>7 (reserved- unused)
- <LI>8 (a) - An array of any type (use with +32/+64/+96 only)
- <LI>+8 (a#%$) - Used with 1/2/4 and +32/+64/+96 to signify an array structure of a specific type (CURRENTLY NEVER USED)
- <LI>16 (h) - A hash of any type (use with +32/+64/+96 only)
- <LI>+16 (h#%$) - Used with 1/2/4 and +32/+64/+96 to signify a hash structure of a specific type (CURRENTLY NEVER USED)
- <LI>+24 (#%$) - [Pop] Operand is ignored. Top stack entry contains data of given type, which is immediately popped, and discarded afterwards (points to actual data) Translates to a pointer to the actual data. (if a string, to the internal String structure) If two operands are [Pop], then the first value popped applies to the first operand, the second to the second. Popping for [Pop] occurs before any popping from the command itself, but is processed in operand order- i.e. a [Stack] entry will refer to the stack pre-pop if the [Stack] operand is before the [Pop] operand, or to the stack post-pop if the [Pop] operand is before the [Stack] operand.
- <LI>32 (S) - [Local] Index of local variable, unknown type, to be modified directly (points to stack entry, not its data) Translates to a pointer to the stack entry.
- <LI>+32 (#%$) - [Local] Index of local variable containing data type (points to actual data) Translates to a pointer to the actual data. (if a string, to the internal String structure)
- <LI>64 (S) - [Stack] Index of stack entry, unknown type, to be modified directly (points to stack entry, not its data) Translates to a pointer to the stack entry.
- <LI>+64 (#%$) - [Stack] Index of stack entry containing data type (points to actual data) Translates to a pointer to the actual data. (if a string, to the internal String structure)
- <LI>96 (G) - [Ptr] Pointer to global variable, unknown type, to be modified directly (points to var, not its data) Translates to a pointer to the variable itself.
- <LI>+96 (#%$) - [Ptr] Pointer to global variable containing data type (points to actual data) Translates to a pointer to the actual data. (if a string, to the internal String structure)
- <LI>+128 (c) - Const; Used with $ to signify translation should result in a pointer to the NUL-terminated string; the resulting string should not be modified. Invalid when used with [String] or a non-$ datatype. Allows a single routine that can work on both [String] and normal ($) operands, as long as it isn't modifying the string.
- </UL></P>
- <H2>5E) Opcodes</H2>
- <P>
- This section describes the available bytecode commands available. Commands marked with * may cause a task switch. (switch to another object) Commands marked with @ may cause a preemption check- if the current object's timeslice has taken too long, a task switch may occur. Task switches will never occur at any other time. Each opcode is listed with all addressing modes it supports. Opcodes may have many variations for different data types- these variations are technically different opcodes, but will have the same name except for extra lowercase letters to denote type.
- </P><P>
- All opcodes automatically have asserts based on their addressing modes to verify that the proper type of data has been given or referenced for storage, and that it is valid and within any range or boundaries as appropriate. (for example, a stack index is asserted to be within the current size of the stack minus local variables.) Any additional assertions are listed with the opcode. Assertions are only checked when debugging is compiled into GCSx. Any assertions that mention the stack apply only to the non-local-variable portion of the stack. Other non-specific assertions are also made, such as a script running past the end of its codebase, or an invalid opcode or addressing mode or combination.
- </P><P>
- Unlike normal C assertions, these assertions merely cause the current object to stop running and produce an error message. They do not cause GCSx itself to exit.
- </P><P>
- All opcodes that have been utilized by the bytecode compiler have been <SPAN STYLE="background: yellow">highlighted</SPAN>. Current opcode count: 96
- </P>
- <H3 STYLE="background: yellow">ADD [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">ADD [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer value given, adds the second value, and stores it back at the given location.</P>
- <H3 STYLE="background: yellow">ADDf [Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">ADDf [Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Takes the floating-point value given, adds the second value, and stores it back at the given location.</P>
- <H3 STYLE="background: yellow">AND [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">AND [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer values given, performs a bitwise AND, and stores the new value back at the given location.</P>
- <H3>ARRAY [Stack]/[Local]/[Ptr](a) [Int]</H3>
- <H3>ARRAY [Stack]/[Local]/[Ptr](a) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>
- Accesses the noted element of the array (the second operand is the index into the array) and pushes the element found onto the stack. If the desired element is outside the array bounds, an empty element (0, 0.0, or "") of the appropriate type is pushed.
- </P>
- <H3>CALL [Ptr](B) *</H3>
- <P>Asserts: PRECALL was previous instruction</P>
- <P>Asserts: Returned value is not undefined</P>
- <P>
- Transfers code execution to the given external/built-in function. [Ptr] points to an actual C++ function, of format "int function(Object* object, StackEntry* stacktop)".
- </P><P>
- This function returns non-zero if the cycle should be ended and the function should be called again next cycle. In this case, the code pointer does not move. The top stack location (from PRECALL) can be used by the function for temporary storage, so that it knows when it is being called repeatedly.
- </P><P>
- This function should return zero normally. The top stack location (from PRECALL) will contain the return value. The code pointer then moves to the next opcode normally.
- </P>
- <H3 STYLE="background: yellow">CONCAT [Stack]/[Local]/[Ptr]($) [String]</H3>
- <H3 STYLE="background: yellow">CONCAT [Stack]/[Local]/[Ptr]($) [Pop]/[Stack]/[Local]/[Ptr](c$)</H3>
- <P>Takes the string value given, concatenate the second value, and store back at the given location.</P>
- <H3 STYLE="background: yellow">COPY [Stack](S)</H3>
- <H3 STYLE="background: yellow">COPY [Local](S)</H3>
- <H3 STYLE="background: yellow">COPY [Global](G)</H3>
- <P>If the noted stack entry or variable is an array or hash, creates an entirely new copy and stores it in that location. Optimized so that if the noted hash or array only has one reference, nothing happens. If the noted entry is not an array or hash, nothing happens.</P>
- <H3 STYLE="background: yellow">CREATEARRAY [Int]</H3>
- <P>Asserts: Value is 1, 2, or 4</P>
- <P>
- Creates a new, empty array and pushes it onto the stack. The type of array created is determined by the value given- 1 for Integer, 2 for Float, 4 for String.
- </P>
- <H3 STYLE="background: yellow">CREATEHASH [Int]</H3>
- <P>Asserts: Value is 1, 2, or 4</P>
- <P>
- Creates a new, empty hash and pushes it onto the stack. The type of hash created is determined by the value given- 1 for Integer, 2 for Float, 4 for String.
- </P>
- <H3>DEBUG [Int] [Int]</H3>
- <P>States the current line and column number within the original source file, for debugging purposes. This opcode is only generated if debugging is enabled.</P>
- <H3 STYLE="background: yellow">DISCARD [Int]</H3>
- <H3>DISCARD [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Asserts: Count of items is not larger than current stack</P>
- <P>Pops the given number of items off of the stack and discards them. Strings are freed, arrays and hashes are dereferenced, pointers to objects waiting on return values return an empty value, and waiting-for-reply pointers (type 130) modify the target 129 to be a NULL pointer.</P>
- <H3 STYLE="background: yellow">DISCARDL [Int]</H3>
- <H3>DISCARDL [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Asserts: Count of items is not larger than current stack</P>
- <P>Asserts: Items being discarded are 0, 1, 2, or 128 types only </P>
- <P>Pops the given number of items off of the stack and discards them. No checking is done for strings, arrays, hashes, or return types. This is a faster version of DISCARD intended for use when you know the stack entries are simple values.</P>
- <H3 STYLE="background: yellow">DIV [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">DIV [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer value given, divides by the second value, and stores the dividend at the given location. Dividing by zero will produce an unpredictable value, but will not cause an error.</P>
- <H3 STYLE="background: yellow">DIVf [Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">DIVf [Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Takes the floating-point value given, divides by the second value, and stores the dividend at the given location. Dividing by zero will produce an unpredictable value, but will not cause an error.</P>
- <H3 STYLE="background: yellow">EQ [Pop]/[Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">EQ [Pop]/[Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Compares the two integer values given. If equal, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">EQf [Pop]/[Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">EQf [Pop]/[Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Compares the two floating-point values given. If equal, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">EQs [Pop]/[Stack]/[Local]/[Ptr](c$) [String]</H3>
- <H3 STYLE="background: yellow">EQs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$)</H3>
- <P>Compares the two string values given. If equal, ignoring case, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">FTOI [Stack](S)</H3>
- <P>Asserts: Stack entry is a floating-point value</P>
- <P>Converts the given floating-point value to an integer in-place.</P>
- <H3 STYLE="background: yellow">FTOS [Stack](S)</H3>
- <P>Asserts: Stack entry is a floating-point value</P>
- <P>Converts the given floating-point value to a string in-place.</P>
- <H3 STYLE="background: yellow">FORCEARRAY [Stack](S) [Int]</H3>
- <P>Asserts: Stack entry is a value or undefined value (not a 128, 129, or 130)</P>
- <P>Asserts: Value is 1, 2, or 4</P>
- <P>
- If the stack entry is an array of the proper type, nothing happens. Otherwise, it is replaced by a newly-created, empty array. The type of array created is determined by the value given- 1 for Int, 2 for Float, 4 for String. If the stack entry was an array of an improper type but could be converted, the newly-created array will contain the converted values.
- </P><P>
- The FORCE* commands are typically used after a QUERY* or SUBRs command, to ensure the return value of an unknown function matches the expected type.
- </P>
- <H3 STYLE="background: yellow">FORCEFLOAT [Stack](S)</H3>
- <P>Asserts: Stack entry is a value or undefined value (not a 128, 129, or 130)</P>
- <P>
- If the stack entry is a floating-point value, nothing happens. If the entry is an integer or string, it is converted to floating-point. Otherwise, it is replaced by a floating-point value with the value 0.0.
- </P>
- <H3 STYLE="background: yellow">FORCEHASH [Stack](S) [Int]</H3>
- <P>Asserts: Stack entry is a value or undefined value (not a 128, 129, or 130)</P>
- <P>Asserts: Value is 1, 2, or 4</P>
- <P>
- If the stack entry is a hash of the proper type, nothing happens. Otherwise, it is replaced by a newly-created, empty hash. The type of hash created is determined by the value given- 1 for Integer, 2 for Float, 4 for String. If the stack entry was a hash of an improper type but could be converted, the newly-created hash will contain the converted values.
- </P>
- <H3 STYLE="background: yellow">FORCEINT [Stack](S)</H3>
- <P>Asserts: Stack entry is a value or undefined value (not a 128, 129, or 130)</P>
- <P>
- If the stack entry is an integer, nothing happens. If the entry is a floating-point value or string, it is converted to an integer. Otherwise, it is replaced by an integer with the value 0.
- </P>
- <H3 STYLE="background: yellow">FORCESTRING [Stack](S)</H3>
- <P>Asserts: Stack entry is a value or undefined value (not a 128, 129, or 130)</P>
- <P>
- If the stack entry is a string, nothing happens. If the entry is a floating-point value or integer, it is converted to a string. Otherwise, it is replaced by an empty string.
- </P>
- <H3 STYLE="background: yellow">GE [Pop]/[Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">GE [Pop]/[Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Compares the two integer values given. If the first value is greater than or equal to the second, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">GEf [Pop]/[Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">GEf [Pop]/[Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Compares the two floating-point values given. If the first value is greater than or equal to the second, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">GEs [Pop]/[Stack]/[Local]/[Ptr](c$) [String]</H3>
- <H3 STYLE="background: yellow">GEs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$)</H3>
- <P>Compares the two strings given. If the first string is greater than or equal to the second, ignoring case, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack. 8-bit ASCII collation is used, with lowercase letters sorting as if they were uppercase.</P>
- <H3 STYLE="background: yellow">GT [Pop]/[Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">GT [Pop]/[Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Compares the two integer values given. If the first value is greater than (but not or equal to) the second, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">GTf [Pop]/[Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">GTf [Pop]/[Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Compares the two floating-point values given. If the first value is greater than (but not equal to) the second, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">GTs [Pop]/[Stack]/[Local]/[Ptr](c$) [String]</H3>
- <H3 STYLE="background: yellow">GTs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$)</H3>
- <P>Compares the two strings given. If the first string is greater than (but not equal to) the second, ignoring case, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack. 8-bit ASCII collation is used, with lowercase letters sorting as if they were uppercase.</P>
- <H3>HASH [Stack]/[Local]/[Ptr](h) [String]</H3>
- <H3>HASH [Stack]/[Local]/[Ptr](h) [Pop]/[Stack]/[Local]/[Ptr](c$)</H3>
- <P>
- Accesses the noted element of the hash (the second operand is the index into the hash) and pushes the element found onto the stack. If no matching element is found, an empty element (0, 0.0, or "") of the appropriate type is pushed.
- </P>
- <H3 STYLE="background: yellow">IFFALSE [Pop]/[Stack]/[Local]/[Ptr](#) [Offset] @</H3>
- <H3 STYLE="background: yellow">IFFALSEf [Pop]/[Stack]/[Local]/[Ptr](%) [Offset] @</H3>
- <P>If the value given is 0 or 0.0, transfers code execution to the given location.</P>
- <H3 STYLE="background: yellow">IFTRUE [Pop]/[Stack]/[Local]/[Ptr](#) [Offset] @</H3>
- <H3 STYLE="background: yellow">IFTRUEf [Pop]/[Stack]/[Local]/[Ptr](%) [Offset] @</H3>
- <P>If the value given is something other than 0 or 0.0, transfers code execution to the given location.</P>
- <H3 STYLE="background: yellow">INIT *</H3>
- <P>Asserts: INIT must be present in all objects (asserted at link-time)</P>
- <P>
- Variable initialization is done. All objects on all scenes get to run once cycle before the game actually starts, during which they are expected to initialize global and local variables and such. INIT marks the end of this segment of code, switching to the next object. This also takes the current stack depth and stores it as the count of local variables. If an object has no initialization code, INIT or STOP should be the first opcode. No restrictions or preemptions are placed on code that runs before INIT, so this code should not enter any infinite loops, etc. or the bytecode engine will hang.
- </P>
- <H3 STYLE="background: yellow">ITOF [Stack](S)</H3>
- <P>Asserts: Stack entry is an integer value</P>
- <P>Converts the given integer to a floating-point value in-place.</P>
- <H3 STYLE="background: yellow">ITOS [Stack](S)</H3>
- <P>Asserts: Stack entry is an integer value</P>
- <P>Converts the given integer to a string in-place.</P>
- <H3 STYLE="background: yellow">JUMP [Offset] @</H3>
- <P>Asserts: Valid-looking opcode at given location</P>
- <P>Transfers code execution to the given location.</P>
- <H3 STYLE="background: yellow">LE [Pop]/[Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">LE [Pop]/[Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Compares the two integer values given. If the first value is less than or equal to the second, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">LEf [Pop]/[Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">LEf [Pop]/[Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Compares the two floating-point values given. If the first value is less than or equal to the second, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">LEs [Pop]/[Stack]/[Local]/[Ptr](c$) [String]</H3>
- <H3 STYLE="background: yellow">LEs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$)</H3>
- <P>Compares the two strings given. If the first string is less than or equal to the second, ignoring case, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack. 8-bit ASCII collation is used, with lowercase letters sorting as if they were uppercase.</P>
- <H3 STYLE="background: yellow">LT [Pop]/[Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">LT [Pop]/[Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Compares the two integer values given. If the first value is less than (but not or equal to) the second, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">LTf [Pop]/[Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">LTf [Pop]/[Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Compares the two floating-point values given. If the first value is less than (but not equal to) the second, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">LTs [Pop]/[Stack]/[Local]/[Ptr](c$) [String]</H3>
- <H3 STYLE="background: yellow">LTs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$)</H3>
- <P>Compares the two strings given. If the first string is less than (but not equal to) the second, ignoring case, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack. 8-bit ASCII collation is used, with lowercase letters sorting as if they were uppercase.</P>
- <H3 STYLE="background: yellow">LOGAND</H3>
- <P>Asserts: Top two entries of stack are values (not 0, 128, 129, or 130)</P>
- <P>Pops the top two entries of the stack. If both are true, pushes an integer 1 onto the stack; otherwise, pushes an integer 0 onto the stack. "true" is considered to be anything but a 0 or 0.0 value.</P>
- <H3>LOGOR</H3>
- <P>Asserts: Top two entries of stack are values (not 0, 128, 129, or 130)</P>
- <P>Pops the top two entries of the stack. If either one is true, pushes an integer 1 onto the stack; otherwise, pushes an integer 0 onto the stack. "true" is considered to be anything but a 0 or 0.0 value.</P>
- <H3 STYLE="background: yellow">MOD [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">MOD [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer value given, divide by the second value, and store the remainder back at the given location. Dividing by zero will produce an unpredictable value, but will not cause an error.</P>
- <H3 STYLE="background: yellow">MULT [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">MULT [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer value given, multiplys by the second value, and stores the product back at the given location.</P>
- <H3 STYLE="background: yellow">MULTf [Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">MULTf [Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Takes the floating-point value given, multiplys by the second value, and stores the product back at the given location.</P>
- <H3 STYLE="background: yellow">NE [Pop]/[Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">NE [Pop]/[Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Compares the two integer values given. If not equal, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">NEf [Pop]/[Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">NEf [Pop]/[Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Compares the two floating-point values given. If not equal, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3 STYLE="background: yellow">NEs [Pop]/[Stack]/[Local]/[Ptr](c$) [String]</H3>
- <H3 STYLE="background: yellow">NEs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$)</H3>
- <P>Compares the two string values given. If not equal, ignoring case, pushes an integer 1 onto the stack. Otherwise, an integer 0 is pushed onto the stack.</P>
- <H3>NEG [Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer value given and negates it, storing the new value back at the given location. (negation results in the opposite sign)</P>
- <H3>NEGf [Stack]/[Local]/[Ptr](%)</H3>
- <P>Takes the floating-point value given and negates it, storing the new value back at the given location. (negation results in the opposite sign)</P>
- <H3>NOOP</H3>
- <P>Does nothing.</P>
- <H3>NOT</H3>
- <P>Asserts: Top entry of stack is a value (not 0, 128, 129, or 130)</P>
- <P>Pops the top entry of the stack. If it was true, pushes an integer 0 onto the stack; otherwise, pushes an integer 1 onto the stack. "true" is considered to be anything but a 0 or 0.0 value.</P>
- <H3 STYLE="background: yellow">OR [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">OR [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer values given, performs a bitwise OR, and stores the new value back at the given location.</P>
- <H3>PRECALL</H3>
- <P>Asserts: CALL is next instruction</P>
- <P>
- Pushes an undefined (different from 0) value onto the stack to hold CALL return information. Always used right before a CALL opcode.
- </P><P>
- This is done separate from the actual CALL so that the code pointer may remain pointed at the CALL instruction with no danger of multiple values being pushed onto the stack- PRECALL will cause one and exactly one return storage value to be pushed.
- </P>
- <H3 STYLE="background: yellow">POP [Stack]/[Local]/[Ptr](#)</H3>
- <P>Asserts: Top entry of stack exists and is an integer</P>
- <P>Asserts: Not popping to [Stack]0</P>
- <P>Pops an integer off the stack and stores it in the given location. Note for all POP opcodes- if storing to a stack entry, the position of the entry is "locked in" before the POP occurs, since addressing occurs before any command results.</P>
- <H3 STYLE="background: yellow">POPa [Stack]/[Local]/[Ptr](a)</H3>
- <P>Asserts: Top entry of stack exists and is an array</P>
- <P>Asserts: Destination is of same array type as array on top of stack</P>
- <P>Asserts: Not popping to [Stack]0</P>
- <P>Pops an array off the stack and stores it in the given location. The array already at the current location is dereferenced. Use COPY if you wish to make a new copy and not potentially reference an existing array.</P>
- <H3 STYLE="background: yellow">POPf [Stack]/[Local]/[Ptr](%)</H3>
- <P>Asserts: Top entry of stack exists and is a floating-point value</P>
- <P>Asserts: Not popping to [Stack]0</P>
- <P>Pops a floating-point value off the stack and stores it in the given location.</P>
- <H3 STYLE="background: yellow">POPh [Stack]/[Local]/[Ptr](h)</H3>
- <P>Asserts: Top entry of stack exists and is a hash</P>
- <P>Asserts: Destination is of same hash type as hash on top of stack</P>
- <P>Asserts: Not popping to [Stack]0</P>
- <P>Pops a hash off the stack and stores it in the given location. The hash already at the current location is dereferenced. Use COPY if you wish to make a new copy and not potentially reference an existing hash.</P>
- <H3 STYLE="background: yellow">POPs [Stack]/[Local]/[Ptr]($)</H3>
- <P>Asserts: Top entry of stack exists and is a string</P>
- <P>Asserts: Not popping to [Stack]0</P>
- <P>Pops a string off the stack and stores it in the given location. The string already at the current location is freed.</P>
- <H3 STYLE="background: yellow">POPv [Stack](S)</H3>
- <H3 STYLE="background: yellow">POPv [Local](S)</H3>
- <H3 STYLE="background: yellow">POPv [Global](G)</H3>
- <P>Asserts: Top entry of stack exists and is not a 0, 128, 129, or 130</P>
- <P>Asserts: If storing to a global, it is the proper type or a variant type</P>
- <P>Pops any type of value off the stack and stores it in the given location. Use COPY if you wish to make a new copy and not potentially reference an existing array or hash.</P>
- <H3>POPARRAY [Stack]/[Local]/[Ptr](a) [Int]</H3>
- <H3>POPARRAY [Stack]/[Local]/[Ptr](a) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Asserts: Top entry of stack exists and is of same type as array</P>
- <P>
- Accesses the noted element of the array (the second operand is the index into the array), pops the top value off of the stack, and stores the popped value into the noted element of the array. If the desired element is beyond the current range of the array, the array is extended until the new element will fit.
- </P>
- <H3>POPHASH [Stack]/[Local]/[Ptr](h) [String]</H3>
- <H3>POPHASH [Stack]/[Local]/[Ptr](h) [Pop]/[Stack]/[Local]/[Ptr](c$)</H3>
- <P>Asserts: Top entry of stack exists and is of same type as hash</P>
- <P>
- Accesses the noted element of the hash (the second operand is the index into the hash), pops the top value off of the stack, and stores the popped value into the noted element of the hash. A new element is created if one doesn't exist.
- </P>
- <H3 STYLE="background: yellow">PUSH [Int]</H3>
- <H3 STYLE="background: yellow">PUSH [Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the given integer and adds it onto the stack as the top item. Note for all PUSH opcodes- if copying from another stack entry, the position of the entry is "locked in" before the PUSH occurs, since addressing occurs before any command results.</P>
- <H3 STYLE="background: yellow">PUSHa [Stack]/[Local]/[Ptr](a)</H3>
- <P>Takes the given array and adds it onto the stack as the top item. Reference count is increased. Use COPY if you wish to make a new copy and not potentially reference an existing array.</P>
- <H3 STYLE="background: yellow">PUSHf [Float]</H3>
- <H3 STYLE="background: yellow">PUSHf [Stack]/[Local]/[Ptr](%)</H3>
- <P>Takes the given floating-point value and adds it onto the stack as the top item.</P>
- <H3 STYLE="background: yellow">PUSHh [Stack]/[Local]/[Ptr](h)</H3>
- <P>Takes the given hash and adds it onto the stack as the top item. Reference count is increased. Use COPY if you wish to make a new copy and not potentially reference an existing hash.</P>
- <H3 STYLE="background: yellow">PUSHs [String]</H3>
- <H3 STYLE="background: yellow">PUSHs [Stack]/[Local]/[Ptr](c$)</H3>
- <P>Takes the given string, copies it, and adds it onto the stack as the top item.</P>
- <H3 STYLE="background: yellow">PUSHv [Stack](S)</H3>
- <H3 STYLE="background: yellow">PUSHv [Local](S)</H3>
- <H3 STYLE="background: yellow">PUSHv [Global](G)</H3>
- <P>Takes the given stack entry or variable, copies it, and adds it to the stack as the top item. Works on all types of variables/stack entries. Use COPY if you wish to make a new copy and not potentially reference an existing array or hash.</P>
- <H3>QUERY [Stack]/[Local]/[Ptr](#) [String] [Int] *@</H3>
- <H3>QUERY [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](c$) [Int] *@</H3>
- <P>Asserts: [Int] entries exist on stack</P>
- <P>Asserts: Next instruction is WAIT</P>
- <P>
- This switches control to another object and calls a function of that object, then waits for a return value.
- </P>
- <P><UL>
- <LI>A number of stack entries equal to the third operand are removed from the current object's stack and remembered.
- <LI>(representing an unknown or unfilled return value)
- <LI>An object is located using the first operand as the object ID. If none is found, an undefined value is pushed onto the stack and nothing further occurs. Execution continues, skipping over the next WAIT opcode.
- <LI>An attempt is made to locate a function by the name given for the second operand. (function libraries and built-in functions, as well as the found object, are searched; object state is taken into account) If none is found, an undefined value is pushed onto the stack and nothing further occurs. Execution continues, skipping over the next WAIT opcode.
- <LI>If the located object has queueing enabled and is busy, the below data is pushed onto its queue instead of its stack.
- <LI>A "return value pointer" (type 129) is pushed onto the located object's stack (or queue), pointing to the top value on the current object's stack. A "reply waiting" (type 130) is pushed onto the current object's stack, pointing to the 129.
- <LI>A number of stack entries equal to the expected number of function parameters are pushed onto the located object's stack (or queue). These entries will be derived and converted from the remembered entries, dropping (and dereferencing) any excess entries or creating empty entries if not enough were present.
- <LI>If queueing, the function location is pushed onto the queue. Otherwise, the location of the instruction that the located object would normally run next is pushed onto the located object's stack (i.e., the located object's current code pointer) and control switches to the located object, at the given function.
- </UL></P>
- <P>
- The next opcode will be WAIT, to prevent resuming code execution until the top value of the stack is no longer type 130, signifying the located object has returned a value.
- </P>
- <H3>QUERYs [Pop]/[Stack]/[Local]/[Ptr](c$) [String] [Int] *@</H3>
- <H3>QUERYs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$) [Int] *@</H3>
- <H3>QUERYs [String] [Pop]/[Stack]/[Local]/[Ptr](c$) [Int] *@</H3>
- <H3>QUERYs [String] [String] [Int] *@</H3>
- <P>Asserts: [Int] entries exist on stack</P>
- <P>Asserts: Next instruction is WAIT</P>
- <P>
- This command is the same as QUERY, except for the third step. Instead of locating an object by ID, an object matching the given name is located. If more than one match is found, one is chosen arbitrarily. (the first one found, although no order is defined)
- </P>
- <H3>QUERYT [Stack]/[Local]/[Ptr](#) [Ptr] [Int] [Int] *@</H3>
- <P>Asserts: Next instruction is WAIT</P>
- <P>Asserts: [Int] (last param) entries exist on stack</P>
- <P>Asserts: [Int] (third param) respresents a valid script id or zero</P>
- <P>Asserts: Parameter types have the proper, matching datatypes</P>
- <P>
- This is the same as QUERY, except a pointer directly to the target function is provided. The first [Int] represents the id of the script being called- this is used simply to verify that the target object is running the right script. This can be a zero value to signify that any script type is valid- this is only valid if [Ptr] points to within a function library.
- </P><P>
- The second [Int] represents the number of function parameters on the stack. It is assumed that the parameters are all of the proper type and count- no automatic parameter (or return value) conversion is done.
- </P>
- <H3>QUERYTs [Pop]/[Stack]/[Local]/[Ptr](c$) [Ptr] [Int] [Int] *@</H3>
- <H3>QUERYTs [String] [Ptr] [Int] [Int] *@</H3>
- <P>Asserts: Next instruction is WAIT</P>
- <P>Asserts: [Int] (last param) entries exist on stack</P>
- <P>Asserts: [Int] (third param) respresents a valid script id or zero</P>
- <P>Asserts: Parameter types have the proper, matching datatypes</P>
- <P>
- This is a combination of QUERYs and QUERYT. When searching for matching objects, only objects matching the given script id are 'found', unless the given script id is zero.
- </P>
- <H3>REPLY [Int] *</H3>
- <P>Asserts: Top entry of stack is a value (not a 0, 128, 129, or 130)</P>
- <P>Asserts: [Int] + 2 entries exist on stack</P>
- <P>Asserts: Stack entry pointed to by "object return value" pointer (if one is present) is type 130</P>
- <P>
- This returns a value to an object waiting on a return value. It is similar to RET in operation, without a code jump. [Int] represents the number of parameters and local variables currently on the stack.
- </P>
- <P><UL>
- <LI>The top stack entry is temporarily saved, and discarded.
- <LI>The entry now at stack position [Int] + 1 is examined. (0 being the current top entry after discarding the top entry)
- <LI>If this stack entry is an "object return value" pointer, (stack type 129) the saved value is stored at that location (if the pointer is not NULL) and the entry is changed to a NULL pointer. (still of type 129)
- </UL></P>
- <P>
- Control will switch if a valid object return value pointer was found, and that object switched control to the current object during the current cycle. This is handled internally by the bytecode interpreter and does not involve any state within the stack or object.
- </P>
- <H3>RET [Int] [Int] *</H3>
- <P>Asserts: Top entry of stack is a value (not a 0, 128, 129, or 130)</P>
- <P>Asserts: [Int] + [Int] + 2 entries exist on stack</P>
- <P>Asserts: 1 entry down is a code location</P>
- <P>Asserts: Stack entry pointed to by "object return value" pointer (if one is present) is type 130</P>
- <P>
- This returns from a "function call", using the top entry of the stack as the return value. [Int] represents the number of locals/temporaries currently on the stack and the number of parameters currently on the stack, respectively.
- </P>
- <P><UL>
- <LI>The top stack entry is temporarily saved and removed.
- <LI>[Int] (first operand) stack entrys are discarded. Note that any entries that reference strings, arrays, or hashes are deallocated/dereferenced.
- <LI>Code returns to the location stored in the top stack entry; that entry is also discarded. (A NULL pointer entry will result in code being stopped once this process is complete)
- <LI>[Int] (second operand) stack entrys are discarded. Again, entries are deallocated/dereferenced.
- <LI>The top stack entry is examined to see if it is an "object return value" pointer. (stack type 129) If it is, the saved return value is stored at that location (if the pointer is not NULL) and the top stack entry is discarded. If it is not, the saved return value is pushed onto the stack, unless code was stopped.
- <LI>If the top entry was ultimately not used (NULL pointer or code stopped) and it was a string, array, or hash, it is deallocated/dereferenced.
- </UL></P>
- <P>
- Control may switch back to another object in some situations. This happens when another object was waiting on the return value and switched control to the current object during the current cycle. This is handled internally by the bytecode interpreter and does not involve any state within the stack or object.
- </P>
- <H3>SEND [Stack]/[Local]/[Ptr](#) [String] [Int] *@</H3>
- <H3>SEND [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](c$) [Int] *@</H3>
- <P>Asserts: [Int] entries exist on stack</P>
- <P>
- This switches control to another object and calls a function of that object, but doesn't wait or accept a return value.
- </P>
- <P><UL>
- <LI>A number of stack entries equal to the third operand are removed from the current object's stack and remembered.
- <LI>An object is located using the first operand as the object ID. If none is found, nothing further occurs.
- <LI>An attempt is made to locate a function by the name given for the second operand. (function libraries and built-in functions, as well as the found object, are searched; object state is taken into account) If none is found, nothing further occurs.
- <LI>If the located object has queueing enabled and is busy, the below data is pushed onto its queue instead of its stack.
- <LI>A NULL 129 entry is pushed onto the located object's stack (or queue). [OPTIONAL]
- <LI>A number of stack entries equal to the expected number of function parameters are pushed onto the located object's stack (or queue). These entries will be derived and converted from the remembered entries, dropping (and dereferencing) any excess entries or creating empty entries if not enough were present.
- <LI>If queueing, the function location is pushed onto the queue. Otherwise, the location of the instruction that the located object would normally run next is pushed onto the located object's stack (i.e., the located object's current code pointer) and control switches to the located object, at the given function.
- </UL></P>
- <P>
- The current object will resume code execution if the located object finishes the function called before a task switch; otherwise, it will resume code execution at the next task switch. This is handled internally by the bytecode interpreter and does not involve any state within the stack or object.
- </P>
- <H3>SENDs [Pop]/[Stack]/[Local]/[Ptr](c$) [String] [Int] *@</H3>
- <H3>SENDs [Pop]/[Stack]/[Local]/[Ptr](c$) [Pop]/[Stack]/[Local]/[Ptr](c$) [Int] *@</H3>
- <H3>SENDs [String] [Pop]/[Stack]/[Local]/[Ptr](c$) [Int] *@</H3>
- <H3>SENDs [String] [String] [Int] *@</H3>
- <P>
- This command is the same as SEND, except for the second step. Instead of locating an object by ID, an object matching the given name is located. If more than one match is found, then each object has the steps applied individually, except that the stack entries are removed only once. Control switches to the first object affected. All objects affected get a task switch, in turn, before control returns to the original object.
- </P>
- <H3>SENDT [Stack]/[Local]/[Ptr](#) [Ptr] [Int] [Int]*@</H3>
- <P>Asserts: [Int] (last param) entries exist on stack</P>
- <P>Asserts: [Int] (third param) respresents a valid script id or zero</P>
- <P>Asserts: Parameter types have the proper, matching datatypes</P>
- <P>
- This is the same as SEND, except a pointer directly to the target function is provided. The first [Int] represents the id of the script being called- this is used simply to verify that the target object is running the right script. This can be a zero value to signify that any script type is valid- this is only valid if [Ptr] points to within a function library.
- </P><P>
- The second [Int] represents the number of function parameters on the stack. It is assumed that the parameters are all of the proper type and count- no automatic parameter (or return value) conversion is done.
- </P>
- <H3>SENDTs [Pop]/[Stack]/[Local]/[Ptr](c$) [Ptr] [Int] [Int]*@</H3>
- <H3>SENDTs [String] [Ptr] [Int] [Int]*@</H3>
- <P>Asserts: [Int] (last param) entries exist on stack</P>
- <P>Asserts: [Int] (third param) respresents a valid script id or zero</P>
- <P>Asserts: Parameter types have the proper, matching datatypes</P>
- <P>
- This is a combination of SENDs and SENDT. When searching for matching objects, only objects matching the given script id are 'found', unless the given script id is zero.
- </P>
- <H3 STYLE="background: yellow">SHIFTL [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">SHIFTL [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer value given, bitwise shifts left the amount of the second value, and stores the result back at the given location.</P>
- <H3 STYLE="background: yellow">SHIFTR [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">SHIFTR [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer value given, bitwise shifts right the amount of the second value, and stores the result back at the given location.</P>
- <H3 STYLE="background: yellow">STOF [Stack](S)</H3>
- <P>Asserts: Stack entry is a string value</P>
- <P>Converts the given string to a floating-point value in-place.</P>
- <H3 STYLE="background: yellow">STOI [Stack](S)</H3>
- <P>Asserts: Stack entry is a string value</P>
- <P>Converts the given string to an integer in-place.</P>
- <H3 STYLE="background: yellow">STOP *</H3>
- <P>Stop running entirely. The stack is cleared. Strings are freed, arrays and hashes are dereferenced, pointers to objects waiting on return values return an empty value, and waiting-for-reply pointers (type 130) modify the target 129 to be a NULL pointer. Control switches to the next object.</P>
- <H3 STYLE="background: yellow">STORE [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">STORE [Stack]/[Local]/[Ptr](#) [Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the given integer and stores it at the given location.</P>
- <H3 STYLE="background: yellow">STOREa [Stack]/[Local]/[Ptr](a) [Stack]/[Local]/[Ptr](a)</H3>
- <P>Asserts: Source and destination are of same array type</P>
- <P>Takes the given array and stores it at the given location, increasing reference count and dereferencing the array previously there. Use COPY if you wish to make a new copy and not potentially reference an existing array.</P>
- <H3 STYLE="background: yellow">STOREf [Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">STOREf [Stack]/[Local]/[Ptr](%) [Stack]/[Local]/[Ptr](%)</H3>
- <P>Takes the given floating-point value and stores it at the given location.</P>
- <H3 STYLE="background: yellow">STOREh [Stack]/[Local]/[Ptr](h) [Stack]/[Local]/[Ptr](h)</H3>
- <P>Asserts: Source and destination are of same hash type</P>
- <P>Takes the given hash and stores it at the given location, increasing reference count and dereferencing the hash previously there. Use COPY if you wish to make a new copy and not potentially reference an existing hash.</P>
- <H3 STYLE="background: yellow">STOREs [Stack]/[Local]/[Ptr]($) [String]</H3>
- <H3 STYLE="background: yellow">STOREs [Stack]/[Local]/[Ptr]($) [Stack]/[Local]/[Ptr](c$)</H3>
- <P>Takes the given string and copies it at the given location, freeing the string currently there.</P>
- <H3 STYLE="background: yellow">SUB [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">SUB [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer value given, subtracts the second value, and stores the result back at the given location.</P>
- <H3 STYLE="background: yellow">SUBf [Stack]/[Local]/[Ptr](%) [Float]</H3>
- <H3 STYLE="background: yellow">SUBf [Stack]/[Local]/[Ptr](%) [Pop]/[Stack]/[Local]/[Ptr](%)</H3>
- <P>Takes the floating-point value given, subtracts the second value, and stores the result back at the given location.</P>
- <H3>SUBR [Offset] @</H3>
- <H3>SUBR [Ptr](F) @</H3>
- <P>Asserts: Valid-looking opcode at given location</P>
- <P>
- Push the location of the next instruction onto the stack, then transfer code execution to the given location. Note that, when the code returns, the top stack location will always contain a return value.
- </P><P>
- Unlike other methods of accessing functions, this one assumes the proper number and type of operands have already been pushed onto the stack.
- </P>
- <H3>SUBRs [Stack]/[Local]/[Ptr]($) [Int] @</H3>
- <P>Asserts: [Int] entries exist on stack</P>
- <P>(note- ($) could become (c$) if more efficient)</P>
- <P>
- This calls a function by name, adjusting the parameters on the stack as needed. This opcode is not affected by queueing.
- </P>
- <P><UL>
- <LI>An attempt is made to locate a function by the name given for the second operand. (function libraries and built-in functions, as well as the current object, are searched; object state IS NOT taken into account and state functions are only accessible explicitly using :: syntax) If none is found, an undefined value is pushed onto the stack and nothing further occurs.
- <LI>A number of stack entries equal to the third operand are removed from the stack and remembered.
- <LI>A number of stack entries equal to the expected number of function parameters are pushed onto the stack. These entries will be derived and converted from the remembered entries, dropping (and dereferencing) any excess entries or creating empty entries if not enough were present.
- <LI>The location of the instruction that would normally run next is pushed onto the stack.
- <LI>Control switches to the given function.
- </UL></P>
- <P>
- Note that, when the code returns, the top stack location will always contain a return value, which may be undefined.
- </P>
- <H3>SWAP [Stack](S) [Stack](S)</H3>
- <P>Asserts: Source and destination are actual data, not code, object return pointers, or undefined</P>
- <P>Takes the given stack entry and swaps it with another stack entry. No copying, freeing, or referencing is required.</P>
- <H3>TYPEOF [Stack](S)</H3>
- <H3>TYPEOF [Local](S)</H3>
- <H3>TYPEOF [Global](G)</H3>
- <P>
- Examines the type of entry or variable at the given location, and pushes an integer value onto the stack representing what it is. The value pushed matches the type values used for stack entries- 1 for integer, 2 for floating point, 4 for string, +8 for array, +16 for hash, 0 for undefined, 128 for code pointer, 129 for return value pointer, and 130 for reply waiting pointer.
- </P>
- <H3>WAIT *</H3>
- <P>Asserts: At least one entry on the stack</P>
- <P>Asserts: Previous instruction is a QUERY variant</P>
- <P>
- The code pointer will remain at this opcode until the top entry of the stack is no longer a type 130 value. This causes the object to wait for a RET or REPLY value immediately after a QUERY command.
- </P>
- <H3 STYLE="background: yellow">XOR [Stack]/[Local]/[Ptr](#) [Int]</H3>
- <H3 STYLE="background: yellow">XOR [Stack]/[Local]/[Ptr](#) [Pop]/[Stack]/[Local]/[Ptr](#)</H3>
- <P>Takes the integer values given, performs a bitwise XOR, and stores the new value back at the given location.</P>
- <H1>6) Bytecode Compilation</H1>
- <P>
- This section describes how the GCSx language translates into bytecode.
- </P>
- <H2>6A) Notes on Global Variables, Constants, and Function Libraries</H2>
- <P>
- Globals and function libraries define things outside of the code that they are referenced in. This is handled as follows-
- </P><P>
- All non-library code is first scanned for global constant and variable declarations, then all code is compiled. Unrecognized identifiers are treated as function library calls. Any missing functions will be noted during linking.
- </P><P>
- During editing, modifying the code of any object that contains (or contained before editing) global declarations will cause a recompile of all objects. Modifying a function library does not require any recompilation.
- </P>
- <H2>6B) Notes on Stack Usage</H2>
- <P>
- Many operations and calculations require judicious usage of the stack for temporary storage. During compilation, the current amount of temporary storage being used is carefully tracked line-by-line, opcode-by-opcode. This space is freed up as soon as the operations are complete. Certain structures such as if-else require temporary storage to remain on the stack for an extended block of code; this storage is freed at the earliest possible opportunity. If a goto exists in such a block, the temporary storage must be freed before the goto. If a label exists in such a block, any goto going to that label must first fill the stack with appropriate values matching the expected amount of temporary storage.
- </P><P>
- The stack is also used for all local and scoped variables.
- </P>
|