diff options
| -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  | 
