aboutsummaryrefslogtreecommitdiff
path: root/engines/glk
diff options
context:
space:
mode:
authorPaul Gilbert2019-06-09 21:24:38 -0700
committerPaul Gilbert2019-06-10 19:08:58 -0700
commit75da8ddd06a08e26fd006ff0033ee911e5bd5411 (patch)
tree1b711a14fb371cf0e988720685577b70fcfe455d /engines/glk
parent8bb7c893f1bd7a884ef55e8a8213fd03889238ad (diff)
downloadscummvm-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.cpp47
-rw-r--r--engines/glk/advsys/vm.h29
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