Files
2026-10-03 13:05:59 +00:00

359 lines
11 KiB
C++

#pragma once
#include "common.h"
/**
* Opcodes of the script virtual machine, as vmcode_t::op holds them.
*/
// clang-format off
enum RS_OPCODE {
RS_OP_LOAD = 1, /**< Push a variable. */
RS_OP_LOAD_ADDR = 2, /**< Push a variable's address. */
RS_OP_PUSH_CONST = 3, /**< Push a constant. */
RS_OP_POP = 4, /**< Pop. */
RS_OP_STORE = 5, /**< Store. */
RS_OP_ADD = 6, /**< Add. */
RS_OP_SUB = 7, /**< Subtract. */
RS_OP_MUL = 8, /**< Multiply. */
RS_OP_DIV = 9, /**< Divide. */
RS_OP_MOD = 10, /**< Remainder. */
RS_OP_NEG = 11, /**< Negate. */
RS_OP_ITOF = 12, /**< Integer to float. */
RS_OP_FTOI = 13, /**< Float to integer. */
RS_OP_CMP = 14, /**< Compare. */
RS_OP_RET = 15, /**< Return. */
RS_OP_JMP = 16, /**< Jump. */
RS_OP_JMP_FALSE = 17, /**< Jump if false. */
RS_OP_JMP_TRUE = 18, /**< Jump if true. */
RS_OP_CALL = 19, /**< Call. */
RS_OP_PRINT = 20, /**< Print. */
RS_OP_EXT = 21, /**< Call an external function. */
RS_OP_WAIT = 23, /**< Wait. */
RS_OP_AND = 24, /**< Logical and. */
RS_OP_OR = 25, /**< Logical or. */
RS_OP_NOT = 26, /**< Logical not. */
RS_OP_END = 27, /**< End. */
RS_OP_SKIP_END = 28, /**< Clear the skip wait. */
RS_OP_SIN = 29, /**< Sine. */
RS_OP_COS = 30, /**< Cosine. */
};
// clang-format on
/**
* How a script load addresses its variable, as vmcode_t::arg2 holds it.
*/
// clang-format off
enum RS_ADDR_MODE {
RS_ADDR_LOCAL = 1, /**< Local slot. */
RS_ADDR_LOCAL_INDEX = 2, /**< Indexed local slot. */
RS_ADDR_POINTER_INDEX = 4, /**< Indexed through a pointer. */
RS_ADDR_LOCAL_FLOAT = 8, /**< Local slot, as a float. */
RS_ADDR_LOCAL_INDEX_FLOAT = 16, /**< Indexed local slot, as a float. */
RS_ADDR_POINTER_INDEX_FLOAT = 32, /**< Indexed through a pointer, as a float. */
};
// clang-format on
/**
* Comparisons of the script compare opcode, as vmcode_t::arg1 holds them.
*/
// clang-format off
enum RS_COMPARE {
RS_CMP_EQ = 40, /**< Equal. */
RS_CMP_NE = 41, /**< Not equal. */
RS_CMP_LT = 42, /**< Less than. */
RS_CMP_LE = 43, /**< Less than or equal. */
RS_CMP_GT = 44, /**< Greater than. */
RS_CMP_GE = 45, /**< Greater than or equal. */
};
// clang-format on
/**
* A tagged value stored on the script interpreter's operand stack.
*/
struct RS_STACKDATA {
int type; /**< Identifies the active value representation. */
union {
int i; /**< Value of an integer. */
float f; /**< Value of a float. */
char *s; /**< Value of a string. */
RS_STACKDATA *p; /**< Stack slot a reference points at. */
};
};
enum {
RS_INT = 0,
RS_FLOAT = 1,
RS_STR = 2,
RS_PTR = 3
};
/**
* A single virtual-machine instruction and its two opcode-specific operands.
*/
struct vmcode_t {
int op; /**< Selects the operation to execute. @see RS_OPCODE. */
int arg1; /**< Supplies the operation's first operand. */
int arg2; /**< Supplies the operation's second operand. */
};
/**
* Describes a script function's code position and stack-frame requirements.
*/
struct funcdata {
int addr; /**< Stores the function's offset in the code block. */
char *name; /**< Names the function for runtime diagnostics. */
int local; /**< Gives the total number of frame slots. */
int arg; /**< Gives the number of argument slots. */
};
/**
* Preserves interpreter state for a suspended script call.
*/
struct RS_CALLDATA {
vmcode_t *ret; /**< Points to the caller's return instruction. */
RS_STACKDATA *frame; /**< Points to the caller's stack frame. */
funcdata *func; /**< Describes the caller's function. */
};
/**
* Maps an external program number to its function description.
*/
struct RS_PROGDATA {
int no; /**< Identifies the externally selectable program. */
int func; /**< Stores the function-description offset. */
};
/**
* Describes the offset-based sections of a compiled script program.
*/
struct RS_PROG_HEADER {
int unk_0;
int main; /**< Stores the main function-description offset. */
int code; /**< Stores the bytecode-section offset. */
int prog; /**< Stores the program-table offset. */
int prog_num; /**< Gives the number of program-table entries. */
};
/**
* Runs one compiled script on a stack machine, suspending at its waits.
*/
class CRunScript {
public:
int ext_func_num; /**< Gives the number of registered external functions. */
int (**ext_func_table)(RS_STACKDATA *, int); /**< Points to the external function table. */
int stack_num; /**< Gives the operand stack capacity. */
RS_STACKDATA *stack; /**< Points to the operand stack storage. */
RS_STACKDATA *sp; /**< Points to the next operand stack slot. */
RS_STACKDATA *stack_end; /**< Points one past the operand stack storage. */
int call_num; /**< Gives the call stack capacity. */
RS_CALLDATA *call; /**< Points to the call stack storage. */
RS_CALLDATA *call_sp; /**< Points to the next call stack entry. */
RS_CALLDATA *call_end; /**< Points one past the call stack storage. */
RS_STACKDATA *frame; /**< Points to the active operand frame. */
funcdata *func; /**< Describes the active script function. */
vmcode_t *pc; /**< Points to the next instruction. */
int end; /**< Records whether execution has completed. */
int skip_wait; /**< Records whether wait operations should be skipped. */
RS_PROG_HEADER *prog; /**< Points to the loaded program header. */
char *code; /**< Points to the loaded bytecode section. */
int result; /**< Stores the script's return value. */
/**
* Nonzero once the script has run to its end.
*/
int IsEnd() { return end; }
/**
* Makes an interpreter with no program, stack or external functions.
*
* @mangled __ct__10CRunScriptFv
* @address 0x23D940
* @size 0x40
*/
CRunScript();
/**
* Stops the game when the operand stack is full.
*
* @mangled check_stack__10CRunScriptFv
* @address 0x23D980
* @size 0x34
* @unknownret
*/
void check_stack();
/**
* Pushes one value onto the operand stack.
*
* @mangled push__10CRunScriptF12RS_STACKDATA
* @address 0x23D9C0
* @size 0x50
* @unknownret
*/
void push(RS_STACKDATA value);
/**
* Pushes an integer onto the operand stack.
*
* @mangled push_int__10CRunScriptFi
* @address 0x23DA10
* @size 0x50
* @unknownret
*/
void push_int(int value);
/**
* Pushes a string onto the operand stack.
*
* @mangled push_str__10CRunScriptFPc
* @address 0x23DA60
* @size 0x54
* @unknownret
*/
void push_str(char *string);
/**
* Pushes a reference to a stack slot onto the operand stack.
*
* @mangled push_ptr__10CRunScriptFP12RS_STACKDATA
* @address 0x23DAC0
* @size 0x54
* @unknownret
*/
void push_ptr(RS_STACKDATA *pointer);
/**
* Pushes a float onto the operand stack.
*
* @mangled push_float__10CRunScriptFf
* @address 0x23DB20
* @size 0x54
* @unknownret
*/
void push_float(float value);
/**
* Pops the top value off the operand stack.
*
* @mangled pop__10CRunScriptFv
* @address 0x23DB80
* @size 0x24
* @unknownret
*/
RS_STACKDATA pop();
/**
* Enters a script function, and gives back its first instruction.
*
* @mangled call_func__10CRunScriptFP8funcdataP8vmcode_t
* @address 0x23DBB0
* @size 0x108
* @unknownret
*/
vmcode_t *call_func(funcdata *callee, vmcode_t *return_pc);
/**
* Leaves the current script function, and gives back the caller's instruction.
*
* @mangled ret_func__10CRunScriptFv
* @address 0x23DCC0
* @size 0x34
* @unknownret
*/
vmcode_t *ret_func();
/**
* Calls the external function the first argument names.
*
* @mangled ext__10CRunScriptFP12RS_STACKDATAi
* @address 0x23DD00
* @size 0xB4
* @unknownret
*/
void ext(RS_STACKDATA *args, int argc);
/**
* Gives the interpreter a program and the stacks to run it on.
*
* @mangled load__10CRunScriptFP14RS_PROG_HEADERP12RS_STACKDATAiP11RS_CALLDATAi
* @address 0x23DDC0
* @size 0x50
* @unknownret
*/
void load(RS_PROG_HEADER *prog, RS_STACKDATA *stack, int stack_num, RS_CALLDATA *call, int call_num);
/**
* Swaps in another program, keeping the stacks.
*
* @mangled reload__10CRunScriptFP14RS_PROG_HEADER
* @address 0x23DE10
* @size 0x18
* @unknownret
*/
void reload(RS_PROG_HEADER *prog);
/**
* Registers the table of external functions scripts can call.
*
* @mangled ext_func__10CRunScriptFPPFP12RS_STACKDATAi_ii
* @address 0x23DE30
* @size 0x10
* @unknownret
*/
void ext_func(int (**table)(RS_STACKDATA *, int), int count);
/**
* Continues a suspended script where it stopped.
*
* @mangled resume__10CRunScriptFv
* @address 0x23DE40
* @size 0x2C
* @unknownret
*/
void resume();
/**
* Starts a numbered program, or the main function for a negative number.
*
* @mangled run__10CRunScriptFi
* @address 0x23DE70
* @size 0x180
* @unknownret
*/
int run(int no);
/**
* Reports whether the program has a numbered entry.
*
* @mangled check_program__10CRunScriptFi
* @address 0x23DFF0
* @size 0x54
* @unknownret
*/
int check_program(int no);
/**
* Resumes the script, running through its waits.
*
* @mangled skip__10CRunScriptFv
* @address 0x23E050
* @size 0x28
* @unknownret
*/
void skip();
/**
* Runs instructions from one until the script ends or waits.
*
* @mangled exe__10CRunScriptFP8vmcode_t
* @address 0x23E080
* @size 0x1508
* @unknownret
*/
void exe(vmcode_t *entry);
};