[Scummvm-git-logs] scummvm master -> 1be46e9207450cdb626e81a2d0347c50577020fc

bluegr bluegr at gmail.com
Fri Dec 28 12:41:47 CET 2018


This automated email contains information about 9 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
91490c27ad GLK: ALAN2: Initial work on the Alan2 subengine
c6d6f8de0a GLK: ALAN2: Fix compilation
d96f9428b3 GLK: ALAN2: Formatting fixes
1abd4bb907 GLK: ALAN2: Indentation fixes
aa8bcac233 GLK: Fix namespace comments
1c055f686e GLK: ALAN2: Move comments to header files
d42cbfde9e GLK: ALAN2: Adapt C-style enums and align comments
20d53d27f6 GLK: ALAN2: Adapt C-style enums / structs
1be46e9207 GLK: ALAN2: Cleanup, merge some functions, move comments to headers


Commit: 91490c27adfde5f41b21bb2f3a6f648aab4270d0
    https://github.com/scummvm/scummvm/commit/91490c27adfde5f41b21bb2f3a6f648aab4270d0
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2018-12-28T13:41:39+02:00

Commit Message:
GLK: ALAN2: Initial work on the Alan2 subengine

Changed paths:
  A engines/glk/alan2/acode.h
  A engines/glk/alan2/decode.cpp
  A engines/glk/alan2/decode.h
  A engines/glk/alan2/execute.cpp
  A engines/glk/alan2/execute.h
  A engines/glk/alan2/interpreter.cpp
  A engines/glk/alan2/interpreter.h
  A engines/glk/alan2/parse.cpp
  A engines/glk/alan2/parse.h
  A engines/glk/alan2/rules.cpp
  A engines/glk/alan2/rules.h
  A engines/glk/alan2/saveload.cpp
  A engines/glk/alan2/saveload.h
  A engines/glk/alan2/types.h
  A engines/glk/alan2/util.h
    engines/glk/alan2/alan2.cpp
    engines/glk/alan2/alan2.h
    engines/glk/module.mk


diff --git a/engines/glk/alan2/acode.h b/engines/glk/alan2/acode.h
new file mode 100644
index 0000000..764eb19
--- /dev/null
+++ b/engines/glk/alan2/acode.h
@@ -0,0 +1,289 @@
+/* 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_ALAN2_ACODE
+#define GLK_ALAN2_ACODE
+
+#include "common/scummsys.h"
+
+namespace Glk {
+namespace Alan2 {
+
+typedef size_t Aptr;			// Type for an ACODE memory address
+typedef uint32 Aword;		   // Type for an ACODE word
+typedef uint32 Aaddr;		   // Type for an ACODE address
+typedef uint32 Abool;		   // Type for an ACODE Boolean value
+typedef int32 Aint;			 // Type for an ACODE Integer value
+typedef int CodeValue;		  // Definition for the packing process
+
+// Constants for the Acode file, words/block & bytes/block
+#define BLOCKLEN 256L
+#define BLOCKSIZE (BLOCKLEN*sizeof(Aword))
+
+
+// Definitions for the packing process
+#define VALUEBITS 16
+
+#define EOFChar 256
+#define TOPVALUE (((CodeValue)1<<VALUEBITS) - 1) // Highest value possible 
+
+// Half and quarter points in the code value range 
+#define ONEQUARTER (TOPVALUE/4+1)	// Point after first quarter 
+#define HALF (2*ONEQUARTER)		// Point after first half 
+#define THREEQUARTER (3*ONEQUARTER)	// Point after third quarter 
+
+
+// AMACHINE Word Classes 
+typedef int WrdKind;
+#define  WRD_SYN 0		// 1 - Synonym 
+#define  WRD_ADJ 1		// 2 - Adjective 
+#define  WRD_ALL 2		// 4 - All 
+#define  WRD_BUT 3		// 8 - But 
+#define  WRD_CONJ 4		// 16 - Conjunction 
+#define  WRD_PREP 5		// 32 - Preposition 
+#define  WRD_DIR 6		// 64 - Direction 
+#define  WRD_IT 7		// 128 - It 
+#define  WRD_NOISE 8		// 256 - Noise word 
+#define  WRD_NOUN 9		// 512 - Noun 
+#define  WRD_ACT 10		// 1024 - Actor 
+#define  WRD_THEM 11		// 2048 - Them 
+#define  WRD_VRB 12		// 4096 - Verb 
+#define  WRD_CLASSES 13
+
+
+
+// Syntax element classifications 
+#define EOS (-2)		// End Of Syntax 
+
+// Syntax element flag bits 
+#define MULTIPLEBIT 0x1
+#define OMNIBIT 0x2
+
+
+// Parameter Classes 
+typedef enum ClaKind {		// NOTE! These must have the same order as 
+	CLA_OBJ = 1,			// the name classes in NAM.H 
+	CLA_CNT = (int)CLA_OBJ<<1,
+	CLA_ACT = (int)CLA_CNT<<1,
+	CLA_NUM = (int)CLA_ACT<<1,
+	CLA_STR = (int)CLA_NUM<<1,
+	CLA_COBJ = (int)CLA_STR<<1,
+	CLA_CACT = (int)CLA_COBJ<<1
+} ClaKind;
+	
+
+// Verb Qualifiers 
+typedef enum QualClass {
+	Q_DEFAULT,
+	Q_AFTER,
+	Q_BEFORE,
+	Q_ONLY
+} QualClass;
+
+
+// The AMACHINE Operations 
+typedef enum OpClass {
+	C_CONST,
+	C_STMOP,
+	C_CURVAR
+} OpClass;
+
+typedef enum InstClass {
+	I_PRINT,			// Print a string from the text file 
+	I_QUIT,
+	I_LOOK,
+	I_SAVE,
+	I_RESTORE,
+	I_LIST,			// List contents of a container 
+	I_EMPTY,
+	I_SCORE,
+	I_VISITS,
+	I_SCHEDULE,
+	I_CANCEL,
+	I_LOCATE,
+	I_MAKE,
+	I_SET,			// Set a numeric attribute to the 
+				// value on top of stack 
+	I_STRSET,			// Set a string valued attribute to a 
+				// copy of the string on top of stack, 
+				// deallocate current contents first 
+	I_GETSTR,			// Get a string contents from text 
+				// file, create a copy and push it 
+				// on top of stack 
+	I_INCR,			// Increment an attribute 
+	I_DECR,			// Decrement a numeric attribute 
+	I_USE,
+	I_IN,
+	I_DESCRIBE,
+	I_SAY,
+	I_SAYINT,
+	I_SAYSTR,
+	I_IF,
+	I_ELSE,
+	I_ENDIF,
+	I_ATTRIBUTE,
+	I_STRATTR,			// Push a copy of a string attribute 
+	I_HERE,
+	I_NEAR,
+	I_WHERE,
+	I_AND,
+	I_OR,
+	I_NE,
+	I_EQ,
+	I_STREQ,			// String compare 
+	I_STREXACT,
+	I_LE,
+	I_GE,
+	I_LT,
+	I_GT,
+	I_PLUS,
+	I_MINUS,
+	I_MULT,
+	I_DIV,
+	I_NOT,
+	I_UMINUS,
+	I_RND,
+	I_SUM,			// SUM-aggregate 
+	I_MAX,			// MAX-aggregate 
+	I_COUNT,			// COUNT-aggregate 
+	I_RETURN,
+	I_SYSTEM,
+	I_RESTART,			// INTRODUCED: v2.7 
+	I_BTW,			// INTRODUCED: v2.8 
+	I_CONTAINS,			//  -""-  
+	I_DEPSTART,			//  -""-  
+	I_DEPCASE,			//  -""-  
+	I_DEPEXEC,			//  -""-  
+	I_DEPELSE,			//  -""-  
+	I_DEPEND			//  -""-  
+} InstClass;
+
+
+typedef enum VarClass {
+	V_PARAM,
+	V_CURLOC,
+	V_CURACT,
+	V_CURVRB,
+	V_SCORE
+} VarClass;
+
+
+#define I_CLASS(x) ((x)>>28)
+#define I_OP(x)	((x&0x8000000)?(x)|0x0f0000000:(x)&0x0fffffff)
+
+
+typedef struct AcdHdr {
+// Important info 
+	char vers[4];			// 01 - Version of compiler 
+	Aword size;			// 02 - Size of ACD-file in Awords 
+// Options 
+	Abool pack;			// 03 - Is the text packed ? 
+	Aword paglen;			// 04 - Length of a page 
+	Aword pagwidth;		// 05 - and width 
+	Aword debug;			// 06 - Option debug 
+// Data structures 
+	Aaddr dict;			// 07 - Dictionary 
+	Aaddr oatrs;			// 08 - Object default attributes 
+	Aaddr latrs;			// 09 - Location default attributes 
+	Aaddr aatrs;			// 0a - Actor default attributes 
+	Aaddr acts;			// 0b - Actor table 
+	Aaddr objs;			// 0c - Object table 
+	Aaddr locs;			// 0d - Location table 
+	Aaddr stxs;			// 0e - Syntax table 
+	Aaddr vrbs;			// 0f - Verb table 
+	Aaddr evts;			// 10 - Event table 
+	Aaddr cnts;			// 11 - Container table 
+	Aaddr ruls;			// 12 - Rule table 
+	Aaddr init;			// 13 - String init table 
+	Aaddr start;			// 14 - Start code 
+	Aword msgs;			// 15 - Messages table 
+// Miscellaneous 
+	Aword objmin, objmax;		// 16 - Interval for object codes 
+	Aword actmin, actmax;		// 18 - Interval for actor codes 
+	Aword cntmin, cntmax;		// 1a - Interval for container codes 
+	Aword locmin, locmax;		// 1c - Interval for location codes 
+	Aword dirmin, dirmax;		// 1e - Interval for direction codes 
+	Aword evtmin, evtmax;		// 20 - Interval for event codes 
+	Aword rulmin, rulmax;		// 22 - Interval for rule codes 
+	Aword maxscore;		// 24 - Maximum score 
+	Aaddr scores;			// 25 - Score table 
+	Aaddr freq;			// 26 - Address to Char freq's for coding 
+	Aword acdcrc;			// 27 - Checksum for acd code (excl. hdr) 
+	Aword txtcrc;			// 28 - Checksum for text data file 
+} AcdHdr;
+
+// Error message numbers 
+typedef enum MsgKind {
+	M_HUH,			// Obsolete 
+	M_WHAT,
+	M_WHAT_ALL,
+	M_WHAT_IT,
+	M_WHAT_THEM,
+	M_MULTIPLE,
+	M_WANT,
+	M_NOUN,
+	M_AFTER_BUT,
+	M_BUT_ALL,
+	M_NOT_MUCH,
+	M_WHICH_ONE,
+	M_NO_SUCH,
+	M_NO_WAY,
+	M_CANT0,
+	M_CANT,
+	M_NOTHING,			// Obsolete 
+	M_SEEOBJ1,
+	M_SEEOBJ2,
+	M_SEEOBJ3,
+	M_SEEOBJ4,
+	M_SEEACT,
+	M_CONTAINS1,
+	M_CONTAINS2,
+	M_CONTAINS3,
+	M_CONTAINS4,
+	M_CONTAINS5,
+	M_EMPTY1,
+	M_EMPTY2,
+	M_SCORE1,
+	M_SCORE2,
+	M_UNKNOWN_WORD,
+	M_MORE,
+	M_AGAIN,
+	M_SAVEWHERE,
+	M_SAVEOVERWRITE,
+	M_SAVEFAILED,
+	M_SAVEMISSING,
+	M_SAVEVERS,
+	M_SAVENAME,
+	M_RESTOREFROM,
+	M_REALLY,			// CHANGED: v2.7 from M_RESTART 
+	M_QUITACTION,			// INTRODUCED: v2.7, so M_ARTICLE moved 
+	M_ARTICLE,			// INTRODUCED: v2.6 but replaced the M_NOMSG
+	MSGMAX
+} MsgKind;
+
+#define M_ARTICLE26 M_QUITACTION
+#define M_MSGMAX26 M_ARTICLE
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
+
+#endif
diff --git a/engines/glk/alan2/alan2.cpp b/engines/glk/alan2/alan2.cpp
index 3869e34..c29a124 100644
--- a/engines/glk/alan2/alan2.cpp
+++ b/engines/glk/alan2/alan2.cpp
@@ -21,6 +21,10 @@
  */
 
 #include "glk/alan2/alan2.h"
+#include "glk/alan2/decode.h"
+#include "glk/alan2/execute.h"
+#include "glk/alan2/interpreter.h"
+#include "glk/alan2/saveload.h"
 #include "common/config-manager.h"
 #include "common/translation.h"
 #include "common/error.h"
@@ -32,14 +36,24 @@
 namespace Glk {
 namespace Alan2 {
 
+Alan2 *_vm = nullptr;
 
 Alan2::Alan2(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
 		vm_exited_cleanly(false) {
+	_vm = this;
 }
 
 void Alan2::runGame(Common::SeekableReadStream *gameFile) {
 	_gameFile = gameFile;
 
+	// TODO: Initialize these properly
+	int tmp = 0;
+	Common::String gameFileName;
+	_decode = new Decode(nullptr, nullptr);
+	_execute = new Execute();
+	_saveLoad = new SaveLoad(gameFileName, nullptr, nullptr, nullptr, nullptr, &tmp);
+	_interpreter = new Interpreter(_execute, _saveLoad, _stack);
+
 	if (!is_gamefile_valid())
 		return;
 
@@ -70,5 +84,32 @@ bool Alan2::is_gamefile_valid() {
 	return true;
 }
 
+void Alan2::output(const Common::String str)
+{
+	// TODO
+}
+
+void Alan2::printMessage(MsgKind msg)
+{
+	// TODO
+}
+
+void Alan2::printError(MsgKind msg)
+{
+	// TODO
+}
+
+void Alan2::paragraph()
+{
+	if (col != 1)
+		newLine();
+	newLine();
+}
+
+void Alan2::newLine()
+{
+	// TODO
+}
+
 } // End of namespace Alan2
 } // End of namespace Glk
diff --git a/engines/glk/alan2/alan2.h b/engines/glk/alan2/alan2.h
index f451551..716e198 100644
--- a/engines/glk/alan2/alan2.h
+++ b/engines/glk/alan2/alan2.h
@@ -26,10 +26,20 @@
 #include "common/scummsys.h"
 #include "common/stack.h"
 #include "glk/glk_api.h"
+#include "glk/alan2/acode.h"
+#include "glk/alan2/types.h"
 
 namespace Glk {
 namespace Alan2 {
 
+typedef Common::FixedStack<Aptr, 100> Alan2Stack;
+class Decode;
+class Execute;
+class Interpreter;
+class SaveLoad;
+
+#define N_EVTS 100
+
 /**
  * Alan2 game interpreter
  */
@@ -67,8 +77,65 @@ public:
 	 * Save the game to the passed stream
 	 */
 	virtual Common::Error saveGameData(strid_t file, const Common::String &desc) override;
+
+	/**
+	 * Output a string to the screen
+	 */
+	void output(const Common::String str);
+
+	/**
+	 * Print a message from the message table
+	 */
+	void printMessage(MsgKind msg);
+
+	/**
+	 * Print an error from the message table, force new player input and abort
+	 */
+	void printError(MsgKind msg);
+
+	/**
+	 * Make a new paragraph, i.e one empty line (one or two newlines)
+	 */
+	void paragraph();
+
+	/**
+	 * Print the the status line on the top of the screen
+	 */
+	void statusLine();
+
+	/**
+	 * Make a newline, but check for screen full
+	 */
+	void newLine();
+
+	// Engine variables
+	Alan2Stack *_stack;
+	int pc;
+	ParamElem *params;
+	Aword *memory;	// The Amachine memory
+	int memTop;		// Top of memory
+	CurVars cur;	// Amachine variables
+	int col;
+	bool fail;
+	int scores[100];	// FIXME: type + size
+	AcdHdr *header;
+	bool _needSpace;		// originally "needsp"
+
+	EvtElem *evts;					// Event table pointer
+	bool looking = false;			// LOOKING? flag
+	int dscrstkp = 0;               // Describe-stack pointer
+	Common::File *_txtFile;
+	bool _anyOutput;
+	winid_t _bottomWindow;
+
+	Decode *_decode;
+	Execute *_execute;
+	Interpreter *_interpreter;
+	SaveLoad *_saveLoad;
 };
 
+extern Alan2 *_vm;
+
 } // End of namespace Alan2
 } // End of namespace Glk
 
diff --git a/engines/glk/alan2/decode.cpp b/engines/glk/alan2/decode.cpp
new file mode 100644
index 0000000..ba14412
--- /dev/null
+++ b/engines/glk/alan2/decode.cpp
@@ -0,0 +1,124 @@
+/* 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/alan2/decode.h"
+
+namespace Glk {
+namespace Alan2 {
+
+int Decode::inputBit() {
+	int bit;
+
+	if (!_bitsToGo) {		// More bits available ?
+		_decodeBuffer = _txtFile->readByte(); // No, so get more
+		if (_txtFile->eos()) {
+			_garbageBits++;
+
+			if (_garbageBits > VALUEBITS - 2)
+				error("Error in encoded data file.");
+		} else
+			_bitsToGo = 8;		// Another Char, 8 new bits
+	}
+
+	bit = _decodeBuffer & 1;			// Get next bit
+	_decodeBuffer = _decodeBuffer >> 1; // and remove it
+	_bitsToGo--;
+
+	return bit;
+}
+
+void Decode::startDecoding() {
+	_bitsToGo = 0;
+	_garbageBits = 0;
+
+	_value = 0;
+	for (int i = 0; i < VALUEBITS; i++)
+		_value = 2 * _value + inputBit();
+
+	_low = 0;
+	_high = TOPVALUE;
+}
+
+int Decode::decodeChar() {
+	const long range = (long)(_high - _low) + 1;
+	const int f = (((long)(_value - _low) + 1) * _freq[0] - 1) / range;
+	int symbol;
+
+	// Find the symbol
+	for (symbol = 1; _freq[symbol] > f; symbol++);
+
+	_high = _low + range * _freq[symbol - 1] / _freq[0] - 1;
+	_low = _low + range * _freq[symbol] / _freq[0];
+
+	for (;;) {
+		if (_high < HALF) {
+			// Do nothing
+		} else if (_low >= HALF) {
+			_value = _value - HALF;
+			_low = _low - HALF;
+			_high = _high - HALF;
+		} else if (_low >= ONEQUARTER && _high < THREEQUARTER) {
+			_value = _value - ONEQUARTER;
+			_low = _low - ONEQUARTER;
+			_high = _high - ONEQUARTER;
+		} else
+			break;
+
+		// Scale up the range
+		_low = 2 * _low;
+		_high = 2 * _high + 1;
+		_value = 2 * _value + inputBit();
+	}
+
+	return symbol - 1;
+}
+
+// Save so much about the decoding process, so it is possible to restore
+// and continue later.
+DecodeInfo* Decode::pushDecode() {
+	DecodeInfo *info = new DecodeInfo();
+
+	info->fpos = _txtFile->pos();
+	info->buffer = _decodeBuffer;
+	info->bits = _bitsToGo;
+	info->value = _value;
+	info->high = _high;
+	info->low = _low;
+
+	return info;
+}
+
+// Restore enough info about the decoding process, so it is possible to
+// continue after having decoded something else
+void Decode::popDecode (DecodeInfo *info){
+	_txtFile->seek(info->fpos, SEEK_CUR);
+	_decodeBuffer = info->buffer;
+	_bitsToGo = info->bits;
+	_value = info->value;
+	_high = info->high;
+	_low = info->low;
+
+	delete info;
+}
+
+} // End of namespace Alan2
+} // End of namespace Glk
diff --git a/engines/glk/alan2/decode.h b/engines/glk/alan2/decode.h
new file mode 100644
index 0000000..fff6819
--- /dev/null
+++ b/engines/glk/alan2/decode.h
@@ -0,0 +1,70 @@
+/* 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_ALAN2_DECODE
+#define GLK_ALAN2_DECODE
+
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/acode.h"
+#include "common/file.h"
+
+namespace Glk {
+namespace Alan2 {
+
+// Structure for saved decode info
+typedef struct DecodeInfo {
+	long fpos;
+	int buffer;
+	int bits;
+	CodeValue value;
+	CodeValue high;
+	CodeValue low;
+} DecodeInfo;
+
+class Decode
+{
+public:
+	Decode(Common::File *txtFile, Aword *freq): _txtFile(txtFile), _freq(freq) {}
+	void startDecoding();
+	int decodeChar();
+	DecodeInfo *pushDecode();
+	void popDecode(DecodeInfo *info);
+	int inputBit();
+
+private:
+	// Bit output
+	int _decodeBuffer;	// Bits to be input
+	int _bitsToGo;		// Bits still in buffer
+	int _garbageBits;	// Bits past EOF
+
+	Aword *_freq;
+	Common::File *_txtFile;
+
+	// Current state of decoding
+	CodeValue _value;			// Currently seen code value
+	CodeValue _low, _high;		// Current code region
+};
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
+
+#endif
diff --git a/engines/glk/alan2/execute.cpp b/engines/glk/alan2/execute.cpp
new file mode 100644
index 0000000..5b81b30
--- /dev/null
+++ b/engines/glk/alan2/execute.cpp
@@ -0,0 +1,1065 @@
+/* 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 "common/stack.h"
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/execute.h"
+#include "glk/alan2/interpreter.h"
+#include "glk/alan2/saveload.h"
+#include "glk/alan2/types.h"
+#include "glk/alan2/util.h"
+#include "common/debug.h"
+#include "common/file.h"
+#include "decode.h"
+
+namespace Glk {
+namespace Alan2 {
+
+#define WIDTH 80
+
+// Is there an exit from one location to another ?
+bool Execute::exitto(int to, int from) {
+	if (_locs[from - LOCMIN].exts == 0)
+		return false; // No exits
+
+	for (ExtElem *ext = (ExtElem *)addrTo(_locs[from - LOCMIN].exts); !endOfTable(ext); ext++)
+		if (ext->next == to)
+			return true;
+
+	return false;
+}
+
+/*
+ * Count the number of items in a container.
+ * 
+ * @param cnt	The container to count
+ */
+int Execute::count(int cnt) {
+	int j = 0;
+
+	for (int i = OBJMIN; i <= OBJMAX; i++)
+		if (in(i, cnt))
+			j++;	// Then it's in this container also
+
+	return j;
+}
+
+/*
+ * Sum the values of one attribute in a container.Recursively.
+ * 
+ * @param atr	The attribute to sum over
+ * @param cnt	the container to sum
+ */
+int Execute::sumatr(Aword atr, Aword cnt) {
+	int sum = 0;
+
+	for (int i = OBJMIN; i <= OBJMAX; i++) {
+		if (_objs[i - OBJMIN].loc == cnt) {	// Then it's in this container
+			if (_objs[i - OBJMIN].cont != 0)	// This is also a container!
+				sum = sum + sumatr(atr, i);
+			sum = sum + attribute(i, atr);
+		}
+	}
+
+	return sum;
+}
+
+/**
+ * Checks if a limit for a container is exceeded.
+ * 
+ * @param cnt	Container code
+ * @param obj	The object to add
+ */
+// 
+bool Execute::checklim(Aword cnt, Aword obj) {
+	LimElem *lim;
+	Aword props;
+
+	_vm->fail = true;
+	if (!isCnt(cnt))
+		error("Checking limits for a non-container.");
+
+	// Find the container properties
+	if (isObj(cnt))
+		props = _objs[cnt - OBJMIN].cont;
+	else if (isAct(cnt))
+		props = _acts[cnt - ACTMIN].cont;
+	else
+		props = cnt;
+
+
+	if (_cnts[props - CNTMIN].lims != 0) { /* Any limits at all? */
+		for (lim = (LimElem *)addrTo(_cnts[props - CNTMIN].lims); !endOfTable(lim); lim++) {
+			if (lim->atr == 0) {
+				if (count(cnt) >= lim->val) {
+					_vm->_interpreter->interpret(lim->stms);
+					return true;		// Limit check failed
+				}
+			} else {
+				if (sumatr(lim->atr, cnt) + attribute(obj, lim->atr) > lim->val) {
+					_vm->_interpreter->interpret(lim->stms);
+					return true;
+				}
+			}
+		}
+	}
+
+	_vm->fail = false;
+
+	return false;
+}
+
+void Execute::print(Aword fpos, Aword len) {
+	char str[2 * WIDTH];          // String buffer
+	int outlen = 0;               // Current output length
+	int ch;
+	int i;
+	long savfp;                   // Temporary saved text file position
+	bool printFlag = false; // Printing already?
+	bool savedPrintFlag = printFlag;
+	DecodeInfo *info;                   // Saved decoding info
+
+
+	if (len == 0)
+		return;
+
+	if (isHere(HERO)) {           // Check if the player will see it
+		if (printFlag) {            // Already printing?
+			// Save current text file position and/or decoding info
+			if (_vm->header->pack)
+				info = _vm->_decode->pushDecode();
+			else
+				savfp = _vm->_txtFile->pos();
+		}
+
+		printFlag = true;           // We're printing now!
+		_vm->_txtFile->seek(fpos, SEEK_CUR);	// Position to start of text
+		if (_vm->header->pack)
+			_vm->_decode->startDecoding();
+
+		for (outlen = 0; outlen != len; outlen = outlen + strlen(str)) {
+			// Fill the buffer from the beginning
+			for (i = 0; i <= WIDTH || (i > WIDTH && ch != ' '); i++) {
+				if (outlen + i == len)  // No more characters?
+					break;
+				if (_vm->header->pack)
+					ch = _vm->_decode->decodeChar();
+				else
+					ch = _vm->_txtFile->readSByte();
+				if (ch == EOFChar)      // Or end of text?
+					break;
+				str[i] = ch;
+			}
+
+			str[i] = '\0';
+
+			// TODO
+	/*
+#if ISO == 0
+      fromIso(str, str);
+#endif
+	*/
+			_vm->output(str);
+		}
+
+		// And restore
+		printFlag = savedPrintFlag;
+		if (printFlag) {
+			if (_vm->header->pack)
+				_vm->_decode->popDecode(info);
+			else
+				_vm->_txtFile->seek(savfp, SEEK_CUR);
+		}
+	}
+}
+
+void Execute::sys(Aword fpos, Aword len) {
+	char *command;
+
+	getstr(fpos, len);            // Returns address to string on stack
+	command = (char *)_vm->_stack->pop();
+
+	warning("Request to execute system command %s", command);
+	free(command);
+}
+
+void Execute::getstr(Aword fpos, Aword len) {
+	char *buf = new char[len + 1];
+
+	_vm->_stack->push((Aptr) buf);            // Push the address to the string
+	_vm->_txtFile->seek(fpos, SEEK_CUR);	// Position to start of text
+	if (_vm->header->pack)
+		_vm->_decode->startDecoding();
+	while (len--) {
+		if (_vm->header->pack)
+			*(buf++) = _vm->_decode->decodeChar();
+		else
+			*(buf++) = _vm->_txtFile->readSByte();
+	}
+	*buf = '\0';
+}
+
+void Execute::score(Aword sc) {
+	char buf[80];
+
+	if (sc == 0) {
+		_vm->printMessage(M_SCORE1);
+		sprintf(buf, "%d", _vm->cur.score);
+		_vm->output(buf);
+		_vm->printMessage(M_SCORE2);
+		sprintf(buf, "%ld.", (unsigned long)_vm->header->maxscore);
+		_vm->output(buf);
+	} else {
+		_vm->cur.score += _vm->scores[sc - 1];
+		_vm->scores[sc - 1] = 0;
+	}
+}
+
+void Execute::visits(Aword v) {
+	_vm->cur.visits = v;
+}
+
+bool Execute::confirm(MsgKind msgno) {
+	char buf[80];
+
+	// This is a bit of a hack since we really want to compare the input,
+    // it could be affirmative, but for now any input is NOT!
+	_vm->printMessage(msgno);
+
+	// TODO
+#if 0
+	//_vm->glk_request_line_event(_bottomWindow, buf, 80 - 1, 0);
+
+#ifdef USE_READLINE
+	if (!readline(buf)) return true;
+#else
+	if (gets(buf) == NULL) return true;
+#endif
+
+#endif
+	_vm->col = 1;
+
+	return (buf[0] == '\0');
+}
+
+
+void Execute::quit() {
+	char buf[80];
+	char choices[10];
+
+	_vm->paragraph();
+	while (true) {
+		_vm->col = 1;
+	    _vm->statusLine();
+	    _vm->printMessage(M_QUITACTION);
+
+		// TODO
+#if 0
+#ifdef USE_READLINE
+    if (!readline(buf)) terminate(0);
+#else
+    if (gets(buf) == NULL) terminate(0);
+#endif
+#endif
+
+	if (strcmp(buf, "restart") == 0) {
+		//longjmp(restart_label, true);	// TODO
+	} else if (strcmp(buf, "restore") == 0) {
+		_vm->_saveLoad->restore();
+		return;
+	} else if (strcmp(buf, "quit") == 0) {
+		_vm->quitGame();
+	}
+  }
+  error("Fallthrough in QUIT");
+}
+
+void Execute::restart() {
+	_vm->paragraph();
+	if (confirm(M_REALLY)) {
+		//longjmp(restart_label, true);	// TODO
+	} else
+		return;
+
+	error("Fallthrough in RESTART");
+}
+
+/*----------------------------------------------------------------------
+  eventchk()
+
+  Check if any events are pending. If so execute them.
+  */
+
+void Execute::eventchk() {
+	while (etop != 0 && eventq[etop - 1].time == _vm->cur.tick) {
+		etop--;
+		if (isLoc(eventq[etop].where))
+			_vm->cur.loc = eventq[etop].where;
+		else
+			_vm->cur.loc = where(eventq[etop].where);
+
+		// TODO
+#if 0
+		if (trcflg) {
+			debug("\n<EVENT %d (at ", eventq[etop].event);
+			debugsay(_vm->cur.loc);
+			debug("):>\n");
+		}
+#endif
+		_vm->_interpreter->interpret(_vm->evts[eventq[etop].event - EVTMIN].code);
+	}
+}
+
+void Execute::cancl(Aword evt) {
+	int i;
+
+	for (i = etop - 1; i >= 0; i--) {
+		if (eventq[i].event == evt) {
+			while (i < etop - 1) {
+				eventq[i].event = eventq[i + 1].event;
+				eventq[i].time = eventq[i + 1].time;
+				eventq[i].where = eventq[i + 1].where;
+				i++;
+			}
+
+			etop--;
+			return;
+		}
+	}
+}
+
+void Execute::schedule(Aword evt, Aword whr, Aword aft) {
+	int i;
+	int time;
+  
+	cancl(evt);
+	// Check for overflow
+	if (etop == N_EVTS)
+		error("Out of event space.");
+  
+	time = _vm->cur.tick+aft;
+  
+	// Bubble this event down
+	for (i = etop; i >= 1 && eventq[i-1].time <= time; i--) {
+	    eventq[i].event = eventq[i-1].event;
+	    eventq[i].time = eventq[i-1].time;
+	    eventq[i].where = eventq[i-1].where;
+	}
+  
+	eventq[i].time = time;
+	eventq[i].where = whr;
+	eventq[i].event = evt;
+	etop++;
+}
+
+/**
+ * Get an attribute value from an attribute list
+ * 
+ * @param atradr	ACODE address to attribute table
+ * @param atr		The attribute to read
+ */
+Aptr Execute::getatr(Aaddr atradr, Aaddr atr) {
+	AtrElem *at = (AtrElem *) addrTo(atradr);
+	return at[atr-1].val;
+}
+
+/**
+ * Set a particular attribute to a value.
+ *
+ * @param atradr	ACODE address to attribute table
+ * @param atr		Attribute code
+ * @param val		New value
+ */
+void Execute::setatr(Aaddr atradr, Aword atr, Aword val) {
+	AtrElem *at = (AtrElem *) addrTo(atradr);
+	at[atr-1].val = val;
+}
+
+void Execute::makloc(Aword loc, Aword atr, Aword val) {
+	setatr(_locs[loc - LOCMIN].atrs, atr, val);
+}
+
+void Execute::makobj(Aword obj, Aword atr, Aword val) {
+	setatr(_objs[obj - OBJMIN].atrs, atr, val);
+}
+
+void Execute::makact(Aword act, Aword atr, Aword val) {
+	setatr(_acts[act - ACTMIN].atrs, atr, val);
+}
+
+void Execute::make(Aword id, Aword atr, Aword val) {
+	if (isObj(id))
+	    makobj(id, atr, val);
+	else if (isLoc(id))
+		makloc(id, atr, val);
+	else if (isAct(id))
+	    makact(id, atr, val);
+	else
+	    error("Can't MAKE item (%ld).", (unsigned long)id);
+}
+
+void Execute::setloc(Aword loc, Aword atr, Aword val) {
+	setatr(_locs[loc - LOCMIN].atrs, atr, val);
+	_locs[loc - LOCMIN].describe = 0;
+}
+
+void Execute::setobj(Aword obj, Aword atr, Aword val) {
+	setatr(_objs[obj - OBJMIN].atrs, atr, val);
+}
+
+void Execute::setact(Aword act, Aword atr, Aword val) {
+	setatr(_acts[act - ACTMIN].atrs, atr, val);
+}
+
+void Execute::set(Aword id, Aword atr, Aword val) {
+	if (isObj(id))
+		setobj(id, atr, val);
+	else if (isLoc(id))
+		setloc(id, atr, val);
+	else if (isAct(id))
+	    setact(id, atr, val);
+	else
+	  error("Can't SET item (%ld).", (unsigned long)id);
+}
+
+void Execute::setstr(Aword id, Aword atr, Aword str) {
+	free((char *)attribute(id, atr));
+	set(id, atr, str);
+}
+
+/**
+ * Increment a particular attribute by a value.
+ * 
+ * @param atradr	ACODE address to attribute table
+ * @param atr		Attribute code
+ * @param step		Step to increment by
+ */
+void Execute::incratr(Aaddr atradr, Aword atr, Aword step) {
+	AtrElem *at = (AtrElem *) addrTo(atradr);
+	at[atr-1].val += step;
+}
+
+void Execute::incrloc(Aword loc, Aword atr, Aword step) {
+	incratr(_locs[loc - LOCMIN].atrs, atr, step);
+	_locs[loc - LOCMIN].describe = 0;
+}
+
+void Execute::incrobj(Aword obj, Aword atr, Aword step) {
+	incratr(_objs[obj - OBJMIN].atrs, atr, step);
+}
+
+void Execute::incract(Aword act, Aword atr, Aword step) {
+	incratr(_acts[act - ACTMIN].atrs, atr, step);
+}
+
+void Execute::incr(Aword id, Aword atr, Aword step) {
+	if (isObj(id))
+		incrobj(id, atr, step);
+	else if (isLoc(id))
+		incrloc(id, atr, step);
+	else if (isAct(id))
+		incract(id, atr, step);
+	else
+		error("Can't INCR item (%ld).", (unsigned long)id);
+}
+
+void Execute::decr(Aword id, Aword atr, Aword step) {
+	if (isObj(id))
+		incrobj(id, atr, -step);
+	else if (isLoc(id))
+	    incrloc(id, atr, -step);
+	else if (isAct(id))
+		incract(id, atr, -step);
+	else
+		error("Can't DECR item (%ld).", (unsigned long)id);
+}
+
+Aptr Execute::locatr(Aword loc, Aword atr) {
+	return getatr(_locs[loc - LOCMIN].atrs, atr);
+}
+
+Aptr Execute::objatr(Aword obj, Aword atr) {
+	return getatr(_objs[obj - OBJMIN].atrs, atr);
+}
+
+Aptr Execute::actatr(Aword act, Aword atr) {
+	return getatr(_acts[act - ACTMIN].atrs, atr);
+}
+
+Aptr Execute::litatr(Aword lit, Aword atr) {
+	if (atr == 1)
+		return litValues[lit - LITMIN].value;
+	else
+		error("Unknown attribute for literal (%ld).", (unsigned long) atr);
+}
+
+Aptr Execute::attribute(Aword id, Aword atr) {
+	if (isObj(id))
+		return objatr(id, atr);
+	else if (isLoc(id))
+	    return locatr(id, atr);
+	else if (isAct(id))
+	    return actatr(id, atr);
+	else if (isLit(id))
+	    return litatr(id, atr);
+	else
+	    error("Can't ATTRIBUTE item (%ld).", (unsigned long) id);
+}
+
+Aptr Execute::strattr(Aword id, Aword atr) {
+	Common::String result = (char *)attribute(id, atr);
+	return (Aptr)result.c_str();
+}
+
+Aword Execute::objloc(Aword obj) {
+	if (isCnt(_objs[obj - OBJMIN].loc)) { // In something ?
+		if (isObj(_objs[obj - OBJMIN].loc) || isAct(_objs[obj - OBJMIN].loc))
+			return(where(_objs[obj - OBJMIN].loc));
+		else // Containers not anywhere is where the hero is!
+			return(where(HERO));
+	} else {
+		return(_objs[obj - OBJMIN].loc);
+	}
+}
+
+Aword Execute::actloc(Aword act) {
+	return(_acts[act - ACTMIN].loc);
+}
+
+Aword Execute::where(Aword id) {
+	if (isObj(id))
+		return objloc(id);
+	else if (isAct(id))
+		return actloc(id);
+	else
+		error("Can't WHERE item (%ld).", (unsigned long) id);
+}
+
+Aint Execute::agrmax(Aword atr, Aword whr) {
+	Aword i;
+	Aint max = 0;
+
+	for (i = OBJMIN; i <= OBJMAX; i++) {
+		if (isLoc(whr)) {
+			if (where(i) == whr && attribute(i, atr) > max)
+				max = attribute(i, atr);
+		} else if (_objs[i - OBJMIN].loc == whr && attribute(i, atr) > max)
+			max = attribute(i, atr);
+	}
+
+	return(max);
+}
+
+Aint Execute::agrsum(Aword atr, Aword whr) {
+	Aword i;
+	Aint sum = 0;
+
+	for (i = OBJMIN; i <= OBJMAX; i++) {
+		if (isLoc(whr)) {
+			if (where(i) == whr)
+				sum += attribute(i, atr);
+		} else if (_objs[i-OBJMIN].loc == whr)
+			sum += attribute(i, atr);
+	}
+
+	return(sum);
+}
+
+Aint Execute::agrcount(Aword whr) {
+	Aword i;
+	Aword count = 0;
+
+	for (i = OBJMIN; i <= OBJMAX; i++) {
+		if (isLoc(whr)) {
+			if (where(i) == whr)
+				count++;
+		} else if (_objs[i-OBJMIN].loc == whr)
+			count++;
+	}
+
+	return(count);
+}
+
+void Execute::locobj(Aword obj, Aword whr) {
+	if (isCnt(whr)) { // Into a container
+		if (whr == obj)
+			error("Locating something inside itself.");
+		if (checklim(whr, obj))
+			return;
+		else
+			_objs[obj-OBJMIN].loc = whr;
+	} else {
+		_objs[obj-OBJMIN].loc = whr;
+		// Make sure the location is described since it's changed
+		_locs[whr-LOCMIN].describe = 0;
+	}
+}
+
+void Execute::locact(Aword act, Aword whr) {
+	Aword prevact = _vm->cur.act;
+	Aword prevloc = _vm->cur.loc;
+
+	_vm->cur.loc = whr;
+	_acts[act - ACTMIN].loc = whr;
+
+	if (act == HERO) {
+		if (_locs[_acts[act - ACTMIN].loc-LOCMIN].describe % (_vm->cur.visits+1) == 0)
+			look();
+		else {
+			if (_vm->_anyOutput)
+				_vm->paragraph();
+
+			say(where(HERO));
+			_vm->printMessage(M_AGAIN);
+			_vm->newLine();
+			dscrobjs();
+			dscracts();
+		}
+
+		_locs[where(HERO)-LOCMIN].describe++;
+		_locs[where(HERO)-LOCMIN].describe %= (_vm->cur.visits+1);
+	} else
+		_locs[whr-LOCMIN].describe = 0;
+
+	if (_locs[_vm->cur.loc-LOCMIN].does != 0) {
+		_vm->cur.act = act;
+		_vm->_interpreter->interpret(_locs[_vm->cur.loc-LOCMIN].does);
+		_vm->cur.act = prevact;
+	}
+
+	if (_vm->cur.act != act)
+		_vm->cur.loc = prevloc;
+}
+
+
+void Execute::locate(Aword id, Aword whr) {
+	if (isObj(id))
+		locobj(id, whr);
+	else if (isAct(id))
+	    locact(id, whr);
+	else
+		error("Can't LOCATE item (%ld).", (unsigned long) id);
+}
+
+Abool Execute::objhere(Aword obj) {
+	if (isCnt(_objs[obj - OBJMIN].loc)) {    // In something?
+		if (isObj(_objs[obj - OBJMIN].loc) || isAct(_objs[obj - OBJMIN].loc))
+			return(isHere(_objs[obj - OBJMIN].loc));
+		else // If the container wasn't anywhere, assume where HERO is!
+			return(where(HERO) == _vm->cur.loc);
+	} else
+		return(_objs[obj - OBJMIN].loc == _vm->cur.loc);
+}
+
+Aword Execute::acthere(Aword act) {
+	return _acts[act - ACTMIN].loc == _vm->cur.loc;
+}
+
+Abool Execute::isHere(Aword id) {
+	if (isObj(id))
+		return objhere(id);
+	else if (isAct(id))
+		return acthere(id);
+	else
+		error("Can't HERE item (%ld).", (unsigned long)id);
+}
+
+Aword Execute::objnear(Aword obj) {
+	if (isCnt(_objs[obj-OBJMIN].loc)) {    // In something?
+		if (isObj(_objs[obj-OBJMIN].loc) || isAct(_objs[obj-OBJMIN].loc))
+			return(isNear(_objs[obj-OBJMIN].loc));
+		else  // If the container wasn't anywhere, assume here, so not nearby!
+			return(false);
+	} else {
+		return(exitto(where(obj), _vm->cur.loc));
+	}
+}
+
+Aword Execute::actnear(Aword act) {
+	return(exitto(where(act), _vm->cur.loc));
+}
+
+
+Abool Execute::isNear(Aword id) {
+	if (isObj(id))
+		return objnear(id);
+	else if (isAct(id))
+		return actnear(id);
+	else
+	    error("Can't NEAR item (%ld).", (unsigned long) id);
+}
+
+Abool Execute::in(Aword obj, Aword cnt) {
+	if (!isObj(obj))
+		return(false);
+	if (!isCnt(cnt))
+		error("IN in a non-container.");
+
+	return(_objs[obj - OBJMIN].loc == cnt);
+}
+
+void Execute::sayloc(Aword loc) {
+	_vm->_interpreter->interpret(_locs[loc - LOCMIN].nams);
+}
+
+void Execute::sayobj(Aword obj) {
+	_vm->_interpreter->interpret(_objs[obj - OBJMIN].dscr2);
+}
+
+void Execute::sayact(Aword act) {
+	_vm->_interpreter->interpret(_acts[act - ACTMIN].nam);
+}
+
+void Execute::sayint(Aword val) {
+	char buf[25];
+
+	if (isHere(HERO)) {
+		sprintf(buf, "%ld", (unsigned long) val);
+		_vm->output(buf);
+	}
+}
+
+void Execute::saystr(char *str) {
+	if (isHere(HERO))
+		_vm->output(str);
+	free(str);
+}
+
+void Execute::saylit(Aword lit) {
+	if (isNum(lit))
+		sayint(litValues[lit - LITMIN].value);
+	else {
+		Common::String str = (char *)litValues[lit - LITMIN].value;
+		saystr((char *)str.c_str());
+	}
+}
+
+void Execute::sayarticle(Aword id) {
+	if (!isObj(id))
+		error("Trying to say article of something *not* an object.");
+	if (_objs[id - OBJMIN].art != 0)
+		_vm->_interpreter->interpret(_objs[id - OBJMIN].art);
+	else
+		_vm->printMessage(M_ARTICLE);
+}
+
+void Execute::say(Aword id) {
+	if (isHere(HERO)) {
+		if (isObj(id))
+			sayobj(id);
+		else if (isLoc(id))
+			sayloc(id);
+		else if (isAct(id))
+			sayact(id);
+		else if (isLit(id))
+			saylit(id);
+		else
+			error("Can't SAY item (%ld).", (unsigned long)id);
+	}
+}
+
+void Execute::dscrloc(Aword loc) {
+	if (_locs[loc - LOCMIN].dscr != 0)
+		_vm->_interpreter->interpret(_locs[loc - LOCMIN].dscr);
+}
+
+void Execute::dscrobj(Aword obj) {
+	_objs[obj - OBJMIN].describe = false;
+	if (_objs[obj - OBJMIN].dscr1 != 0)
+		_vm->_interpreter->interpret(_objs[obj - OBJMIN].dscr1);
+	else {
+		_vm->printMessage(M_SEEOBJ1);
+		sayarticle(obj);
+		say(obj);
+		_vm->printMessage(M_SEEOBJ4);
+		if (_objs[obj - OBJMIN].cont != 0)
+			list(obj);
+	}
+}
+
+
+void Execute::dscract(Aword act) {
+	ScrElem *scr = NULL;
+
+	if (_acts[act - ACTMIN].script != 0) {
+		for (scr = (ScrElem *) addrTo(_acts[act - ACTMIN].scradr); !endOfTable(scr); scr++)
+			if (scr->code == _acts[act - ACTMIN].script)
+				break;
+		if (endOfTable(scr))
+			scr = NULL;
+	}
+
+	if (scr != NULL && scr->dscr != 0)
+		_vm->_interpreter->interpret(scr->dscr);
+	else if (_acts[act - ACTMIN].dscr != 0)
+		_vm->_interpreter->interpret(_acts[act - ACTMIN].dscr);
+	else {
+		_vm->_interpreter->interpret(_acts[act - ACTMIN].nam);
+		_vm->printMessage(M_SEEACT);
+	}
+
+	_acts[act - ACTMIN].describe = false;
+}
+
+void Execute::describe(Aword id) {
+	for (int i = 0; i < _describeStack.size(); i++) {
+		_describeStack.push(id);
+
+		if (isObj(id))
+			dscrobj(id);
+		else if (isLoc(id))
+			dscrloc(id);
+		else if (isAct(id))
+			dscract(id);
+		else
+			error("Can't DESCRIBE item (%ld).", (unsigned long)id);
+	}
+
+	_describeStack.pop();
+}
+
+void Execute::use(Aword act, Aword scr) {
+	if (!isAct(act))
+		error("Item is not an Actor (%ld).", (unsigned long) act);
+
+	_acts[act - ACTMIN].script = scr;
+	_acts[act - ACTMIN].step = 0;
+}
+
+void Execute::list(Aword cnt) {
+	int i;
+	Aword props;
+	Aword prevobj;
+	bool found = false;
+	bool multiple = false;
+
+	// Find container properties
+	if (isObj(cnt))
+		props = _objs[cnt-OBJMIN].cont;
+	else if (isAct(cnt))
+		props = _acts[cnt-ACTMIN].cont;
+	else
+		props = cnt;
+
+	for (i = OBJMIN; i <= OBJMAX; i++) {
+		if (in(i, cnt)) { // Yes, it's in this container
+			if (!found) {
+				found = true;
+				if (_cnts[props-CNTMIN].header != 0)
+					_vm->_interpreter->interpret(_cnts[props-CNTMIN].header);
+				else {
+					_vm->printMessage(M_CONTAINS1);
+					if (_cnts[props-CNTMIN].nam != 0) // It has it's own name
+						_vm->_interpreter->interpret(_cnts[props-CNTMIN].nam);
+					else
+						say(_cnts[props-CNTMIN].parent); // It is actually an object or actor
+
+					_vm->printMessage(M_CONTAINS2);
+				}
+			} else {
+				if (multiple) {
+					_vm->_needSpace = false;
+					_vm->printMessage(M_CONTAINS3);
+				}
+
+				multiple = true;
+				sayarticle(prevobj);
+				say(prevobj);
+			}
+
+			prevobj = i;
+		}
+	}
+
+	if (found) {
+		if (multiple)
+			_vm->printMessage(M_CONTAINS4);
+
+		sayarticle(prevobj);
+		say(prevobj);
+		_vm->printMessage(M_CONTAINS5);
+	} else {
+		if (_cnts[props-CNTMIN].empty != 0)
+			_vm->_interpreter->interpret(_cnts[props-CNTMIN].empty);
+		else {
+			_vm->printMessage(M_EMPTY1);
+
+			if (_cnts[props-CNTMIN].nam != 0) // It has it's own name
+				_vm->_interpreter->interpret(_cnts[props-CNTMIN].nam);
+			else
+				say(_cnts[props-CNTMIN].parent);	// It is actually an actor or object
+
+			_vm->printMessage(M_EMPTY2);
+		}
+	}
+
+	_vm->_needSpace = true;
+}
+
+void Execute::empty(Aword cnt, Aword whr) {
+	for (int i = OBJMIN; i <= OBJMAX; i++)
+		if (in(i, cnt))
+			locate(i, whr);
+}
+
+// Description of current location
+void Execute::dscrobjs() {
+	int i;
+	int prevobj;
+	bool found = false;
+	bool multiple = false;
+
+	// First describe everything here with its own description
+	for (i = OBJMIN; i <= OBJMAX; i++) {
+		if (_objs[i - OBJMIN].loc == _vm->cur.loc &&
+			_objs[i - OBJMIN].describe &&
+			_objs[i - OBJMIN].dscr1)
+			describe(i);
+	}
+
+	// Then list everything else here
+	for (i = OBJMIN; i <= OBJMAX; i++) {
+		if (_objs[i - OBJMIN].loc == _vm->cur.loc &&
+			_objs[i - OBJMIN].describe) {
+			if (!found) {
+				_vm->printMessage(M_SEEOBJ1);
+				sayarticle(i);
+				say(i);
+				found = true;
+			}
+			else {
+				if (multiple) {
+					_vm->_needSpace = false;
+					_vm->printMessage(M_SEEOBJ2);
+					sayarticle(prevobj);
+					say(prevobj);
+				}
+
+				multiple = true;
+			}
+
+			prevobj = i;
+		}
+	}
+
+	if (found) {
+		if (multiple) {
+			_vm->printMessage(M_SEEOBJ3);
+			sayarticle(prevobj);
+			say(prevobj);
+		}
+
+		_vm->printMessage(M_SEEOBJ4);
+	}
+  
+	// Set describe flag for all objects
+	for (i = OBJMIN; i <= OBJMAX; i++)
+		_objs[i-OBJMIN].describe = true;
+}
+
+
+void Execute::dscracts() {
+	for (int i = HERO+1; i <= ACTMAX; i++)
+		if (_acts[i-ACTMIN].loc == _vm->cur.loc &&
+			_acts[i-ACTMIN].describe)
+			describe(i);
+
+	// Set describe flag for all actors
+	for (int i = HERO; i <= ACTMAX; i++)
+		_acts[i-ACTMIN].describe = true;
+}
+
+void Execute::look() {
+	int i;
+	_vm->looking = true;
+
+	// Set describe flag for all objects and actors
+	for (i = OBJMIN; i <= OBJMAX; i++)
+		_objs[i-OBJMIN].describe = true;
+	for (i = ACTMIN; i <= ACTMAX; i++)
+		_acts[i-ACTMIN].describe = true;
+
+	if (_vm->_anyOutput)
+		_vm->paragraph();
+
+	//glk_set_style(style_Subheader);	// TODO
+	_vm->_needSpace = false;
+	say(_vm->cur.loc);
+
+	_vm->_needSpace = false;
+	_vm->output(".");
+
+	//glk_set_style(style_Normal);	// TODO
+	_vm->newLine();
+	_vm->_needSpace = false;
+	describe(_vm->cur.loc);
+	dscrobjs();
+	dscracts();
+	_vm->looking = false;
+}
+
+Aword Execute::rnd(Aword from, Aword to) {
+	if (to == from)
+		return to;
+	else if (to > from)
+		return to;	// TODO
+		//return (rand()/10)%(to-from+1)+from;
+	else
+		return to;	// TODO
+		//return (rand()/10)%(from-to+1)+to;
+}
+
+// Between
+Abool Execute::btw(Aint val, Aint low, Aint high) {
+  if (high > low)
+    return low <= val && val <= high;
+  else
+    return high <= val && val <= low;
+}
+
+// TODO: Replace this with Common::String functionality
+Aword Execute::contains(Aptr string, Aptr substring) {
+	Common::String str = (char *)string;
+	char *substr = (char *)substring;
+	bool result = str.contains(substr);
+
+	free((char *)string);
+	free((char *)substring);
+
+	return result;
+}
+
+// TODO: Replace this with Common::String functionality
+// Compare two strings approximately, ignore case
+Abool Execute::streq(char *a, char *b) {
+	Common::String str1 = a;
+	Common::String str2 = b;
+	bool result = str1.equalsIgnoreCase(str2);
+
+	free(a);
+	free(b);
+
+	return result;
+}
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
diff --git a/engines/glk/alan2/execute.h b/engines/glk/alan2/execute.h
new file mode 100644
index 0000000..82d5c07
--- /dev/null
+++ b/engines/glk/alan2/execute.h
@@ -0,0 +1,134 @@
+/* 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_ALAN2_EXECUTE
+#define GLK_ALAN2_EXECUTE
+
+#include "glk/alan2/acode.h"
+#include "glk/alan2/rules.h"
+#include "common/list.h"
+
+namespace Glk {
+namespace Alan2 {
+
+class Execute {
+public:
+	Execute() {}
+
+	void sys(Aword fpos, Aword len);
+	bool confirm(MsgKind msgno);
+	Aptr attribute(Aword item, Aword atr);
+	void say(Aword item);
+	void saynum(Aword num);
+	void saystr(char *str);
+	Aptr strattr(Aword id, Aword atr);
+	void setstr(Aword id, Aword atr, Aword str);
+	void getstr(Aword fpos, Aword len);
+	void print(Aword fpos, Aword len);
+	void look();
+	void make(Aword id, Aword atr, Aword val);
+	void set(Aword id, Aword atr, Aword val);
+	void incr(Aword id, Aword atr, Aword step);
+	void decr(Aword id, Aword atr, Aword step);
+	void use(Aword act, Aword scr);
+	void describe(Aword id);
+	void list(Aword cnt);
+	void locate(Aword id, Aword whr);
+	void empty(Aword cnt, Aword whr);
+	void score(Aword sc);
+	void visits(Aword v);
+
+	void eventchk();
+	void schedule(Aword evt, Aword whr, Aword aft);
+	void cancl(Aword evt);
+
+	void quit();
+	void restart();
+	void sayint(Aword val);
+	Aword rnd(Aword from, Aword to);
+	Abool btw(Aint val, Aint from, Aint to);
+	Aword contains(Aptr string, Aptr substring);
+	Abool streq(char a[], char b[]);
+	Abool in(Aword obj, Aword cnt);
+	Aword where(Aword item);
+	Aint agrmax(Aword atr, Aword whr);
+	Aint agrsum(Aword atr, Aword whr);
+	Aint agrcount(Aword whr);
+	Abool isHere(Aword item);
+	Abool isNear(Aword item);
+
+private:
+	bool exitto(int to, int from);
+	int count(int cnt);
+	int sumatr(Aword atr, Aword cnt);
+	bool checklim(Aword cnt, Aword obj);
+	Aptr getatr(Aaddr atradr, Aaddr atr);
+	void setatr(Aaddr atradr, Aword atr, Aword val);
+	void makloc(Aword loc, Aword atr, Aword val);
+	void makobj(Aword obj, Aword atr, Aword val);
+	void makact(Aword act, Aword atr, Aword val);
+	void setloc(Aword loc, Aword atr, Aword val);
+	void setobj(Aword obj, Aword atr, Aword val);
+	void setact(Aword act, Aword atr, Aword val);
+	void incratr(Aaddr atradr, Aword atr, Aword step);
+	void incrloc(Aword loc, Aword atr, Aword step);
+	void incrobj(Aword obj, Aword atr, Aword step);
+	void incract(Aword act, Aword atr, Aword step);
+	Aword objloc(Aword obj);
+	Aword actloc(Aword act);
+	void locobj(Aword obj, Aword whr);
+	void locact(Aword act, Aword whr);
+	Abool objhere(Aword obj);
+	Aword acthere(Aword act);
+	Aword objnear(Aword obj);
+	Aword actnear(Aword act);
+	void sayloc(Aword loc);
+	void sayobj(Aword obj);
+	void sayact(Aword act);
+	void saylit(Aword lit);
+	void sayarticle(Aword id);
+	void dscrloc(Aword loc);
+	void dscrobj(Aword obj);
+	void dscract(Aword act);
+	void dscrobjs();
+	void dscracts();
+	Aptr locatr(Aword loc, Aword atr);
+	Aptr objatr(Aword obj, Aword atr);
+	Aptr actatr(Aword act, Aword atr);
+	Aptr litatr(Aword lit, Aword atr);
+
+	// The event queue
+	EvtqElem *eventq;	// Event queue
+	int etop;			// Event queue top pointer
+
+	// Amachine data structures
+	ActElem *_acts;		// Actor table pointer
+	LocElem *_locs;		// Location table pointer
+	ObjElem *_objs;		// Object table pointer
+	CntElem *_cnts;		// Container table pointer
+	Common::Stack<Aword> _describeStack;
+};
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
+
+#endif
diff --git a/engines/glk/alan2/interpreter.cpp b/engines/glk/alan2/interpreter.cpp
new file mode 100644
index 0000000..c8c53a0
--- /dev/null
+++ b/engines/glk/alan2/interpreter.cpp
@@ -0,0 +1,768 @@
+/* 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/alan2/acode.h"
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/execute.h"
+#include "glk/alan2/interpreter.h"
+#include "glk/alan2/saveload.h"
+#include "glk/alan2/types.h"
+#include "common/debug.h"
+
+namespace Glk {
+namespace Alan2 {
+
+// TODO: Refactor these into debug flags
+const bool trcflg = false;
+const bool stpflg = false;
+
+void Interpreter::if_(Aword v) {
+	int lev = 1;
+	Aword i;
+
+	if (!v) {
+		// Skip to next ELSE or ENDIF on same level
+		while (true) {
+			i = _vm->memory[_vm->pc++];
+			if (I_CLASS(i) == (Aword)C_STMOP) {
+				switch (I_OP(i)) {
+				case I_ELSE:
+					if (lev == 1)
+						return;
+					break;
+				case I_IF:
+					lev++;
+					break;
+				case I_ENDIF:
+					lev--;
+					if (lev == 0)
+						return;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+	}
+}
+
+void Interpreter::else_() {
+	int lev = 1;
+	Aword i;
+
+	while (true) {
+		// Skip to ENDIF on the same level
+		i = _vm->memory[_vm->pc++];
+		if (I_CLASS(i) == (Aword)C_STMOP) {
+			switch (I_OP(i)) {
+			case I_ENDIF:
+				lev--;
+				if (lev == 0)
+					return;
+				break;
+			case I_IF:
+				lev++;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+}
+
+void Interpreter::depstart() {
+	// A DEPSTART was executed, so skip across the redundant DEPCASE to
+	// start at the first expression
+	_vm->pc++;
+}
+
+void Interpreter::swap() {
+	Aptr v1 = _stack->pop();
+	Aptr v2 = _stack->pop();
+
+	_stack->push(v1);
+	_stack->push(v2);
+}
+
+void Interpreter::depexec(Aword v) {
+	int lev = 1;
+	Aword i;
+
+	if (!v) {
+		// The expression was not true, skip to next CASE on the same
+		//   level which could be a DEPCASE or DEPELSE
+		while (true) {
+			i = _vm->memory[_vm->pc++];
+			if (I_CLASS(i) == (Aword)C_STMOP) {
+				switch (I_OP(i)) {
+				case I_DEPSTART:
+					lev++;
+					break;
+				case I_DEPEND:
+					if (lev == 1)
+						return;
+					lev--;
+					break;
+				case I_DEPCASE:
+				case I_DEPELSE:
+					if (lev == 1)
+						return;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+	}
+}
+
+void Interpreter::depcase() {
+	int lev = 1;
+	Aword i;
+
+	// Skip to end of DEPENDING block (next DEPEND on same level) because
+	// we have just executed a DEPCASE/DEPELSE statement as a result of a DEPCASE
+	// catching
+
+	while (true) {
+		i = _vm->memory[_vm->pc++];
+		if (I_CLASS(i) == (Aword)C_STMOP) {
+			switch (I_OP(i)) {
+			case I_DEPSTART:
+				lev++;
+				break;
+			case I_DEPEND:
+				lev--;
+				if (lev == 0) return;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+}
+
+void Interpreter::curVar(Aword i) {
+	switch (I_OP(i)) {
+	case V_PARAM:
+		if (stpflg)
+			debug("PARAM \t%5ld\t\t(%ld)", _stack->top(), _vm->params[_stack->top() - 1].code);
+		_stack->push(_vm->params[_stack->pop() - 1].code);
+		break;
+	case V_CURLOC:
+		if (stpflg)
+			debug("CURLOC \t\t\t(%d)", _vm->cur.loc);
+		_stack->push(_vm->cur.loc);
+		break;
+	case V_CURACT:
+		if (stpflg)
+			debug("CURACT \t\t\t(%d)", _vm->cur.act);
+		_stack->push(_vm->cur.act);
+		break;
+	case V_CURVRB:
+		if (stpflg)
+			debug("CURVRB \t\t\t(%d)", _vm->cur.vrb);
+		_stack->push(_vm->cur.vrb);
+		break;
+	case V_SCORE:
+		if (stpflg)
+			debug("CURSCORE \t\t\t(%d)", _vm->cur.score);
+		_stack->push(_vm->cur.score);
+		break;
+	default:
+		error("Unknown CURVAR instruction.");
+	}
+}
+
+void Interpreter::adaptOldOpcodes(Aword i) {
+	switch (I_OP(i)) {
+	case I_AND:
+	case I_OR:
+	case I_NE:
+	case I_EQ:
+	case I_STREQ:
+	case I_STREXACT:
+	case I_LE:
+	case I_GE:
+	case I_LT:
+	case I_GT:
+	case I_PLUS:
+	case I_MINUS:
+	case I_MULT:
+	case I_DIV:
+		if (_vm->header->vers[0] == 2 && _vm->header->vers[1] == 7) // Check for 2.7 version
+			swap();
+	}
+}
+
+void Interpreter::stMop(Aword i, Aaddr oldpc) {
+	Aptr arg1, arg2, arg3, lh, rh;
+
+	adaptOldOpcodes(i);
+
+	switch (I_OP(i)) {
+	case I_PRINT:
+		arg1 = _stack->pop();	// fpos
+		arg2 = _stack->pop();	// len
+		if (stpflg) {
+			debug("PRINT \t%5ld, %5ld\t\"", arg1, arg2);
+			_vm->col = 34;		// To format it better!
+		}
+		_execute->print(arg1, arg2);
+		if (stpflg)
+			debug("\"");
+		break;
+	case I_SYSTEM:
+		arg1 = _stack->pop();	// fpos
+		arg2 = _stack->pop();	// len
+		if (stpflg) {
+			debug("SYSTEM \t%5ld, %5ld\t\"", arg1, arg2);
+			_vm->col = 34;		// To format it better!
+		}
+		_execute->sys(arg1, arg2);
+		break;
+	case I_GETSTR:
+		arg1 = _stack->pop();	// fpos
+		arg2 = _stack->pop();	// len
+		if (stpflg)
+			debug("GETSTR\t%5ld, %5ld", arg1, arg2);
+		_execute->getstr(arg1, arg2);
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_QUIT:
+		if (stpflg)
+			debug("QUIT");
+		_execute->quit();
+		break;
+	case I_LOOK:
+		if (stpflg)
+			debug("LOOK");
+		_execute->look();
+		break;
+	case I_SAVE:
+		if (stpflg)
+			debug("SAVE");
+		_saveLoad->save();
+		break;
+	case I_RESTORE:
+		if (stpflg)
+			debug("RESTORE");
+		_saveLoad->restore();
+		break;
+	case I_RESTART:
+		if (stpflg)
+			debug("RESTART");
+		_execute->restart();
+		break;
+	case I_LIST:
+		arg1 = _stack->pop();	// cnt
+		if (stpflg)
+			debug("LIST \t%5ld", arg1);
+		_execute->list(arg1);
+		break;
+	case I_EMPTY:
+		arg1 = _stack->pop();	// cnt
+		arg2 = _stack->pop();	// whr
+		if (stpflg)
+			debug("EMPTY \t%5ld, %5ld", arg1, arg2);
+		_execute->empty(arg1, arg2);
+		break;
+	case I_SCORE:
+		arg1 = _stack->pop();	// score
+		if (stpflg)
+			debug("SCORE \t%5ld\t\t(%ld)", arg1, _vm->scores[arg1 - 1]);
+		_execute->score(arg1);
+		break;
+	case I_VISITS:
+		arg1 = _stack->pop();	// visits
+		if (stpflg)
+			debug("VISITS \t%5ld", arg1);
+		_execute->visits(arg1);
+		break;
+	case I_SCHEDULE:
+		arg1 = _stack->pop();	// evt
+		arg2 = _stack->pop();	// whr
+		arg3 = _stack->pop();	// aft
+		if (stpflg)
+			debug("SCHEDULE \t%5ld, %5ld, %5ld", arg1, arg2, arg3);
+		_execute->schedule(arg1, arg2, arg3);
+		break;
+	case I_CANCEL:
+		arg1 = _stack->pop();	// evt
+		if (stpflg)
+			debug("CANCEL \t%5ld", arg1);
+		_execute->cancl(arg1);
+		break;
+	case I_MAKE:
+		arg1 = _stack->pop();	// id
+		arg2 = _stack->pop();	// atr
+		arg3 = _stack->pop();	// val
+		if (stpflg) {
+			debug("MAKE \t%5ld, %5ld, ", arg1, arg2);
+			if (arg3)
+				debug("TRUE");
+			else
+				debug("FALSE");
+		}
+		_execute->make(arg1, arg2, arg3);
+		break;
+	case I_SET:
+		arg1 = _stack->pop();	// id
+		arg2 = _stack->pop();	// atr
+		arg3 = _stack->pop();	// val
+		if (stpflg)
+			debug("SET \t%5ld, %5ld, %5ld", arg1, arg2, arg3);
+		_execute->set(arg1, arg2, arg3);
+		break;
+	case I_STRSET:
+		arg1 = _stack->pop();	// id
+		arg2 = _stack->pop();	// atr
+		arg3 = _stack->pop();	// str
+		if (stpflg)
+			debug("STRSET\t%5ld, %5ld, %5ld", arg1, arg2, arg3);
+		_execute->setstr(arg1, arg2, arg3);
+		break;
+	case I_INCR:
+		arg1 = _stack->pop();	// id
+		arg2 = _stack->pop();	// atr
+		arg3 = _stack->pop();	// step
+		if (stpflg)
+			debug("INCR\t%5ld, %5ld, %5ld", arg1, arg2, arg3);
+		_execute->incr(arg1, arg2, arg3);
+		break;
+	case I_DECR:
+		arg1 = _stack->pop();	// id
+		arg2 = _stack->pop();	// atr
+		arg3 = _stack->pop();	// step
+		if (stpflg)
+			debug("DECR\t%5ld, %5ld, %5ld", arg1, arg2, arg3);
+		_execute->decr(arg1, arg2, arg3);
+		break;
+	case I_ATTRIBUTE:
+		arg1 = _stack->pop();	// id
+		arg2 = _stack->pop();	// atr
+		if (stpflg)
+			debug("ATTRIBUTE %5ld, %5ld", arg1, arg2);
+		_stack->push(_execute->attribute(arg1, arg2));
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_STRATTR:
+		arg1 = _stack->pop();	// id
+		arg2 = _stack->pop();	// atr
+		if (stpflg)
+			debug("STRATTR \t%5ld, %5ld", arg1, arg2);
+		_stack->push(_execute->strattr(arg1, arg2));
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_LOCATE:
+		arg1 = _stack->pop();	// id
+		arg2 = _stack->pop();	// whr
+		if (stpflg)
+			debug("LOCATE \t%5ld, %5ld", arg1, arg2);
+		_execute->locate(arg1, arg2);
+		break;
+	case I_WHERE:
+		arg1 = _stack->pop();	// id
+		if (stpflg)
+			debug("WHERE \t%5ld", arg1);
+		_stack->push(_execute->where(arg1));
+		if (stpflg)
+			debug("\t\t(%ld)", _stack->top());
+		break;
+	case I_HERE:
+		arg1 = _stack->pop();	// id
+		if (stpflg)
+			debug("HERE \t%5ld", arg1);
+		_stack->push(_execute->isHere(arg1));
+		if (stpflg) {
+			if (_stack->top())
+				debug("\t(TRUE)");
+			else
+				debug("\t(FALSE)");
+		}
+		break;
+	case I_NEAR:
+		arg1 = _stack->pop();	// id
+		if (stpflg)
+			debug("NEAR \t%5ld", arg1);
+		_stack->push(_execute->isNear(arg1));
+		if (stpflg) {
+			if (_stack->top())
+				debug("\t(TRUE)");
+			else
+				debug("\t(FALSE)");
+		}
+		break;
+	case I_USE:
+		arg1 = _stack->pop();	// act
+		arg2 = _stack->pop();	// scr
+		if (stpflg)
+			debug("USE \t%5ld, %5ld", arg1, arg2);
+		_execute->use(arg1, arg2);
+		break;
+	case I_IN:
+		arg1 = _stack->pop();	// obj
+		arg2 = _stack->pop();	// cnt
+		if (stpflg)
+			debug("IN \t%5ld, %5ld ", arg1, arg2);
+		_stack->push(_execute->in(arg1, arg2));
+		if (stpflg)
+			if (_stack->top()) debug("\t(TRUE)"); else debug("\t(FALSE)");
+		break;
+	case I_DESCRIBE:
+		arg1 = _stack->pop();	// id
+		if (stpflg) {
+			debug("DESCRIBE \t%5ld\t", arg1);
+			_vm->col = 34;		// To format it better!
+		}
+		_execute->describe(arg1);
+		break;
+	case I_SAY:
+		arg1 = _stack->pop();	// id
+		if (stpflg)
+			debug("SAY \t%5ld\t\t\"", arg1);
+		_execute->say(arg1);
+		if (stpflg)
+			debug("\"");
+		break;
+	case I_SAYINT:
+		arg1 = _stack->pop();	// val
+		if (stpflg)
+			debug("SAYINT\t%5ld\t\t\"", arg1);
+		_execute->sayint(arg1);
+		if (stpflg)
+			debug("\"");
+		break;
+	case I_SAYSTR:
+		arg1 = _stack->pop();	// adr
+		if (stpflg)
+			debug("SAYSTR\t%5ld\t\t\"", arg1);
+		_execute->saystr((char *)arg1);
+		if (stpflg)
+			debug("\"");
+		break;
+	case I_IF:
+		arg1 = _stack->pop();	// v
+		if (stpflg) {
+			debug("IF \t");
+			if (arg1) debug(" TRUE"); else debug("FALSE");
+		}
+		if_(arg1);
+		break;
+	case I_ELSE:
+		if (stpflg)
+			debug("ELSE");
+		else_();
+		break;
+	case I_ENDIF:
+		if (stpflg)
+			debug("ENDIF");
+		break;
+	case I_AND:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg) {
+			debug("AND \t");
+			if (lh) debug("TRUE, "); else debug("FALSE, ");
+			if (rh) debug("TRUE"); else debug("FALSE");
+		}
+		_stack->push(lh && rh);
+		if (stpflg)
+			if (_stack->top()) debug("\t(TRUE)"); else debug("\t(FALSE)");
+		break;
+	case I_OR:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg) {
+			debug("OR \t");
+			if (lh) debug("TRUE, "); else debug("FALSE, ");
+			if (rh) debug("TRUE"); else debug("FALSE");
+		}
+		_stack->push(lh || rh);
+		if (stpflg) {
+			if (_stack->top())
+				debug("\t(TRUE)");
+			else
+				debug("\t(FALSE)");
+		}
+		break;
+	case I_NE:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("NE \t%5ld, %5ld", lh, rh);
+		_stack->push(lh != rh);
+		if (stpflg)
+			if (_stack->top()) debug("\t(TRUE)"); else debug("\t(FALSE)");
+		break;
+	case I_EQ:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("EQ \t%5ld, %5ld", lh, rh);
+		_stack->push(lh == rh);
+		if (stpflg) {
+			if (_stack->top())
+				debug("\t(TRUE)");
+			else
+				debug("\t(FALSE)");
+		}
+		break;
+	case I_STREQ:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("STREQ \t%5ld, %5ld", lh, rh);
+		_stack->push(_execute->streq((char *)lh, (char *)rh));
+		if (stpflg)
+			if (_stack->top()) debug("\t(TRUE)"); else debug("\t(FALSE)");
+		break;
+	case I_STREXACT:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("STREXACT \t%5ld, %5ld", lh, rh);
+		_stack->push(strcmp((char *)lh, (char *)rh) == 0);
+		if (stpflg)
+			if (_stack->top()) debug("\t(TRUE)"); else debug("\t(FALSE)");
+		free((void *)lh);
+		free((void *)rh);
+		break;
+	case I_LE:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("LE \t%5ld, %5ld", lh, rh);
+		_stack->push(lh <= rh);
+		if (stpflg)
+			if (_stack->top()) debug("\t(TRUE)"); else debug("\t(FALSE)");
+		break;
+	case I_GE:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("GE \t%5ld, %5ld", lh, rh);
+		_stack->push(lh >= rh);
+		if (stpflg)
+			if (_stack->top()) debug("\t(TRUE)"); else debug("\t(FALSE)");
+		break;
+	case I_LT:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("LT \t%5ld, %5ld", lh, rh);
+		_stack->push((signed int)lh < (signed int)rh);
+		if (stpflg)
+			if (_stack->top()) debug("\t(TRUE)"); else debug("\t(FALSE)");
+		break;
+	case I_GT:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("GT \t%5ld, %5ld", lh, rh);
+		_stack->push(lh > rh);
+		if (stpflg)
+			if (_stack->top()) debug("\t(TRUE)"); else debug("\t(FALSE)");
+		break;
+	case I_PLUS:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("PLUS \t%5ld, %5ld", lh, rh);
+		_stack->push(lh + rh);
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_MINUS:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("MINUS \t%5ld, %5ld", lh, rh);
+		_stack->push(lh - rh);
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_MULT:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("MULT \t%5ld, %5ld", lh, rh);
+		_stack->push(lh * rh);
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_DIV:
+		rh = _stack->pop();
+		lh = _stack->pop();
+		if (stpflg)
+			debug("DIV \t%5ld, %5ld", lh, rh);
+		_stack->push(lh / rh);
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_NOT:
+		arg1 = _stack->pop();	// val
+		if (stpflg) {
+			debug("NOT \t");
+			if (arg1) debug("TRUE"); else debug("FALSE");
+		}
+		_stack->push(!arg1);
+		if (stpflg)
+			if (_stack->top()) debug("\t\t(TRUE)"); else debug("\t\t(FALSE)");
+		break;
+	case I_MAX:
+		arg1 = _stack->pop();	// atr
+		arg2 = _stack->pop();	// whr
+		if (stpflg)
+			debug("MAX \t%5ld, %5ld", arg1, arg2);
+		_stack->push(_execute->agrmax(arg1, arg2));
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_SUM:
+		arg1 = _stack->pop();	// atr
+		arg2 = _stack->pop();	// whr
+		if (stpflg)
+			debug("SUM \t%5ld, %5ld", arg1, arg2);
+		_stack->push(_execute->agrsum(arg1, arg2));
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_COUNT:
+		arg1 = _stack->pop();	// whr
+		if (stpflg)
+			debug("COUNT \t%5ld", arg1);
+		_stack->push(_execute->agrcount(arg1));
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_RND:
+		arg1 = _stack->pop();	// from
+		arg2 = _stack->pop();	// to
+		if (stpflg)
+			debug("RANDOM \t%5ld, %5ld", arg1, arg2);
+		_stack->push(_execute->rnd(arg1, arg2));
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_BTW:
+		arg1 = _stack->pop();	// high
+		arg2 = _stack->pop();	// low
+		arg3 = _stack->pop();	// val
+		if (stpflg)
+			debug("BETWEEN \t%5ld, %5ld, %5ld", arg1, arg2, arg3);
+		_stack->push(_execute->btw(arg1, arg2, arg3));
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_CONTAINS:
+		arg1 = _stack->pop();	// substring
+		arg2 = _stack->pop();	// string
+		if (stpflg)
+			debug("CONTAINS \t%5ld, %5ld", arg2, arg1);
+		_stack->push(_execute->contains(arg2, arg1));
+		if (stpflg)
+			debug("\t(%ld)", _stack->top());
+		break;
+	case I_DEPSTART:
+		if (stpflg)
+			debug("DEPSTART");
+		depstart();
+		break;
+	case I_DEPCASE:
+		if (stpflg)
+			debug("DEPCASE");
+		depcase();
+		break;
+	case I_DEPEXEC:
+		arg1 = _stack->pop();	// v
+		if (stpflg) {
+			debug("DEPEXEC \t");
+			if (arg1) debug(" TRUE"); else debug("FALSE");
+		}
+		depexec(arg1);
+		break;
+	case I_DEPELSE:
+		if (stpflg)
+			debug("DEPELSE");
+		depcase();
+		break;
+	case I_DEPEND:
+		if (stpflg)
+			debug("DEPEND");
+		break;
+	case I_RETURN:
+		if (stpflg)
+			debug("RETURN\n--------------------------------------------------\n");
+		_vm->pc = oldpc;
+		return;
+	default:
+		error("Unknown STMOP instruction.");
+	}
+
+	if (_vm->fail) {
+		_vm->pc = oldpc;
+		return;		// TODO: Return true/false, and stop execution if necessary
+	}
+}
+
+void Interpreter::interpret(Aaddr adr) {
+	Aaddr oldpc = _vm->pc;
+	Aword i;
+ 	
+	if (stpflg)
+		debug("\n++++++++++++++++++++++++++++++++++++++++++++++++++");
+ 	
+	_vm->pc = adr;
+
+	while(true) {
+		if (stpflg)
+			debug("\n%4x: ", _vm->pc);
+
+		if (_vm->pc > _vm->memTop)
+			error("Interpreting outside program.");
+
+		i = _vm->memory[_vm->pc++];
+    
+		switch (I_CLASS(i)) {
+		case C_CONST:
+			if (stpflg)
+				debug("PUSH  \t%5ld", I_OP(i));
+			_stack->push(I_OP(i));
+			break;
+		case C_CURVAR:
+			curVar(i);
+		break;
+		case C_STMOP: 
+			stMop(i, oldpc);
+	      break;
+	    default:
+			error("Unknown instruction class.");
+    }
+  }
+}
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
diff --git a/engines/glk/alan2/interpreter.h b/engines/glk/alan2/interpreter.h
new file mode 100644
index 0000000..dbc1558
--- /dev/null
+++ b/engines/glk/alan2/interpreter.h
@@ -0,0 +1,59 @@
+/* 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_ALAN2_INTERPRETER
+#define GLK_ALAN2_INTERPRETER
+
+#include "glk/alan2/acode.h"
+#include "glk/alan2/alan2.h"
+
+namespace Glk {
+namespace Alan2 {
+
+class Execute;
+class SaveLoad;
+
+class Interpreter {
+public:
+	Interpreter(Execute *execute, SaveLoad *saveLoad, Alan2Stack *stack) : _execute(execute), _saveLoad(saveLoad), _stack(stack) {}
+	void interpret(Aaddr adr);
+
+private:
+	void if_(Aword v);
+	void else_();
+	void depstart();
+	void swap();
+	void depexec(Aword v);
+	void depcase();
+	void curVar(Aword i);
+	void stMop(Aword i, Aaddr oldpc);
+	void adaptOldOpcodes(Aword i);
+
+	Execute *_execute;
+	SaveLoad *_saveLoad;
+	Alan2Stack *_stack;
+};
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
+
+#endif
diff --git a/engines/glk/alan2/parse.cpp b/engines/glk/alan2/parse.cpp
new file mode 100644
index 0000000..ebb0af9
--- /dev/null
+++ b/engines/glk/alan2/parse.cpp
@@ -0,0 +1,976 @@
+/* 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 "common/stack.h"
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/execute.h"
+#include "glk/alan2/interpreter.h"
+#include "glk/alan2/parse.h"
+#include "glk/alan2/types.h"
+#include "glk/alan2/util.h"
+#include "common/debug.h"
+#include "common/file.h"
+#include "decode.h"
+
+namespace Glk {
+namespace Alan2 {
+
+// All procedures for getting a command and turning it into a list of
+// dictionary entries are placed here.
+
+Parser::Parser() {
+	wrds[0] = EOF;
+
+	// TODO
+}
+
+void Parser::unknown(char *inputStr) {
+	Common::String str = Common::String::format("'%s'?", inputStr);
+
+	// TODO
+#if 0
+#if ISO == 0
+  fromIso(str, str);
+#endif
+#endif
+
+	_vm->output(str);
+	eol = true;
+	_vm->printError(M_UNKNOWN_WORD);
+}
+
+int Parser::lookup(char *wrd) {
+#if 0
+	for (int i = 0; !endOfTable(&dict[i]); i++) {
+		if (strcmp(wrd, (char *) addrTo(dict[i].wrd)) == 0)
+			return (i);
+	}
+#endif
+
+	unknown(wrd);
+	return(EOF);
+}
+
+char *Parser::gettoken(char *tokenBuffer) {
+	static char *marker;
+	static char oldch;
+
+	if (tokenBuffer == NULL)
+		*marker = oldch;
+	else
+		marker = tokenBuffer;
+
+	while (*marker != '\0' && Common::isSpace(*marker) && *marker != '\n') marker++;
+	tokenBuffer = marker;
+
+	if (Common::isAlpha(*marker))
+		while (*marker && (Common::isAlpha(*marker) || Common::isDigit(*marker) || *marker == '\'')) marker++;
+	else if (Common::isDigit(*marker))
+		while (Common::isDigit(*marker)) marker++;
+	else if (*marker == '\"') {
+		marker++;
+		while (*marker != '\"') marker++;
+		marker++;
+	} else if (*marker == '\0' || *marker == '\n')
+		return NULL;
+	else
+		marker++;
+
+	oldch = *marker;
+	*marker = '\0';
+	return tokenBuffer;
+}
+
+void Parser::agetline() {
+	static char buf[LISTLEN + 1];	// The input buffer
+	static char isobuf[LISTLEN + 1];	// The input buffer in ISO
+
+	_vm->paragraph();
+
+	// TODO
+#if 0
+
+	do {
+#if defined(HAVE_ANSI) || defined(GLK)
+		statusline();
+#endif
+		debug("> ");
+
+#if 0
+	    if (logflg)
+			fprintf(logfil, "> ");
+#endif
+
+#ifdef USE_READLINE
+	    if (!readline(buf)) {
+			newline();
+			quit();
+	    }
+#else
+	    if (fgets(buf, LISTLEN, stdin) == NULL) {
+			newline();
+			quit();
+	    }
+#endif
+
+		getPageSize();
+		anyOutput = FALSE;
+
+		if (logflg)
+			fprintf(logfil, "%s\n", buf);
+
+#if ISO == 0
+		toIso(isobuf, buf, NATIVECHARSET);
+#else
+		strcpy(isobuf, buf);
+#endif
+
+		token = gettoken(isobuf);
+
+	    if (token != NULL && strcmp("debug", token) == 0 && _vm->header->debug) {
+			dbgflg = true;
+			debug();
+			token = NULL;
+	    }
+	} while (token == NULL);
+
+  eol = false;
+  lin = 1;
+
+#endif
+}
+
+void Parser::scan() {
+	int i;
+	int w;
+	char *str;
+
+	agetline();
+	wrds[0] = 0;
+
+	for (i = 0; i < litCount; i++)
+		if (litValues[i].type == TYPSTR && litValues[i].value != 0)
+			free((char *) litValues[i].value);
+
+	litCount = 0;
+
+	do {
+		if (Common::isAlpha(token[0])) {
+			Common::String tmp = token;
+			tmp.toLowercase();
+			strcpy(token, tmp.c_str());
+
+			w = lookup(token);
+
+			// TODO
+			//if (!isNoise(w))
+			//	wrds[i++] = w;
+		} else if (Common::isDigit(token[0])) {
+			if (litCount > MAXPARAMS)
+				error("Too many parameters.");
+
+			wrds[i++] = dictsize + litCount; // Word outside dictionary = literal
+			litValues[litCount].type = TYPNUM;
+			litValues[litCount++].value = atoi(token);
+		} else if (token[0] == '\"') {
+			if (litCount > MAXPARAMS)
+				error("Too many parameters.");
+      
+			wrds[i++] = dictsize + litCount; // Word outside dictionary = literal
+			litValues[litCount].type = TYPSTR;
+
+			// Remove the string quotes while copying
+			Common::String tmp = token;
+			tmp.deleteChar(0);
+			tmp.deleteLastChar();
+			strcpy(str, tmp.c_str());
+
+			litValues[litCount++].value = (Aptr) str;
+		} else if (token[0] == ',') {
+			//wrds[i++] = conjWord;		// TODO
+		} else
+			unknown(token);
+
+		wrds[i] = EOF;
+		eol = (token = gettoken(NULL)) == NULL;
+	} while (!eol);
+}
+
+// Search for a non-verb command
+void Parser::nonverb() {
+	if (isDir(wrds[wrdidx])) {
+		wrdidx++;
+		if (wrds[wrdidx] != EOF && !isConj(wrds[wrdidx]))
+			_vm->printError(M_WHAT);
+// TODO
+#if 0
+		else
+			go(dict[wrds[wrdidx-1]].code);
+#endif
+
+		if (wrds[wrdidx] != EOF)
+			wrdidx++;
+	} else
+		_vm->printError(M_WHAT);
+}
+
+Abool Parser::objhere(Aword obj) {
+	if (isCnt(objs[obj - OBJMIN].loc)) {    // In something?
+		if (isObj(objs[obj - OBJMIN].loc) || isAct(objs[obj - OBJMIN].loc))
+			return(isHere(objs[obj - OBJMIN].loc));
+// TODO
+#if 0
+		else // If the container wasn't anywhere, assume where HERO is!
+			return(where(HERO) == _vm->cur.loc);
+#endif
+
+	} else
+		return(objs[obj - OBJMIN].loc == _vm->cur.loc);
+}
+
+
+Aword Parser::acthere(Aword act) {
+	return(acts[act - ACTMIN].loc == _vm->cur.loc);
+}
+
+Abool Parser::isHere(Aword id) {
+	if (isObj(id))
+		return objhere(id);
+	else if (isAct(id))
+		return acthere(id);
+	else
+		error("Can't HERE item (%ld).", (unsigned long)id);
+}
+
+// ----------------------------------------------------------------------------
+
+// Build a list of objects matching 'all'
+void Parser::buildall(ParamElem list[]) {
+	int o, i = 0;
+	bool found = false;
+  
+	for (o = OBJMIN; o <= OBJMAX; o++) {
+		if (isHere(o)) {
+			found = true;
+			list[i].code = o;
+			list[i++].firstWord = EOF;
+		}
+	}
+
+	if (!found)
+		_vm->printError(M_WHAT_ALL);
+	else
+	    list[i].code = EOF;
+}
+
+void Parser::listCopy(ParamElem a[], ParamElem b[]) {
+	int i;
+
+	for (i = 0; b[i].code != EOF; i++)
+		a[i] = b[i];
+
+	a[i].code = EOF;
+}
+
+bool Parser::listContains(ParamElem l[], Aword e) {
+	int i;
+
+	for (i = 0; l[i].code != EOF && l[i].code != e; i++);
+
+	return (l[i].code == e);
+}
+
+void Parser::listIntersection(ParamElem a[], ParamElem b[]) {
+	int i, last = 0;
+
+	for (i = 0; a[i].code != EOF; i++)
+		if (listContains(b, a[i].code))
+			a[last++] = a[i];
+
+	a[last].code = EOF;
+}
+
+// Copy the refs (in dictionary) to a paramList
+void Parser::listCopyFromDictionary(ParamElem p[], Aword r[]) {
+	int i;
+
+	for (i = 0; r[i] != EOF; i++) {
+		p[i].code = r[i];
+		p[i].firstWord = EOF;
+	}
+
+	p[i].code = EOF;
+}
+
+int Parser::listLength(ParamElem a[]) {
+	int i = 0;
+
+	while (a[i].code != EOF)
+		i++;
+
+	return (i);
+}
+
+// Compact a list, i.e remove any NULL elements
+void Parser::listCompact(ParamElem a[]) {
+	int i, j;
+
+	for (i = 0, j = 0; a[j].code != EOF; j++)
+		if (a[j].code != 0)
+			a[i++] = a[j];
+
+	a[i].code = EOF;
+}
+
+// Merge the paramElems of one list into the first
+void Parser::listMerge(ParamElem a[], ParamElem b[]) {
+	int i, last;
+
+	for (last = 0; a[last].code != EOF; last++); // Find end of list
+
+	for (i = 0; b[i].code != EOF; i++) {
+		if (!listContains(a, b[i].code)) {
+			a[last++] = b[i];
+			a[last].code = EOF;
+		}
+	}
+}
+
+// Subtract two lists
+void Parser::listSubtract(ParamElem a[], ParamElem b[]) {
+	for (int i = 0; a[i].code != EOF; i++)
+		if (listContains(b, a[i].code))
+			a[i].code = 0;		// Mark empty
+
+	listCompact(a);
+}
+
+// Match an unambigous object reference
+void Parser::unambig(ParamElem plst[]) {
+	int i;
+	bool found = false;		// Adjective or noun found?
+	static ParamElem *refs;	// Entities referenced by word
+	static ParamElem *savlst;	// Saved list for backup at EOF
+	int firstWord, lastWord;	// The words the player used
+
+	if (refs == NULL)
+		refs = new ParamElem[MAXENTITY + 1];
+
+	if (savlst == NULL)
+		savlst = new ParamElem[MAXENTITY + 1];
+
+	if (isLiteral(wrds[wrdidx])) {
+		// Transform the word into a reference to the literal value
+		plst[0].code = wrds[wrdidx++]-dictsize+LITMIN;
+		plst[0].firstWord = EOF;	// No words used!
+		plst[1].code = EOF;
+		return;
+	}
+
+	plst[0].code = EOF;		// Make empty
+
+	if (isIt(wrds[wrdidx])) {
+	    wrdidx++;
+		// Use last object in previous command!
+		for (i = listLength(pparams)-1; i >= 0 && (pparams[i].code == 0 || pparams[i].code >= LITMIN); i--);
+		
+		if (i < 0)
+			_vm->printError(M_WHAT_IT);
+
+		if (!isHere(pparams[i].code)) {
+			params[0].code = pparams[i].code;
+			params[0].firstWord = EOF;
+			params[1].code = EOF;
+			_vm->printError(M_NO_SUCH);
+		}
+
+		plst[0] = pparams[i];
+		plst[0].firstWord = EOF;	// No words used!
+		plst[1].code = EOF;
+		return;
+	}
+
+	firstWord = wrdidx;
+
+	while (wrds[wrdidx] != EOF && isAdj(wrds[wrdidx])) {
+		// If this word can be a noun and there is no noun following break loop
+		if (isNoun(wrds[wrdidx]) && (wrds[wrdidx+1] == EOF || !isNoun(wrds[wrdidx+1])))
+			break;
+
+		listCopyFromDictionary(refs, (Aword *)addrTo(dict[wrds[wrdidx]].adjrefs));
+		listCopy(savlst, plst);	// To save it for backtracking
+
+		if (found)
+			listIntersection(plst, refs);
+		else {
+			listCopy(plst, refs);
+			found = true;
+		}
+
+		wrdidx++;
+	}
+
+	if (wrds[wrdidx] != EOF) {
+		if (isNoun(wrds[wrdidx])) {
+			listCopyFromDictionary(refs, (Aword *)addrTo(dict[wrds[wrdidx]].nounrefs));
+			if (found)
+				listIntersection(plst, refs);
+			else {
+				listCopy(plst, refs);
+				found = true;
+			}
+
+			wrdidx++;
+		} else
+			_vm->printError(M_NOUN);
+	} else if (found) {
+		if (isNoun(wrds[wrdidx-1])) {
+			// Perhaps the last word was also a noun?
+			listCopy(plst, savlst);	// Restore to before last adjective
+			listCopyFromDictionary(refs, (Aword *)addrTo(dict[wrds[wrdidx-1]].nounrefs));
+			if (plst[0].code == EOF)
+				listCopy(plst, refs);
+		else
+			listIntersection(plst, refs);
+	} else
+		_vm->printError(M_NOUN);
+	}
+
+	lastWord = wrdidx - 1;
+
+	// Allow remote objects, but resolve ambiguities by presence
+	if (listLength(plst) > 1) {
+		for (i=0; plst[i].code != EOF; i++)
+			if (!isHere(plst[i].code))
+				plst[i].code = 0;
+
+		listCompact(plst);
+	}
+    
+	if (listLength(plst) > 1 || (found && listLength(plst) == 0)) {
+		params[0].code = 0;		/* Just make it anything != EOF */
+		params[0].firstWord = firstWord; /* Remember words for errors below */
+		params[0].lastWord = lastWord;
+		params[1].code = EOF;	/* But be sure to terminate */
+
+		if (listLength(plst) > 1)
+			_vm->printError(M_WHICH_ONE);
+		else if (found && listLength(plst) == 0)
+			_vm->printError(M_NO_SUCH);
+	} else {
+		plst[0].firstWord = firstWord;
+		plst[0].lastWord = lastWord;
+	}
+}
+
+// Match a simple verb command
+void Parser::simple(ParamElem olst[]) {
+	static ParamElem *tlst = NULL;
+	int savidx = wrdidx;
+	bool savplur = false;
+	int i;
+
+	if (tlst == NULL)
+		tlst = new ParamElem[MAXENTITY + 1];
+
+	tlst[0].code = EOF;
+
+	for (;;) {
+		if (isThem(wrds[wrdidx])) {
+			plural = true;
+
+			for (i = 0; pmlst[i].code != EOF; i++)
+				if (!isHere(pmlst[i].code))
+					pmlst[i].code = 0;
+
+			listCompact(pmlst);
+
+			if (listLength(pmlst) == 0)
+				_vm->printError(M_WHAT_THEM);
+
+			listCopy(olst, pmlst);
+			olst[0].firstWord = EOF;	// No words used
+			wrdidx++;
+		} else {
+			unambig(olst);		// Look for unambigous noun phrase
+
+			if (listLength(olst) == 0) {	// Failed!
+				listCopy(olst, tlst);
+				wrdidx = savidx;
+				plural = savplur;
+				return;
+			}
+		}
+
+		listMerge(tlst, olst);
+
+		if (wrds[wrdidx] != EOF
+			&& (isConj(wrds[wrdidx])
+			&& (isAdj(wrds[wrdidx+1]) || isNoun(wrds[wrdidx+1])))) {
+			// More parameters in a conjunction separated list ?
+			savplur = plural;
+			savidx = wrdidx;
+			wrdidx++;
+			plural = true;
+		} else {
+			listCopy(olst, tlst);
+			return;
+		}
+	}
+}
+
+// Match a complex verb command
+void Parser::complex(ParamElem olst[]) {
+	// Above this procedure we can use the is* tests, but not below since
+	// they work on words.Below all is converted to indices into the
+	// entity tables.Particularly this goes for literals...
+
+	static ParamElem *alst = NULL;
+
+	if (alst == NULL)
+		alst = new ParamElem[MAXENTITY + 1];
+
+	if (isAll(wrds[wrdidx])) {
+		plural = true;
+		buildall(alst);		// Build list of all objects
+		wrdidx++;
+		if (wrds[wrdidx] != EOF && isBut(wrds[wrdidx])) {
+			wrdidx++;
+			simple(olst);
+
+			if (listLength(olst) == 0)
+				_vm->printError(M_AFTER_BUT);
+
+			listSubtract(alst, olst);
+			if (listLength(alst) == 0)
+				_vm->printError(M_NOT_MUCH);
+		}
+
+		listCopy(olst, alst);
+		allLength = listLength(olst);
+	} else
+		simple(olst);		// Look for simple noun group
+}
+
+bool Parser::claCheck(ClaElem *cla) {
+	bool ok = false;
+
+	if ((cla->classes&(Aword)CLA_OBJ) != 0)
+		ok = ok || isObj(params[cla->code-1].code);
+	if ((cla->classes&(Aword)CLA_CNT) != 0)
+		ok = ok || isCnt(params[cla->code-1].code);
+	if ((cla->classes&(Aword)CLA_ACT) != 0)
+	    ok = ok || isAct(params[cla->code-1].code);
+	if ((cla->classes&(Aword)CLA_NUM) != 0)
+		ok = ok || isNum(params[cla->code-1].code);
+	if ((cla->classes&(Aword)CLA_STR) != 0)
+	    ok = ok || isStr(params[cla->code-1].code);
+	if ((cla->classes&(Aword)CLA_COBJ) != 0)
+	    ok = ok || (isCnt(params[cla->code-1].code) && isObj(params[cla->code-1].code));
+	if ((cla->classes&(Aword)CLA_CACT) != 0)
+	    ok = ok || (isCnt(params[cla->code-1].code) && isAct(params[cla->code-1].code));
+
+  return ok;
+}
+
+// In case the syntax did not indicate omnipotent powers (allowed
+// access to remote object), we need to remove non - present parameters
+void Parser::resolve(ParamElem plst[]) {
+	if (allLength > 0)
+		return;	// ALL has already done this
+
+	// Resolve ambiguities by presence
+	for (int i = 0; plst[i].code != EOF; i++)  {
+		if (plst[i].code < LITMIN)	// Literals are always 'here'
+			if (!isHere(plst[i].code)) {
+				params[0] = plst[i];	// Copy error param as first one for message
+				params[1].code = EOF;	// But be sure to terminate
+				_vm->printError(M_NO_SUCH);
+			}
+    }
+}
+
+bool Parser::endOfTable(StxElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+bool Parser::endOfTable(ElmElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+bool Parser::endOfTable(ClaElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+bool Parser::endOfTable(VrbElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+bool Parser::endOfTable(AltElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+bool Parser::endOfTable(ChkElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+/**
+ * Find the verb alternative wanted in a verb list and return
+ * the address to it.
+ * 
+ * @param vrbsadr	Address to start of list
+ * @param param		Which parameter to match
+ */
+AltElem *Parser::findalt(Aword vrbsadr, Aword param) {
+	VrbElem *vrb;
+	AltElem *alt;
+
+	if (vrbsadr == 0)
+		return NULL;
+
+	for (vrb = (VrbElem *)addrTo(vrbsadr); !endOfTable(vrb); vrb++) {
+		if (vrb->code == _vm->cur.vrb) {
+			for (alt = (AltElem *)addrTo(vrb->alts); !endOfTable(alt); alt++)
+				if (alt->param == param || alt->param == 0)
+					return alt;
+			return NULL;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * Tries a check, returns TRUE if it passed, FALSE otherwise
+ * 
+ * @param adr	ACODE address to check table
+ * @param act	Act if it fails?
+ */
+bool Parser::trycheck(Aaddr adr, bool act) {
+	ChkElem *chk = (ChkElem *)addrTo(adr);
+
+	if (chk->exp == 0) {
+		_vm->_interpreter->interpret(chk->stms);
+		return false;
+	} else {
+		while (!endOfTable(chk)) {
+			_vm->_interpreter->interpret(chk->exp);
+			if (!(Abool)_vm->_stack->pop()) {
+				if (act)
+					_vm->_interpreter->interpret(chk->stms);
+				return false;
+			}
+			chk++;
+		}
+		return true;
+	}
+}
+
+// Check if current action is possible according to the CHECKs.
+bool Parser::possible() {
+	AltElem *alt[MAXPARAMS + 2];	// List of alt-pointers, one for each param
+	int i;			// Parameter index
+
+	_vm->fail = false;
+	alt[0] = findalt(_vm->header->vrbs, 0);
+
+	// Perform global checks
+	if (alt[0] != 0 && alt[0]->checks != 0) {
+		if (!trycheck(alt[0]->checks, false))
+			return false;
+		if (_vm->fail)
+			return false;
+	}
+
+	// Now CHECKs in this location
+	alt[1] = findalt(locs[_vm->cur.loc - LOCMIN].vrbs, 0);
+	if (alt[1] != 0 && alt[1]->checks != 0)
+		if (!trycheck(alt[1]->checks, false))
+			return false;
+
+	for (i = 0; params[i].code != EOF; i++) {
+		alt[i + 2] = findalt(objs[params[i].code - OBJMIN].vrbs, i + 1);
+		// CHECKs in a possible parameter
+		if (alt[i + 2] != 0 && alt[i + 2]->checks != 0)
+			if (!trycheck(alt[i + 2]->checks, false))
+				return false;
+	}
+
+	for (i = 0; i < 2 || params[i - 2].code != EOF; i++)
+		if (alt[i] != 0 && alt[i]->action != 0)
+			break;
+	if (i >= 2 && params[i - 2].code == EOF)
+		// Didn't find any code for this verb/object combination
+		return false;
+	else
+		return true;
+}
+
+void Parser::tryMatch(ParamElem mlst[]) {
+	ElmElem *elms;		// Pointer to element list
+	StxElem *stx;			// Pointer to syntax list
+	ClaElem *cla;			// Pointer to class definitions
+	bool anyPlural = false;	// Any parameter that was plural?
+	int i, p;
+	static ParamElem *tlst = NULL; // List of params found by complex()
+	static bool *checked = NULL; // Corresponding parameter checked?
+
+	if (tlst == NULL) {
+		tlst = new ParamElem[MAXENTITY + 1];
+		checked = new bool[MAXENTITY + 1];
+	}
+
+	for (stx = stxs; !endOfTable(stx); stx++)
+		if (stx->code == vrbcode)
+			break;
+
+	if (endOfTable(stx))
+		_vm->printError(M_WHAT);
+
+	elms = (ElmElem *) addrTo(stx->elms);
+
+	while (true) {
+		// End of input?
+		if (wrds[wrdidx] == EOF || isConj(wrds[wrdidx])) {
+			while (!endOfTable(elms) && elms->code != EOS)
+				elms++;
+
+				if (endOfTable(elms))
+					_vm->printError(M_WHAT);
+				else
+					break;
+		} else {
+			// A preposition?
+			if (isPrep(wrds[wrdidx])) {
+				while (!endOfTable(elms) && elms->code != dict[wrds[wrdidx]].code)
+					elms++;
+
+				if (endOfTable(elms))
+					_vm->printError(M_WHAT);
+				else
+					wrdidx++;
+			} else {
+				// Must be a parameter!
+				while (!endOfTable(elms) && elms->code != 0)
+					elms++;
+
+				if (endOfTable(elms))
+					_vm->printError(M_WHAT);
+
+				// Get it!
+				plural = false;
+				complex(tlst);
+
+				if (listLength(tlst) == 0) // No object!?
+					_vm->printError(M_WHAT);
+
+				if ((elms->flags & OMNIBIT) == 0) // Omnipotent parameter?
+					resolve(tlst);	// If its not an omnipotent parameter, resolve by presence
+
+				if (plural) {
+					if ((elms->flags & MULTIPLEBIT) == 0)	// Allowed multiple?
+						_vm->printError(M_MULTIPLE);
+					else {
+						// Mark this as the multiple position in which to insert
+						// actual parameter values later
+						params[paramidx++].code = 0;
+						listCopy(mlst, tlst);
+						anyPlural = true;
+					}
+				} else
+					params[paramidx++] = tlst[0];
+					params[paramidx].code = EOF;
+			}
+
+			elms = (ElmElem *) addrTo(elms->next);
+		}
+	}
+  
+	// Now perform class checks
+	if (elms->next == 0)	// No verb code, verb not declared!
+		_vm->printError(M_CANT0);
+
+	for (p = 0; params[p].code != EOF; p++) /* Mark all parameters unchecked */
+		checked[p] = false;
+
+	for (cla = (ClaElem *) addrTo(elms->next); !endOfTable(cla); cla++) {
+		if (params[cla->code - 1].code == 0) {
+			// This was a multiple parameter, so check all and remove failing
+			for (i = 0; mlst[i].code != EOF; i++) {
+				params[cla->code-1] = mlst[i];
+				if (!claCheck(cla)) {
+					// Multiple could be both an explicit list of params and an ALL
+					if (allLength == 0) {
+						char marker[80];
+						// It wasn't ALL, we need to say something about it, so
+						// prepare a printout with $1/2/3
+						sprintf(marker, "($%ld)", (unsigned long) cla->code); 
+						_vm->output(marker);
+						_vm->_interpreter->interpret(cla->stms);
+						_vm->paragraph();
+					}
+
+					mlst[i].code = 0;	  // In any case remove it from the list
+				}
+			}
+
+			params[cla->code - 1].code = 0;
+		} else {
+			if (!claCheck(cla)) {
+				_vm->_interpreter->interpret(cla->stms);
+				_vm->printError(MSGMAX);		// Return to player without saying anything
+			}
+		}
+
+		checked[cla->code - 1] = true; // Remember that it's already checked
+	}
+
+	// Now check the rest of the parameters, must be objects
+	for (p = 0; params[p].code != EOF; p++) {
+		if (!checked[p]) {
+			if (params[p].code == 0) {
+				// This was a multiple parameter, check all and remove failing
+				for (i = 0; mlst[i].code != EOF; i++) {
+					if (mlst[i].code != 0 && !isObj(mlst[i].code)) // Skip any empty slots
+						mlst[i].code = 0;
+				}
+			} else if (!isObj(params[p].code))
+				_vm->printError(M_CANT0);
+		}
+	}
+
+	// Set verb code
+	_vm->cur.vrb = ((Aword *) cla)[1];	// Take first word after end of table!
+
+	// Finally, if ALL was used, try to find out what was applicable
+	if (allLength > 0) {
+		for (p = 0; params[p].code != 0; p++); // Find multiple marker
+
+		for (i = 0; i < allLength; i++) {
+			if (mlst[i].code != 0) {	// Already empty?
+				params[p] = mlst[i];
+
+				if (!possible())
+					mlst[i].code = 0;	// Remove this from list
+			}
+		}
+
+		params[p].code = 0;		// Restore multiple marker
+		listCompact(mlst);
+
+		if (listLength(mlst) == 0) {
+			params[0].code = EOF;
+			_vm->printError(M_WHAT_ALL);
+		}
+	} else if (anyPlural) {
+		listCompact(mlst);
+
+		// If there where multiple parameters but non left, exit without a
+		// word, assuming we have already said enough
+		if (listLength(mlst) == 0)
+			_vm->printError(MSGMAX);
+	}
+
+	plural = anyPlural;		// Remember that we found plural objects
+}
+
+// Find the verb class (not used currently) and 'tryMatch()'
+void Parser::match(ParamElem *mlst) {
+	tryMatch(mlst);			// try to understand what the user said
+
+	if (wrds[wrdidx] != EOF && !isConj(wrds[wrdidx]))
+	    _vm->printError(M_WHAT);
+	if (wrds[wrdidx] != EOF)	// More on this line?
+		wrdidx++;			// If so skip the AND
+}
+
+// Execute all activities commanded.Handles possible multiple actions
+// such as THEM or lists of objects.
+void Parser::action(ParamElem plst[]) {
+	int i, mpos;
+	char marker[10];
+
+	if (plural) {
+		// The code == 0 means this is a multiple position. We must loop
+		// over this position (and replace it by each present in the plst)
+		for (mpos = 0; params[mpos].code != 0; mpos++); // Find multiple position
+		
+		sprintf(marker, "($%d)", mpos + 1); // Prepare a printout with $1/2/3
+
+		for (i = 0; plst[i].code != EOF; i++) {
+			params[mpos] = plst[i];
+			_vm->output(marker);
+			//do_it();	// TODO
+
+			if (plst[i + 1].code != EOF)
+				_vm->paragraph();
+		}
+
+		params[mpos].code = 0;
+	} //else // TODO
+		//do_it();
+}
+
+void Parser::parse() {
+	if (mlst == NULL) {		// Allocate large enough paramlists
+		mlst = new ParamElem[MAXENTITY + 1];
+		mlst[0].code = EOF;
+		pmlst = new ParamElem[MAXENTITY + 1];
+		params = new ParamElem[MAXENTITY + 1];
+		params[0].code = EOF;
+		pparams = new ParamElem[MAXENTITY + 1];
+	}
+
+	if (wrds[wrdidx] == EOF) {
+		wrdidx = 0;
+		scan();
+	} else if (false/*anyOutput*/)	// TODO
+		_vm->paragraph();
+
+	allLength = 0;
+	paramidx = 0;
+	listCopy(pparams, params);
+	params[0].code = EOF;
+	listCopy(pmlst, mlst);
+	mlst[0].code = EOF;
+
+	if (isVerb(wrds[wrdidx])) {
+		vrbwrd = wrds[wrdidx];
+		vrbcode = dict[vrbwrd].code;
+		wrdidx++;
+		match(mlst);
+		action(mlst);		// mlst contains possible multiple params
+	} else {
+	    params[0].code = EOF;
+		pmlst[0].code = EOF;
+		nonverb();
+	}
+}
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
diff --git a/engines/glk/alan2/parse.h b/engines/glk/alan2/parse.h
new file mode 100644
index 0000000..4642e74
--- /dev/null
+++ b/engines/glk/alan2/parse.h
@@ -0,0 +1,112 @@
+/* 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_ALAN2_PARSE
+#define GLK_ALAN2_PARSE
+
+namespace Glk {
+namespace Alan2 {
+
+#define LISTLEN 100
+
+class Parser {
+public:
+	Parser();
+
+	/**
+	 * Parse a new player command
+	 */
+	void parse();
+
+private:
+	void unknown(char *inputStr);
+	int lookup(char *wrd);
+	char *gettoken(char *tokenBuffer);
+	void agetline();
+	void scan();
+	void nonverb();
+	Abool objhere(Aword obj);
+	Aword acthere(Aword act);
+	Abool isHere(Aword id);
+	void buildall(ParamElem list[]);
+	void listCopy(ParamElem a[], ParamElem b[]);
+	bool listContains(ParamElem l[], Aword e);
+	void listIntersection(ParamElem a[], ParamElem b[]);
+	void listCopyFromDictionary(ParamElem p[], Aword r[]);
+	int listLength(ParamElem a[]);
+	void listCompact(ParamElem a[]);
+	void listMerge(ParamElem a[], ParamElem b[]);
+	void listSubtract(ParamElem a[], ParamElem b[]);
+	void unambig(ParamElem plst[]);
+	void simple(ParamElem olst[]);
+	void complex(ParamElem olst[]);
+	bool claCheck(ClaElem *cla);
+	void resolve(ParamElem plst[]);
+	bool endOfTable(StxElem *addr);
+	bool endOfTable(ElmElem *addr);
+	bool endOfTable(ClaElem *addr);
+	bool endOfTable(VrbElem *addr);
+	bool endOfTable(AltElem *addr);
+	bool endOfTable(ChkElem *addr);
+	AltElem *findalt(Aword vrbsadr, Aword param);
+	bool trycheck(Aaddr adr, bool act);
+	bool possible();
+	void tryMatch(ParamElem mlst[]);
+	void match(ParamElem *mlst);
+	void action(ParamElem plst[]);
+
+	// TODO: Initialize / move these
+	int wrds[LISTLEN / 2];	// List of parsed words
+	int wrdidx;			// and an index into it
+
+	bool plural = false;
+
+	// Syntax Parameters
+	int paramidx;			// Index in params
+	ParamElem *params;		// List of params
+	static ParamElem *pparams;	// Previous parameter list
+	static ParamElem *mlst;		// Multiple objects list
+	static ParamElem *pmlst;	// Previous multiple list
+
+	StxElem *stxs;		// Syntax table pointer
+	LocElem *locs;		// Location table pointer
+
+	// Literals
+	LitElem litValues[MAXPARAMS + 1];
+
+	// What did the user say?
+	int vrbwrd;			// The word he used
+	int vrbcode;			// The code for that verb
+
+	bool eol;	// Looking at End of line? Yes, initially
+	char *token;
+
+	WrdElem *dict;		// Dictionary pointer
+	int dictsize;
+
+	int allLength;		// No. of objects matching 'all'
+};
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
+
+#endif
diff --git a/engines/glk/alan2/rules.cpp b/engines/glk/alan2/rules.cpp
new file mode 100644
index 0000000..14c8671
--- /dev/null
+++ b/engines/glk/alan2/rules.cpp
@@ -0,0 +1,87 @@
+/* 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/alan2/acode.h"
+#include "glk/alan2/interpreter.h"
+#include "glk/alan2/rules.h"
+#include "glk/alan2/types.h"
+#include "common/debug.h"
+
+namespace Glk {
+namespace Alan2 {
+
+// TODO: Refactor these into debug flags
+const bool trcflg = false;
+const bool stpflg = false;
+
+void Rules::parseRules() {
+	bool change = true;
+	int i;
+
+	for (i = 1; !endOfTable(&_ruls[i - 1]); i++)
+		_ruls[i - 1].run = false;
+
+	while (change) {
+		change = false;
+		for (i = 1; !endOfTable(&_ruls[i - 1]); i++) {
+			if (!_ruls[i - 1].run) {
+				if (trcflg) {
+					debug("\n<RULE %d (at ", i);
+					//debugsay(cur.loc);	// TODO
+					if (!stpflg)
+						debug("), Evaluating");
+					else
+						debug("), Evaluating:>\n");
+				}
+
+				_interpreter->interpret(_ruls[i - 1].exp);
+
+				if (_stack->pop()) {
+					change = true;
+					_ruls[i - 1].run = true;
+
+					if (trcflg)
+						if (!stpflg)
+							debug(", Executing:>\n");
+						else {
+							debug("\nRULE %d (at ", i);
+							//debugsay(cur.loc);	// TODO
+							debug("), Executing:>\n");
+						}
+
+					_interpreter->interpret(_ruls[i - 1].stms);
+					
+				} else if (trcflg && !stpflg) {
+					debug(":>\n");
+				}
+			}
+		}
+	}
+}
+
+bool Rules::endOfTable(RulElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
diff --git a/engines/glk/alan2/rules.h b/engines/glk/alan2/rules.h
new file mode 100644
index 0000000..9d5e8bf
--- /dev/null
+++ b/engines/glk/alan2/rules.h
@@ -0,0 +1,51 @@
+/* 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_ALAN2_RULES
+#define GLK_ALAN2_RULES
+
+#include "common/stack.h"
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/types.h"
+
+namespace Glk {
+namespace Alan2 {
+
+class Interpreter;
+
+class Rules {
+public:
+	Rules(RulElem *rules, Alan2Stack *stack, Interpreter *interpreter) : _ruls(rules), _stack(stack), _interpreter(interpreter) {}
+	void parseRules();
+
+private:
+	bool endOfTable(RulElem *addr);
+
+	RulElem *_ruls;
+	Alan2Stack *_stack;
+	Interpreter *_interpreter;
+};
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
+
+#endif
diff --git a/engines/glk/alan2/saveload.cpp b/engines/glk/alan2/saveload.cpp
new file mode 100644
index 0000000..c68c54d
--- /dev/null
+++ b/engines/glk/alan2/saveload.cpp
@@ -0,0 +1,218 @@
+/* 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 "common/savefile.h"
+#include "glk/alan2/acode.h"
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/saveload.h"
+#include "glk/alan2/types.h"
+
+namespace Glk {
+namespace Alan2 {
+
+void SaveLoad::save() {
+	int i;
+	Common::SaveFileManager *saveFileMan = _vm->getSaveFileManager();
+	Common::OutSaveFile *saveFile = nullptr;
+	Common::String str;
+	AtrElem *atr;
+
+	// TODO
+#if 0
+	frefid_t fref = glk_fileref_create_by_prompt(fileusage_SavedGame, filemode_Write, 0);
+	if (fref == NULL)
+		_vm->printError(M_SAVEFAILED);
+
+	strcpy(str, garglk_fileref_get_name(fref));
+	glk_fileref_destroy(fref);
+#endif
+
+	if (str.empty())
+		str = _prevSaveName;
+
+	_vm->col = 1;
+
+	// TODO
+#if 0
+	if ((savfil = fopen(str, READ_MODE)) != NULL)
+		// It already existed
+		if (!confirm(M_SAVEOVERWRITE))
+			_vm->printError(MSGMAX);            // Return to player without saying anything
+
+	if ((savfil = fopen(str, WRITE_MODE)) == NULL)
+		_vm->printError(M_SAVEFAILED);
+#endif
+
+	saveFile = saveFileMan->openForSaving(str);
+
+	_prevSaveName = str;
+
+	// Save version of interpreter and name of game
+	saveFile->write(_vm->header->vers, sizeof(Aword));
+	saveFile->writeString(_gameName);
+	saveFile->writeByte('\0');
+	// Save current values
+	saveFile->write(&_vm->cur, sizeof(_vm->cur));
+
+	// Save actors
+	for (i = ACTMIN; i <= ACTMAX; i++) {
+		saveFile->writeUint32LE(_actors[i - ACTMIN].loc);
+		saveFile->writeUint32LE(_actors[i - ACTMIN].script);
+		saveFile->writeUint32LE(_actors[i - ACTMIN].step);
+		saveFile->writeUint32LE(_actors[i - ACTMIN].count);
+		if (_actors[i - ACTMIN].atrs)
+			for (atr = (AtrElem *)addrTo(_actors[i - ACTMIN].atrs); !endOfTable(atr); atr++)
+				saveFile->writeUint32LE(atr->val);
+	}
+
+	// Save locations
+	for (i = LOCMIN; i <= LOCMAX; i++) {
+		saveFile->writeUint32LE(_locations[i - LOCMIN].describe);
+		if (_locations[i - LOCMIN].atrs)
+			for (atr = (AtrElem *)addrTo(_locations[i - LOCMIN].atrs); !endOfTable(atr); atr++)
+				saveFile->writeUint32LE(atr->val);
+	}
+
+	// Save objects
+	for (i = OBJMIN; i <= OBJMAX; i++) {
+		saveFile->writeUint32LE(_objects[i - OBJMIN].loc);
+		if (_objects[i - OBJMIN].atrs)
+			for (atr = (AtrElem *)addrTo(_objects[i - OBJMIN].atrs); !endOfTable(atr); atr++)
+				saveFile->writeUint32LE(atr->val);
+	}
+
+	// Save the event queue
+	_events[*_eventTop].time = 0;        // Mark the top
+	for (i = 0; i < *_eventTop + 1; i++)
+		saveFile->write(&_events[i], sizeof(_events[0]));
+
+	// Save scores
+	for (i = 0; _vm->scores[i] != EOF; i++)
+		saveFile->writeUint32LE(_vm->scores[i]);
+
+	delete saveFile;
+}
+
+void SaveLoad::restore() {
+	int i, tmp;
+	Common::SaveFileManager *saveFileMan = _vm->getSaveFileManager();
+	Common::InSaveFile *saveFile = nullptr;
+	Common::String str;
+	AtrElem *atr;
+	char savedVersion[4];
+	char savedName[256];
+
+	// TODO
+#if 0
+	frefid_t fref = glk_fileref_create_by_prompt(fileusage_SavedGame, filemode_Read, 0);
+	if (fref == NULL)
+		_vm->printError(M_SAVEFAILED);
+
+	strcpy(str, garglk_fileref_get_name(fref));
+	glk_fileref_destroy(fref);
+#endif
+
+	_vm->col = 1;
+
+	if (str.empty())
+		str = _prevSaveName;	// Use the name temporarily
+
+	if ((saveFile = saveFileMan->openForLoading(str)) == nullptr) {
+		_vm->printError(M_SAVEMISSING);
+		return;
+	}
+
+	_prevSaveName = str;		// Save it for future use
+
+	saveFile->read(savedVersion, sizeof(Aword));
+
+	// 4f - save file version check doesn't seem to work on PC's!
+	if (strncmp(savedVersion, _vm->header->vers, 4)) {
+		delete saveFile;
+		_vm->printError(M_SAVEVERS);
+		return;
+	}
+
+	i = 0;
+
+	while ((savedName[i++] = saveFile->readByte()) != '\0');
+
+	if (savedName != _gameName) {
+		delete saveFile;
+		_vm->printError(M_SAVENAME);
+		return;
+	}
+
+	// Restore current values
+	saveFile->read(&_vm->cur, sizeof(_vm->cur));
+
+	// Restore actors
+	for (i = ACTMIN; i <= ACTMAX; i++) {
+		_actors[i - ACTMIN].loc = saveFile->readUint32LE();
+		_actors[i - ACTMIN].script = saveFile->readUint32LE();
+		_actors[i - ACTMIN].step = saveFile->readUint32LE();
+		_actors[i - ACTMIN].count = saveFile->readUint32LE();
+
+		if (_actors[i - ACTMIN].atrs)
+			for (atr = (AtrElem *)addrTo(_actors[i - ACTMIN].atrs); !endOfTable(atr); atr++)
+				atr->val = saveFile->readUint32LE();
+	}
+
+	// Restore locations
+	for (i = LOCMIN; i <= LOCMAX; i++) {
+		_locations[i - LOCMIN].describe = saveFile->readUint32LE();
+		if (_locations[i - LOCMIN].atrs)
+			for (atr = (AtrElem *)addrTo(_locations[i - LOCMIN].atrs); !endOfTable(atr); atr++)
+				atr->val = saveFile->readUint32LE();
+	}
+
+	// Restore objects
+	for (i = OBJMIN; i <= OBJMAX; i++) {
+		_objects[i - OBJMIN].loc = saveFile->readUint32LE();
+		if (_objects[i - OBJMIN].atrs)
+			for (atr = (AtrElem *)addrTo(_objects[i - OBJMIN].atrs); !endOfTable(atr); atr++)
+				atr->val = saveFile->readUint32LE();
+	}
+
+	// Restore the event queue
+	*_eventTop = 0;
+	do {
+		saveFile->read(&_events[*_eventTop], sizeof(_events[0]));
+		(*_eventTop)++;
+	} while (_events[*_eventTop - 1].time != 0);
+
+	(*_eventTop)--;
+
+	// Restore scores
+	for (i = 0; _vm->scores[i] != EOF; i++)
+		_vm->scores[i] = saveFile->readUint32LE();
+
+	delete saveFile;
+}
+
+bool SaveLoad::endOfTable(AtrElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
diff --git a/engines/glk/alan2/saveload.h b/engines/glk/alan2/saveload.h
new file mode 100644
index 0000000..32a02bb
--- /dev/null
+++ b/engines/glk/alan2/saveload.h
@@ -0,0 +1,55 @@
+/* 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_ALAN2_SAVELOAD
+#define GLK_ALAN2_SAVELOAD
+
+#include "common/scummsys.h"
+#include "glk/alan2/types.h"
+
+namespace Glk {
+namespace Alan2 {
+
+class SaveLoad {
+public:
+	SaveLoad(Common::String &gameName, ActElem *actors, LocElem *locations, ObjElem *objects, EvtqElem *events, int *eventTop) : 
+	_gameName(gameName), _actors(actors), _locations(locations), _objects(objects), _events(events), _eventTop(eventTop) {}
+	void save();
+	void restore();
+private:
+	bool endOfTable(AtrElem *addr);
+	
+	Common::String _prevSaveName;
+
+	// Save state related variables
+	Common::String _gameName;
+	ActElem *_actors;
+	LocElem *_locations;
+	ObjElem *_objects;
+	EvtqElem *_events;
+	int *_eventTop;
+};
+
+} // End of namespace Alan2
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/alan2/types.h b/engines/glk/alan2/types.h
new file mode 100644
index 0000000..b403cf9
--- /dev/null
+++ b/engines/glk/alan2/types.h
@@ -0,0 +1,271 @@
+/* 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_ALAN2_TYPES
+#define GLK_ALAN2_TYPES
+
+#include "glk/alan2/acode.h"
+
+namespace Glk {
+namespace Alan2 {
+
+// CONSTANTS
+
+#define ACTMIN (_vm->header->actmin)
+#define ACTMAX (_vm->header->actmax)
+#define OBJMIN (_vm->header->objmin)
+#define OBJMAX (_vm->header->objmax)
+#define LOCMIN (_vm->header->locmin)
+#define LOCMAX (_vm->header->locmax)
+#define CNTMIN (_vm->header->cntmin)
+#define CNTMAX (_vm->header->cntmax)
+#define LITMIN (_vm->header->locmax + 1)
+#define LITMAX (_vm->header->locmax + 1 + litCount)
+#define EVTMIN (_vm->header->evtmin)
+#define EVTMAX (_vm->header->evtmax)
+
+#define HERO ACTMIN
+
+
+#define addrTo(x) (&_vm->memory[x])
+
+// The word classes are represented as numbers but in the dictonary they are generated as bits
+#define isVerb(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_VRB))!=0)
+#define isConj(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_CONJ))!=0)
+#define isBut(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_BUT))!=0)
+#define isThem(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_THEM))!=0)
+#define isIt(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_IT))!=0)
+#define isNoun(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_NOUN))!=0)
+#define isAdj(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_ADJ))!=0)
+#define isPrep(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_PREP))!=0)
+#define isAll(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_ALL))!=0)
+#define isDir(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_DIR))!=0)
+#define isNoise(word) (word < dictsize && (dict[word].wordClass&((Aword)1L<<WRD_NOISE))!=0)
+#define isLiteral(word) (word >= dictsize)
+
+
+// TYPES
+
+// Amachine variables 
+typedef struct CurVars {
+	int
+	  vrb,
+	  obj,
+	  loc,
+	  act,
+	  tick,
+	  score,
+	  visits;
+} CurVars;
+
+// The various tables 
+typedef struct WrdElem {	// Dictionary 
+	Aaddr wrd;			// ACODE address to string 
+	Aword wordClass;		// Word class 
+	Aword code;
+	Aaddr adjrefs;		// Address to reference list 
+	Aaddr nounrefs;		// Address to reference list 
+} WrdElem;
+
+typedef struct ActElem {	// ACTOR TABLE 
+	Aword loc;			// Location 
+	Abool describe;		// Description flag 
+	Aaddr nam;			// Address to name printing code 
+	Aaddr atrs;			// Address to attribute list 
+	Aword cont;			// Code for the container props if any 
+	Aword script;			// Which script is he using 
+	Aaddr scradr;			// Address to script table 
+	Aword step;
+	Aword count;
+	Aaddr vrbs;
+	Aaddr dscr;			// Address of description code 
+} ActElem;
+
+typedef struct ScrElem {	// SCRIPT TABLE 
+	Aword code;			// Script number 
+	Aaddr dscr;			// Optional description statements 
+	Aaddr steps;			// Address to steps 
+} ScrElem;
+
+typedef struct StepElem {	// STEP TABLE 
+	Aword after;			// After how many ticks? 
+	Aaddr exp;			// Address to expression saying when 
+	Aaddr stm;			// Address to the actual code 
+} StepElem;
+
+typedef struct LocElem {	// LOCATION TABLE 
+	Aaddr nams;			// Address of name printing code 
+	Aaddr dscr;			// Address of description code 
+	Aaddr does;			// Address of does code 
+	Aword describe;		// Description flag & counter 
+	Aaddr atrs;			// Address of attribute list 
+	Aaddr exts;			// Address of exit list 
+	Aaddr vrbs;			// Address of local verb list 
+} LocElem;
+
+typedef struct ExtElem {	// EXIT TABLE structure 
+	Abool done;			// Flag for reverse/convert process 
+	Aword code;			// Direction code 
+	Aaddr checks;			// Address of check table 
+	Aaddr action;			// Address of action code 
+	Aword next;			// Number of next location 
+} ExtElem;
+
+typedef struct ChkElem {	// CHECK TABLE 
+	Aaddr exp;			// ACODE address to expression code 
+	Aaddr stms;			// ACODE address to statement code 
+} ChkElem;
+
+typedef struct VrbElem {	// VERB TABLE 
+	Aword code;			// Code for the verb 
+	Aaddr alts;			// Address to alternatives 
+} VrbElem;
+
+typedef struct StxElem {	// SYNTAX TABLE 
+	Aword code;			// Code for verb word 
+	Aaddr elms;			// Address to element tables 
+} StxElem;
+
+typedef struct ElmElem26 {	// ELEMENT TABLES 
+	Aword code;			// Code for this element, 0 -> parameter 
+	Abool multiple;		// May be multiple (if parameter) 
+	Aaddr next;			// Address to next element table ... 
+				// ... or class check if EOS 
+} ElmElem26;
+
+typedef struct ElmElem {	// ELEMENT TABLES 
+	Aword code;			// Code for this element, 0 -> parameter 
+	Aword flags;			// Flags for multiple/omni (if parameter) 
+				// CHANGED: v2.7 from Abool for multiple 
+	Aaddr next;			// Address to next element table ... 
+				// ... or class check if EOS 
+} ElmElem;
+
+typedef struct ClaElem {	// CLASS DEFINITION TABLE 
+	Aword code;			// Parameter number 
+	Aword classes;		// Parameter classes 
+	Aaddr stms;			// Exception statements 
+} ClaElem;
+
+typedef struct AltElem {	// VERB ALTERNATIVE TABLE 
+	Abool done;			// Flag for patching (reverse/convert) process 
+	Aword param;			// Parameter number 
+	Aword qual;			// Verb execution qualifier 
+	Aaddr checks;			// Address of the check table 
+	Aaddr action;			// Address of the action code 
+} AltElem;
+
+typedef struct AtrElem {	// ATTRIBUTE LIST 
+	Aword val;			// Its value 
+	Aaddr stradr;			// Address to the name 
+} AtrElem;
+
+typedef struct ObjElem25 {	// OBJECT TABLE of 2.5 format
+	Aword loc;			// Current location 
+	Abool describe;		// Describe flag 
+	Aaddr atrs;			// Address of attribute list 
+	Aword cont;			// Index to container properties if any 
+	Aaddr vrbs;			// Address to local verb table 
+	Aaddr dscr1;			// Address to Aword description code 
+	Aaddr dscr2;			// Address to short description code 
+} ObjElem25;
+
+typedef struct ObjElem {	// OBJECT TABLE 
+	Aword loc;			// Current location 
+	Abool describe;		// Describe flag 
+	Aaddr atrs;			// Address of attribute list 
+	Aword cont;			// Index to container properties if any 
+	Aaddr vrbs;			// Address to local verb table 
+	Aaddr dscr1;			// Address to Aword description code 
+	Aaddr art;			// Article printing code? Else use default 
+				// INTRODUCED: v2.6 
+	Aaddr dscr2;			// Address to short description code 
+} ObjElem;
+
+typedef struct CntElem {	// CONTAINER TABLE 
+	Aaddr lims;			// Address to limit check code 
+	Aaddr header;			// Address to header code 
+	Aaddr empty;			// Address to empty code 
+	Aword parent;			// Object or actor index 
+	Aaddr nam;			// Address to statement printing name 
+} CntElem;
+
+typedef struct LimElem {	// LIMIT Type 
+	Aword atr;			// Attribute that limits 
+	Aword val;			// And the limiting value 
+	Aaddr stms;			// Statements if fail 
+} LimElem;
+
+typedef struct RulElem {	// RULE TABLE 
+	Abool run;			// Is rule already run? 
+	Aaddr exp;			// Address to expression code 
+	Aaddr stms;			// Address to run 
+} RulElem;
+
+typedef struct EvtElem {	// EVENT TABLE 
+	Aaddr stradr;			// Address to name string 
+	Aaddr code;			// Address of code to run 
+} EvtElem;
+
+typedef struct EvtqElem {	// EVENT QUEUE ELEMENT 
+	int time;
+	int event;
+	int where;
+} EvtqElem;
+
+typedef struct IniElem {	// STRING INITIALISATION TABLE 
+	Aword fpos;			// File position 
+	Aword len;			// Length 
+	Aword adr;			// Where to store the string 
+} IniElem;
+
+typedef struct MsgElem26 {	// MESSAGE TABLE 
+	Aword fpos;			// File position 
+	Aword len;			// Length of message 
+} MsgElem26;
+
+typedef struct MsgElem {	// MESSAGE TABLE 
+	Aaddr stms;			// Address to statements
+				// Changed v2.7 from fpos+len in .dat 
+} MsgElem;
+
+
+typedef struct ParamElem {	// PARAMETER 
+	Aword code;			// Code for this parameter (0=multiple) 
+	Aword firstWord;		// Index to first word used by player 
+	Aword lastWord;			// d:o to last 
+} ParamElem;
+
+typedef enum Type {TYPNUM, TYPSTR} Type;
+
+typedef struct LitElem {	// LITERAL 
+	Type type;
+	Aptr value;
+} LitElem;
+
+#define MAXPARAMS 9
+#define MAXENTITY (_vm->header->actmax)
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
+
+#endif
diff --git a/engines/glk/alan2/util.h b/engines/glk/alan2/util.h
new file mode 100644
index 0000000..3f5a482
--- /dev/null
+++ b/engines/glk/alan2/util.h
@@ -0,0 +1,88 @@
+/* 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_ALAN2_UTIL
+#define GLK_ALAN2_UTIL
+
+#include "glk/alan2/acode.h"
+#include "glk/alan2/alan2.h"
+#include "glk/alan2/types.h"
+
+namespace Glk {
+namespace Alan2 {
+
+// TODO: Move these
+LitElem litValues[];
+uint32 litCount = 0;	// for LITMAX
+extern ActElem *acts;	// Actor table pointer
+extern ObjElem *objs;	// Object table pointer
+
+// Type checks 
+bool isObj(Aword x) {
+	return x >= OBJMIN && x <= OBJMAX;
+}
+
+bool isAct(Aword x) {
+	return x >= ACTMIN && x <= ACTMAX;
+}
+
+bool isCnt(Aword x) {
+	return (x >= CNTMIN && x <= CNTMAX) ||
+		(isObj(x) && objs[x - OBJMIN].cont != 0) ||
+		(isAct(x) && acts[x - ACTMIN].cont != 0);
+}
+
+bool isLoc(Aword x) {
+	return x >= LOCMIN && x <= LOCMAX;
+}
+
+bool isNum(Aword x) {
+	return x >= LITMIN && x <= LITMAX && litValues[x - LITMIN].type == TYPNUM;
+}
+
+bool isStr(Aword x) {
+	return x >= LITMIN && x <= LITMAX && litValues[x - LITMIN].type == TYPSTR;
+}
+
+bool isLit(Aword x) {
+	return x >= LITMIN && x <= LITMAX;
+}
+
+bool endOfTable(LimElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+bool endOfTable(ScrElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+bool endOfTable(ExtElem *addr) {
+	Aword *x = (Aword *)addr;
+	return *x == EOF;
+}
+
+} // End of namespace Alan2
+} // Engine of namespace GLK
+
+#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 13d6305..8125a02 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -23,7 +23,13 @@ MODULE_OBJS := \
 	window_text_buffer.o \
 	window_text_grid.o \
 	alan2/alan2.o \
+	alan2/decode.o \
 	alan2/detection.o \
+	alan2/execute.o \
+	alan2/interpreter.o \
+	alan2/parse.o \
+	alan2/rules.o \
+	alan2/saveload.o \
 	frotz/config.o \
 	frotz/detection.o \
 	frotz/frotz.o \


Commit: c6d6f8de0a0347932cd6fd1ec8ef5e12ce5e9de9
    https://github.com/scummvm/scummvm/commit/c6d6f8de0a0347932cd6fd1ec8ef5e12ce5e9de9
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2018-12-28T13:41:39+02:00

Commit Message:
GLK: ALAN2: Fix compilation

Changed paths:
    engines/glk/alan2/util.h


diff --git a/engines/glk/alan2/util.h b/engines/glk/alan2/util.h
index 3f5a482..fa33af3 100644
--- a/engines/glk/alan2/util.h
+++ b/engines/glk/alan2/util.h
@@ -31,7 +31,7 @@ namespace Glk {
 namespace Alan2 {
 
 // TODO: Move these
-LitElem litValues[];
+extern LitElem *litValues;
 uint32 litCount = 0;	// for LITMAX
 extern ActElem *acts;	// Actor table pointer
 extern ObjElem *objs;	// Object table pointer


Commit: d96f9428b396be5342bfb0bdfe38a810a22e22fd
    https://github.com/scummvm/scummvm/commit/d96f9428b396be5342bfb0bdfe38a810a22e22fd
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2018-12-28T13:41:39+02:00

Commit Message:
GLK: ALAN2: Formatting fixes

Changed paths:
    engines/glk/alan2/alan2.cpp
    engines/glk/alan2/decode.cpp
    engines/glk/alan2/decode.h
    engines/glk/alan2/execute.cpp
    engines/glk/alan2/parse.cpp
    engines/glk/alan2/rules.cpp
    engines/glk/alan2/types.h


diff --git a/engines/glk/alan2/alan2.cpp b/engines/glk/alan2/alan2.cpp
index c29a124..f9e65fc 100644
--- a/engines/glk/alan2/alan2.cpp
+++ b/engines/glk/alan2/alan2.cpp
@@ -84,30 +84,25 @@ bool Alan2::is_gamefile_valid() {
 	return true;
 }
 
-void Alan2::output(const Common::String str)
-{
+void Alan2::output(const Common::String str) {
 	// TODO
 }
 
-void Alan2::printMessage(MsgKind msg)
-{
+void Alan2::printMessage(MsgKind msg) {
 	// TODO
 }
 
-void Alan2::printError(MsgKind msg)
-{
+void Alan2::printError(MsgKind msg) {
 	// TODO
 }
 
-void Alan2::paragraph()
-{
+void Alan2::paragraph() {
 	if (col != 1)
 		newLine();
 	newLine();
 }
 
-void Alan2::newLine()
-{
+void Alan2::newLine() {
 	// TODO
 }
 
diff --git a/engines/glk/alan2/decode.cpp b/engines/glk/alan2/decode.cpp
index ba14412..aaf297b 100644
--- a/engines/glk/alan2/decode.cpp
+++ b/engines/glk/alan2/decode.cpp
@@ -94,7 +94,7 @@ int Decode::decodeChar() {
 
 // Save so much about the decoding process, so it is possible to restore
 // and continue later.
-DecodeInfo* Decode::pushDecode() {
+DecodeInfo *Decode::pushDecode() {
 	DecodeInfo *info = new DecodeInfo();
 
 	info->fpos = _txtFile->pos();
@@ -109,7 +109,7 @@ DecodeInfo* Decode::pushDecode() {
 
 // Restore enough info about the decoding process, so it is possible to
 // continue after having decoded something else
-void Decode::popDecode (DecodeInfo *info){
+void Decode::popDecode (DecodeInfo *info) {
 	_txtFile->seek(info->fpos, SEEK_CUR);
 	_decodeBuffer = info->buffer;
 	_bitsToGo = info->bits;
diff --git a/engines/glk/alan2/decode.h b/engines/glk/alan2/decode.h
index fff6819..1361bad 100644
--- a/engines/glk/alan2/decode.h
+++ b/engines/glk/alan2/decode.h
@@ -40,8 +40,7 @@ typedef struct DecodeInfo {
 	CodeValue low;
 } DecodeInfo;
 
-class Decode
-{
+class Decode {
 public:
 	Decode(Common::File *txtFile, Aword *freq): _txtFile(txtFile), _freq(freq) {}
 	void startDecoding();
diff --git a/engines/glk/alan2/execute.cpp b/engines/glk/alan2/execute.cpp
index 5b81b30..c60d927 100644
--- a/engines/glk/alan2/execute.cpp
+++ b/engines/glk/alan2/execute.cpp
@@ -22,6 +22,7 @@
 
 #include "common/stack.h"
 #include "glk/alan2/alan2.h"
+#include "glk/alan2/decode.h"
 #include "glk/alan2/execute.h"
 #include "glk/alan2/interpreter.h"
 #include "glk/alan2/saveload.h"
@@ -29,7 +30,6 @@
 #include "glk/alan2/util.h"
 #include "common/debug.h"
 #include "common/file.h"
-#include "decode.h"
 
 namespace Glk {
 namespace Alan2 {
diff --git a/engines/glk/alan2/parse.cpp b/engines/glk/alan2/parse.cpp
index ebb0af9..c0777e0 100644
--- a/engines/glk/alan2/parse.cpp
+++ b/engines/glk/alan2/parse.cpp
@@ -589,7 +589,7 @@ bool Parser::claCheck(ClaElem *cla) {
 	if ((cla->classes&(Aword)CLA_CACT) != 0)
 	    ok = ok || (isCnt(params[cla->code-1].code) && isAct(params[cla->code-1].code));
 
-  return ok;
+	return ok;
 }
 
 // In case the syntax did not indicate omnipotent powers (allowed
@@ -804,7 +804,8 @@ void Parser::tryMatch(ParamElem mlst[]) {
 					}
 				} else
 					params[paramidx++] = tlst[0];
-					params[paramidx].code = EOF;
+				
+				params[paramidx].code = EOF;
 			}
 
 			elms = (ElmElem *) addrTo(elms->next);
diff --git a/engines/glk/alan2/rules.cpp b/engines/glk/alan2/rules.cpp
index 14c8671..04fc00a 100644
--- a/engines/glk/alan2/rules.cpp
+++ b/engines/glk/alan2/rules.cpp
@@ -45,7 +45,7 @@ void Rules::parseRules() {
 		for (i = 1; !endOfTable(&_ruls[i - 1]); i++) {
 			if (!_ruls[i - 1].run) {
 				if (trcflg) {
-					debug("\n<RULE %d (at ", i);
+					debug("\n<RULE %d (at ", i);	// TODO: Debug output formatting?
 					//debugsay(cur.loc);	// TODO
 					if (!stpflg)
 						debug("), Evaluating");
diff --git a/engines/glk/alan2/types.h b/engines/glk/alan2/types.h
index b403cf9..aefe451 100644
--- a/engines/glk/alan2/types.h
+++ b/engines/glk/alan2/types.h
@@ -67,163 +67,162 @@ namespace Alan2 {
 
 // Amachine variables 
 typedef struct CurVars {
-	int
-	  vrb,
-	  obj,
-	  loc,
-	  act,
-	  tick,
-	  score,
-	  visits;
+	int vrb;
+	int obj;
+	int loc;
+	int act;
+	int tick;
+	int score;
+	int visits;
 } CurVars;
 
 // The various tables 
 typedef struct WrdElem {	// Dictionary 
-	Aaddr wrd;			// ACODE address to string 
+	Aaddr wrd;				// ACODE address to string 
 	Aword wordClass;		// Word class 
 	Aword code;
-	Aaddr adjrefs;		// Address to reference list 
-	Aaddr nounrefs;		// Address to reference list 
+	Aaddr adjrefs;			// Address to reference list 
+	Aaddr nounrefs;			// Address to reference list 
 } WrdElem;
 
 typedef struct ActElem {	// ACTOR TABLE 
-	Aword loc;			// Location 
-	Abool describe;		// Description flag 
-	Aaddr nam;			// Address to name printing code 
-	Aaddr atrs;			// Address to attribute list 
-	Aword cont;			// Code for the container props if any 
+	Aword loc;				// Location 
+	Abool describe;			// Description flag 
+	Aaddr nam;				// Address to name printing code 
+	Aaddr atrs;				// Address to attribute list 
+	Aword cont;				// Code for the container props if any 
 	Aword script;			// Which script is he using 
 	Aaddr scradr;			// Address to script table 
 	Aword step;
 	Aword count;
 	Aaddr vrbs;
-	Aaddr dscr;			// Address of description code 
+	Aaddr dscr;				// Address of description code 
 } ActElem;
 
 typedef struct ScrElem {	// SCRIPT TABLE 
-	Aword code;			// Script number 
-	Aaddr dscr;			// Optional description statements 
+	Aword code;				// Script number 
+	Aaddr dscr;				// Optional description statements 
 	Aaddr steps;			// Address to steps 
 } ScrElem;
 
 typedef struct StepElem {	// STEP TABLE 
 	Aword after;			// After how many ticks? 
-	Aaddr exp;			// Address to expression saying when 
-	Aaddr stm;			// Address to the actual code 
+	Aaddr exp;				// Address to expression saying when 
+	Aaddr stm;				// Address to the actual code 
 } StepElem;
 
 typedef struct LocElem {	// LOCATION TABLE 
-	Aaddr nams;			// Address of name printing code 
-	Aaddr dscr;			// Address of description code 
-	Aaddr does;			// Address of does code 
-	Aword describe;		// Description flag & counter 
-	Aaddr atrs;			// Address of attribute list 
-	Aaddr exts;			// Address of exit list 
-	Aaddr vrbs;			// Address of local verb list 
+	Aaddr nams;				// Address of name printing code 
+	Aaddr dscr;				// Address of description code 
+	Aaddr does;				// Address of does code 
+	Aword describe;			// Description flag & counter 
+	Aaddr atrs;				// Address of attribute list 
+	Aaddr exts;				// Address of exit list 
+	Aaddr vrbs;				// Address of local verb list 
 } LocElem;
 
 typedef struct ExtElem {	// EXIT TABLE structure 
-	Abool done;			// Flag for reverse/convert process 
-	Aword code;			// Direction code 
+	Abool done;				// Flag for reverse/convert process 
+	Aword code;				// Direction code 
 	Aaddr checks;			// Address of check table 
 	Aaddr action;			// Address of action code 
-	Aword next;			// Number of next location 
+	Aword next;				// Number of next location 
 } ExtElem;
 
 typedef struct ChkElem {	// CHECK TABLE 
-	Aaddr exp;			// ACODE address to expression code 
-	Aaddr stms;			// ACODE address to statement code 
+	Aaddr exp;				// ACODE address to expression code 
+	Aaddr stms;				// ACODE address to statement code 
 } ChkElem;
 
 typedef struct VrbElem {	// VERB TABLE 
-	Aword code;			// Code for the verb 
-	Aaddr alts;			// Address to alternatives 
+	Aword code;				// Code for the verb 
+	Aaddr alts;				// Address to alternatives 
 } VrbElem;
 
 typedef struct StxElem {	// SYNTAX TABLE 
-	Aword code;			// Code for verb word 
-	Aaddr elms;			// Address to element tables 
+	Aword code;				// Code for verb word 
+	Aaddr elms;				// Address to element tables 
 } StxElem;
 
 typedef struct ElmElem26 {	// ELEMENT TABLES 
-	Aword code;			// Code for this element, 0 -> parameter 
-	Abool multiple;		// May be multiple (if parameter) 
-	Aaddr next;			// Address to next element table ... 
-				// ... or class check if EOS 
+	Aword code;				// Code for this element, 0 -> parameter 
+	Abool multiple;			// May be multiple (if parameter) 
+	Aaddr next;				// Address to next element table ... 
+							// ... or class check if EOS 
 } ElmElem26;
 
 typedef struct ElmElem {	// ELEMENT TABLES 
-	Aword code;			// Code for this element, 0 -> parameter 
+	Aword code;				// Code for this element, 0 -> parameter 
 	Aword flags;			// Flags for multiple/omni (if parameter) 
-				// CHANGED: v2.7 from Abool for multiple 
-	Aaddr next;			// Address to next element table ... 
-				// ... or class check if EOS 
+							// CHANGED: v2.7 from Abool for multiple 
+	Aaddr next;				// Address to next element table ... 
+							// ... or class check if EOS 
 } ElmElem;
 
 typedef struct ClaElem {	// CLASS DEFINITION TABLE 
-	Aword code;			// Parameter number 
-	Aword classes;		// Parameter classes 
-	Aaddr stms;			// Exception statements 
+	Aword code;				// Parameter number 
+	Aword classes;			// Parameter classes 
+	Aaddr stms;				// Exception statements 
 } ClaElem;
 
 typedef struct AltElem {	// VERB ALTERNATIVE TABLE 
-	Abool done;			// Flag for patching (reverse/convert) process 
+	Abool done;				// Flag for patching (reverse/convert) process 
 	Aword param;			// Parameter number 
-	Aword qual;			// Verb execution qualifier 
+	Aword qual;				// Verb execution qualifier 
 	Aaddr checks;			// Address of the check table 
 	Aaddr action;			// Address of the action code 
 } AltElem;
 
 typedef struct AtrElem {	// ATTRIBUTE LIST 
-	Aword val;			// Its value 
+	Aword val;				// Its value 
 	Aaddr stradr;			// Address to the name 
 } AtrElem;
 
 typedef struct ObjElem25 {	// OBJECT TABLE of 2.5 format
-	Aword loc;			// Current location 
-	Abool describe;		// Describe flag 
-	Aaddr atrs;			// Address of attribute list 
-	Aword cont;			// Index to container properties if any 
-	Aaddr vrbs;			// Address to local verb table 
+	Aword loc;				// Current location 
+	Abool describe;			// Describe flag 
+	Aaddr atrs;				// Address of attribute list 
+	Aword cont;				// Index to container properties if any 
+	Aaddr vrbs;				// Address to local verb table 
 	Aaddr dscr1;			// Address to Aword description code 
 	Aaddr dscr2;			// Address to short description code 
 } ObjElem25;
 
 typedef struct ObjElem {	// OBJECT TABLE 
-	Aword loc;			// Current location 
-	Abool describe;		// Describe flag 
-	Aaddr atrs;			// Address of attribute list 
-	Aword cont;			// Index to container properties if any 
-	Aaddr vrbs;			// Address to local verb table 
+	Aword loc;				// Current location 
+	Abool describe;			// Describe flag 
+	Aaddr atrs;				// Address of attribute list 
+	Aword cont;				// Index to container properties if any 
+	Aaddr vrbs;				// Address to local verb table 
 	Aaddr dscr1;			// Address to Aword description code 
-	Aaddr art;			// Article printing code? Else use default 
-				// INTRODUCED: v2.6 
+	Aaddr art;				// Article printing code? Else use default 
+							// INTRODUCED: v2.6 
 	Aaddr dscr2;			// Address to short description code 
 } ObjElem;
 
 typedef struct CntElem {	// CONTAINER TABLE 
-	Aaddr lims;			// Address to limit check code 
+	Aaddr lims;				// Address to limit check code 
 	Aaddr header;			// Address to header code 
 	Aaddr empty;			// Address to empty code 
 	Aword parent;			// Object or actor index 
-	Aaddr nam;			// Address to statement printing name 
+	Aaddr nam;				// Address to statement printing name 
 } CntElem;
 
 typedef struct LimElem {	// LIMIT Type 
-	Aword atr;			// Attribute that limits 
-	Aword val;			// And the limiting value 
-	Aaddr stms;			// Statements if fail 
+	Aword atr;				// Attribute that limits 
+	Aword val;				// And the limiting value 
+	Aaddr stms;				// Statements if fail 
 } LimElem;
 
 typedef struct RulElem {	// RULE TABLE 
-	Abool run;			// Is rule already run? 
-	Aaddr exp;			// Address to expression code 
-	Aaddr stms;			// Address to run 
+	Abool run;				// Is rule already run? 
+	Aaddr exp;				// Address to expression code 
+	Aaddr stms;				// Address to run 
 } RulElem;
 
 typedef struct EvtElem {	// EVENT TABLE 
 	Aaddr stradr;			// Address to name string 
-	Aaddr code;			// Address of code to run 
+	Aaddr code;				// Address of code to run 
 } EvtElem;
 
 typedef struct EvtqElem {	// EVENT QUEUE ELEMENT 
@@ -233,24 +232,24 @@ typedef struct EvtqElem {	// EVENT QUEUE ELEMENT
 } EvtqElem;
 
 typedef struct IniElem {	// STRING INITIALISATION TABLE 
-	Aword fpos;			// File position 
-	Aword len;			// Length 
-	Aword adr;			// Where to store the string 
+	Aword fpos;				// File position 
+	Aword len;				// Length 
+	Aword adr;				// Where to store the string 
 } IniElem;
 
 typedef struct MsgElem26 {	// MESSAGE TABLE 
-	Aword fpos;			// File position 
-	Aword len;			// Length of message 
+	Aword fpos;				// File position 
+	Aword len;				// Length of message 
 } MsgElem26;
 
 typedef struct MsgElem {	// MESSAGE TABLE 
-	Aaddr stms;			// Address to statements
-				// Changed v2.7 from fpos+len in .dat 
+	Aaddr stms;				// Address to statements
+							// Changed v2.7 from fpos+len in .dat 
 } MsgElem;
 
 
 typedef struct ParamElem {	// PARAMETER 
-	Aword code;			// Code for this parameter (0=multiple) 
+	Aword code;				// Code for this parameter (0=multiple) 
 	Aword firstWord;		// Index to first word used by player 
 	Aword lastWord;			// d:o to last 
 } ParamElem;


Commit: 1abd4bb9072148547494d85c39ca540c1a7647f9
    https://github.com/scummvm/scummvm/commit/1abd4bb9072148547494d85c39ca540c1a7647f9
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2018-12-28T13:41:39+02:00

Commit Message:
GLK: ALAN2: Indentation fixes

Changed paths:
    engines/glk/alan2/execute.cpp
    engines/glk/alan2/interpreter.cpp
    engines/glk/alan2/parse.cpp


diff --git a/engines/glk/alan2/execute.cpp b/engines/glk/alan2/execute.cpp
index c60d927..0d72f07 100644
--- a/engines/glk/alan2/execute.cpp
+++ b/engines/glk/alan2/execute.cpp
@@ -129,12 +129,12 @@ bool Execute::checklim(Aword cnt, Aword obj) {
 }
 
 void Execute::print(Aword fpos, Aword len) {
-	char str[2 * WIDTH];          // String buffer
-	int outlen = 0;               // Current output length
+	char str[2 * WIDTH];			// String buffer
+	int outlen = 0;					// Current output length
 	int ch;
 	int i;
-	long savfp;                   // Temporary saved text file position
-	bool printFlag = false; // Printing already?
+	long savfp;						// Temporary saved text file position
+	bool printFlag = false;			// Printing already?
 	bool savedPrintFlag = printFlag;
 	DecodeInfo *info;                   // Saved decoding info
 
@@ -175,7 +175,7 @@ void Execute::print(Aword fpos, Aword len) {
 			// TODO
 	/*
 #if ISO == 0
-      fromIso(str, str);
+		fromIso(str, str);
 #endif
 	*/
 			_vm->output(str);
@@ -242,7 +242,7 @@ bool Execute::confirm(MsgKind msgno) {
 	char buf[80];
 
 	// This is a bit of a hack since we really want to compare the input,
-    // it could be affirmative, but for now any input is NOT!
+	// it could be affirmative, but for now any input is NOT!
 	_vm->printMessage(msgno);
 
 	// TODO
@@ -267,17 +267,18 @@ void Execute::quit() {
 	char choices[10];
 
 	_vm->paragraph();
+	
 	while (true) {
 		_vm->col = 1;
-	    _vm->statusLine();
-	    _vm->printMessage(M_QUITACTION);
+		_vm->statusLine();
+		_vm->printMessage(M_QUITACTION);
 
 		// TODO
 #if 0
 #ifdef USE_READLINE
-    if (!readline(buf)) terminate(0);
+	if (!readline(buf)) terminate(0);
 #else
-    if (gets(buf) == NULL) terminate(0);
+	if (gets(buf) == NULL) terminate(0);
 #endif
 #endif
 
@@ -360,9 +361,9 @@ void Execute::schedule(Aword evt, Aword whr, Aword aft) {
   
 	// Bubble this event down
 	for (i = etop; i >= 1 && eventq[i-1].time <= time; i--) {
-	    eventq[i].event = eventq[i-1].event;
-	    eventq[i].time = eventq[i-1].time;
-	    eventq[i].where = eventq[i-1].where;
+		eventq[i].event = eventq[i-1].event;
+		eventq[i].time = eventq[i-1].time;
+		eventq[i].where = eventq[i-1].where;
 	}
   
 	eventq[i].time = time;
@@ -378,8 +379,8 @@ void Execute::schedule(Aword evt, Aword whr, Aword aft) {
  * @param atr		The attribute to read
  */
 Aptr Execute::getatr(Aaddr atradr, Aaddr atr) {
-	AtrElem *at = (AtrElem *) addrTo(atradr);
-	return at[atr-1].val;
+	AtrElem *at = (AtrElem *)addrTo(atradr);
+	return at[atr - 1].val;
 }
 
 /**
@@ -390,8 +391,8 @@ Aptr Execute::getatr(Aaddr atradr, Aaddr atr) {
  * @param val		New value
  */
 void Execute::setatr(Aaddr atradr, Aword atr, Aword val) {
-	AtrElem *at = (AtrElem *) addrTo(atradr);
-	at[atr-1].val = val;
+	AtrElem *at = (AtrElem *)addrTo(atradr);
+	at[atr - 1].val = val;
 }
 
 void Execute::makloc(Aword loc, Aword atr, Aword val) {
@@ -408,13 +409,13 @@ void Execute::makact(Aword act, Aword atr, Aword val) {
 
 void Execute::make(Aword id, Aword atr, Aword val) {
 	if (isObj(id))
-	    makobj(id, atr, val);
+		makobj(id, atr, val);
 	else if (isLoc(id))
 		makloc(id, atr, val);
 	else if (isAct(id))
-	    makact(id, atr, val);
+		makact(id, atr, val);
 	else
-	    error("Can't MAKE item (%ld).", (unsigned long)id);
+		error("Can't MAKE item (%ld).", (unsigned long)id);
 }
 
 void Execute::setloc(Aword loc, Aword atr, Aword val) {
@@ -436,9 +437,9 @@ void Execute::set(Aword id, Aword atr, Aword val) {
 	else if (isLoc(id))
 		setloc(id, atr, val);
 	else if (isAct(id))
-	    setact(id, atr, val);
+		setact(id, atr, val);
 	else
-	  error("Can't SET item (%ld).", (unsigned long)id);
+		error("Can't SET item (%ld).", (unsigned long)id);
 }
 
 void Execute::setstr(Aword id, Aword atr, Aword str) {
@@ -455,7 +456,7 @@ void Execute::setstr(Aword id, Aword atr, Aword str) {
  */
 void Execute::incratr(Aaddr atradr, Aword atr, Aword step) {
 	AtrElem *at = (AtrElem *) addrTo(atradr);
-	at[atr-1].val += step;
+	at[atr - 1].val += step;
 }
 
 void Execute::incrloc(Aword loc, Aword atr, Aword step) {
@@ -486,7 +487,7 @@ void Execute::decr(Aword id, Aword atr, Aword step) {
 	if (isObj(id))
 		incrobj(id, atr, -step);
 	else if (isLoc(id))
-	    incrloc(id, atr, -step);
+		incrloc(id, atr, -step);
 	else if (isAct(id))
 		incract(id, atr, -step);
 	else
@@ -516,13 +517,13 @@ Aptr Execute::attribute(Aword id, Aword atr) {
 	if (isObj(id))
 		return objatr(id, atr);
 	else if (isLoc(id))
-	    return locatr(id, atr);
+		return locatr(id, atr);
 	else if (isAct(id))
-	    return actatr(id, atr);
+		return actatr(id, atr);
 	else if (isLit(id))
-	    return litatr(id, atr);
+		return litatr(id, atr);
 	else
-	    error("Can't ATTRIBUTE item (%ld).", (unsigned long) id);
+		error("Can't ATTRIBUTE item (%ld).", (unsigned long) id);
 }
 
 Aptr Execute::strattr(Aword id, Aword atr) {
@@ -655,13 +656,13 @@ void Execute::locate(Aword id, Aword whr) {
 	if (isObj(id))
 		locobj(id, whr);
 	else if (isAct(id))
-	    locact(id, whr);
+		locact(id, whr);
 	else
-		error("Can't LOCATE item (%ld).", (unsigned long) id);
+		error("Can't LOCATE item (%ld).", (unsigned long)id);
 }
 
 Abool Execute::objhere(Aword obj) {
-	if (isCnt(_objs[obj - OBJMIN].loc)) {    // In something?
+	if (isCnt(_objs[obj - OBJMIN].loc)) {	// In something?
 		if (isObj(_objs[obj - OBJMIN].loc) || isAct(_objs[obj - OBJMIN].loc))
 			return(isHere(_objs[obj - OBJMIN].loc));
 		else // If the container wasn't anywhere, assume where HERO is!
@@ -684,7 +685,7 @@ Abool Execute::isHere(Aword id) {
 }
 
 Aword Execute::objnear(Aword obj) {
-	if (isCnt(_objs[obj-OBJMIN].loc)) {    // In something?
+	if (isCnt(_objs[obj-OBJMIN].loc)) {		// In something?
 		if (isObj(_objs[obj-OBJMIN].loc) || isAct(_objs[obj-OBJMIN].loc))
 			return(isNear(_objs[obj-OBJMIN].loc));
 		else  // If the container wasn't anywhere, assume here, so not nearby!
@@ -705,7 +706,7 @@ Abool Execute::isNear(Aword id) {
 	else if (isAct(id))
 		return actnear(id);
 	else
-	    error("Can't NEAR item (%ld).", (unsigned long) id);
+		error("Can't NEAR item (%ld).", (unsigned long) id);
 }
 
 Abool Execute::in(Aword obj, Aword cnt) {
@@ -945,8 +946,7 @@ void Execute::dscrobjs() {
 				sayarticle(i);
 				say(i);
 				found = true;
-			}
-			else {
+			} else {
 				if (multiple) {
 					_vm->_needSpace = false;
 					_vm->printMessage(M_SEEOBJ2);
@@ -1030,10 +1030,10 @@ Aword Execute::rnd(Aword from, Aword to) {
 
 // Between
 Abool Execute::btw(Aint val, Aint low, Aint high) {
-  if (high > low)
-    return low <= val && val <= high;
-  else
-    return high <= val && val <= low;
+	if (high > low)
+		return low <= val && val <= high;
+	else
+		return high <= val && val <= low;
 }
 
 // TODO: Replace this with Common::String functionality
diff --git a/engines/glk/alan2/interpreter.cpp b/engines/glk/alan2/interpreter.cpp
index c8c53a0..5b5024e 100644
--- a/engines/glk/alan2/interpreter.cpp
+++ b/engines/glk/alan2/interpreter.cpp
@@ -754,10 +754,10 @@ void Interpreter::interpret(Aaddr adr) {
 			break;
 		case C_CURVAR:
 			curVar(i);
-		break;
+			break;
 		case C_STMOP: 
 			stMop(i, oldpc);
-	      break;
+			break;
 	    default:
 			error("Unknown instruction class.");
     }
diff --git a/engines/glk/alan2/parse.cpp b/engines/glk/alan2/parse.cpp
index c0777e0..789080f 100644
--- a/engines/glk/alan2/parse.cpp
+++ b/engines/glk/alan2/parse.cpp
@@ -61,13 +61,13 @@ void Parser::unknown(char *inputStr) {
 int Parser::lookup(char *wrd) {
 #if 0
 	for (int i = 0; !endOfTable(&dict[i]); i++) {
-		if (strcmp(wrd, (char *) addrTo(dict[i].wrd)) == 0)
-			return (i);
+		if (strcmp(wrd, (char *)addrTo(dict[i].wrd)) == 0)
+			return i;
 	}
 #endif
 
 	unknown(wrd);
-	return(EOF);
+	return EOF;
 }
 
 char *Parser::gettoken(char *tokenBuffer) {
@@ -97,6 +97,7 @@ char *Parser::gettoken(char *tokenBuffer) {
 
 	oldch = *marker;
 	*marker = '\0';
+	
 	return tokenBuffer;
 }
 
@@ -116,20 +117,20 @@ void Parser::agetline() {
 		debug("> ");
 
 #if 0
-	    if (logflg)
+		if (logflg)
 			fprintf(logfil, "> ");
 #endif
 
 #ifdef USE_READLINE
-	    if (!readline(buf)) {
+		if (!readline(buf)) {
 			newline();
 			quit();
-	    }
+		}
 #else
-	    if (fgets(buf, LISTLEN, stdin) == NULL) {
+		if (fgets(buf, LISTLEN, stdin) == NULL) {
 			newline();
 			quit();
-	    }
+		}
 #endif
 
 		getPageSize();
@@ -146,11 +147,11 @@ void Parser::agetline() {
 
 		token = gettoken(isobuf);
 
-	    if (token != NULL && strcmp("debug", token) == 0 && _vm->header->debug) {
+		if (token != NULL && strcmp("debug", token) == 0 && _vm->header->debug) {
 			dbgflg = true;
 			debug();
 			token = NULL;
-	    }
+		}
 	} while (token == NULL);
 
   eol = false;
@@ -194,7 +195,7 @@ void Parser::scan() {
 		} else if (token[0] == '\"') {
 			if (litCount > MAXPARAMS)
 				error("Too many parameters.");
-      
+  
 			wrds[i++] = dictsize + litCount; // Word outside dictionary = literal
 			litValues[litCount].type = TYPSTR;
 
@@ -234,7 +235,7 @@ void Parser::nonverb() {
 }
 
 Abool Parser::objhere(Aword obj) {
-	if (isCnt(objs[obj - OBJMIN].loc)) {    // In something?
+	if (isCnt(objs[obj - OBJMIN].loc)) {	// In something?
 		if (isObj(objs[obj - OBJMIN].loc) || isAct(objs[obj - OBJMIN].loc))
 			return(isHere(objs[obj - OBJMIN].loc));
 // TODO
@@ -279,7 +280,7 @@ void Parser::buildall(ParamElem list[]) {
 	if (!found)
 		_vm->printError(M_WHAT_ALL);
 	else
-	    list[i].code = EOF;
+		list[i].code = EOF;
 }
 
 void Parser::listCopy(ParamElem a[], ParamElem b[]) {
@@ -380,7 +381,7 @@ void Parser::unambig(ParamElem plst[]) {
 
 	if (isLiteral(wrds[wrdidx])) {
 		// Transform the word into a reference to the literal value
-		plst[0].code = wrds[wrdidx++]-dictsize+LITMIN;
+		plst[0].code = wrds[wrdidx++] - dictsize + LITMIN;
 		plst[0].firstWord = EOF;	// No words used!
 		plst[1].code = EOF;
 		return;
@@ -389,7 +390,8 @@ void Parser::unambig(ParamElem plst[]) {
 	plst[0].code = EOF;		// Make empty
 
 	if (isIt(wrds[wrdidx])) {
-	    wrdidx++;
+		wrdidx++;
+		
 		// Use last object in previous command!
 		for (i = listLength(pparams)-1; i >= 0 && (pparams[i].code == 0 || pparams[i].code >= LITMIN); i--);
 		
@@ -447,12 +449,13 @@ void Parser::unambig(ParamElem plst[]) {
 			// Perhaps the last word was also a noun?
 			listCopy(plst, savlst);	// Restore to before last adjective
 			listCopyFromDictionary(refs, (Aword *)addrTo(dict[wrds[wrdidx-1]].nounrefs));
+			
 			if (plst[0].code == EOF)
 				listCopy(plst, refs);
-		else
-			listIntersection(plst, refs);
-	} else
-		_vm->printError(M_NOUN);
+			else
+				listIntersection(plst, refs);
+		} else
+			_vm->printError(M_NOUN);
 	}
 
 	lastWord = wrdidx - 1;
@@ -465,7 +468,7 @@ void Parser::unambig(ParamElem plst[]) {
 
 		listCompact(plst);
 	}
-    
+
 	if (listLength(plst) > 1 || (found && listLength(plst) == 0)) {
 		params[0].code = 0;		/* Just make it anything != EOF */
 		params[0].firstWord = firstWord; /* Remember words for errors below */
@@ -579,15 +582,15 @@ bool Parser::claCheck(ClaElem *cla) {
 	if ((cla->classes&(Aword)CLA_CNT) != 0)
 		ok = ok || isCnt(params[cla->code-1].code);
 	if ((cla->classes&(Aword)CLA_ACT) != 0)
-	    ok = ok || isAct(params[cla->code-1].code);
+		ok = ok || isAct(params[cla->code-1].code);
 	if ((cla->classes&(Aword)CLA_NUM) != 0)
 		ok = ok || isNum(params[cla->code-1].code);
 	if ((cla->classes&(Aword)CLA_STR) != 0)
-	    ok = ok || isStr(params[cla->code-1].code);
+		ok = ok || isStr(params[cla->code-1].code);
 	if ((cla->classes&(Aword)CLA_COBJ) != 0)
-	    ok = ok || (isCnt(params[cla->code-1].code) && isObj(params[cla->code-1].code));
+		ok = ok || (isCnt(params[cla->code-1].code) && isObj(params[cla->code-1].code));
 	if ((cla->classes&(Aword)CLA_CACT) != 0)
-	    ok = ok || (isCnt(params[cla->code-1].code) && isAct(params[cla->code-1].code));
+		ok = ok || (isCnt(params[cla->code-1].code) && isAct(params[cla->code-1].code));
 
 	return ok;
 }
@@ -606,7 +609,7 @@ void Parser::resolve(ParamElem plst[]) {
 				params[1].code = EOF;	// But be sure to terminate
 				_vm->printError(M_NO_SUCH);
 			}
-    }
+	}
 }
 
 bool Parser::endOfTable(StxElem *addr) {
@@ -905,7 +908,7 @@ void Parser::match(ParamElem *mlst) {
 	tryMatch(mlst);			// try to understand what the user said
 
 	if (wrds[wrdidx] != EOF && !isConj(wrds[wrdidx]))
-	    _vm->printError(M_WHAT);
+		_vm->printError(M_WHAT);
 	if (wrds[wrdidx] != EOF)	// More on this line?
 		wrdidx++;			// If so skip the AND
 }
@@ -967,7 +970,7 @@ void Parser::parse() {
 		match(mlst);
 		action(mlst);		// mlst contains possible multiple params
 	} else {
-	    params[0].code = EOF;
+		params[0].code = EOF;
 		pmlst[0].code = EOF;
 		nonverb();
 	}


Commit: aa8bcac2335804a8e8be47ea7fb27b09148ed49c
    https://github.com/scummvm/scummvm/commit/aa8bcac2335804a8e8be47ea7fb27b09148ed49c
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2018-12-28T13:41:39+02:00

Commit Message:
GLK: Fix namespace comments

Changed paths:
    engines/glk/alan2/interpreter.cpp
    engines/glk/alan2/interpreter.h
    engines/glk/alan2/rules.cpp
    engines/glk/alan2/rules.h
    engines/glk/alan2/saveload.cpp
    engines/glk/alan2/util.h
    engines/glk/tads/tads2/data.cpp
    engines/glk/tads/tads2/data.h
    engines/glk/tads/tads2/regex.cpp
    engines/glk/tads/tads2/regex.h


diff --git a/engines/glk/alan2/interpreter.cpp b/engines/glk/alan2/interpreter.cpp
index 5b5024e..2f0775e 100644
--- a/engines/glk/alan2/interpreter.cpp
+++ b/engines/glk/alan2/interpreter.cpp
@@ -765,4 +765,4 @@ void Interpreter::interpret(Aaddr adr) {
 }
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
diff --git a/engines/glk/alan2/interpreter.h b/engines/glk/alan2/interpreter.h
index dbc1558..cbc9bcb 100644
--- a/engines/glk/alan2/interpreter.h
+++ b/engines/glk/alan2/interpreter.h
@@ -54,6 +54,6 @@ private:
 };
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
 
 #endif
diff --git a/engines/glk/alan2/rules.cpp b/engines/glk/alan2/rules.cpp
index 04fc00a..1d20429 100644
--- a/engines/glk/alan2/rules.cpp
+++ b/engines/glk/alan2/rules.cpp
@@ -84,4 +84,4 @@ bool Rules::endOfTable(RulElem *addr) {
 }
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
diff --git a/engines/glk/alan2/rules.h b/engines/glk/alan2/rules.h
index 9d5e8bf..194c7d0 100644
--- a/engines/glk/alan2/rules.h
+++ b/engines/glk/alan2/rules.h
@@ -46,6 +46,6 @@ private:
 };
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
 
 #endif
diff --git a/engines/glk/alan2/saveload.cpp b/engines/glk/alan2/saveload.cpp
index c68c54d..8d2f7a4 100644
--- a/engines/glk/alan2/saveload.cpp
+++ b/engines/glk/alan2/saveload.cpp
@@ -215,4 +215,4 @@ bool SaveLoad::endOfTable(AtrElem *addr) {
 }
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
diff --git a/engines/glk/alan2/util.h b/engines/glk/alan2/util.h
index fa33af3..a9cd26f 100644
--- a/engines/glk/alan2/util.h
+++ b/engines/glk/alan2/util.h
@@ -83,6 +83,6 @@ bool endOfTable(ExtElem *addr) {
 }
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
 
 #endif
diff --git a/engines/glk/tads/tads2/data.cpp b/engines/glk/tads/tads2/data.cpp
index e142f37..a2bbf74 100644
--- a/engines/glk/tads/tads2/data.cpp
+++ b/engines/glk/tads/tads2/data.cpp
@@ -69,4 +69,4 @@ size_t Data::size() const {
 
 } // End of namespace TADS2
 } // End of namespace TADS
-} // Engine of namespace GLK
+} // End of namespace Glk
diff --git a/engines/glk/tads/tads2/data.h b/engines/glk/tads/tads2/data.h
index 2276d37..8db2153 100644
--- a/engines/glk/tads/tads2/data.h
+++ b/engines/glk/tads/tads2/data.h
@@ -66,6 +66,6 @@ public:
 
 } // End of namespace TADS2
 } // End of namespace TADS
-} // Engine of namespace Glk
+} // End of namespace Glk
 
 #endif
diff --git a/engines/glk/tads/tads2/regex.cpp b/engines/glk/tads/tads2/regex.cpp
index d5eee3a..c040420 100644
--- a/engines/glk/tads/tads2/regex.cpp
+++ b/engines/glk/tads/tads2/regex.cpp
@@ -1272,4 +1272,4 @@ int re_context::compile_and_match(const char *pattern, size_t patlen,
 
 } // End of namespace TADS2
 } // End of namespace TADS
-} // Engine of namespace GLK
+} // End of namespace Glk
diff --git a/engines/glk/tads/tads2/regex.h b/engines/glk/tads/tads2/regex.h
index e945efb..4c48a89 100644
--- a/engines/glk/tads/tads2/regex.h
+++ b/engines/glk/tads/tads2/regex.h
@@ -310,6 +310,6 @@ public:
 
 } // End of namespace TADS2
 } // End of namespace TADS
-} // Engine of namespace GLK
+} // End of namespace Glk
 
 #endif


Commit: 1c055f686e94c1676b8617cc21e0221c0d97dad9
    https://github.com/scummvm/scummvm/commit/1c055f686e94c1676b8617cc21e0221c0d97dad9
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2018-12-28T13:41:39+02:00

Commit Message:
GLK: ALAN2: Move comments to header files

Changed paths:
    engines/glk/alan2/decode.cpp
    engines/glk/alan2/decode.h
    engines/glk/alan2/parse.cpp
    engines/glk/alan2/parse.h


diff --git a/engines/glk/alan2/decode.cpp b/engines/glk/alan2/decode.cpp
index aaf297b..3a93d1d 100644
--- a/engines/glk/alan2/decode.cpp
+++ b/engines/glk/alan2/decode.cpp
@@ -92,8 +92,6 @@ int Decode::decodeChar() {
 	return symbol - 1;
 }
 
-// Save so much about the decoding process, so it is possible to restore
-// and continue later.
 DecodeInfo *Decode::pushDecode() {
 	DecodeInfo *info = new DecodeInfo();
 
@@ -107,8 +105,6 @@ DecodeInfo *Decode::pushDecode() {
 	return info;
 }
 
-// Restore enough info about the decoding process, so it is possible to
-// continue after having decoded something else
 void Decode::popDecode (DecodeInfo *info) {
 	_txtFile->seek(info->fpos, SEEK_CUR);
 	_decodeBuffer = info->buffer;
diff --git a/engines/glk/alan2/decode.h b/engines/glk/alan2/decode.h
index 1361bad..75a35dc 100644
--- a/engines/glk/alan2/decode.h
+++ b/engines/glk/alan2/decode.h
@@ -31,22 +31,33 @@ namespace Glk {
 namespace Alan2 {
 
 // Structure for saved decode info
-typedef struct DecodeInfo {
+struct DecodeInfo {
 	long fpos;
 	int buffer;
 	int bits;
 	CodeValue value;
 	CodeValue high;
 	CodeValue low;
-} DecodeInfo;
+};
 
 class Decode {
 public:
 	Decode(Common::File *txtFile, Aword *freq): _txtFile(txtFile), _freq(freq) {}
 	void startDecoding();
 	int decodeChar();
+	
+	/**
+	 * Save so much about the decoding process, so it is possible to restore
+	 * and continue later.
+	 */
 	DecodeInfo *pushDecode();
+	
+	/**
+	 * Restore enough info about the decoding process, so it is possible to
+	 * continue after having decoded something else.
+	 */
 	void popDecode(DecodeInfo *info);
+	
 	int inputBit();
 
 private:
@@ -64,6 +75,6 @@ private:
 };
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
 
 #endif
diff --git a/engines/glk/alan2/parse.cpp b/engines/glk/alan2/parse.cpp
index 789080f..45fac67 100644
--- a/engines/glk/alan2/parse.cpp
+++ b/engines/glk/alan2/parse.cpp
@@ -216,7 +216,6 @@ void Parser::scan() {
 	} while (!eol);
 }
 
-// Search for a non-verb command
 void Parser::nonverb() {
 	if (isDir(wrds[wrdidx])) {
 		wrdidx++;
@@ -264,7 +263,6 @@ Abool Parser::isHere(Aword id) {
 
 // ----------------------------------------------------------------------------
 
-// Build a list of objects matching 'all'
 void Parser::buildall(ParamElem list[]) {
 	int o, i = 0;
 	bool found = false;
@@ -310,7 +308,6 @@ void Parser::listIntersection(ParamElem a[], ParamElem b[]) {
 	a[last].code = EOF;
 }
 
-// Copy the refs (in dictionary) to a paramList
 void Parser::listCopyFromDictionary(ParamElem p[], Aword r[]) {
 	int i;
 
@@ -331,7 +328,6 @@ int Parser::listLength(ParamElem a[]) {
 	return (i);
 }
 
-// Compact a list, i.e remove any NULL elements
 void Parser::listCompact(ParamElem a[]) {
 	int i, j;
 
@@ -342,7 +338,6 @@ void Parser::listCompact(ParamElem a[]) {
 	a[i].code = EOF;
 }
 
-// Merge the paramElems of one list into the first
 void Parser::listMerge(ParamElem a[], ParamElem b[]) {
 	int i, last;
 
@@ -356,7 +351,6 @@ void Parser::listMerge(ParamElem a[], ParamElem b[]) {
 	}
 }
 
-// Subtract two lists
 void Parser::listSubtract(ParamElem a[], ParamElem b[]) {
 	for (int i = 0; a[i].code != EOF; i++)
 		if (listContains(b, a[i].code))
@@ -365,7 +359,6 @@ void Parser::listSubtract(ParamElem a[], ParamElem b[]) {
 	listCompact(a);
 }
 
-// Match an unambigous object reference
 void Parser::unambig(ParamElem plst[]) {
 	int i;
 	bool found = false;		// Adjective or noun found?
@@ -485,7 +478,6 @@ void Parser::unambig(ParamElem plst[]) {
 	}
 }
 
-// Match a simple verb command
 void Parser::simple(ParamElem olst[]) {
 	static ParamElem *tlst = NULL;
 	int savidx = wrdidx;
@@ -541,7 +533,6 @@ void Parser::simple(ParamElem olst[]) {
 	}
 }
 
-// Match a complex verb command
 void Parser::complex(ParamElem olst[]) {
 	// Above this procedure we can use the is* tests, but not below since
 	// they work on words.Below all is converted to indices into the
@@ -595,8 +586,6 @@ bool Parser::claCheck(ClaElem *cla) {
 	return ok;
 }
 
-// In case the syntax did not indicate omnipotent powers (allowed
-// access to remote object), we need to remove non - present parameters
 void Parser::resolve(ParamElem plst[]) {
 	if (allLength > 0)
 		return;	// ALL has already done this
@@ -642,13 +631,6 @@ bool Parser::endOfTable(ChkElem *addr) {
 	return *x == EOF;
 }
 
-/**
- * Find the verb alternative wanted in a verb list and return
- * the address to it.
- * 
- * @param vrbsadr	Address to start of list
- * @param param		Which parameter to match
- */
 AltElem *Parser::findalt(Aword vrbsadr, Aword param) {
 	VrbElem *vrb;
 	AltElem *alt;
@@ -668,12 +650,6 @@ AltElem *Parser::findalt(Aword vrbsadr, Aword param) {
 	return NULL;
 }
 
-/**
- * Tries a check, returns TRUE if it passed, FALSE otherwise
- * 
- * @param adr	ACODE address to check table
- * @param act	Act if it fails?
- */
 bool Parser::trycheck(Aaddr adr, bool act) {
 	ChkElem *chk = (ChkElem *)addrTo(adr);
 
@@ -694,7 +670,6 @@ bool Parser::trycheck(Aaddr adr, bool act) {
 	}
 }
 
-// Check if current action is possible according to the CHECKs.
 bool Parser::possible() {
 	AltElem *alt[MAXPARAMS + 2];	// List of alt-pointers, one for each param
 	int i;			// Parameter index
@@ -903,7 +878,6 @@ void Parser::tryMatch(ParamElem mlst[]) {
 	plural = anyPlural;		// Remember that we found plural objects
 }
 
-// Find the verb class (not used currently) and 'tryMatch()'
 void Parser::match(ParamElem *mlst) {
 	tryMatch(mlst);			// try to understand what the user said
 
@@ -913,8 +887,6 @@ void Parser::match(ParamElem *mlst) {
 		wrdidx++;			// If so skip the AND
 }
 
-// Execute all activities commanded.Handles possible multiple actions
-// such as THEM or lists of objects.
 void Parser::action(ParamElem plst[]) {
 	int i, mpos;
 	char marker[10];
@@ -977,4 +949,4 @@ void Parser::parse() {
 }
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
diff --git a/engines/glk/alan2/parse.h b/engines/glk/alan2/parse.h
index 4642e74..7198b2d 100644
--- a/engines/glk/alan2/parse.h
+++ b/engines/glk/alan2/parse.h
@@ -43,35 +43,106 @@ private:
 	char *gettoken(char *tokenBuffer);
 	void agetline();
 	void scan();
+	
+	/**
+	 * Search for a non-verb command
+	 */
 	void nonverb();
+	
 	Abool objhere(Aword obj);
 	Aword acthere(Aword act);
 	Abool isHere(Aword id);
+	
+	/**
+	 * Build a list of objects matching 'all'
+	 */
 	void buildall(ParamElem list[]);
+	
 	void listCopy(ParamElem a[], ParamElem b[]);
 	bool listContains(ParamElem l[], Aword e);
 	void listIntersection(ParamElem a[], ParamElem b[]);
+	
+	/**
+	 * Copy the refs (in dictionary) to a paramList
+	 */
 	void listCopyFromDictionary(ParamElem p[], Aword r[]);
+	
 	int listLength(ParamElem a[]);
+	
+	/**
+	 * Compact a list, i.e remove any NULL elements
+	 */
 	void listCompact(ParamElem a[]);
+	
+	/**
+	 * Merge the paramElems of one list into the first
+	 */
 	void listMerge(ParamElem a[], ParamElem b[]);
+	
+	/**
+	 * Subtract two lists
+	 */
 	void listSubtract(ParamElem a[], ParamElem b[]);
+	
+	/**
+	 * Match an unambigous object reference
+	 */
 	void unambig(ParamElem plst[]);
+	
+	/**
+	 * Match a simple verb command
+	 */
 	void simple(ParamElem olst[]);
+	
+	/**
+	 * Match a complex verb command
+	 */
 	void complex(ParamElem olst[]);
+	
 	bool claCheck(ClaElem *cla);
+	
+	/**
+	 * In case the syntax did not indicate omnipotent powers (allowed
+	 * access to remote object), we need to remove non - present parameters
+	 */
 	void resolve(ParamElem plst[]);
+	
 	bool endOfTable(StxElem *addr);
 	bool endOfTable(ElmElem *addr);
 	bool endOfTable(ClaElem *addr);
 	bool endOfTable(VrbElem *addr);
 	bool endOfTable(AltElem *addr);
 	bool endOfTable(ChkElem *addr);
+	
+	/**
+	 * Find the verb alternative wanted in a verb list and return
+	 * the address to it.
+	 * 
+	 * @param vrbsadr	Address to start of list
+	 * @param param		Which parameter to match
+	 */	
 	AltElem *findalt(Aword vrbsadr, Aword param);
+	
+	/**
+	 * Tries a check, returns TRUE if it passed, FALSE otherwise
+	 * 
+	 * @param adr	ACODE address to check table
+	 * @param act	Act if it fails?
+	 */
 	bool trycheck(Aaddr adr, bool act);
+
+	/**
+	 * Check if current action is possible according to the CHECKs.
+	 */
 	bool possible();
+	
 	void tryMatch(ParamElem mlst[]);
 	void match(ParamElem *mlst);
+	
+	/**
+	 * Execute all activities commanded. Handles possible multiple actions
+	 * such as THEM or lists of objects.
+	 */
 	void action(ParamElem plst[]);
 
 	// TODO: Initialize / move these
@@ -107,6 +178,6 @@ private:
 };
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
 
 #endif


Commit: d42cbfde9e1b188222e15bb41801f16ac99515ce
    https://github.com/scummvm/scummvm/commit/d42cbfde9e1b188222e15bb41801f16ac99515ce
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2018-12-28T13:41:39+02:00

Commit Message:
GLK: ALAN2: Adapt C-style enums and align comments

Changed paths:
    engines/glk/alan2/acode.h


diff --git a/engines/glk/alan2/acode.h b/engines/glk/alan2/acode.h
index 764eb19..5b5a5be 100644
--- a/engines/glk/alan2/acode.h
+++ b/engines/glk/alan2/acode.h
@@ -28,12 +28,12 @@
 namespace Glk {
 namespace Alan2 {
 
-typedef size_t Aptr;			// Type for an ACODE memory address
-typedef uint32 Aword;		   // Type for an ACODE word
-typedef uint32 Aaddr;		   // Type for an ACODE address
-typedef uint32 Abool;		   // Type for an ACODE Boolean value
-typedef int32 Aint;			 // Type for an ACODE Integer value
-typedef int CodeValue;		  // Definition for the packing process
+typedef size_t Aptr;				// Type for an ACODE memory address
+typedef uint32 Aword;				// Type for an ACODE word
+typedef uint32 Aaddr;				// Type for an ACODE address
+typedef uint32 Abool;				// Type for an ACODE Boolean value
+typedef int32 Aint;					// Type for an ACODE Integer value
+typedef int CodeValue;				// Definition for the packing process
 
 // Constants for the Acode file, words/block & bytes/block
 #define BLOCKLEN 256L
@@ -47,9 +47,9 @@ typedef int CodeValue;		  // Definition for the packing process
 #define TOPVALUE (((CodeValue)1<<VALUEBITS) - 1) // Highest value possible 
 
 // Half and quarter points in the code value range 
-#define ONEQUARTER (TOPVALUE/4+1)	// Point after first quarter 
-#define HALF (2*ONEQUARTER)		// Point after first half 
-#define THREEQUARTER (3*ONEQUARTER)	// Point after third quarter 
+#define ONEQUARTER (TOPVALUE / 4 + 1)			// Point after first quarter 
+#define HALF (2 * ONEQUARTER)					// Point after first half 
+#define THREEQUARTER (3 * ONEQUARTER)			// Point after third quarter 
 
 
 // AMACHINE Word Classes 
@@ -62,10 +62,10 @@ typedef int WrdKind;
 #define  WRD_PREP 5		// 32 - Preposition 
 #define  WRD_DIR 6		// 64 - Direction 
 #define  WRD_IT 7		// 128 - It 
-#define  WRD_NOISE 8		// 256 - Noise word 
+#define  WRD_NOISE 8	// 256 - Noise word 
 #define  WRD_NOUN 9		// 512 - Noun 
 #define  WRD_ACT 10		// 1024 - Actor 
-#define  WRD_THEM 11		// 2048 - Them 
+#define  WRD_THEM 11	// 2048 - Them 
 #define  WRD_VRB 12		// 4096 - Verb 
 #define  WRD_CLASSES 13
 
@@ -80,40 +80,40 @@ typedef int WrdKind;
 
 
 // Parameter Classes 
-typedef enum ClaKind {		// NOTE! These must have the same order as 
-	CLA_OBJ = 1,			// the name classes in NAM.H 
-	CLA_CNT = (int)CLA_OBJ<<1,
-	CLA_ACT = (int)CLA_CNT<<1,
-	CLA_NUM = (int)CLA_ACT<<1,
-	CLA_STR = (int)CLA_NUM<<1,
-	CLA_COBJ = (int)CLA_STR<<1,
-	CLA_CACT = (int)CLA_COBJ<<1
-} ClaKind;
+enum ClaKind {					// NOTE! These must have the same order as 
+	CLA_OBJ = 1 << 0,			// the name classes in NAM.H 
+	CLA_CNT = 1 << 1,
+	CLA_ACT = 1 << 2,
+	CLA_NUM = 1 << 3,
+	CLA_STR = 1 << 4,
+	CLA_COBJ = 1 << 5,
+	CLA_CACT = 1 << 6
+};
 	
 
 // Verb Qualifiers 
-typedef enum QualClass {
+enum QualClass {
 	Q_DEFAULT,
 	Q_AFTER,
 	Q_BEFORE,
 	Q_ONLY
-} QualClass;
+};
 
 
 // The AMACHINE Operations 
-typedef enum OpClass {
+enum OpClass {
 	C_CONST,
 	C_STMOP,
 	C_CURVAR
-} OpClass;
+};
 
-typedef enum InstClass {
+enum InstClass {
 	I_PRINT,			// Print a string from the text file 
 	I_QUIT,
 	I_LOOK,
 	I_SAVE,
 	I_RESTORE,
-	I_LIST,			// List contents of a container 
+	I_LIST,				// List contents of a container 
 	I_EMPTY,
 	I_SCORE,
 	I_VISITS,
@@ -121,16 +121,16 @@ typedef enum InstClass {
 	I_CANCEL,
 	I_LOCATE,
 	I_MAKE,
-	I_SET,			// Set a numeric attribute to the 
-				// value on top of stack 
+	I_SET,				// Set a numeric attribute to the 
+						// value on top of stack 
 	I_STRSET,			// Set a string valued attribute to a 
-				// copy of the string on top of stack, 
-				// deallocate current contents first 
+						// copy of the string on top of stack, 
+						// deallocate current contents first 
 	I_GETSTR,			// Get a string contents from text 
-				// file, create a copy and push it 
-				// on top of stack 
-	I_INCR,			// Increment an attribute 
-	I_DECR,			// Decrement a numeric attribute 
+						// file, create a copy and push it 
+						// on top of stack 
+	I_INCR,				// Increment an attribute 
+	I_DECR,				// Decrement a numeric attribute 
 	I_USE,
 	I_IN,
 	I_DESCRIBE,
@@ -162,60 +162,60 @@ typedef enum InstClass {
 	I_NOT,
 	I_UMINUS,
 	I_RND,
-	I_SUM,			// SUM-aggregate 
-	I_MAX,			// MAX-aggregate 
+	I_SUM,				// SUM-aggregate 
+	I_MAX,				// MAX-aggregate 
 	I_COUNT,			// COUNT-aggregate 
 	I_RETURN,
 	I_SYSTEM,
 	I_RESTART,			// INTRODUCED: v2.7 
-	I_BTW,			// INTRODUCED: v2.8 
+	I_BTW,				// INTRODUCED: v2.8 
 	I_CONTAINS,			//  -""-  
 	I_DEPSTART,			//  -""-  
 	I_DEPCASE,			//  -""-  
 	I_DEPEXEC,			//  -""-  
 	I_DEPELSE,			//  -""-  
 	I_DEPEND			//  -""-  
-} InstClass;
+};
 
 
-typedef enum VarClass {
+enum VarClass {
 	V_PARAM,
 	V_CURLOC,
 	V_CURACT,
 	V_CURVRB,
 	V_SCORE
-} VarClass;
+};
 
 
 #define I_CLASS(x) ((x)>>28)
 #define I_OP(x)	((x&0x8000000)?(x)|0x0f0000000:(x)&0x0fffffff)
 
 
-typedef struct AcdHdr {
+struct AcdHdr {
 // Important info 
-	char vers[4];			// 01 - Version of compiler 
-	Aword size;			// 02 - Size of ACD-file in Awords 
+	char vers[4];				// 01 - Version of compiler 
+	Aword size;					// 02 - Size of ACD-file in Awords 
 // Options 
-	Abool pack;			// 03 - Is the text packed ? 
-	Aword paglen;			// 04 - Length of a page 
-	Aword pagwidth;		// 05 - and width 
-	Aword debug;			// 06 - Option debug 
+	Abool pack;					// 03 - Is the text packed ? 
+	Aword paglen;				// 04 - Length of a page 
+	Aword pagwidth;				// 05 - and width 
+	Aword debug;				// 06 - Option debug 
 // Data structures 
-	Aaddr dict;			// 07 - Dictionary 
-	Aaddr oatrs;			// 08 - Object default attributes 
-	Aaddr latrs;			// 09 - Location default attributes 
-	Aaddr aatrs;			// 0a - Actor default attributes 
-	Aaddr acts;			// 0b - Actor table 
-	Aaddr objs;			// 0c - Object table 
-	Aaddr locs;			// 0d - Location table 
-	Aaddr stxs;			// 0e - Syntax table 
-	Aaddr vrbs;			// 0f - Verb table 
-	Aaddr evts;			// 10 - Event table 
-	Aaddr cnts;			// 11 - Container table 
-	Aaddr ruls;			// 12 - Rule table 
-	Aaddr init;			// 13 - String init table 
-	Aaddr start;			// 14 - Start code 
-	Aword msgs;			// 15 - Messages table 
+	Aaddr dict;					// 07 - Dictionary 
+	Aaddr oatrs;				// 08 - Object default attributes 
+	Aaddr latrs;				// 09 - Location default attributes 
+	Aaddr aatrs;				// 0a - Actor default attributes 
+	Aaddr acts;					// 0b - Actor table 
+	Aaddr objs;					// 0c - Object table 
+	Aaddr locs;					// 0d - Location table 
+	Aaddr stxs;					// 0e - Syntax table 
+	Aaddr vrbs;					// 0f - Verb table 
+	Aaddr evts;					// 10 - Event table 
+	Aaddr cnts;					// 11 - Container table 
+	Aaddr ruls;					// 12 - Rule table 
+	Aaddr init;					// 13 - String init table 
+	Aaddr start;				// 14 - Start code 
+	Aword msgs;					// 15 - Messages table 
 // Miscellaneous 
 	Aword objmin, objmax;		// 16 - Interval for object codes 
 	Aword actmin, actmax;		// 18 - Interval for actor codes 
@@ -224,16 +224,16 @@ typedef struct AcdHdr {
 	Aword dirmin, dirmax;		// 1e - Interval for direction codes 
 	Aword evtmin, evtmax;		// 20 - Interval for event codes 
 	Aword rulmin, rulmax;		// 22 - Interval for rule codes 
-	Aword maxscore;		// 24 - Maximum score 
-	Aaddr scores;			// 25 - Score table 
-	Aaddr freq;			// 26 - Address to Char freq's for coding 
-	Aword acdcrc;			// 27 - Checksum for acd code (excl. hdr) 
-	Aword txtcrc;			// 28 - Checksum for text data file 
-} AcdHdr;
+	Aword maxscore;				// 24 - Maximum score 
+	Aaddr scores;				// 25 - Score table 
+	Aaddr freq;					// 26 - Address to Char freq's for coding 
+	Aword acdcrc;				// 27 - Checksum for acd code (excl. hdr) 
+	Aword txtcrc;				// 28 - Checksum for text data file 
+};
 
 // Error message numbers 
-typedef enum MsgKind {
-	M_HUH,			// Obsolete 
+enum MsgKind {
+	M_HUH,						// Obsolete 
 	M_WHAT,
 	M_WHAT_ALL,
 	M_WHAT_IT,
@@ -249,7 +249,7 @@ typedef enum MsgKind {
 	M_NO_WAY,
 	M_CANT0,
 	M_CANT,
-	M_NOTHING,			// Obsolete 
+	M_NOTHING,					// Obsolete 
 	M_SEEOBJ1,
 	M_SEEOBJ2,
 	M_SEEOBJ3,
@@ -274,16 +274,16 @@ typedef enum MsgKind {
 	M_SAVEVERS,
 	M_SAVENAME,
 	M_RESTOREFROM,
-	M_REALLY,			// CHANGED: v2.7 from M_RESTART 
-	M_QUITACTION,			// INTRODUCED: v2.7, so M_ARTICLE moved 
-	M_ARTICLE,			// INTRODUCED: v2.6 but replaced the M_NOMSG
+	M_REALLY,					// CHANGED: v2.7 from M_RESTART 
+	M_QUITACTION,				// INTRODUCED: v2.7, so M_ARTICLE moved 
+	M_ARTICLE,					// INTRODUCED: v2.6 but replaced the M_NOMSG
 	MSGMAX
-} MsgKind;
+};
 
 #define M_ARTICLE26 M_QUITACTION
 #define M_MSGMAX26 M_ARTICLE
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
 
 #endif


Commit: 20d53d27f60fa40cad13c4a9fb18b656303a2956
    https://github.com/scummvm/scummvm/commit/20d53d27f60fa40cad13c4a9fb18b656303a2956
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2018-12-28T13:41:39+02:00

Commit Message:
GLK: ALAN2: Adapt C-style enums / structs

Changed paths:
    engines/glk/alan2/types.h


diff --git a/engines/glk/alan2/types.h b/engines/glk/alan2/types.h
index aefe451..7da9e1d 100644
--- a/engines/glk/alan2/types.h
+++ b/engines/glk/alan2/types.h
@@ -66,7 +66,7 @@ namespace Alan2 {
 // TYPES
 
 // Amachine variables 
-typedef struct CurVars {
+struct CurVars {
 	int vrb;
 	int obj;
 	int loc;
@@ -74,18 +74,18 @@ typedef struct CurVars {
 	int tick;
 	int score;
 	int visits;
-} CurVars;
+};
 
 // The various tables 
-typedef struct WrdElem {	// Dictionary 
+struct WrdElem {			// Dictionary 
 	Aaddr wrd;				// ACODE address to string 
 	Aword wordClass;		// Word class 
 	Aword code;
 	Aaddr adjrefs;			// Address to reference list 
 	Aaddr nounrefs;			// Address to reference list 
-} WrdElem;
+};
 
-typedef struct ActElem {	// ACTOR TABLE 
+struct ActElem {			// ACTOR TABLE 
 	Aword loc;				// Location 
 	Abool describe;			// Description flag 
 	Aaddr nam;				// Address to name printing code 
@@ -97,21 +97,21 @@ typedef struct ActElem {	// ACTOR TABLE
 	Aword count;
 	Aaddr vrbs;
 	Aaddr dscr;				// Address of description code 
-} ActElem;
+};
 
-typedef struct ScrElem {	// SCRIPT TABLE 
+struct ScrElem {			// SCRIPT TABLE 
 	Aword code;				// Script number 
 	Aaddr dscr;				// Optional description statements 
 	Aaddr steps;			// Address to steps 
-} ScrElem;
+};
 
-typedef struct StepElem {	// STEP TABLE 
+struct StepElem {			// STEP TABLE 
 	Aword after;			// After how many ticks? 
 	Aaddr exp;				// Address to expression saying when 
 	Aaddr stm;				// Address to the actual code 
-} StepElem;
+};
 
-typedef struct LocElem {	// LOCATION TABLE 
+struct LocElem {			// LOCATION TABLE 
 	Aaddr nams;				// Address of name printing code 
 	Aaddr dscr;				// Address of description code 
 	Aaddr does;				// Address of does code 
@@ -119,66 +119,66 @@ typedef struct LocElem {	// LOCATION TABLE
 	Aaddr atrs;				// Address of attribute list 
 	Aaddr exts;				// Address of exit list 
 	Aaddr vrbs;				// Address of local verb list 
-} LocElem;
+};
 
-typedef struct ExtElem {	// EXIT TABLE structure 
+struct ExtElem {			// EXIT TABLE structure 
 	Abool done;				// Flag for reverse/convert process 
 	Aword code;				// Direction code 
 	Aaddr checks;			// Address of check table 
 	Aaddr action;			// Address of action code 
 	Aword next;				// Number of next location 
-} ExtElem;
+};
 
-typedef struct ChkElem {	// CHECK TABLE 
+struct ChkElem {			// CHECK TABLE 
 	Aaddr exp;				// ACODE address to expression code 
 	Aaddr stms;				// ACODE address to statement code 
-} ChkElem;
+};
 
-typedef struct VrbElem {	// VERB TABLE 
+struct VrbElem {			// VERB TABLE 
 	Aword code;				// Code for the verb 
 	Aaddr alts;				// Address to alternatives 
-} VrbElem;
+};
 
-typedef struct StxElem {	// SYNTAX TABLE 
+struct StxElem {			// SYNTAX TABLE 
 	Aword code;				// Code for verb word 
 	Aaddr elms;				// Address to element tables 
-} StxElem;
+};
 
-typedef struct ElmElem26 {	// ELEMENT TABLES 
+struct ElmElem26 {			// ELEMENT TABLES 
 	Aword code;				// Code for this element, 0 -> parameter 
 	Abool multiple;			// May be multiple (if parameter) 
 	Aaddr next;				// Address to next element table ... 
 							// ... or class check if EOS 
-} ElmElem26;
+};
 
-typedef struct ElmElem {	// ELEMENT TABLES 
+struct ElmElem {			// ELEMENT TABLES 
 	Aword code;				// Code for this element, 0 -> parameter 
 	Aword flags;			// Flags for multiple/omni (if parameter) 
 							// CHANGED: v2.7 from Abool for multiple 
 	Aaddr next;				// Address to next element table ... 
 							// ... or class check if EOS 
-} ElmElem;
+};
 
-typedef struct ClaElem {	// CLASS DEFINITION TABLE 
+struct ClaElem {			// CLASS DEFINITION TABLE 
 	Aword code;				// Parameter number 
 	Aword classes;			// Parameter classes 
 	Aaddr stms;				// Exception statements 
-} ClaElem;
+};
 
-typedef struct AltElem {	// VERB ALTERNATIVE TABLE 
+struct AltElem {			// VERB ALTERNATIVE TABLE 
 	Abool done;				// Flag for patching (reverse/convert) process 
 	Aword param;			// Parameter number 
 	Aword qual;				// Verb execution qualifier 
 	Aaddr checks;			// Address of the check table 
 	Aaddr action;			// Address of the action code 
-} AltElem;
+};
 
-typedef struct AtrElem {	// ATTRIBUTE LIST 
+struct AtrElem {			// ATTRIBUTE LIST 
 	Aword val;				// Its value 
 	Aaddr stradr;			// Address to the name 
-} AtrElem;
+};
 
-typedef struct ObjElem25 {	// OBJECT TABLE of 2.5 format
+struct ObjElem25 {			// OBJECT TABLE of 2.5 format
 	Aword loc;				// Current location 
 	Abool describe;			// Describe flag 
 	Aaddr atrs;				// Address of attribute list 
@@ -186,9 +186,9 @@ typedef struct ObjElem25 {	// OBJECT TABLE of 2.5 format
 	Aaddr vrbs;				// Address to local verb table 
 	Aaddr dscr1;			// Address to Aword description code 
 	Aaddr dscr2;			// Address to short description code 
-} ObjElem25;
+};
 
-typedef struct ObjElem {	// OBJECT TABLE 
+struct ObjElem {			// OBJECT TABLE 
 	Aword loc;				// Current location 
 	Abool describe;			// Describe flag 
 	Aaddr atrs;				// Address of attribute list 
@@ -198,73 +198,75 @@ typedef struct ObjElem {	// OBJECT TABLE
 	Aaddr art;				// Article printing code? Else use default 
 							// INTRODUCED: v2.6 
 	Aaddr dscr2;			// Address to short description code 
-} ObjElem;
+};
 
-typedef struct CntElem {	// CONTAINER TABLE 
+struct CntElem {			// CONTAINER TABLE 
 	Aaddr lims;				// Address to limit check code 
 	Aaddr header;			// Address to header code 
 	Aaddr empty;			// Address to empty code 
 	Aword parent;			// Object or actor index 
 	Aaddr nam;				// Address to statement printing name 
-} CntElem;
+};
 
-typedef struct LimElem {	// LIMIT Type 
+struct LimElem {			// LIMIT Type 
 	Aword atr;				// Attribute that limits 
 	Aword val;				// And the limiting value 
 	Aaddr stms;				// Statements if fail 
-} LimElem;
+};
 
-typedef struct RulElem {	// RULE TABLE 
+struct RulElem {			// RULE TABLE 
 	Abool run;				// Is rule already run? 
 	Aaddr exp;				// Address to expression code 
 	Aaddr stms;				// Address to run 
-} RulElem;
+};
 
-typedef struct EvtElem {	// EVENT TABLE 
+struct EvtElem {			// EVENT TABLE 
 	Aaddr stradr;			// Address to name string 
 	Aaddr code;				// Address of code to run 
-} EvtElem;
+};
 
-typedef struct EvtqElem {	// EVENT QUEUE ELEMENT 
+struct EvtqElem {			// EVENT QUEUE ELEMENT 
 	int time;
 	int event;
 	int where;
-} EvtqElem;
+};
 
-typedef struct IniElem {	// STRING INITIALISATION TABLE 
+struct IniElem {			// STRING INITIALISATION TABLE 
 	Aword fpos;				// File position 
 	Aword len;				// Length 
 	Aword adr;				// Where to store the string 
-} IniElem;
+};
 
-typedef struct MsgElem26 {	// MESSAGE TABLE 
+struct MsgElem26 {			// MESSAGE TABLE 
 	Aword fpos;				// File position 
 	Aword len;				// Length of message 
-} MsgElem26;
+};
 
-typedef struct MsgElem {	// MESSAGE TABLE 
+struct MsgElem {			// MESSAGE TABLE 
 	Aaddr stms;				// Address to statements
 							// Changed v2.7 from fpos+len in .dat 
-} MsgElem;
+};
 
-
-typedef struct ParamElem {	// PARAMETER 
+struct ParamElem {			// PARAMETER 
 	Aword code;				// Code for this parameter (0=multiple) 
 	Aword firstWord;		// Index to first word used by player 
 	Aword lastWord;			// d:o to last 
-} ParamElem;
+};
 
-typedef enum Type {TYPNUM, TYPSTR} Type;
+enum Type {
+	TYPNUM,
+	TYPSTR
+};
 
-typedef struct LitElem {	// LITERAL 
+struct LitElem {			// LITERAL 
 	Type type;
 	Aptr value;
-} LitElem;
+};
 
 #define MAXPARAMS 9
 #define MAXENTITY (_vm->header->actmax)
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
 
 #endif


Commit: 1be46e9207450cdb626e81a2d0347c50577020fc
    https://github.com/scummvm/scummvm/commit/1be46e9207450cdb626e81a2d0347c50577020fc
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2018-12-28T13:41:39+02:00

Commit Message:
GLK: ALAN2: Cleanup, merge some functions, move comments to headers

Changed paths:
    engines/glk/alan2/execute.cpp
    engines/glk/alan2/execute.h


diff --git a/engines/glk/alan2/execute.cpp b/engines/glk/alan2/execute.cpp
index 0d72f07..64b405b 100644
--- a/engines/glk/alan2/execute.cpp
+++ b/engines/glk/alan2/execute.cpp
@@ -48,11 +48,6 @@ bool Execute::exitto(int to, int from) {
 	return false;
 }
 
-/*
- * Count the number of items in a container.
- * 
- * @param cnt	The container to count
- */
 int Execute::count(int cnt) {
 	int j = 0;
 
@@ -63,19 +58,13 @@ int Execute::count(int cnt) {
 	return j;
 }
 
-/*
- * Sum the values of one attribute in a container.Recursively.
- * 
- * @param atr	The attribute to sum over
- * @param cnt	the container to sum
- */
-int Execute::sumatr(Aword atr, Aword cnt) {
+int Execute::sumAttributes(Aword atr, Aword cnt) {
 	int sum = 0;
 
 	for (int i = OBJMIN; i <= OBJMAX; i++) {
 		if (_objs[i - OBJMIN].loc == cnt) {	// Then it's in this container
 			if (_objs[i - OBJMIN].cont != 0)	// This is also a container!
-				sum = sum + sumatr(atr, i);
+				sum = sum + sumAttributes(atr, i);
 			sum = sum + attribute(i, atr);
 		}
 	}
@@ -83,14 +72,7 @@ int Execute::sumatr(Aword atr, Aword cnt) {
 	return sum;
 }
 
-/**
- * Checks if a limit for a container is exceeded.
- * 
- * @param cnt	Container code
- * @param obj	The object to add
- */
-// 
-bool Execute::checklim(Aword cnt, Aword obj) {
+bool Execute::checkContainerLimit(Aword cnt, Aword obj) {
 	LimElem *lim;
 	Aword props;
 
@@ -115,7 +97,7 @@ bool Execute::checklim(Aword cnt, Aword obj) {
 					return true;		// Limit check failed
 				}
 			} else {
-				if (sumatr(lim->atr, cnt) + attribute(obj, lim->atr) > lim->val) {
+				if (sumAttributes(lim->atr, cnt) + attribute(obj, lim->atr) > lim->val) {
 					_vm->_interpreter->interpret(lim->stms);
 					return true;
 				}
@@ -304,12 +286,6 @@ void Execute::restart() {
 	error("Fallthrough in RESTART");
 }
 
-/*----------------------------------------------------------------------
-  eventchk()
-
-  Check if any events are pending. If so execute them.
-  */
-
 void Execute::eventchk() {
 	while (etop != 0 && eventq[etop - 1].time == _vm->cur.tick) {
 		etop--;
@@ -372,72 +348,35 @@ void Execute::schedule(Aword evt, Aword whr, Aword aft) {
 	etop++;
 }
 
-/**
- * Get an attribute value from an attribute list
- * 
- * @param atradr	ACODE address to attribute table
- * @param atr		The attribute to read
- */
-Aptr Execute::getatr(Aaddr atradr, Aaddr atr) {
+Aptr Execute::getAttribute(Aaddr atradr, Aaddr atr) {
 	AtrElem *at = (AtrElem *)addrTo(atradr);
 	return at[atr - 1].val;
 }
 
-/**
- * Set a particular attribute to a value.
- *
- * @param atradr	ACODE address to attribute table
- * @param atr		Attribute code
- * @param val		New value
- */
-void Execute::setatr(Aaddr atradr, Aword atr, Aword val) {
+void Execute::setAttribute(Aaddr atradr, Aword atr, Aword val) {
 	AtrElem *at = (AtrElem *)addrTo(atradr);
 	at[atr - 1].val = val;
 }
 
-void Execute::makloc(Aword loc, Aword atr, Aword val) {
-	setatr(_locs[loc - LOCMIN].atrs, atr, val);
-}
-
-void Execute::makobj(Aword obj, Aword atr, Aword val) {
-	setatr(_objs[obj - OBJMIN].atrs, atr, val);
-}
-
-void Execute::makact(Aword act, Aword atr, Aword val) {
-	setatr(_acts[act - ACTMIN].atrs, atr, val);
-}
-
 void Execute::make(Aword id, Aword atr, Aword val) {
 	if (isObj(id))
-		makobj(id, atr, val);
+		setAttribute(_objs[id - OBJMIN].atrs, atr, val);
 	else if (isLoc(id))
-		makloc(id, atr, val);
+		setAttribute(_locs[id - LOCMIN].atrs, atr, val);
 	else if (isAct(id))
-		makact(id, atr, val);
+		setAttribute(_acts[id - ACTMIN].atrs, atr, val);
 	else
 		error("Can't MAKE item (%ld).", (unsigned long)id);
 }
 
-void Execute::setloc(Aword loc, Aword atr, Aword val) {
-	setatr(_locs[loc - LOCMIN].atrs, atr, val);
-	_locs[loc - LOCMIN].describe = 0;
-}
-
-void Execute::setobj(Aword obj, Aword atr, Aword val) {
-	setatr(_objs[obj - OBJMIN].atrs, atr, val);
-}
-
-void Execute::setact(Aword act, Aword atr, Aword val) {
-	setatr(_acts[act - ACTMIN].atrs, atr, val);
-}
-
 void Execute::set(Aword id, Aword atr, Aword val) {
 	if (isObj(id))
-		setobj(id, atr, val);
-	else if (isLoc(id))
-		setloc(id, atr, val);
-	else if (isAct(id))
-		setact(id, atr, val);
+		setAttribute(_objs[id - OBJMIN].atrs, atr, val);
+	else if (isLoc(id)) {
+		setAttribute(_locs[id - LOCMIN].atrs, atr, val);
+		_locs[id - LOCMIN].describe = 0;
+	} else if (isAct(id))
+		setAttribute(_acts[id - ACTMIN].atrs, atr, val);
 	else
 		error("Can't SET item (%ld).", (unsigned long)id);
 }
@@ -447,36 +386,29 @@ void Execute::setstr(Aword id, Aword atr, Aword str) {
 	set(id, atr, str);
 }
 
-/**
- * Increment a particular attribute by a value.
- * 
- * @param atradr	ACODE address to attribute table
- * @param atr		Attribute code
- * @param step		Step to increment by
- */
-void Execute::incratr(Aaddr atradr, Aword atr, Aword step) {
+void Execute::incAttribute(Aaddr atradr, Aword atr, Aword step) {
 	AtrElem *at = (AtrElem *) addrTo(atradr);
 	at[atr - 1].val += step;
 }
 
-void Execute::incrloc(Aword loc, Aword atr, Aword step) {
-	incratr(_locs[loc - LOCMIN].atrs, atr, step);
+void Execute::incLocation(Aword loc, Aword atr, Aword step) {
+	incAttribute(_locs[loc - LOCMIN].atrs, atr, step);
 	_locs[loc - LOCMIN].describe = 0;
 }
 
-void Execute::incrobj(Aword obj, Aword atr, Aword step) {
-	incratr(_objs[obj - OBJMIN].atrs, atr, step);
+void Execute::incObject(Aword obj, Aword atr, Aword step) {
+	incAttribute(_objs[obj - OBJMIN].atrs, atr, step);
 }
 
 void Execute::incract(Aword act, Aword atr, Aword step) {
-	incratr(_acts[act - ACTMIN].atrs, atr, step);
+	incAttribute(_acts[act - ACTMIN].atrs, atr, step);
 }
 
 void Execute::incr(Aword id, Aword atr, Aword step) {
 	if (isObj(id))
-		incrobj(id, atr, step);
+		incObject(id, atr, step);
 	else if (isLoc(id))
-		incrloc(id, atr, step);
+		incLocation(id, atr, step);
 	else if (isAct(id))
 		incract(id, atr, step);
 	else
@@ -485,44 +417,28 @@ void Execute::incr(Aword id, Aword atr, Aword step) {
 
 void Execute::decr(Aword id, Aword atr, Aword step) {
 	if (isObj(id))
-		incrobj(id, atr, -step);
+		incObject(id, atr, -step);
 	else if (isLoc(id))
-		incrloc(id, atr, -step);
+		incLocation(id, atr, -step);
 	else if (isAct(id))
 		incract(id, atr, -step);
 	else
 		error("Can't DECR item (%ld).", (unsigned long)id);
 }
 
-Aptr Execute::locatr(Aword loc, Aword atr) {
-	return getatr(_locs[loc - LOCMIN].atrs, atr);
-}
-
-Aptr Execute::objatr(Aword obj, Aword atr) {
-	return getatr(_objs[obj - OBJMIN].atrs, atr);
-}
-
-Aptr Execute::actatr(Aword act, Aword atr) {
-	return getatr(_acts[act - ACTMIN].atrs, atr);
-}
-
-Aptr Execute::litatr(Aword lit, Aword atr) {
-	if (atr == 1)
-		return litValues[lit - LITMIN].value;
-	else
-		error("Unknown attribute for literal (%ld).", (unsigned long) atr);
-}
-
 Aptr Execute::attribute(Aword id, Aword atr) {
 	if (isObj(id))
-		return objatr(id, atr);
+		return getAttribute(_objs[id - OBJMIN].atrs, atr);
 	else if (isLoc(id))
-		return locatr(id, atr);
+		return getAttribute(_locs[id - LOCMIN].atrs, atr);
 	else if (isAct(id))
-		return actatr(id, atr);
-	else if (isLit(id))
-		return litatr(id, atr);
-	else
+		return getAttribute(_acts[id - ACTMIN].atrs, atr);
+	else if (isLit(id)) {
+		if (atr == 1)
+			return litValues[id - LITMIN].value;
+		else
+			error("Unknown attribute for literal (%ld).", (unsigned long)atr);
+	} else
 		error("Can't ATTRIBUTE item (%ld).", (unsigned long) id);
 }
 
@@ -604,7 +520,7 @@ void Execute::locobj(Aword obj, Aword whr) {
 	if (isCnt(whr)) { // Into a container
 		if (whr == obj)
 			error("Locating something inside itself.");
-		if (checklim(whr, obj))
+		if (checkContainerLimit(whr, obj))
 			return;
 		else
 			_objs[obj-OBJMIN].loc = whr;
@@ -718,42 +634,6 @@ Abool Execute::in(Aword obj, Aword cnt) {
 	return(_objs[obj - OBJMIN].loc == cnt);
 }
 
-void Execute::sayloc(Aword loc) {
-	_vm->_interpreter->interpret(_locs[loc - LOCMIN].nams);
-}
-
-void Execute::sayobj(Aword obj) {
-	_vm->_interpreter->interpret(_objs[obj - OBJMIN].dscr2);
-}
-
-void Execute::sayact(Aword act) {
-	_vm->_interpreter->interpret(_acts[act - ACTMIN].nam);
-}
-
-void Execute::sayint(Aword val) {
-	char buf[25];
-
-	if (isHere(HERO)) {
-		sprintf(buf, "%ld", (unsigned long) val);
-		_vm->output(buf);
-	}
-}
-
-void Execute::saystr(char *str) {
-	if (isHere(HERO))
-		_vm->output(str);
-	free(str);
-}
-
-void Execute::saylit(Aword lit) {
-	if (isNum(lit))
-		sayint(litValues[lit - LITMIN].value);
-	else {
-		Common::String str = (char *)litValues[lit - LITMIN].value;
-		saystr((char *)str.c_str());
-	}
-}
-
 void Execute::sayarticle(Aword id) {
 	if (!isObj(id))
 		error("Trying to say article of something *not* an object.");
@@ -766,14 +646,17 @@ void Execute::sayarticle(Aword id) {
 void Execute::say(Aword id) {
 	if (isHere(HERO)) {
 		if (isObj(id))
-			sayobj(id);
+			_vm->_interpreter->interpret(_objs[id - OBJMIN].dscr2);
 		else if (isLoc(id))
-			sayloc(id);
+			_vm->_interpreter->interpret(_locs[id - LOCMIN].nams);
 		else if (isAct(id))
-			sayact(id);
-		else if (isLit(id))
-			saylit(id);
-		else
+			_vm->_interpreter->interpret(_acts[id - ACTMIN].nam);
+		else if (isLit(id)) {
+			if (isNum(id))
+				_vm->output(Common::String::format("%ld", litValues[id - LITMIN].value));
+			else
+				_vm->output((char *)litValues[id - LITMIN].value);
+		} else
 			error("Can't SAY item (%ld).", (unsigned long)id);
 	}
 }
@@ -922,7 +805,6 @@ void Execute::empty(Aword cnt, Aword whr) {
 			locate(i, whr);
 }
 
-// Description of current location
 void Execute::dscrobjs() {
 	int i;
 	int prevobj;
@@ -1062,4 +944,4 @@ Abool Execute::streq(char *a, char *b) {
 }
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
diff --git a/engines/glk/alan2/execute.h b/engines/glk/alan2/execute.h
index 82d5c07..9f04ca5 100644
--- a/engines/glk/alan2/execute.h
+++ b/engines/glk/alan2/execute.h
@@ -57,6 +57,9 @@ public:
 	void score(Aword sc);
 	void visits(Aword v);
 
+	/**
+	 * Check if any events are pending. If so execute them.
+	 */
 	void eventchk();
 	void schedule(Aword evt, Aword whr, Aword aft);
 	void cancl(Aword evt);
@@ -78,20 +81,57 @@ public:
 
 private:
 	bool exitto(int to, int from);
+	
+	/**
+	 * Count the number of items in a container.
+	 * 
+	 * @param cnt	The container to count
+	 */
 	int count(int cnt);
-	int sumatr(Aword atr, Aword cnt);
-	bool checklim(Aword cnt, Aword obj);
-	Aptr getatr(Aaddr atradr, Aaddr atr);
-	void setatr(Aaddr atradr, Aword atr, Aword val);
-	void makloc(Aword loc, Aword atr, Aword val);
-	void makobj(Aword obj, Aword atr, Aword val);
-	void makact(Aword act, Aword atr, Aword val);
-	void setloc(Aword loc, Aword atr, Aword val);
-	void setobj(Aword obj, Aword atr, Aword val);
-	void setact(Aword act, Aword atr, Aword val);
-	void incratr(Aaddr atradr, Aword atr, Aword step);
-	void incrloc(Aword loc, Aword atr, Aword step);
-	void incrobj(Aword obj, Aword atr, Aword step);
+	
+	/**
+	 * Sum the values of one attribute in a container. Recursively.
+	 * 
+	 * @param atr	The attribute to sum over
+	 * @param cnt	the container to sum
+	 */
+	int sumAttributes(Aword atr, Aword cnt);
+	
+	/**
+	 * Checks if a limit for a container is exceeded.
+	 * 
+	 * @param cnt	Container code
+	 * @param obj	The object to add
+	 */
+	bool checkContainerLimit(Aword cnt, Aword obj);
+
+	/**
+	 * Get an attribute value from an attribute list
+	 * 
+	 * @param atradr	ACODE address to attribute table
+	 * @param atr		The attribute to read
+	 */	
+	Aptr getAttribute(Aaddr atradr, Aaddr atr);
+	
+	/**
+	 * Set a particular attribute to a value.
+	 *
+	 * @param atradr	ACODE address to attribute table
+	 * @param atr		Attribute code
+	 * @param val		New value
+	 */
+	void setAttribute(Aaddr atradr, Aword atr, Aword val);
+
+	/**
+	 * Increment a particular attribute by a value.
+	 * 
+	 * @param atradr	ACODE address to attribute table
+	 * @param atr		Attribute code
+	 * @param step		Step to increment by
+	 */
+	void incAttribute(Aaddr atradr, Aword atr, Aword step);
+	void incLocation(Aword loc, Aword atr, Aword step);
+	void incObject(Aword obj, Aword atr, Aword step);
 	void incract(Aword act, Aword atr, Aword step);
 	Aword objloc(Aword obj);
 	Aword actloc(Aword act);
@@ -101,20 +141,17 @@ private:
 	Aword acthere(Aword act);
 	Aword objnear(Aword obj);
 	Aword actnear(Aword act);
-	void sayloc(Aword loc);
-	void sayobj(Aword obj);
-	void sayact(Aword act);
-	void saylit(Aword lit);
 	void sayarticle(Aword id);
 	void dscrloc(Aword loc);
 	void dscrobj(Aword obj);
 	void dscract(Aword act);
+	
+	/**
+	 * Description of current location
+	 */
 	void dscrobjs();
+	
 	void dscracts();
-	Aptr locatr(Aword loc, Aword atr);
-	Aptr objatr(Aword obj, Aword atr);
-	Aptr actatr(Aword act, Aword atr);
-	Aptr litatr(Aword lit, Aword atr);
 
 	// The event queue
 	EvtqElem *eventq;	// Event queue
@@ -129,6 +166,6 @@ private:
 };
 
 } // End of namespace Alan2
-} // Engine of namespace GLK
+} // End of namespace Glk
 
 #endif





More information about the Scummvm-git-logs mailing list