Type | Length | Description |
---|---|---|
Double | 8 | |
Int64 | 8 | |
Float | 4 | |
Int32 | 4 | |
Bool | 4 | True if 1, else false |
Int24 | 3 | |
Int16 | 2 | |
TypePair | 1 | Each type is 4-bit long |
String | 4 | Index of the string in the Strg chunk. |
The interpreter is stack-based. Data is pushed and popped from the stack.
When parsing a Variable, if the Type is VariableType.Array: the index is at the stack top and has to be popped, and is followed by the Int16 -5, which also has to be popped. When an array is pushed and the Dup instruction occurs, the index is also duplicated. When Pop's or Push's InstanceType is InstanceType.StackTopOrGlobal, if Type is VariableType.StackTop then one additional value, representing the instance, will be popped from the stack.
Each ReferenceDefinition has a pointer to memory address of the first instruction that accesses it. In the second block of the instruction, there is the offset (calculated in blocks, not bytes) to the next occurrence of the reference. Note that the Type of the reference can change between different instances of said reference; for instance in one case an array item can be accessed, while in case the same array is accessed as a whole. Functions don't have a Type, only the offset to the next occurrence.
Each instruction is composed of one or more 32-bit blocks. The most significant byte is the opcode.
For bytecode version 0xE, the opcode table is as follows:
The following is valid for version 0xF:
If you want to decompile the code in high level language, you'll have to do some structuring. Some graph theory is required to get good output. There are while, do..while, for loops and special Repeat statements (essentially For loops without declared variables); no improper loops, but breaks and continues. There are ifs, if..else's and switch..case's. Also considering that there are returns and exits, you'll have to heuristically simulate the stack and branch it when the control flow breaks. For any questions or if I've made mistakes, message me on Reddit.