diff options
author | Paul Gilbert | 2019-06-09 21:24:38 -0700 |
---|---|---|
committer | Paul Gilbert | 2019-06-10 19:08:58 -0700 |
commit | 75da8ddd06a08e26fd006ff0033ee911e5bd5411 (patch) | |
tree | 1b711a14fb371cf0e988720685577b70fcfe455d /engines/glk | |
parent | 8bb7c893f1bd7a884ef55e8a8213fd03889238ad (diff) | |
download | scummvm-rg350-75da8ddd06a08e26fd006ff0033ee911e5bd5411.tar.gz scummvm-rg350-75da8ddd06a08e26fd006ff0033ee911e5bd5411.tar.bz2 scummvm-rg350-75da8ddd06a08e26fd006ff0033ee911e5bd5411.zip |
GLK: ADVSYS: Subroutine call & return opcodes
Diffstat (limited to 'engines/glk')
-rw-r--r-- | engines/glk/advsys/vm.cpp | 47 | ||||
-rw-r--r-- | engines/glk/advsys/vm.h | 29 |
2 files changed, 53 insertions, 23 deletions
diff --git a/engines/glk/advsys/vm.cpp b/engines/glk/advsys/vm.cpp index 0e59fe34e0..ef943e620f 100644 --- a/engines/glk/advsys/vm.cpp +++ b/engines/glk/advsys/vm.cpp @@ -83,7 +83,7 @@ OpcodeMethod VM::_METHODS[0x34] = { }; VM::VM(OSystem *syst, const GlkGameDescription &gameDesc) : GlkInterface(syst, gameDesc), Game(), - _pc(0), _status(IN_PROGRESS) { + _pc(0), _fp(-1), _status(IN_PROGRESS) { } ExecutionResult VM::execute(int offset) { @@ -238,21 +238,46 @@ void VM::opPNUMBER() { } void VM::opFINISH() { + _status = FINISH; } void VM::opCHAIN() { + _status = CHAIN; } void VM::opABORT() { + _status = ABORT; } void VM::opEXIT() { + quitGame(); + _status = ABORT; } void VM::opRETURN() { + if (_stack.empty()) { + _status = CHAIN; + } else { + int val = _stack.top(); + _stack.resize(_fp); + _fp = _stack.pop(); + _pc = _stack.pop(); + + int varsSize = _stack.pop(); + _stack.resize(_stack.size() - varsSize); + _stack.top() = val; + } } void VM::opCALL() { + int varSize = readCodeByte(); + int topIndex = _stack.size() - 1; + + _stack.push(varSize); + _stack.push(_pc); + _stack.push(_fp); + _fp = _stack.size(); + _pc = getActionField(_stack[topIndex - varSize], A_CODE); } void VM::opSVAR() { @@ -311,6 +336,26 @@ void VM::opRNDMIZE() { } void VM::opSEND() { + int varSize = readCodeByte(); + int topIndex = _stack.size() - 1; + + _stack.push(varSize); + _stack.push(_pc); + _stack.push(_fp); + _fp = _stack.size(); + + int val = _stack[topIndex - varSize]; + if (val) + val = getObjectField(val, O_CLASS); + else + val = _stack[topIndex - varSize + 1]; + + if (val && (val = getObjectProperty(val, _stack[topIndex - varSize + 2])) != 0) { + _pc = getActionField(val, A_CODE); + } else { + // Return NIL if there's no action for the given message + opRETURN(); + } } void VM::opVOWEL() { diff --git a/engines/glk/advsys/vm.h b/engines/glk/advsys/vm.h index 9718b044f4..e5432d3f0a 100644 --- a/engines/glk/advsys/vm.h +++ b/engines/glk/advsys/vm.h @@ -25,7 +25,7 @@ #include "glk/advsys/glk_interface.h" #include "glk/advsys/game.h" -#include "common/array.h" +#include "common/stack.h" namespace Glk { namespace AdvSys { @@ -110,34 +110,19 @@ typedef void (VM::*OpcodeMethod)(); * Main VM for AdvSys */ class VM : public GlkInterface, public Game { - class ArrayStack : public Common::Array<int> { + class FixedStack : public Common::FixedStack<int, 500> { public: - /** - * Push a value onto the stack - */ - void push(int v) { - push_back(v); + void resize(size_t newSize) { + assert(newSize <= _size); + _size = newSize; } - - /** - * Pop a value from the stack - */ - int pop() { - int v = back(); - pop_back(); - return v; - } - - /** - * Returns the top of the stack (the most recently added value - */ - int &top() { return back(); } }; private: static OpcodeMethod _METHODS[0x34]; int _pc; ExecutionResult _status; - ArrayStack _stack; + FixedStack _stack; + int _fp; private: /** * Execute a single opcode within the script |