GLK: ADVSYS: Subroutine call & return opcodes

This commit is contained in:
Paul Gilbert 2019-06-09 21:24:38 -07:00
parent 8bb7c893f1
commit 75da8ddd06
2 changed files with 53 additions and 23 deletions

View File

@ -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() {

View File

@ -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