aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/glk/advsys/advsys.h7
-rw-r--r--engines/glk/advsys/definitions.h1
-rw-r--r--engines/glk/advsys/game.h9
-rw-r--r--engines/glk/advsys/glk_interface.cpp30
-rw-r--r--engines/glk/advsys/glk_interface.h46
-rw-r--r--engines/glk/advsys/vm.cpp278
-rw-r--r--engines/glk/advsys/vm.h223
-rw-r--r--engines/glk/module.mk2
8 files changed, 591 insertions, 5 deletions
diff --git a/engines/glk/advsys/advsys.h b/engines/glk/advsys/advsys.h
index ea2558fa58..9aa1305415 100644
--- a/engines/glk/advsys/advsys.h
+++ b/engines/glk/advsys/advsys.h
@@ -24,8 +24,7 @@
#define GLK_ADVSYS_ADVSYS
#include "common/scummsys.h"
-#include "glk/glk_api.h"
-#include "glk/advsys/game.h"
+#include "glk/advsys/vm.h"
namespace Glk {
namespace AdvSys {
@@ -33,7 +32,7 @@ namespace AdvSys {
/**
* AdvSys game interpreter
*/
-class AdvSys : public GlkAPI, public Game {
+class AdvSys : public VM {
private:
winid_t _window;
private:
@@ -55,7 +54,7 @@ public:
/**
* Constructor
*/
- AdvSys(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc) {}
+ AdvSys(OSystem *syst, const GlkGameDescription &gameDesc) : VM(syst, gameDesc) {}
/**
* Run the game
diff --git a/engines/glk/advsys/definitions.h b/engines/glk/advsys/definitions.h
index 8c96a9ea0a..39e07ca3aa 100644
--- a/engines/glk/advsys/definitions.h
+++ b/engines/glk/advsys/definitions.h
@@ -26,7 +26,6 @@
namespace Glk {
namespace AdvSys {
-#define NIL 0
} // End of namespace AdvSys
} // End of namespace Glk
diff --git a/engines/glk/advsys/game.h b/engines/glk/advsys/game.h
index d74245b67c..40b4fb65ec 100644
--- a/engines/glk/advsys/game.h
+++ b/engines/glk/advsys/game.h
@@ -29,6 +29,8 @@
namespace Glk {
namespace AdvSys {
+#define NIL 0
+
/**
* Actions
*/
@@ -306,6 +308,13 @@ public:
}
/**
+ * Gets a code byte
+ */
+ int getCodeWord(int offset) const {
+ return READ_LE_UINT16(_codeSpace + offset);
+ }
+
+ /**
* Read a word
*/
int readWord(int offset) const {
diff --git a/engines/glk/advsys/glk_interface.cpp b/engines/glk/advsys/glk_interface.cpp
new file mode 100644
index 0000000000..3bc6800d0c
--- /dev/null
+++ b/engines/glk/advsys/glk_interface.cpp
@@ -0,0 +1,30 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/advsys/glk_interface.h"
+
+namespace Glk {
+namespace AdvSys {
+
+
+} // End of namespace AdvSys
+} // End of namespace Glk
diff --git a/engines/glk/advsys/glk_interface.h b/engines/glk/advsys/glk_interface.h
new file mode 100644
index 0000000000..58ff831509
--- /dev/null
+++ b/engines/glk/advsys/glk_interface.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GLK_ADVSYS_GLK_INTERFACE
+#define GLK_ADVSYS_GLK_INTERFACE
+
+#include "glk/glk_api.h"
+
+namespace Glk {
+namespace AdvSys {
+
+/**
+ * Interface class that sits between AdvSys and the GLK base, providing methods for
+ * input and output
+ */
+class GlkInterface : public GlkAPI {
+public:
+ /**
+ * Constructor
+ */
+ GlkInterface(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc) {}
+};
+
+} // End of namespace AdvSys
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/advsys/vm.cpp b/engines/glk/advsys/vm.cpp
new file mode 100644
index 0000000000..a467a592d2
--- /dev/null
+++ b/engines/glk/advsys/vm.cpp
@@ -0,0 +1,278 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "glk/advsys/vm.h"
+
+namespace Glk {
+namespace AdvSys {
+
+OpcodeMethod VM::_METHODS[0x34] = {
+ &VM::opBRT,
+ &VM::opBRF,
+ &VM::opBR,
+ &VM::opT,
+ &VM::opNIL,
+ &VM::opPUSH,
+ &VM::opNOT,
+ &VM::opADD,
+ &VM::opSUB,
+ &VM::opMUL,
+ &VM::opDIV,
+ &VM::opREM,
+ &VM::opBAND,
+ &VM::opBOR,
+ &VM::opBNOT,
+ &VM::opLT,
+ &VM::opEQ,
+ &VM::opGT,
+ &VM::opLIT,
+ &VM::opVAR,
+ &VM::opGETP,
+ &VM::opSETP,
+ &VM::opSET,
+ &VM::opPRINT,
+ &VM::opTERPRI,
+ &VM::opPNUMBER,
+ &VM::opFINISH,
+ &VM::opCHAIN,
+ &VM::opABORT,
+ &VM::opEXIT,
+ &VM::opRETURN,
+ &VM::opCALL,
+ &VM::opSVAR,
+ &VM::opSSET,
+ &VM::opSPLIT,
+ &VM::opSNLIT,
+ &VM::opYORN,
+ &VM::opSAVE,
+ &VM::opRESTORE,
+ &VM::opARG,
+ &VM::opASET,
+ &VM::opTMP,
+ &VM::opTSET,
+ &VM::opTSPACE,
+ &VM::opCLASS,
+ &VM::opMATCH,
+ &VM::opPNOUN,
+ &VM::opRESTART,
+ &VM::opRAND,
+ &VM::opRNDMIZE,
+ &VM::opSEND,
+ &VM::opVOWEL
+};
+
+VM::VM(OSystem *syst, const GlkGameDescription &gameDesc) : GlkInterface(syst, gameDesc), Game(),
+ _pc(0), _status(IN_PROGRESS) {
+}
+
+ExecutionResult VM::execute(int offset) {
+ // Set the code pointer
+ _pc = offset;
+
+ // Clear the stack
+ _stack.clear();
+
+ // Iterate through the script
+ for (_status = IN_PROGRESS; !shouldQuit() && _status == IN_PROGRESS; )
+ executeOpcode();
+
+ return _status;
+}
+
+void VM::executeOpcode() {
+ // Get next opcode
+ uint opcode = getCodeByte(_pc);
+ ++_pc;
+
+ if (opcode >= OP_BRT && opcode <= OP_VOWEL) {
+ (this->*_METHODS[(int)opcode - 1])();
+ } else if (opcode >= OP_XVAR && opcode < OP_XSET) {
+ _stack.back() = getVariable((int)opcode - OP_XVAR);
+ } else if (opcode >= OP_XSET && opcode < OP_XPLIT) {
+ setVariable((int)opcode - OP_XSET, _stack.back());
+ } else if (opcode >= OP_XPLIT && opcode < OP_XNLIT) {
+ _stack.back() = (int)opcode - OP_XPLIT;
+ } else if (opcode >= OP_XNLIT && (int)opcode < 256) {
+ _stack.back() = OP_XNLIT - opcode;
+ } else {
+ error("Unknown opcode %x at offset %d", opcode, _pc);
+ }
+}
+
+void VM::opBRT() {
+}
+
+void VM::opBRF() {
+}
+
+void VM::opBR() {
+}
+
+void VM::opT() {
+}
+
+void VM::opNIL() {
+}
+
+void VM::opPUSH() {
+}
+
+void VM::opNOT() {
+}
+
+void VM::opADD() {
+}
+
+void VM::opSUB() {
+}
+
+void VM::opMUL() {
+}
+
+void VM::opDIV() {
+}
+
+void VM::opREM() {
+}
+
+void VM::opBAND() {
+}
+
+void VM::opBOR() {
+}
+
+void VM::opBNOT() {
+}
+
+void VM::opLT() {
+}
+
+void VM::opEQ() {
+}
+
+void VM::opGT() {
+}
+
+void VM::opLIT() {
+}
+
+void VM::opVAR() {
+}
+
+void VM::opGETP() {
+}
+
+void VM::opSETP() {
+}
+
+void VM::opSET() {
+}
+
+void VM::opPRINT() {
+}
+
+void VM::opTERPRI() {
+}
+
+void VM::opPNUMBER() {
+}
+
+void VM::opFINISH() {
+}
+
+void VM::opCHAIN() {
+}
+
+void VM::opABORT() {
+}
+
+void VM::opEXIT() {
+}
+
+void VM::opRETURN() {
+}
+
+void VM::opCALL() {
+}
+
+void VM::opSVAR() {
+}
+
+void VM::opSSET() {
+}
+
+void VM::opSPLIT() {
+}
+
+void VM::opSNLIT() {
+}
+
+void VM::opYORN() {
+}
+
+void VM::opSAVE() {
+}
+
+void VM::opRESTORE() {
+}
+
+void VM::opARG() {
+}
+
+void VM::opASET() {
+}
+
+void VM::opTMP() {
+}
+
+void VM::opTSET() {
+}
+
+void VM::opTSPACE() {
+}
+
+void VM::opCLASS() {
+}
+
+void VM::opMATCH() {
+}
+
+void VM::opPNOUN() {
+}
+
+void VM::opRESTART() {
+}
+
+void VM::opRAND() {
+}
+
+void VM::opRNDMIZE() {
+}
+
+void VM::opSEND() {
+}
+
+void VM::opVOWEL() {
+}
+
+} // End of namespace AdvSys
+} // End of namespace Glk
diff --git a/engines/glk/advsys/vm.h b/engines/glk/advsys/vm.h
new file mode 100644
index 0000000000..84cd313961
--- /dev/null
+++ b/engines/glk/advsys/vm.h
@@ -0,0 +1,223 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GLK_ADVSYS_VM
+#define GLK_ADVSYS_VM
+
+#include "glk/advsys/glk_interface.h"
+#include "glk/advsys/game.h"
+#include "common/array.h"
+
+namespace Glk {
+namespace AdvSys {
+
+/**
+ * Execution result states
+ */
+enum ExecutionResult {
+ IN_PROGRESS = 0, ///< Default state whilst script is in progress
+ FINISH = 1, ///< Script was finished
+ CHAIN = 2, ///< Another script is being chained to
+ ABORT = 3 ///< Script was aborted
+};
+
+/**
+ * Opcode list
+ */
+enum Opcode {
+ OP_BRT = 0x01, ///< Branch on true
+ OP_BRF = 0x02, ///< Branch on false
+ OP_BR = 0x03, ///< Branch unconditionally
+ OP_T = 0x04, ///< Load top of stack with t
+ OP_NIL = 0x05, ///< Load top of stack with nil
+ OP_PUSH = 0x06, ///< Push nil onto stack
+ OP_NOT = 0x07, ///< Logical negate top of stack
+ OP_ADD = 0x08, ///< Add two numeric expressions
+ OP_SUB = 0x09, ///< Subtract two numeric expressions
+ OP_MUL = 0x0A, ///< Multiply two numeric expressions
+ OP_DIV = 0x0B, ///< Divide two numeric expressions
+ OP_REM = 0x0C, ///< Remainder of two numeric expressions
+ OP_BAND = 0x0D, ///< Bitwise and of two numeric expressions
+ OP_BOR = 0x0E, ///< Bitwise or of two numeric expressions
+ OP_BNOT = 0x0F, ///< Bitwise not
+ OP_LT = 0x10, ///< Less than
+ OP_EQ = 0x11, ///< Equal to
+ OP_GT = 0x12, ///< Greater than
+ OP_LIT = 0x13, ///< Load literal
+ OP_VAR = 0x14, ///< Load a variable value
+ OP_GETP = 0x15, ///< Get the value of an object property
+ OP_SETP = 0x16, ///< Set the value of an object property
+ OP_SET = 0x17, ///< Set the value of a variable
+ OP_PRINT = 0x18, ///< Print messages
+ OP_TERPRI = 0x19, ///< Terminate the print line
+ OP_PNUMBER = 0x1A, ///< Print a number
+ OP_FINISH = 0x1B, ///< Finish handling this command
+ OP_CHAIN = 0x1C, ///< Chain to the next handler
+ OP_ABORT = 0x1D, ///< Abort this command
+ OP_EXIT = 0x1E, ///< Exit the game
+ OP_RETURN = 0x1F, ///< Return from function
+ OP_CALL = 0x20, ///< Call subroutine
+ OP_SVAR = 0x21, ///< Short load a variable
+ OP_SSET = 0x22, ///< Short set a variable
+ OP_SPLIT = 0x23, ///< Short load a positive literal
+ OP_SNLIT = 0x24, ///< Short load a negative literal
+ OP_YORN = 0x25, ///< Yes or No predicate
+ OP_SAVE = 0x26, ///< Save data structures
+ OP_RESTORE = 0x27, ///< Restore data structures
+ OP_ARG = 0x28, ///< Load an argument value
+ OP_ASET = 0x29, ///< Set an argument value
+ OP_TMP = 0x2A, ///< Load a temporary variable value
+ OP_TSET = 0x2B, ///< Set a temporary variable
+ OP_TSPACE = 0x2C, ///< Allocate temporary variable space
+ OP_CLASS = 0x2D, ///< Get the class of an object
+ OP_MATCH = 0x2E, ///< Match a noun phrase with an object
+ OP_PNOUN = 0x2F, ///< Print a noun phrase
+ OP_RESTART = 0x30, ///< Restart the current game
+ OP_RAND = 0x31, ///< Generate a random number
+ OP_RNDMIZE = 0x32, ///< Seed the random number generator
+ OP_SEND = 0x33, ///< Send a message to an object
+ OP_VOWEL = 0x34, ///< Check for vowel beginning string
+
+ OP_XVAR = 0x40, ///< Extra short load a variable
+ OP_XSET = 0x60, ///< Extra short set a variable
+ OP_XPLIT = 0x80, ///< Extra short load a positive literal
+ OP_XNLIT = 0xC0 ///< Extra short load a negative literal
+};
+
+class VM;
+typedef void (VM::*OpcodeMethod)();
+
+/**
+ * Main VM for AdvSys
+ */
+class VM : public GlkInterface, public Game {
+ class ArrayStack : public Common::Array<int> {
+ public:
+ /**
+ * Push a value onto the stack
+ */
+ void push(int v) { push_back(v); }
+
+ /**
+ * Pop a value from the stack
+ */
+ int pop() {
+ int v = back();
+ pop_back();
+ return v;
+ }
+ };
+private:
+ static OpcodeMethod _METHODS[0x34];
+ int _pc;
+ ExecutionResult _status;
+ ArrayStack _stack;
+private:
+ /**
+ * Execute a single opcode within the script
+ */
+ void executeOpcode();
+
+ /**
+ * Get the next code byte and increments the PC counter
+ */
+ int readCodeByte() {
+ return getCodeByte(_pc++);
+ }
+
+ /**
+ * Gets the next code word and increases the PC counter to after it
+ */
+ int readCodeWord() {
+ return getCodeWord(_pc += 2);
+ }
+private:
+ void opBRT();
+ void opBRF();
+ void opBR();
+ void opT();
+ void opNIL();
+ void opPUSH();
+ void opNOT();
+ void opADD();
+ void opSUB();
+ void opMUL();
+ void opDIV();
+ void opREM();
+ void opBAND();
+ void opBOR();
+ void opBNOT();
+ void opLT();
+ void opEQ();
+ void opGT();
+ void opLIT();
+ void opVAR();
+ void opGETP();
+ void opSETP();
+ void opSET();
+ void opPRINT();
+ void opTERPRI();
+ void opPNUMBER();
+ void opFINISH();
+ void opCHAIN();
+ void opABORT();
+ void opEXIT();
+ void opRETURN();
+ void opCALL();
+ void opSVAR();
+ void opSSET();
+ void opSPLIT();
+ void opSNLIT();
+ void opYORN();
+ void opSAVE();
+ void opRESTORE();
+ void opARG();
+ void opASET();
+ void opTMP();
+ void opTSET();
+ void opTSPACE();
+ void opCLASS();
+ void opMATCH();
+ void opPNOUN();
+ void opRESTART();
+ void opRAND();
+ void opRNDMIZE();
+ void opSEND();
+ void opVOWEL();
+public:
+ /**
+ * Constructor
+ */
+ VM(OSystem *syst, const GlkGameDescription &gameDesc);
+
+ /**
+ * Exeecute a script
+ * @param offset Script offset
+ * @returns Script result code
+ */
+ ExecutionResult execute(int offset);
+};
+
+} // End of namespace AdvSys
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 827b5e4d78..b599f02fb9 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -28,6 +28,8 @@ MODULE_OBJS := \
advsys/advsys.o \
advsys/detection.o \
advsys/game.o \
+ advsys/glk_interface.o \
+ advsys/vm.o \
alan2/alan2.o \
alan2/decode.o \
alan2/detection.o \