--- .gitignore
+++ .gitignore
@@ -23,9 +23,6 @@
 /src/xlat/xlat_parser.c
 /src/xlat/xlat_parser.h
 /src/xlat/xlat_parser.out
-/src/zscript/zcc-parse.c
-/src/zscript/zcc-parse.h
-/src/zscript/zcc-parse.out
 /tools/*/debug
 /tools/*/release
 /tools/*/*.exe
--- src/CMakeLists.txt
+++ src/CMakeLists.txt
@@ -746,13 +746,11 @@ else()
 endif()
 
 add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h
-	COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y
+	COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y .
+	COMMAND lemon xlat_parser.y
+	WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
 	DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y )
 
-add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h
-	COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon
-	DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon )
-
 add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h
 	COMMAND re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re
 	DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re )
@@ -819,7 +817,6 @@ file( GLOB HEADER_FILES
 	textures/*.h
 	thingdef/*.h
 	xlat/*.h
-	zscript/*.h
 	gl/*.h
 	gl/api/*.h
 	gl/data/*.h
@@ -922,9 +919,6 @@ set( NOT_COMPILED_SOURCE_FILES
 	xlat/xlat_parser.y
 	xlat_parser.c
 	xlat_parser.h
-	zscript/zcc-parse.lemon
-	zcc-parse.c
-	zcc-parse.h
 
 	# We could have the ASM macro add these files, but it wouldn't add all
 	# platforms.
@@ -1319,14 +1313,6 @@ set (PCH_SOURCES
 	r_data/renderstyle.cpp
 	r_data/r_interpolate.cpp
 	sfmt/SFMT.cpp
-	zscript/ast.cpp
-	zscript/vmbuilder.cpp
-	zscript/vmdisasm.cpp
-	zscript/vmexec.cpp
-	zscript/vmframe.cpp
-	zscript/zcc_compile.cpp
-	zscript/zcc_expr.cpp
-	zscript/zcc_parser.cpp
 )
 enable_precompiled_headers( g_pch.h PCH_SOURCES )
 
@@ -1390,7 +1376,6 @@ include_directories( .
 	thingdef
 	timidity
 	xlat
-	zscript
 	../gdtoa
 	../dumb/include
 	${CMAKE_BINARY_DIR}/gdtoa
@@ -1520,5 +1505,4 @@ source_group("Shared Game" REGULAR_EXPRE
 source_group("Versioning" FILES version.h win32/zdoom.rc)
 source_group("Win32 Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/win32/.+")
 source_group("Xlat" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/xlat/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h)
-source_group("ZScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/zscript/.+" FILES ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.c ${CMAKE_CURRENT_BINARY_DIR}/zcc-parse.h)
 source_group("Source Files" FILES ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h sc_man_scanner.re)
--- src/zscript/ast.cpp
+++ src/zscript/ast.cpp
@@ -1,831 +0,0 @@
-#include "dobject.h"
-#include "sc_man.h"
-#include "memarena.h"
-#include "zcc_parser.h"
-#include "zcc-parse.h"
-
-class FLispString;
-extern void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *);
-
-static const char *BuiltInTypeNames[] =
-{
-	"sint8", "uint8",
-	"sint16", "uint16",
-	"sint32", "uint32",
-	"intauto",
-
-	"bool",
-	"float32", "float64", "floatauto",
-	"string",
-	"vector2",
-	"vector3",
-	"vector4",
-	"name",
-	"usertype"
-};
-
-class FLispString
-{
-public:
-	operator FString &() { return Str; }
-
-	FLispString()
-	{
-		NestDepth = Column = 0;
-		WrapWidth = 72;
-		NeedSpace = false;
-		ConsecOpens = 0;
-	}
-
-	void Open(const char *label)
-	{
-		size_t labellen = label != NULL ? strlen(label) : 0;
-		CheckWrap(labellen + 1 + NeedSpace);
-		if (NeedSpace)
-		{
-			Str << ' ';
-			ConsecOpens = 0;
-		}
-		Str << '(';
-		ConsecOpens++;
-		if (label != NULL)
-		{
-			Str.AppendCStrPart(label, labellen);
-		}
-		Column += labellen + 1 + NeedSpace;
-		NestDepth++;
-		NeedSpace = (label != NULL);
-	}
-	void Close()
-	{
-		assert(NestDepth != 0);
-		Str << ')';
-		Column++;
-		NestDepth--;
-		NeedSpace = true;
-	}
-	void Break()
-	{
-		// Don't break if not needed.
-		if (Column != NestDepth)
-		{
-			if (NeedSpace)
-			{
-				ConsecOpens = 0;
-			}
-			else
-			{ // Move hanging ( characters to the new line
-				Str.Truncate(long(Str.Len() - ConsecOpens));
-				NestDepth -= ConsecOpens;
-			}
-			Str << '\n';
-			Column = NestDepth;
-			NeedSpace = false;
-			if (NestDepth > 0)
-			{
-				Str.AppendFormat("%*s", (int)NestDepth, "");
-			}
-			if (ConsecOpens > 0)
-			{
-				for (size_t i = 0; i < ConsecOpens; ++i)
-				{
-					Str << '(';
-				}
-				NestDepth += ConsecOpens;
-			}
-		}
-	}
-	bool CheckWrap(size_t len)
-	{
-		if (len + Column > WrapWidth)
-		{
-			Break();
-			return true;
-		}
-		return false;
-	}
-	void Add(const char *str, size_t len)
-	{
-		CheckWrap(len + NeedSpace);
-		if (NeedSpace)
-		{
-			Str << ' ';
-		}
-		Str.AppendCStrPart(str, len);
-		Column += len + NeedSpace;
-		NeedSpace = true;
-	}
-	void Add(const char *str)
-	{
-		Add(str, strlen(str));
-	}
-	void Add(FString &str)
-	{
-		Add(str.GetChars(), str.Len());
-	}
-	void AddName(FName name)
-	{
-		size_t namelen = strlen(name.GetChars());
-		CheckWrap(namelen + 2 + NeedSpace);
-		if (NeedSpace)
-		{
-			NeedSpace = false;
-			Str << ' ';
-		}
-		Str << '\'' << name.GetChars() << '\'';
-		Column += namelen + 2 + NeedSpace;
-		NeedSpace = true;
-	}
-	void AddChar(char c)
-	{
-		Add(&c, 1);
-	}
-	void AddInt(int i, bool un=false)
-	{
-		char buf[16];
-		size_t len;
-		if (!un)
-		{
-			len = mysnprintf(buf, countof(buf), "%d", i);
-		}
-		else
-		{
-			len = mysnprintf(buf, countof(buf), "%uu", i);
-		}
-		Add(buf, len);
-	}
-	void AddHex(unsigned x)
-	{
-		char buf[10];
-		size_t len = mysnprintf(buf, countof(buf), "%08x", x);
-		Add(buf, len);
-	}
-	void AddFloat(double f, bool single)
-	{
-		char buf[32];
-		size_t len = mysnprintf(buf, countof(buf), "%.4f", f);
-		if (single)
-		{
-			buf[len++] = 'f';
-			buf[len] = '\0';
-		}
-		Add(buf, len);
-	}
-private:
-	FString Str;
-	size_t NestDepth;
-	size_t Column;
-	size_t WrapWidth;
-	size_t ConsecOpens;
-	bool NeedSpace;
-};
-
-static void PrintNode(FLispString &out, ZCC_TreeNode *node)
-{
-	assert(TreeNodePrinter[NUM_AST_NODE_TYPES-1] != NULL);
-	if (node->NodeType >= 0 && node->NodeType < NUM_AST_NODE_TYPES)
-	{
-		TreeNodePrinter[node->NodeType](out, node);
-	}
-	else
-	{
-		out.Open("unknown-node-type");
-		out.AddInt(node->NodeType);
-		out.Close();
-	}
-}
-
-static void PrintNodes(FLispString &out, ZCC_TreeNode *node, bool newlist=true, bool addbreaks=false)
-{
-	ZCC_TreeNode *p;
-
-	if (node == NULL)
-	{
-		out.Add("nil", 3);
-	}
-	else
-	{
-		if (newlist)
-		{
-			out.Open(NULL);
-		}
-		p = node;
-		do
-		{
-			if (addbreaks)
-			{
-				out.Break();
-			}
-			PrintNode(out, p);
-			p = p->SiblingNext;
-		} while (p != node);
-		if (newlist)
-		{
-			out.Close();
-		}
-	}
-}
-
-static void PrintBuiltInType(FLispString &out, EZCCBuiltinType type)
-{
-	assert(ZCC_NUM_BUILT_IN_TYPES == countof(BuiltInTypeNames));
-	if (unsigned(type) >= unsigned(ZCC_NUM_BUILT_IN_TYPES))
-	{
-		char buf[30];
-		size_t len = mysnprintf(buf, countof(buf), "bad-type-%u", type);
-		out.Add(buf, len);
-	}
-	else
-	{
-		out.Add(BuiltInTypeNames[type]);
-	}
-}
-
-static void PrintIdentifier(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_Identifier *inode = (ZCC_Identifier *)node;
-	out.Open("identifier");
-	out.AddName(inode->Id);
-	out.Close();
-}
-
-static void PrintStringConst(FLispString &out, FString str)
-{
-	FString outstr;
-	outstr << '"';
-	for (size_t i = 0; i < str.Len(); ++i)
-	{
-		if (str[i] == '"')
-		{
-			outstr << "\"";
-		}
-		else if (str[i] == '\\')
-		{
-			outstr << "\\\\";
-		}
-		else if (str[i] >= 32)
-		{
-			outstr << str[i];
-		}
-		else
-		{
-			outstr.AppendFormat("\\x%02X", str[i]);
-		}
-	}
-	outstr << '"';
-	out.Add(outstr);
-}
-
-static void PrintClass(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_Class *cnode = (ZCC_Class *)node;
-	out.Break();
-	out.Open("class");
-	out.AddName(cnode->NodeName);
-	PrintNodes(out, cnode->ParentName);
-	PrintNodes(out, cnode->Replaces);
-	out.AddHex(cnode->Flags);
-	PrintNodes(out, cnode->Body, false, true);
-	out.Close();
-}
-
-static void PrintStruct(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_Struct *snode = (ZCC_Struct *)node;
-	out.Break();
-	out.Open("struct");
-	out.AddName(snode->NodeName);
-	PrintNodes(out, snode->Body, false, true);
-	out.Close();
-}
-
-static void PrintEnum(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_Enum *enode = (ZCC_Enum *)node;
-	out.Break();
-	out.Open("enum");
-	out.AddName(enode->NodeName);
-	PrintBuiltInType(out, enode->EnumType);
-	out.Add(enode->Elements == NULL ? "nil" : "...", 3);
-	out.Close();
-}
-
-static void PrintEnumTerminator(FLispString &out, ZCC_TreeNode *node)
-{
-	out.Open("enum-term");
-	out.Close();
-}
-
-static void PrintStates(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_States *snode = (ZCC_States *)node;
-	out.Break();
-	out.Open("states");
-	PrintNodes(out, snode->Body, false, true);
-	out.Close();
-}
-
-static void PrintStatePart(FLispString &out, ZCC_TreeNode *node)
-{
-	out.Open("state-part");
-	out.Close();
-}
-
-static void PrintStateLabel(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_StateLabel *snode = (ZCC_StateLabel *)node;
-	out.Open("state-label");
-	out.AddName(snode->Label);
-	out.Close();
-}
-
-static void PrintStateStop(FLispString &out, ZCC_TreeNode *node)
-{
-	out.Open("state-stop");
-	out.Close();
-}
-
-static void PrintStateWait(FLispString &out, ZCC_TreeNode *node)
-{
-	out.Open("state-wait");
-	out.Close();
-}
-
-static void PrintStateFail(FLispString &out, ZCC_TreeNode *node)
-{
-	out.Open("state-fail");
-	out.Close();
-}
-
-static void PrintStateLoop(FLispString &out, ZCC_TreeNode *node)
-{
-	out.Open("state-loop");
-	out.Close();
-}
-
-static void PrintStateGoto(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_StateGoto *snode = (ZCC_StateGoto *)node;
-	out.Open("state-goto");
-	PrintNodes(out, snode->Label);
-	PrintNodes(out, snode->Offset);
-	out.Close();
-}
-
-static void PrintStateLine(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_StateLine *snode = (ZCC_StateLine *)node;
-	out.Open("state-line");
-	out.Add(snode->Sprite, 4);
-	if (snode->bNoDelay) out.Add("nodelay", 7);
-	if (snode->bBright) out.Add("bright", 6);
-	if (snode->bFast) out.Add("fast", 4);
-	if (snode->bSlow) out.Add("slow", 4);
-	if (snode->bCanRaise) out.Add("canraise", 8);
-	out.Add(*(snode->Frames));
-	PrintNodes(out, snode->Offset);
-	PrintNodes(out, snode->Action, false);
-	out.Close();
-}
-
-static void PrintVarName(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_VarName *vnode = (ZCC_VarName *)node;
-	out.Open("var-name");
-	PrintNodes(out, vnode->ArraySize);
-	out.AddName(vnode->Name);
-	out.Close();
-}
-
-static void PrintType(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_Type *tnode = (ZCC_Type *)node;
-	out.Open("bad-type");
-	PrintNodes(out, tnode->ArraySize);
-	out.Close();
-}
-
-static void PrintBasicType(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_BasicType *tnode = (ZCC_BasicType *)node;
-	out.Open("basic-type");
-	PrintNodes(out, tnode->ArraySize);
-	PrintBuiltInType(out, tnode->Type);
-	if (tnode->Type == ZCC_UserType)
-	{
-		PrintNodes(out, tnode->UserType, false);
-	}
-	out.Close();
-}
-
-static void PrintMapType(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_MapType *tnode = (ZCC_MapType *)node;
-	out.Open("map-type");
-	PrintNodes(out, tnode->ArraySize);
-	PrintNodes(out, tnode->KeyType);
-	PrintNodes(out, tnode->ValueType);
-	out.Close();
-}
-
-static void PrintDynArrayType(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_DynArrayType *tnode = (ZCC_DynArrayType *)node;
-	out.Open("dyn-array-type");
-	PrintNodes(out, tnode->ArraySize);
-	PrintNodes(out, tnode->ElementType);
-	out.Close();
-}
-
-static void PrintClassType(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ClassType *tnode = (ZCC_ClassType *)node;
-	out.Open("class-type");
-	PrintNodes(out, tnode->ArraySize);
-	PrintNodes(out, tnode->Restriction);
-	out.Close();
-}
-
-static void OpenExprType(FLispString &out, EZCCExprType type)
-{
-	char buf[32];
-
-	if (unsigned(type) < PEX_COUNT_OF)
-	{
-		mysnprintf(buf, countof(buf), "expr-%s", ZCC_OpInfo[type].OpName);
-	}
-	else
-	{
-		mysnprintf(buf, countof(buf), "bad-pex-%u", type);
-	}
-	out.Open(buf);
-}
-
-static void PrintExpression(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_Expression *enode = (ZCC_Expression *)node;
-	OpenExprType(out, enode->Operation);
-	out.Close();
-}
-
-static void PrintExprID(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ExprID *enode = (ZCC_ExprID *)node;
-	assert(enode->Operation == PEX_ID);
-	out.Open("expr-id");
-	out.AddName(enode->Identifier);
-	out.Close();
-}
-
-static void PrintExprTypeRef(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ExprTypeRef *enode = (ZCC_ExprTypeRef *)node;
-	assert(enode->Operation == PEX_TypeRef);
-	out.Open("expr-type-ref");
-		 if (enode->RefType == TypeSInt8) { out.Add("sint8"); }
-	else if (enode->RefType == TypeUInt8) { out.Add("uint8"); }
-	else if (enode->RefType == TypeSInt16) { out.Add("sint16"); }
-	else if (enode->RefType == TypeSInt32) { out.Add("sint32"); }
-	else if (enode->RefType == TypeFloat32) { out.Add("float32"); }
-	else if (enode->RefType == TypeFloat64) { out.Add("float64"); }
-	else if (enode->RefType == TypeString) { out.Add("string"); }
-	else if (enode->RefType == TypeName) { out.Add("name"); }
-	else if (enode->RefType == TypeColor) { out.Add("color"); }
-	else if (enode->RefType == TypeSound) { out.Add("sound"); }
-	else { out.Add("other"); }
-	out.Close();
-}
-
-static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ExprConstant *enode = (ZCC_ExprConstant *)node;
-	assert(enode->Operation == PEX_ConstValue);
-	out.Open("expr-const");
-	if (enode->Type == TypeString)
-	{
-		PrintStringConst(out, *enode->StringVal);
-	}
-	else if (enode->Type == TypeFloat64)
-	{
-		out.AddFloat(enode->DoubleVal, false);
-	}
-	else if (enode->Type == TypeFloat32)
-	{
-		out.AddFloat(enode->DoubleVal, true);
-	}
-	else if (enode->Type == TypeName)
-	{
-		out.AddName(ENamedName(enode->IntVal));
-	}
-	else if (enode->Type->IsKindOf(RUNTIME_CLASS(PInt)))
-	{
-		out.AddInt(enode->IntVal, static_cast<PInt *>(enode->Type)->Unsigned);
-	}
-	out.Close();
-}
-
-static void PrintExprFuncCall(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ExprFuncCall *enode = (ZCC_ExprFuncCall *)node;
-	assert(enode->Operation == PEX_FuncCall);
-	out.Open("expr-func-call");
-	PrintNodes(out, enode->Function);
-	PrintNodes(out, enode->Parameters, false);
-	out.Close();
-}
-
-static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node;
-	assert(enode->Operation == PEX_MemberAccess);
-	out.Open("expr-member-access");
-	PrintNodes(out, enode->Left);
-	out.AddName(enode->Right);
-	out.Close();
-}
-
-static void PrintExprUnary(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ExprUnary *enode = (ZCC_ExprUnary *)node;
-	OpenExprType(out, enode->Operation);
-	PrintNodes(out, enode->Operand, false);
-	out.Close();
-}
-
-static void PrintExprBinary(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ExprBinary *enode = (ZCC_ExprBinary *)node;
-	OpenExprType(out, enode->Operation);
-	PrintNodes(out, enode->Left);
-	PrintNodes(out, enode->Right);
-	out.Close();
-}
-
-static void PrintExprTrinary(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ExprTrinary *enode = (ZCC_ExprTrinary *)node;
-	OpenExprType(out, enode->Operation);
-	PrintNodes(out, enode->Test);
-	PrintNodes(out, enode->Left);
-	PrintNodes(out, enode->Right);
-	out.Close();
-}
-
-static void PrintFuncParam(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_FuncParm *pnode = (ZCC_FuncParm *)node;
-	out.Break();
-	out.Open("func-parm");
-	out.AddName(pnode->Label);
-	PrintNodes(out, pnode->Value, false);
-	out.Close();
-}
-
-static void PrintStatement(FLispString &out, ZCC_TreeNode *node)
-{
-	out.Open("statement");
-	out.Close();
-}
-
-static void PrintCompoundStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_CompoundStmt *snode = (ZCC_CompoundStmt *)node;
-	out.Break();
-	out.Open("compound-stmt");
-	PrintNodes(out, snode->Content, false, true);
-	out.Close();
-}
-
-static void PrintContinueStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	out.Break();
-	out.Open("continue-stmt");
-	out.Close();
-}
-
-static void PrintBreakStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	out.Break();
-	out.Open("break-stmt");
-	out.Close();
-}
-
-static void PrintReturnStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ReturnStmt *snode = (ZCC_ReturnStmt *)node;
-	out.Break();
-	out.Open("return-stmt");
-	PrintNodes(out, snode->Values, false);
-	out.Close();
-}
-
-static void PrintExpressionStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ExpressionStmt *snode = (ZCC_ExpressionStmt *)node;
-	out.Break();
-	out.Open("expression-stmt");
-	PrintNodes(out, snode->Expression, false);
-	out.Close();
-}
-
-static void PrintIterationStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_IterationStmt *snode = (ZCC_IterationStmt *)node;
-	out.Break();
-	out.Open("iteration-stmt");
-	out.Add((snode->CheckAt == ZCC_IterationStmt::Start) ? "start" : "end");
-	out.Break();
-	PrintNodes(out, snode->LoopCondition);
-	out.Break();
-	PrintNodes(out, snode->LoopBumper);
-	out.Break();
-	PrintNodes(out, snode->LoopStatement);
-	out.Close();
-}
-
-static void PrintIfStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_IfStmt *snode = (ZCC_IfStmt *)node;
-	out.Break();
-	out.Open("if-stmt");
-	PrintNodes(out, snode->Condition);
-	out.Break();
-	PrintNodes(out, snode->TruePath);
-	out.Break();
-	PrintNodes(out, snode->FalsePath);
-	out.Close();
-}
-
-static void PrintSwitchStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_SwitchStmt *snode = (ZCC_SwitchStmt *)node;
-	out.Break();
-	out.Open("switch-stmt");
-	PrintNodes(out, snode->Condition);
-	out.Break();
-	PrintNodes(out, snode->Content, false);
-	out.Close();
-}
-
-static void PrintCaseStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_CaseStmt *snode = (ZCC_CaseStmt *)node;
-	out.Break();
-	out.Open("case-stmt");
-	PrintNodes(out, snode->Condition, false);
-	out.Close();
-}
-
-static void BadAssignOp(FLispString &out, int op)
-{
-	char buf[32];
-	size_t len = mysnprintf(buf, countof(buf), "assign-op-%d", op);
-	out.Add(buf, len);
-}
-
-static void PrintAssignStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_AssignStmt *snode = (ZCC_AssignStmt *)node;
-	out.Open("assign-stmt");
-	switch (snode->AssignOp)
-	{
-	case ZCC_EQ:		out.AddChar('='); break;
-	case ZCC_MULEQ:		out.Add("*=", 2); break;
-	case ZCC_DIVEQ:		out.Add("/=", 2); break;
-	case ZCC_MODEQ:		out.Add("%=", 2); break;
-	case ZCC_ADDEQ:		out.Add("+=", 2); break;
-	case ZCC_SUBEQ:		out.Add("-=", 2); break;
-	case ZCC_LSHEQ:		out.Add("<<=", 2); break;
-	case ZCC_RSHEQ:		out.Add(">>=", 2); break;
-	case ZCC_ANDEQ:		out.Add("&=", 2); break;
-	case ZCC_OREQ:		out.Add("|=", 2); break;
-	case ZCC_XOREQ:		out.Add("^=", 2); break;
-	default:			BadAssignOp(out, snode->AssignOp); break;
-	}
-	PrintNodes(out, snode->Dests);
-	PrintNodes(out, snode->Sources);
-	out.Close();
-}
-
-static void PrintLocalVarStmt(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node;
-	out.Open("local-var-stmt");
-	PrintNodes(out, snode->Type);
-	PrintNodes(out, snode->Vars);
-	PrintNodes(out, snode->Inits);
-	out.Close();
-}
-
-static void PrintFuncParamDecl(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_FuncParamDecl *dnode = (ZCC_FuncParamDecl *)node;
-	out.Break();
-	out.Open("func-param-decl");
-	PrintNodes(out, dnode->Type);
-	out.AddName(dnode->Name);
-	out.AddHex(dnode->Flags);
-	out.Close();
-}
-
-static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node;
-	out.Break();
-	out.Open("constant-def");
-	out.AddName(dnode->NodeName);
-	PrintNodes(out, dnode->Value, false);
-	out.Close();
-}
-
-static void PrintDeclarator(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_Declarator *dnode = (ZCC_Declarator *)node;
-	out.Break();
-	out.Open("declarator");
-	out.AddHex(dnode->Flags);
-	PrintNodes(out, dnode->Type);
-	out.Close();
-}
-
-static void PrintVarDeclarator(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_VarDeclarator *dnode = (ZCC_VarDeclarator *)node;
-	out.Break();
-	out.Open("var-declarator");
-	out.AddHex(dnode->Flags);
-	PrintNodes(out, dnode->Type);
-	PrintNodes(out, dnode->Names);
-	out.Close();
-}
-
-static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node)
-{
-	ZCC_FuncDeclarator *dnode = (ZCC_FuncDeclarator *)node;
-	out.Break();
-	out.Open("func-declarator");
-	out.AddHex(dnode->Flags);
-	PrintNodes(out, dnode->Type);
-	out.AddName(dnode->Name);
-	PrintNodes(out, dnode->Params);
-	PrintNodes(out, dnode->Body, false);
-	out.Close();
-}
-
-void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *) =
-{
-	PrintIdentifier,
-	PrintClass,
-	PrintStruct,
-	PrintEnum,
-	PrintEnumTerminator,
-	PrintStates,
-	PrintStatePart,
-	PrintStateLabel,
-	PrintStateStop,
-	PrintStateWait,
-	PrintStateFail,
-	PrintStateLoop,
-	PrintStateGoto,
-	PrintStateLine,
-	PrintVarName,
-	PrintType,
-	PrintBasicType,
-	PrintMapType,
-	PrintDynArrayType,
-	PrintClassType,
-	PrintExpression,
-	PrintExprID,
-	PrintExprTypeRef,
-	PrintExprConstant,
-	PrintExprFuncCall,
-	PrintExprMemberAccess,
-	PrintExprUnary,
-	PrintExprBinary,
-	PrintExprTrinary,
-	PrintFuncParam,
-	PrintStatement,
-	PrintCompoundStmt,
-	PrintContinueStmt,
-	PrintBreakStmt,
-	PrintReturnStmt,
-	PrintExpressionStmt,
-	PrintIterationStmt,
-	PrintIfStmt,
-	PrintSwitchStmt,
-	PrintCaseStmt,
-	PrintAssignStmt,
-	PrintLocalVarStmt,
-	PrintFuncParamDecl,
-	PrintConstantDef,
-	PrintDeclarator,
-	PrintVarDeclarator,
-	PrintFuncDeclarator
-};
-
-FString ZCC_PrintAST(ZCC_TreeNode *root)
-{
-	FLispString out;
-	PrintNodes(out, root);
-	return out;
-}
--- src/zscript/vm.h
+++ src/zscript/vm.h
@@ -1,950 +0,0 @@
-#ifndef VM_H
-#define VM_H
-
-#include "zstring.h"
-#include "dobject.h"
-
-#define MAX_RETURNS		8	// Maximum number of results a function called by script code can return
-#define MAX_TRY_DEPTH	8	// Maximum number of nested TRYs in a single function
-
-
-typedef unsigned char		VM_UBYTE;
-typedef signed char			VM_SBYTE;
-typedef unsigned short		VM_UHALF;
-typedef signed short		VM_SHALF;
-typedef unsigned int		VM_UWORD;
-typedef signed int			VM_SWORD;
-typedef VM_UBYTE			VM_ATAG;
-
-#define VM_EPSILON			(1/1024.0)
-
-union VMOP
-{
-	struct
-	{
-		VM_UBYTE op, a, b, c;
-	};
-	struct
-	{
-		VM_SBYTE pad0, as, bs, cs;
-	};
-	struct
-	{
-		VM_SWORD pad1:8, i24:24;
-	};
-	struct
-	{
-		VM_SWORD pad2:16, i16:16;
-	};
-	struct
-	{
-		VM_UHALF pad3, i16u;
-	};
-	VM_UWORD word;
-
-	// Interesting fact: VC++ produces better code for i16 when it's defined
-	// as a bitfield than when it's defined as two discrete units.
-	// Compare:
-	//		mov		eax,dword ptr [op]		; As two discrete units
-	//		shr		eax,10h
-	//		movsx	eax,ax
-	// versus:
-	//		mov		eax,dword ptr [op]		; As a bitfield
-	//		sar		eax,10h
-};
-
-enum
-{
-#include "vmops.h"
-NUM_OPS
-};
-
-// Flags for A field of CMPS
-enum
-{
-	CMP_CHECK = 1,
-
-	CMP_EQ = 0,
-	CMP_LT = 2,
-	CMP_LE = 4,
-	CMP_METHOD_MASK = 6,
-
-	CMP_BK = 8,
-	CMP_CK = 16,
-	CMP_APPROX = 32,
-};
-
-// Floating point operations for FLOP
-enum
-{
-	FLOP_ABS,
-	FLOP_NEG,
-	FLOP_EXP,
-	FLOP_LOG,
-	FLOP_LOG10,
-	FLOP_SQRT,
-	FLOP_CEIL,
-	FLOP_FLOOR,
-
-	FLOP_ACOS,			// This group works with radians
-	FLOP_ASIN,
-	FLOP_ATAN,
-	FLOP_COS,
-	FLOP_SIN,
-	FLOP_TAN,
-
-	FLOP_ACOS_DEG,		// This group works with degrees
-	FLOP_ASIN_DEG,
-	FLOP_ATAN_DEG,
-	FLOP_COS_DEG,
-	FLOP_SIN_DEG,
-	FLOP_TAN_DEG,
-
-	FLOP_COSH,
-	FLOP_SINH,
-	FLOP_TANH,
-};
-
-// Cast operations
-enum
-{
-	CAST_I2F,
-	CAST_I2S,
-	CAST_F2I,
-	CAST_F2S,
-	CAST_P2S,
-	CAST_S2I,
-	CAST_S2F,
-};
-
-// Register types for VMParam
-enum
-{
-	REGT_INT		= 0,
-	REGT_FLOAT		= 1,
-	REGT_STRING		= 2,
-	REGT_POINTER	= 3,
-	REGT_TYPE		= 3,
-
-	REGT_KONST		= 4,
-	REGT_MULTIREG	= 8,	// (e.g. a vector)
-	REGT_ADDROF		= 32,	// used with PARAM: pass address of this register
-
-	REGT_NIL		= 255	// parameter was omitted
-};
-
-#define RET_FINAL	(0x80)	// Used with RET and RETI in the destination slot: this is the final return value
-
-
-// Tags for address registers
-enum
-{
-	ATAG_GENERIC,			// pointer to something; we don't care what
-	ATAG_OBJECT,			// pointer to an object; will be followed by GC
-
-	// The following are all for documentation during debugging and are
-	// functionally no different than ATAG_GENERIC.
-
-	ATAG_FRAMEPOINTER,		// pointer to extra stack frame space for this function
-	ATAG_DREGISTER,			// pointer to a data register
-	ATAG_FREGISTER,			// pointer to a float register
-	ATAG_SREGISTER,			// pointer to a string register
-	ATAG_AREGISTER,			// pointer to an address register
-
-	ATAG_STATE,				// pointer to FState
-	ATAG_RNG,				// pointer to FRandom
-};
-
-class VMFunction : public DObject
-{
-	DECLARE_ABSTRACT_CLASS(VMFunction, DObject);
-	HAS_OBJECT_POINTERS;
-public:
-	bool Native;
-	FName Name;
-
-	class PPrototype *Proto;
-
-	VMFunction() : Native(false), Name(NAME_None), Proto(NULL) {}
-	VMFunction(FName name) : Native(false), Name(name), Proto(NULL) {}
-};
-
-enum EVMOpMode
-{
-	MODE_ASHIFT		= 0,
-	MODE_BSHIFT		= 4,
-	MODE_CSHIFT		= 8,
-	MODE_BCSHIFT	= 12,
-
-	MODE_ATYPE		= 15 << MODE_ASHIFT,
-	MODE_BTYPE		= 15 << MODE_BSHIFT,
-	MODE_CTYPE		= 15 << MODE_CSHIFT,
-	MODE_BCTYPE		= 31 << MODE_BCSHIFT,
-
-	MODE_I			= 0,
-	MODE_F,
-	MODE_S,
-	MODE_P,
-	MODE_V,
-	MODE_X,
-	MODE_KI,
-	MODE_KF,
-	MODE_KS,
-	MODE_KP,
-	MODE_KV,
-	MODE_UNUSED,
-	MODE_IMMS,
-	MODE_IMMZ,
-	MODE_JOINT,
-	MODE_CMP,
-
-	MODE_PARAM,
-	MODE_THROW,
-	MODE_CATCH,
-	MODE_CAST,
-
-	MODE_AI			= MODE_I << MODE_ASHIFT,
-	MODE_AF			= MODE_F << MODE_ASHIFT,
-	MODE_AS			= MODE_S << MODE_ASHIFT,
-	MODE_AP			= MODE_P << MODE_ASHIFT,
-	MODE_AV			= MODE_V << MODE_ASHIFT,
-	MODE_AX			= MODE_X << MODE_ASHIFT,
-	MODE_AKP		= MODE_KP << MODE_ASHIFT,
-	MODE_AUNUSED	= MODE_UNUSED << MODE_ASHIFT,
-	MODE_AIMMS		= MODE_IMMS << MODE_ASHIFT,
-	MODE_AIMMZ		= MODE_IMMZ << MODE_ASHIFT,
-	MODE_ACMP		= MODE_CMP << MODE_ASHIFT,
-
-	MODE_BI			= MODE_I << MODE_BSHIFT,
-	MODE_BF			= MODE_F << MODE_BSHIFT,
-	MODE_BS			= MODE_S << MODE_BSHIFT,
-	MODE_BP			= MODE_P << MODE_BSHIFT,
-	MODE_BV			= MODE_V << MODE_BSHIFT,
-	MODE_BX			= MODE_X << MODE_BSHIFT,
-	MODE_BKI		= MODE_KI << MODE_BSHIFT,
-	MODE_BKF		= MODE_KF << MODE_BSHIFT,
-	MODE_BKS		= MODE_KS << MODE_BSHIFT,
-	MODE_BKP		= MODE_KP << MODE_BSHIFT,
-	MODE_BKV		= MODE_KV << MODE_BSHIFT,
-	MODE_BUNUSED	= MODE_UNUSED << MODE_BSHIFT,
-	MODE_BIMMS		= MODE_IMMS << MODE_BSHIFT,
-	MODE_BIMMZ		= MODE_IMMZ << MODE_BSHIFT,
-
-	MODE_CI			= MODE_I << MODE_CSHIFT,
-	MODE_CF			= MODE_F << MODE_CSHIFT,
-	MODE_CS			= MODE_S << MODE_CSHIFT,
-	MODE_CP			= MODE_P << MODE_CSHIFT,
-	MODE_CV			= MODE_V << MODE_CSHIFT,
-	MODE_CX			= MODE_X << MODE_CSHIFT,
-	MODE_CKI		= MODE_KI << MODE_CSHIFT,
-	MODE_CKF		= MODE_KF << MODE_CSHIFT,
-	MODE_CKS		= MODE_KS << MODE_CSHIFT,
-	MODE_CKP		= MODE_KP << MODE_CSHIFT,
-	MODE_CKV		= MODE_KV << MODE_CSHIFT,
-	MODE_CUNUSED	= MODE_UNUSED << MODE_CSHIFT,
-	MODE_CIMMS		= MODE_IMMS << MODE_CSHIFT,
-	MODE_CIMMZ		= MODE_IMMZ << MODE_CSHIFT,
-
-	MODE_BCJOINT	= (MODE_JOINT << MODE_BSHIFT) | (MODE_JOINT << MODE_CSHIFT),
-	MODE_BCKI		= MODE_KI << MODE_BCSHIFT,
-	MODE_BCKF		= MODE_KF << MODE_BCSHIFT,
-	MODE_BCKS		= MODE_KS << MODE_BCSHIFT,
-	MODE_BCKP		= MODE_KP << MODE_BCSHIFT,
-	MODE_BCIMMS		= MODE_IMMS << MODE_BCSHIFT,
-	MODE_BCIMMZ		= MODE_IMMZ << MODE_BCSHIFT,
-	MODE_BCPARAM	= MODE_PARAM << MODE_BCSHIFT,
-	MODE_BCTHROW	= MODE_THROW << MODE_BCSHIFT,
-	MODE_BCCATCH	= MODE_CATCH << MODE_BCSHIFT,
-	MODE_BCCAST		= MODE_CAST << MODE_BCSHIFT,
-
-	MODE_ABCJOINT	= (MODE_JOINT << MODE_ASHIFT) | MODE_BCJOINT,
-};
-
-struct VMOpInfo
-{
-	const char *Name;
-	int Mode;
-};
-
-extern const VMOpInfo OpInfo[NUM_OPS];
-
-struct VMReturn
-{
-	void *Location;
-	VM_SHALF TagOfs;	// for pointers: Offset from Location to ATag; set to 0 if the caller is native code and doesn't care
-	VM_UBYTE RegType;	// Same as VMParam RegType, except REGT_KONST is invalid; only used by asserts
-
-	void SetInt(int val)
-	{
-		assert(RegType == REGT_INT);
-		*(int *)Location = val;
-	}
-	void SetFloat(double val)
-	{
-		assert(RegType == REGT_FLOAT);
-		*(double *)Location = val;
-	}
-	void SetVector(const double val[3])
-	{	
-		//assert(RegType == REGT_FLOAT);
-		((double *)Location)[0] = val[0];
-		((double *)Location)[1] = val[1];
-		((double *)Location)[2] = val[2];
-	}
-	void SetString(const FString &val)
-	{
-		assert(RegType == REGT_STRING);
-		*(FString *)Location = val;
-	}
-	void SetPointer(void *val, int tag)
-	{
-		assert(RegType == REGT_POINTER);
-		*(void **)Location = val;
-		if (TagOfs != 0)
-		{
-			*((VM_ATAG *)Location + TagOfs) = tag;
-		}
-	}
-
-	void IntAt(int *loc)
-	{
-		Location = loc;
-		TagOfs = 0;
-		RegType = REGT_INT;
-	}
-	void FloatAt(double *loc)
-	{
-		Location = loc;
-		TagOfs = 0;
-		RegType = REGT_FLOAT;
-	}
-	void StringAt(FString *loc)
-	{
-		Location = loc;
-		TagOfs = 0;
-		RegType = REGT_STRING;
-	}
-	void PointerAt(void **loc)
-	{
-		Location = loc;
-		TagOfs = 0;
-		RegType = REGT_POINTER;
-	}
-};
-
-struct VMRegisters;
-
-
-struct VMValue
-{
-	union
-	{
-		int i;
-		struct { void *a; int atag; };
-		double f;
-		struct { int pad[3]; VM_UBYTE Type; };
-		struct { int foo[4]; } biggest;
-	};
-
-	// Unfortunately, FString cannot be used directly.
-	// Fortunately, it is relatively simple.
-	FString &s() { return *(FString *)&a; }
-	const FString &s() const { return *(FString *)&a; }
-
-	VMValue()
-	{
-		a = NULL;
-		Type = REGT_NIL;
-	}
-	~VMValue()
-	{
-		Kill();
-	}
-	VMValue(const VMValue &o)
-	{
-		biggest = o.biggest;
-		if (Type == REGT_STRING)
-		{
-			::new(&s()) FString(o.s());
-		}
-	}
-	VMValue(int v)
-	{
-		i = v;
-		Type = REGT_INT;
-	}
-	VMValue(double v)
-	{
-		f = v;
-		Type = REGT_FLOAT;
-	}
-	VMValue(const char *s)
-	{
-		::new(&a) FString(s);
-		Type = REGT_STRING;
-	}
-	VMValue(const FString &s)
-	{
-		::new(&a) FString(s);
-		Type = REGT_STRING;
-	}
-	VMValue(DObject *v)
-	{
-		a = v;
-		atag = ATAG_OBJECT;
-		Type = REGT_POINTER;
-	}
-	VMValue(void *v)
-	{
-		a = v;
-		atag = ATAG_GENERIC;
-		Type = REGT_POINTER;
-	}
-	VMValue(void *v, int tag)
-	{
-		a = v;
-		atag = tag;
-		Type = REGT_POINTER;
-	}
-	VMValue &operator=(const VMValue &o)
-	{
-		if (o.Type == REGT_STRING)
-		{
-			if (Type == REGT_STRING)
-			{
-				s() = o.s();
-			}
-			else
-			{
-				new(&s()) FString(o.s());
-				Type = REGT_STRING;
-			}
-		}
-		else
-		{
-			Kill();
-			biggest = o.biggest;
-		}
-		return *this;
-	}
-	VMValue &operator=(int v)
-	{
-		Kill();
-		i = v;
-		Type = REGT_INT;
-		return *this;
-	}
-	VMValue &operator=(double v)
-	{
-		Kill();
-		f = v;
-		Type = REGT_FLOAT;
-		return *this;
-	}
-	VMValue &operator=(const FString &v)
-	{
-		if (Type == REGT_STRING)
-		{
-			s() = v;
-		}
-		else
-		{
-			::new(&s()) FString(v);
-			Type = REGT_STRING;
-		}
-		return *this;
-	}
-	VMValue &operator=(const char *v)
-	{
-		if (Type == REGT_STRING)
-		{
-			s() = v;
-		}
-		else
-		{
-			::new(&s()) FString(v);
-			Type = REGT_STRING;
-		}
-		return *this;
-	}
-	VMValue &operator=(DObject *v)
-	{
-		Kill();
-		a = v;
-		atag = ATAG_OBJECT;
-		Type = REGT_POINTER;
-		return *this;
-	}
-	void SetPointer(void *v, VM_ATAG atag=ATAG_GENERIC)
-	{
-		Kill();
-		a = v;
-		this->atag = atag;
-		Type = REGT_POINTER;
-	}
-	void SetNil()
-	{
-		Kill();
-		Type = REGT_NIL;
-	}
-	bool operator==(const VMValue &o)
-	{
-		return Test(o) == 0;
-	}
-	bool operator!=(const VMValue &o)
-	{
-		return Test(o) != 0;
-	}
-	bool operator< (const VMValue &o)
-	{
-		return Test(o) <  0;
-	}
-	bool operator<=(const VMValue &o)
-	{
-		return Test(o) <= 0;
-	}
-	bool operator> (const VMValue &o)
-	{
-		return Test(o) >  0;
-	}
-	bool operator>=(const VMValue &o)
-	{
-		return Test(o) >= 0;
-	}
-	int Test(const VMValue &o, int inexact=false)
-	{
-		double diff;
-
-		if (Type == o.Type)
-		{
-			switch(Type)
-			{
-			case REGT_NIL:
-				return 0;
-
-			case REGT_INT:
-				return i - o.i;
-
-			case REGT_FLOAT:
-				diff = f - o.f;
-do_double:		if (inexact)
-				{
-					return diff < -VM_EPSILON ? -1 : diff > VM_EPSILON ? 1 : 0;
-				}
-				return diff < 0 ? -1 : diff > 0 ? 1 : 0;
-
-			case REGT_STRING:
-				return inexact ? s().CompareNoCase(o.s()) : s().Compare(o.s());
-
-			case REGT_POINTER:
-				return int((const VM_UBYTE *)a - (const VM_UBYTE *)o.a);
-			}
-			assert(0);		// Should not get here
-			return 2;
-		}
-		if (Type == REGT_FLOAT && o.Type == REGT_INT)
-		{
-			diff = f - o.i;
-			goto do_double;
-		}
-		if (Type == REGT_INT && o.Type == REGT_FLOAT)
-		{
-			diff = i - o.f;
-			goto do_double;
-		}
-		// Bad comparison
-		return 2;
-	}
-	FString ToString()
-	{
-		if (Type == REGT_STRING)
-		{
-			return s();
-		}
-		else if (Type == REGT_NIL)
-		{
-			return "nil";
-		}
-		FString t;
-		if (Type == REGT_INT)
-		{
-			t.Format ("%d", i);
-		}
-		else if (Type == REGT_FLOAT)
-		{
-			t.Format ("%.14g", f);
-		}
-		else if (Type == REGT_POINTER)
-		{
-			// FIXME
-			t.Format ("Object: %p", a);
-		}
-		return t;
-	}
-	int ToInt()
-	{
-		if (Type == REGT_INT)
-		{
-			return i;
-		}
-		if (Type == REGT_FLOAT)
-		{
-			return int(f);
-		}
-		if (Type == REGT_STRING)
-		{
-			return s().ToLong();
-		}
-		// FIXME
-		return 0;
-	}
-	double ToDouble()
-	{
-		if (Type == REGT_FLOAT)
-		{
-			return f;
-		}
-		if (Type == REGT_INT)
-		{
-			return i;
-		}
-		if (Type == REGT_STRING)
-		{
-			return s().ToDouble();
-		}
-		// FIXME
-		return 0;
-	}
-	void Kill()
-	{
-		if (Type == REGT_STRING)
-		{
-			s().~FString();
-		}
-	}
-};
-
-// VM frame layout:
-//	VMFrame header
-//  parameter stack		- 16 byte boundary, 16 bytes each
-//	double registers	- 8 bytes each
-//	string registers	- 4 or 8 bytes each
-//	address registers	- 4 or 8 bytes each
-//	data registers		- 4 bytes each
-//	address register tags-1 byte each
-//	extra space			- 16 byte boundary
-struct VMFrame
-{
-	VMFrame *ParentFrame;
-	VMFunction *Func;
-	VM_UBYTE NumRegD;
-	VM_UBYTE NumRegF;
-	VM_UBYTE NumRegS;
-	VM_UBYTE NumRegA;
-	VM_UHALF MaxParam;
-	VM_UHALF NumParam;		// current number of parameters
-
-	static int FrameSize(int numregd, int numregf, int numregs, int numrega, int numparam, int numextra)
-	{
-		int size = (sizeof(VMFrame) + 15) & ~15;
-		size += numparam * sizeof(VMValue);
-		size += numregf * sizeof(double);
-		size += numrega * (sizeof(void *) + sizeof(VM_UBYTE));
-		size += numregs * sizeof(FString);
-		size += numregd * sizeof(int);
-		if (numextra != 0)
-		{
-			size = (size + 15) & ~15;
-			size += numextra;
-		}
-		return size;
-	}
-
-	int *GetRegD() const
-	{
-		return (int *)(GetRegA() + NumRegA);
-	}
-
-	double *GetRegF() const
-	{
-		return (double *)(GetParam() + MaxParam);
-	}
-
-	FString *GetRegS() const
-	{
-		return (FString *)(GetRegF() + NumRegF);
-	}
-
-	void **GetRegA() const
-	{
-		return (void **)(GetRegS() + NumRegS);
-	}
-
-	VM_ATAG *GetRegATag() const
-	{
-		return (VM_ATAG *)(GetRegD() + NumRegD);
-	}
-
-	VMValue *GetParam() const
-	{
-		assert(((size_t)this & 15) == 0 && "VM frame is unaligned");
-		return (VMValue *)(((size_t)(this + 1) + 15) & ~15);
-	}
-
-	void *GetExtra() const
-	{
-		VM_ATAG *ptag = GetRegATag();
-		ptrdiff_t ofs = ptag - (VM_ATAG *)this;
-		return (VM_UBYTE *)this + ((ofs + NumRegA + 15) & ~15);
-	}
-
-	void GetAllRegs(int *&d, double *&f, FString *&s, void **&a, VM_ATAG *&atag, VMValue *&param) const
-	{
-		// Calling the individual functions produces suboptimal code. :(
-		param = GetParam();
-		f = (double *)(param + MaxParam);
-		s = (FString *)(f + NumRegF);
-		a = (void **)(s + NumRegS);
-		d = (int *)(a + NumRegA);
-		atag = (VM_ATAG *)(d + NumRegD);
-	}
-
-	void InitRegS();
-};
-
-struct VMRegisters
-{
-	VMRegisters(const VMFrame *frame)
-	{
-		frame->GetAllRegs(d, f, s, a, atag, param);
-	}
-
-	VMRegisters(const VMRegisters &o)
-		: d(o.d), f(o.f), s(o.s), a(o.a), atag(o.atag), param(o.param)
-	{ }
-
-	int *d;
-	double *f;
-	FString *s;
-	void **a;
-	VM_ATAG *atag;
-	VMValue *param;
-};
-
-struct VMException : public DObject
-{
-	DECLARE_CLASS(VMException, DObject);
-};
-
-union FVoidObj
-{
-	DObject *o;
-	void *v;
-};
-
-class VMScriptFunction : public VMFunction
-{
-	DECLARE_CLASS(VMScriptFunction, VMFunction);
-public:
-	VMScriptFunction(FName name=NAME_None);
-	~VMScriptFunction();
-	size_t PropagateMark();
-	void Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta);
-
-	VM_ATAG *KonstATags() { return (VM_UBYTE *)(KonstA + NumKonstA); }
-	const VM_ATAG *KonstATags() const { return (VM_UBYTE *)(KonstA + NumKonstA); }
-
-	VMOP *Code;
-	int *KonstD;
-	double *KonstF;
-	FString *KonstS;
-	FVoidObj *KonstA;
-	int ExtraSpace;
-	int CodeSize;			// Size of code in instructions (not bytes)
-	VM_UBYTE NumRegD;
-	VM_UBYTE NumRegF;
-	VM_UBYTE NumRegS;
-	VM_UBYTE NumRegA;
-	VM_UBYTE NumKonstD;
-	VM_UBYTE NumKonstF;
-	VM_UBYTE NumKonstS;
-	VM_UBYTE NumKonstA;
-	VM_UHALF MaxParam;		// Maximum number of parameters this function has on the stack at once
-	VM_UBYTE NumArgs;		// Number of arguments this function takes
-};
-
-class VMFrameStack
-{
-public:
-	VMFrameStack();
-	~VMFrameStack();
-	VMFrame *AllocFrame(int numregd, int numregf, int numregs, int numrega);
-	VMFrame *AllocFrame(VMScriptFunction *func);
-	VMFrame *PopFrame();
-	VMFrame *TopFrame()
-	{
-		assert(Blocks != NULL && Blocks->LastFrame != NULL);
-		return Blocks->LastFrame;
-	}
-	int Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap=NULL);
-private:
-	enum { BLOCK_SIZE = 4096 };		// Default block size
-	struct BlockHeader
-	{
-		BlockHeader *NextBlock;
-		VMFrame *LastFrame;
-		VM_UBYTE *FreeSpace;
-		int BlockSize;
-
-		void InitFreeSpace()
-		{
-			FreeSpace = (VM_UBYTE *)(((size_t)(this + 1) + 15) & ~15);
-		}
-	};
-	BlockHeader *Blocks;
-	BlockHeader *UnusedBlocks;
-	VMFrame *Alloc(int size);
-};
-
-class VMNativeFunction : public VMFunction
-{
-	DECLARE_CLASS(VMNativeFunction, VMFunction);
-public:
-	typedef int (*NativeCallType)(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret);
-
-	VMNativeFunction() : NativeCall(NULL) { Native = true; }
-	VMNativeFunction(NativeCallType call) : NativeCall(call) { Native = true; }
-	VMNativeFunction(NativeCallType call, FName name) : VMFunction(name), NativeCall(call) { Native = true; }
-
-	// Return value is the number of results.
-	NativeCallType NativeCall;
-};
-
-class VMParamFiller
-{
-public:
-	VMParamFiller(const VMFrame *frame) : Reg(frame), RegD(0), RegF(0), RegS(0), RegA(0) {}
-	VMParamFiller(const VMRegisters *reg) : Reg(*reg), RegD(0), RegF(0), RegS(0), RegA(0) {}
-
-	void ParamInt(int val)
-	{
-		Reg.d[RegD++] = val;
-	}
-
-	void ParamFloat(double val)
-	{
-		Reg.f[RegF++] = val;
-	}
-
-	void ParamString(FString &val)
-	{
-		Reg.s[RegS++] = val;
-	}
-
-	void ParamString(const char *val)
-	{
-		Reg.s[RegS++] = val;
-	}
-
-	void ParamObject(DObject *obj)
-	{
-		Reg.a[RegA] = obj;
-		Reg.atag[RegA] = ATAG_OBJECT;
-		RegA++;
-	}
-
-	void ParamPointer(void *ptr, VM_ATAG atag)
-	{
-		Reg.a[RegA] = ptr;
-		Reg.atag[RegA] = atag;
-		RegA++;
-	}
-
-private:
-	const VMRegisters Reg;
-	int RegD, RegF, RegS, RegA;
-};
-
-
-enum EVMEngine
-{
-	VMEngine_Default,
-	VMEngine_Unchecked,
-	VMEngine_Checked
-};
-
-void VMSelectEngine(EVMEngine engine);
-extern int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret);
-void VMFillParams(VMValue *params, VMFrame *callee, int numparam);
-
-void VMDumpConstants(FILE *out, const VMScriptFunction *func);
-void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func);
-
-// Use this in the prototype for a native function.
-#define VM_ARGS			VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret
-#define VM_ARGS_NAMES	stack, param, numparam, ret, numret
-
-// Use these to collect the parameters in a native function.
-// variable name <x> at position <p>
-
-// For required parameters.
-#define PARAM_INT_AT(p,x)			assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i;
-#define PARAM_BOOL_AT(p,x)			assert((p) < numparam); assert(param[p].Type == REGT_INT); bool x = !!param[p].i;
-#define PARAM_NAME_AT(p,x)			assert((p) < numparam); assert(param[p].Type == REGT_INT); FName x = ENamedName(param[p].i);
-#define PARAM_SOUND_AT(p,x)			assert((p) < numparam); assert(param[p].Type == REGT_INT); FSoundID x = param[p].i;
-#define PARAM_COLOR_AT(p,x)			assert((p) < numparam); assert(param[p].Type == REGT_INT); PalEntry x; x.d = param[p].i;
-#define PARAM_FLOAT_AT(p,x)			assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f;
-#define PARAM_ANGLE_AT(p,x)		assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); DAngle x = param[p].f;
-#define PARAM_STRING_AT(p,x)		assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s();
-#define PARAM_STATE_AT(p,x)			assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a;
-#define PARAM_POINTER_AT(p,x,type)	assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a;
-#define PARAM_OBJECT_AT(p,x,type)	assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
-#define PARAM_CLASS_AT(p,x,base)	assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
-
-// For optional paramaters. These have dangling elses for you to fill in the default assignment. e.g.:
-//		PARAM_INT_OPT(0,myint) { myint = 55; }
-// Just make sure to fill it in when using these macros, because the compiler isn't likely
-// to give useful error messages if you don't.
-#define PARAM_INT_OPT_AT(p,x)			int x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = param[p].i; } else
-#define PARAM_BOOL_OPT_AT(p,x)			bool x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = !!param[p].i; } else
-#define PARAM_NAME_OPT_AT(p,x)			FName x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = ENamedName(param[p].i); } else
-#define PARAM_SOUND_OPT_AT(p,x)			FSoundID x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x = FSoundID(param[p].i); } else
-#define PARAM_COLOR_OPT_AT(p,x)			PalEntry x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_INT); x.d = param[p].i; } else
-#define PARAM_FLOAT_OPT_AT(p,x)			double x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else
-#define PARAM_ANGLE_OPT_AT(p,x)		DAngle x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else
-#define PARAM_STRING_OPT_AT(p,x)		FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else
-#define PARAM_STATE_OPT_AT(p,x)			FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else
-#define PARAM_POINTER_OPT_AT(p,x,type)	type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else
-#define PARAM_OBJECT_OPT_AT(p,x,type)	type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else
-#define PARAM_CLASS_OPT_AT(p,x,base)	base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); } else
-
-// The above, but with an automatically increasing position index.
-#define PARAM_PROLOGUE				int paramnum = -1;
-
-#define PARAM_INT(x)				++paramnum; PARAM_INT_AT(paramnum,x)
-#define PARAM_BOOL(x)				++paramnum; PARAM_BOOL_AT(paramnum,x)
-#define PARAM_NAME(x)				++paramnum; PARAM_NAME_AT(paramnum,x)
-#define PARAM_SOUND(x)				++paramnum; PARAM_SOUND_AT(paramnum,x)
-#define PARAM_COLOR(x)				++paramnum; PARAM_COLOR_AT(paramnum,x)
-#define PARAM_FLOAT(x)				++paramnum; PARAM_FLOAT_AT(paramnum,x)
-#define PARAM_ANGLE(x)				++paramnum; PARAM_ANGLE_AT(paramnum,x)
-#define PARAM_STRING(x)				++paramnum; PARAM_STRING_AT(paramnum,x)
-#define PARAM_STATE(x)				++paramnum; PARAM_STATE_AT(paramnum,x)
-#define PARAM_POINTER(x,type)		++paramnum; PARAM_POINTER_AT(paramnum,x,type)
-#define PARAM_OBJECT(x,type)		++paramnum; PARAM_OBJECT_AT(paramnum,x,type)
-#define PARAM_CLASS(x,base)			++paramnum; PARAM_CLASS_AT(paramnum,x,base)
-
-#define PARAM_INT_OPT(x)			++paramnum; PARAM_INT_OPT_AT(paramnum,x)
-#define PARAM_BOOL_OPT(x)			++paramnum; PARAM_BOOL_OPT_AT(paramnum,x)
-#define PARAM_NAME_OPT(x)			++paramnum; PARAM_NAME_OPT_AT(paramnum,x)
-#define PARAM_SOUND_OPT(x)			++paramnum; PARAM_SOUND_OPT_AT(paramnum,x)
-#define PARAM_COLOR_OPT(x)			++paramnum; PARAM_COLOR_OPT_AT(paramnum,x)
-#define PARAM_FLOAT_OPT(x)			++paramnum; PARAM_FLOAT_OPT_AT(paramnum,x)
-#define PARAM_ANGLE_OPT(x)			++paramnum; PARAM_ANGLE_OPT_AT(paramnum,x)
-#define PARAM_STRING_OPT(x)			++paramnum; PARAM_STRING_OPT_AT(paramnum,x)
-#define PARAM_STATE_OPT(x)			++paramnum; PARAM_STATE_OPT_AT(paramnum,x)
-#define PARAM_POINTER_OPT(x,type)	++paramnum; PARAM_POINTER_OPT_AT(paramnum,x,type)
-#define PARAM_OBJECT_OPT(x,type)	++paramnum; PARAM_OBJECT_OPT_AT(paramnum,x,type)
-#define PARAM_CLASS_OPT(x,base)		++paramnum; PARAM_CLASS_OPT_AT(paramnum,x,base)
-
-#endif
--- src/zscript/vmbuilder.cpp
+++ src/zscript/vmbuilder.cpp
@@ -1,591 +0,0 @@
-#include "vmbuilder.h"
-
-//==========================================================================
-//
-// VMFunctionBuilder - Constructor
-//
-//==========================================================================
-
-VMFunctionBuilder::VMFunctionBuilder()
-{
-	NumIntConstants = 0;
-	NumFloatConstants = 0;
-	NumAddressConstants = 0;
-	NumStringConstants = 0;
-	MaxParam = 0;
-	ActiveParam = 0;
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder - Destructor
-//
-//==========================================================================
-
-VMFunctionBuilder::~VMFunctionBuilder()
-{
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: MakeFunction
-//
-// Creates a new VMScriptFunction out of the data passed to this class.
-//
-//==========================================================================
-
-VMScriptFunction *VMFunctionBuilder::MakeFunction()
-{
-	VMScriptFunction *func = new VMScriptFunction;
-
-	func->Alloc(Code.Size(), NumIntConstants, NumFloatConstants, NumStringConstants, NumAddressConstants);
-
-	// Copy code block.
-	memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP));
-
-	// Create constant tables.
-	if (NumIntConstants > 0)
-	{
-		FillIntConstants(func->KonstD);
-	}
-	if (NumFloatConstants > 0)
-	{
-		FillFloatConstants(func->KonstF);
-	}
-	if (NumAddressConstants > 0)
-	{
-		FillAddressConstants(func->KonstA, func->KonstATags());
-	}
-	if (NumStringConstants > 0)
-	{
-		FillStringConstants(func->KonstS);
-	}
-
-	// Assign required register space.
-	func->NumRegD = Registers[REGT_INT].MostUsed;
-	func->NumRegF = Registers[REGT_FLOAT].MostUsed;
-	func->NumRegA = Registers[REGT_POINTER].MostUsed;
-	func->NumRegS = Registers[REGT_STRING].MostUsed;
-	func->MaxParam = MaxParam;
-
-	// Technically, there's no reason why we can't end the function with
-	// entries on the parameter stack, but it means the caller probably
-	// did something wrong.
-	assert(ActiveParam == 0);
-
-	return func;
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: FillIntConstants
-//
-//==========================================================================
-
-void VMFunctionBuilder::FillIntConstants(int *konst)
-{
-	TMapIterator<int, int> it(IntConstants);
-	TMap<int, int>::Pair *pair;
-
-	while (it.NextPair(pair))
-	{
-		konst[pair->Value] = pair->Key;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: FillFloatConstants
-//
-//==========================================================================
-
-void VMFunctionBuilder::FillFloatConstants(double *konst)
-{
-	TMapIterator<double, int> it(FloatConstants);
-	TMap<double, int>::Pair *pair;
-
-	while (it.NextPair(pair))
-	{
-		konst[pair->Value] = pair->Key;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: FillAddressConstants
-//
-//==========================================================================
-
-void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags)
-{
-	TMapIterator<void *, AddrKonst> it(AddressConstants);
-	TMap<void *, AddrKonst>::Pair *pair;
-
-	while (it.NextPair(pair))
-	{
-		konst[pair->Value.KonstNum].v = pair->Key;
-		tags[pair->Value.KonstNum] = pair->Value.Tag;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: FillStringConstants
-//
-//==========================================================================
-
-void VMFunctionBuilder::FillStringConstants(FString *konst)
-{
-	TMapIterator<FString, int> it(StringConstants);
-	TMap<FString, int>::Pair *pair;
-
-	while (it.NextPair(pair))
-	{
-		konst[pair->Value] = pair->Key;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: GetConstantInt
-//
-// Returns a constant register initialized with the given value, or -1 if
-// there were no more constants free.
-//
-//==========================================================================
-
-int VMFunctionBuilder::GetConstantInt(int val)
-{
-	int *locp = IntConstants.CheckKey(val);
-	if (locp != NULL)
-	{
-		return *locp;
-	}
-	else
-	{
-		int loc = NumIntConstants++;
-		IntConstants.Insert(val, loc);
-		return loc;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: GetConstantFloat
-//
-// Returns a constant register initialized with the given value, or -1 if
-// there were no more constants free.
-//
-//==========================================================================
-
-int VMFunctionBuilder::GetConstantFloat(double val)
-{
-	int *locp = FloatConstants.CheckKey(val);
-	if (locp != NULL)
-	{
-		return *locp;
-	}
-	else
-	{
-		int loc = NumFloatConstants++;
-		FloatConstants.Insert(val, loc);
-		return loc;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: GetConstantString
-//
-// Returns a constant register initialized with the given value, or -1 if
-// there were no more constants free.
-//
-//==========================================================================
-
-int VMFunctionBuilder::GetConstantString(FString val)
-{
-	int *locp = StringConstants.CheckKey(val);
-	if (locp != NULL)
-	{
-		return *locp;
-	}
-	else
-	{
-		int loc = NumStringConstants++;
-		StringConstants.Insert(val, loc);
-		return loc;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: GetConstantAddress
-//
-// Returns a constant register initialized with the given value, or -1 if
-// there were no more constants free.
-//
-//==========================================================================
-
-int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag)
-{
-	if (ptr == NULL)
-	{ // Make all NULL pointers generic. (Or should we allow typed NULLs?)
-		tag = ATAG_GENERIC;
-	}
-	AddrKonst *locp = AddressConstants.CheckKey(ptr);
-	if (locp != NULL)
-	{
-		// There should only be one tag associated with a memory location.
-		assert(locp->Tag == tag);
-		return locp->KonstNum;
-	}
-	else
-	{
-		AddrKonst loc = { NumAddressConstants++, tag };
-		AddressConstants.Insert(ptr, loc);
-		return loc.KonstNum;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: ParamChange
-//
-// Adds delta to ActiveParam and keeps track of MaxParam.
-//
-//==========================================================================
-
-void VMFunctionBuilder::ParamChange(int delta)
-{
-	assert(delta > 0 || -delta <= ActiveParam);
-	ActiveParam += delta;
-	if (ActiveParam > MaxParam)
-	{
-		MaxParam = ActiveParam;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: RegAvailability - Constructor
-//
-//==========================================================================
-
-VMFunctionBuilder::RegAvailability::RegAvailability()
-{
-	memset(Used, 0, sizeof(Used));
-	MostUsed = 0;
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: RegAvailability :: Get
-//
-// Gets one or more unused registers. If getting multiple registers, they
-// will all be consecutive. Returns -1 if there were not enough consecutive
-// registers to satisfy the request.
-//
-// Preference is given to low-numbered registers in an attempt to keep
-// the maximum register count low so as to preserve VM stack space when this
-// function is executed.
-//
-//==========================================================================
-
-int VMFunctionBuilder::RegAvailability::Get(int count)
-{
-	VM_UWORD mask;
-	int i, firstbit;
-
-	// Getting fewer than one register makes no sense, and
-	// the algorithm used here can only obtain ranges of up to 32 bits.
-	if (count < 1 || count > 32)
-	{
-		return -1;
-	}
-
-	mask = count == 32 ? ~0u : (1 << count) - 1;
-
-	for (i = 0; i < 256/32; ++i)
-	{
-		// Find the first word with free registers
-		VM_UWORD bits = Used[i];
-		if (bits != ~0u)
-		{
-			// Are there enough consecutive bits to satisfy the request?
-			// Search by 16, then 8, then 1 bit at a time for the first
-			// free register.
-			if ((bits & 0xFFFF) == 0xFFFF)
-			{
-				firstbit = ((bits & 0xFF0000) == 0xFF0000) ? 24 : 16;
-			}
-			else
-			{
-				firstbit = ((bits & 0xFF) == 0xFF) ? 8 : 0;
-			}
-			for (; firstbit < 32; ++firstbit)
-			{
-				if (((bits >> firstbit) & mask) == 0)
-				{
-					if (firstbit + count <= 32)
-					{ // Needed bits all fit in one word, so we got it.
-						if (firstbit + count > MostUsed)
-						{
-							MostUsed = firstbit + count;
-						}
-						Used[i] |= mask << firstbit;
-						return i * 32 + firstbit;
-					}
-					// Needed bits span two words, so check the next word.
-					else if (i < 256/32 - 1)
-					{ // There is a next word.
-						if (((Used[i + 1]) & (mask >> (32 - firstbit))) == 0)
-						{ // The next word has the needed open space, too.
-							if (firstbit + count > MostUsed)
-							{
-								MostUsed = firstbit + count;
-							}
-							Used[i] |= mask << firstbit;
-							Used[i + 1] |= mask >> (32 - firstbit);
-							return i * 32 + firstbit;
-						}
-						else
-						{ // Skip to the next word, because we know we won't find
-						  // what we need if we stay inside this one. All bits
-						  // from firstbit to the end of the word are 0. If the
-						  // next word does not start with the x amount of 0's, we
-						  // need to satisfy the request, then it certainly won't
-						  // have the x+1 0's we would need if we started at
-						  // firstbit+1 in this one.
-							firstbit = 32;
-						}
-					}
-					else
-					{ // Out of words.
-						break;
-					}
-				}
-			}
-		}
-	}
-	// No room!
-	return -1;
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: RegAvailibity :: Return
-//
-// Marks a range of registers as free again.
-//
-//==========================================================================
-
-void VMFunctionBuilder::RegAvailability::Return(int reg, int count)
-{
-	assert(count >= 1 && count <= 32);
-	assert(reg >= 0 && reg + count <= 256);
-
-	VM_UWORD mask, partialmask;
-	int firstword, firstbit;
-
-	mask = count == 32 ? ~0u : (1 << count) - 1;
-	firstword = reg / 32;
-	firstbit = reg & 31;
-
-	if (firstbit + count <= 32)
-	{ // Range is all in one word.
-		mask <<= firstbit;
-		// If we are trying to return registers that are already free,
-		// it probably means that the caller messed up somewhere.
-		assert((Used[firstword] & mask) == mask);
-		Used[firstword] &= ~mask;
-	}
-	else
-	{ // Range is in two words.
-		partialmask = mask << firstbit;
-		assert((Used[firstword] & partialmask) == partialmask);
-		Used[firstword] &= ~partialmask;
-
-		partialmask = mask >> (32 - firstbit);
-		assert((Used[firstword + 1] & partialmask) == partialmask);
-		Used[firstword + 1] &= ~partialmask;
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: RegAvailability :: Reuse
-//
-// Marks an unused register as in-use. Returns false if the register is
-// already in use or true if it was successfully reused.
-//
-//==========================================================================
-
-bool VMFunctionBuilder::RegAvailability::Reuse(int reg)
-{
-	assert(reg >= 0 && reg <= 255);
-	assert(reg < MostUsed && "Attempt to reuse a register that was never used");
-
-	VM_UWORD mask = 1 << (reg & 31);
-	int word = reg / 32;
-
-	if (Used[word] & mask)
-	{ // It's already in use!
-		return false;
-	}
-	Used[word] |= mask;
-	return true;
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: Emit
-//
-// Just dumbly output an instruction. Returns instruction position, not
-// byte position. (Because all instructions are exactly four bytes long.)
-//
-//==========================================================================
-
-size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc)
-{
-	assert(opcode >= 0 && opcode < NUM_OPS);
-	assert(opa >= 0 && opa <= 255);
-	assert(opb >= 0 && opb <= 255);
-	assert(opc >= 0 && opc <= 255);
-	if (opcode == OP_PARAM)
-	{
-		ParamChange(1);
-	}
-	else if (opcode == OP_CALL || opcode == OP_CALL_K || opcode == OP_TAIL || opcode == OP_TAIL_K)
-	{
-		ParamChange(-opb);
-	}
-	VMOP op;
-	op.op = opcode;
-	op.a = opa;
-	op.b = opb;
-	op.c = opc;
-	return Code.Push(op);
-}
-
-size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc)
-{
-	assert(opcode >= 0 && opcode < NUM_OPS);
-	assert(opa >= 0 && opa <= 255);
-	//assert(opbc >= -32768 && opbc <= 32767);	always true due to parameter's width
-	VMOP op;
-	op.op = opcode;
-	op.a = opa;
-	op.i16 = opbc;
-	return Code.Push(op);
-}
-
-size_t VMFunctionBuilder::Emit(int opcode, int opabc)
-{
-	assert(opcode >= 0 && opcode < NUM_OPS);
-	assert(opabc >= -(1 << 23) && opabc <= (1 << 24) - 1);
-	if (opcode == OP_PARAMI)
-	{
-		ParamChange(1);
-	}
-	VMOP op;
-	op.op = opcode;
-	op.i24 = opabc;
-	return Code.Push(op);
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: EmitParamInt
-//
-// Passes a constant integer parameter, using either PARAMI and an immediate
-// value or PARAM and a constant register, as appropriate.
-//
-//==========================================================================
-
-size_t VMFunctionBuilder::EmitParamInt(int value)
-{
-	// Immediates for PARAMI must fit in 24 bits.
-	if (((value << 8) >> 8) == value)
-	{
-		return Emit(OP_PARAMI, value);
-	}
-	else
-	{
-		return Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, GetConstantInt(value));
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: EmitLoadInt
-//
-// Loads an integer constant into a register, using either an immediate
-// value or a constant register, as appropriate.
-//
-//==========================================================================
-
-size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value)
-{
-	assert(regnum >= 0 && regnum < Registers[REGT_INT].MostUsed);
-	if (value >= -32768 && value <= 32767)
-	{
-		return Emit(OP_LI, regnum, value);
-	}
-	else
-	{
-		return Emit(OP_LK, regnum, GetConstantInt(value));
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: EmitRetInt
-//
-// Returns an integer, using either an immediate value or a constant
-// register, as appropriate.
-//
-//==========================================================================
-
-size_t VMFunctionBuilder::EmitRetInt(int retnum, bool final, int value)
-{
-	assert(retnum >= 0 && retnum <= 127);
-	if (value >= -32768 && value <= 32767)
-	{
-		return Emit(OP_RETI, retnum | (final << 7), value);
-	}
-	else
-	{
-		return Emit(OP_RET, retnum | (final << 7), REGT_INT | REGT_KONST, GetConstantInt(value));
-	}
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: Backpatch
-//
-// Store a JMP instruction at <loc> that points at <target>.
-//
-//==========================================================================
-
-void VMFunctionBuilder::Backpatch(size_t loc, size_t target)
-{
-	assert(loc < Code.Size());
-	int offset = int(target - loc - 1);
-	assert(((offset << 8) >> 8) == offset);
-	Code[loc].op = OP_JMP;
-	Code[loc].i24 = offset;
-}
-
-//==========================================================================
-//
-// VMFunctionBuilder :: BackpatchToHere
-//
-// Store a JMP instruction at <loc> that points to the current code gen
-// location.
-//
-//==========================================================================
-
-void VMFunctionBuilder::BackpatchToHere(size_t loc)
-{
-	Backpatch(loc, Code.Size());
-}
--- src/zscript/vmbuilder.h
+++ src/zscript/vmbuilder.h
@@ -1,84 +0,0 @@
-#ifndef VMUTIL_H
-#define VMUTIL_H
-
-#include "vm.h"
-
-class VMFunctionBuilder
-{
-public:
-	// Keeps track of which registers are available by way of a bitmask table.
-	class RegAvailability
-	{
-	public:
-		RegAvailability();
-		int GetMostUsed() { return MostUsed; }
-		int Get(int count);			// Returns the first register in the range
-		void Return(int reg, int count);
-		bool Reuse(int regnum);
-
-	private:
-		VM_UWORD Used[256/32];		// Bitmap of used registers (bit set means reg is used)
-		int MostUsed;
-
-		friend class VMFunctionBuilder;
-	};
-
-	VMFunctionBuilder();
-	~VMFunctionBuilder();
-
-	VMScriptFunction *MakeFunction();
-
-	// Returns the constant register holding the value.
-	int GetConstantInt(int val);
-	int GetConstantFloat(double val);
-	int GetConstantAddress(void *ptr, VM_ATAG tag);
-	int GetConstantString(FString str);
-
-	// Returns the address of the newly-emitted instruction.
-	size_t Emit(int opcode, int opa, int opb, int opc);
-	size_t Emit(int opcode, int opa, VM_SHALF opbc);
-	size_t Emit(int opcode, int opabc);
-	size_t EmitParamInt(int value);
-	size_t EmitLoadInt(int regnum, int value);
-	size_t EmitRetInt(int retnum, bool final, int value);
-
-	void Backpatch(size_t addr, size_t target);
-	void BackpatchToHere(size_t addr);
-
-	// Write out complete constant tables.
-	void FillIntConstants(int *konst);
-	void FillFloatConstants(double *konst);
-	void FillAddressConstants(FVoidObj *konst, VM_ATAG *tags);
-	void FillStringConstants(FString *strings);
-
-	// PARAM increases ActiveParam; CALL decreases it.
-	void ParamChange(int delta);
-
-	// Track available registers.
-	RegAvailability Registers[4];
-
-private:
-	struct AddrKonst
-	{
-		int KonstNum;
-		VM_ATAG Tag;
-	};
-	// These map from the constant value to its position in the constant table.
-	TMap<int, int> IntConstants;
-	TMap<double, int> FloatConstants;
-	TMap<void *, AddrKonst> AddressConstants;
-	TMap<FString, int> StringConstants;
-
-	int NumIntConstants;
-	int NumFloatConstants;
-	int NumAddressConstants;
-	int NumStringConstants;
-
-	int MaxParam;
-	int ActiveParam;
-
-	TArray<VMOP> Code;
-
-};
-
-#endif
--- src/zscript/vmdisasm.cpp
+++ src/zscript/vmdisasm.cpp
@@ -1,556 +0,0 @@
-#include "vm.h"
-#include "c_console.h"
-
-#define NOP		MODE_AUNUSED | MODE_BUNUSED | MODE_CUNUSED
-
-#define LI		MODE_AI | MODE_BCJOINT | MODE_BCIMMS
-#define LKI		MODE_AI | MODE_BCJOINT | MODE_BCKI
-#define LKF		MODE_AF | MODE_BCJOINT | MODE_BCKF
-#define LKS		MODE_AS | MODE_BCJOINT | MODE_BCKS
-#define LKP		MODE_AP | MODE_BCJOINT | MODE_BCKP
-#define LFP		MODE_AP | MODE_BUNUSED | MODE_CUNUSED
-
-#define RIRPKI	MODE_AI | MODE_BP | MODE_CKI
-#define RIRPRI	MODE_AI | MODE_BP | MODE_CI
-#define RFRPKI	MODE_AF | MODE_BP | MODE_CKI
-#define RFRPRI	MODE_AF | MODE_BP | MODE_CI
-#define RSRPKI	MODE_AS | MODE_BP | MODE_CKI
-#define RSRPRI	MODE_AS | MODE_BP | MODE_CI
-#define RPRPKI	MODE_AP | MODE_BP | MODE_CKI
-#define RPRPRI	MODE_AP | MODE_BP | MODE_CI
-#define RVRPKI	MODE_AV | MODE_BP | MODE_CKI
-#define RVRPRI	MODE_AV | MODE_BP | MODE_CI
-#define RIRPI8	MODE_AI | MODE_BP | MODE_CIMMZ
-
-#define RPRIKI	MODE_AP | MODE_BI | MODE_CKI
-#define RPRIRI	MODE_AP | MODE_BI | MODE_CI
-#define RPRFKI	MODE_AP | MODE_BF | MODE_CKI
-#define RPRFRI	MODE_AP | MODE_BF | MODE_CI
-#define RPRSKI	MODE_AP | MODE_BS | MODE_CKI
-#define RPRSRI	MODE_AP | MODE_BS | MODE_CI
-#define RPRPKI	MODE_AP | MODE_BP | MODE_CKI
-#define RPRPRI	MODE_AP | MODE_BP | MODE_CI
-#define RPRVKI	MODE_AP | MODE_BV | MODE_CKI
-#define RPRVRI	MODE_AP | MODE_BV | MODE_CI
-#define RPRII8	MODE_AP | MODE_BI | MODE_CIMMZ
-
-#define RIRI	MODE_AI | MODE_BI | MODE_CUNUSED
-#define RFRF	MODE_AF | MODE_BF | MODE_CUNUSED
-#define	RSRS	MODE_AS | MODE_BS | MODE_CUNUSED
-#define RPRP	MODE_AP | MODE_BP | MODE_CUNUSED
-#define RXRXI8	MODE_AX | MODE_BX | MODE_CIMMZ
-#define RPRPRP	MODE_AP | MODE_BP | MODE_CP
-#define RPRPKP	MODE_AP | MODE_BP | MODE_CKP
-
-#define RII16	MODE_AI | MODE_BCJOINT | MODE_BCIMMS
-#define I24		MODE_ABCJOINT
-#define I8		MODE_AIMMZ | MODE_BUNUSED | MODE_CUNUSED
-#define I8I16	MODE_AIMMZ | MODE_BCIMMZ
-#define __BCP	MODE_AUNUSED | MODE_BCJOINT | MODE_BCPARAM
-#define RPI8	MODE_AP | MODE_BIMMZ | MODE_CUNUSED
-#define KPI8	MODE_AKP | MODE_BIMMZ | MODE_CUNUSED
-#define RPI8I8	MODE_AP | MODE_BIMMZ | MODE_CIMMZ
-#define KPI8I8	MODE_AKP | MODE_BIMMZ | MODE_CIMMZ
-#define I8BCP	MODE_AIMMZ | MODE_BCJOINT | MODE_BCPARAM
-#define THROW	MODE_AIMMZ | MODE_BCTHROW
-#define CATCH	MODE_AIMMZ | MODE_BCCATCH
-#define CAST	MODE_AX | MODE_BX | MODE_CIMMZ | MODE_BCCAST
-
-#define RSRSRS	MODE_AS | MODE_BS | MODE_CS
-#define RIRS	MODE_AI | MODE_BS | MODE_CUNUSED
-#define I8RXRX	MODE_AIMMZ | MODE_BX | MODE_CX
-
-#define RIRIRI	MODE_AI | MODE_BI | MODE_CI
-#define RIRII8	MODE_AI | MODE_BI | MODE_CIMMZ
-#define RIRIKI	MODE_AI | MODE_BI | MODE_CKI
-#define RIKIRI	MODE_AI | MODE_BKI | MODE_CI
-#define RIKII8	MODE_AI | MODE_BKI | MODE_CIMMZ
-#define RIRIIs	MODE_AI | MODE_BI | MODE_CIMMS
-#define RIRI	MODE_AI | MODE_BI | MODE_CUNUSED
-#define I8RIRI	MODE_AIMMZ | MODE_BI | MODE_CI
-#define I8RIKI	MODE_AIMMZ | MODE_BI | MODE_CKI
-#define I8KIRI	MODE_AIMMZ | MODE_BKI | MODE_CI
-
-#define RFRFRF	MODE_AF | MODE_BF | MODE_CF
-#define RFRFKF	MODE_AF | MODE_BF | MODE_CKF
-#define RFKFRF	MODE_AF | MODE_BKF | MODE_CF
-#define I8RFRF	MODE_AIMMZ | MODE_BF | MODE_CF
-#define I8RFKF	MODE_AIMMZ | MODE_BF | MODE_CKF
-#define I8KFRF	MODE_AIMMZ | MODE_BKF | MODE_CF
-#define RFRFI8	MODE_AF | MODE_BF | MODE_CIMMZ
-
-#define RVRV	MODE_AV | MODE_BV | MODE_CUNUSED
-#define RVRVRV	MODE_AV | MODE_BV | MODE_CV
-#define RVRVKV	MODE_AV | MODE_BV | MODE_CKV
-#define RVKVRV	MODE_AV | MODE_BKV | MODE_CV
-#define RFRV	MODE_AF | MODE_BV | MODE_CUNUSED
-#define I8RVRV	MODE_AIMMZ | MODE_BV | MODE_CV
-#define I8RVKV	MODE_AIMMZ | MODE_BV | MODE_CKV
-
-#define RPRPRI	MODE_AP | MODE_BP | MODE_CI
-#define RPRPKI	MODE_AP | MODE_BP | MODE_CKI
-#define RIRPRP	MODE_AI | MODE_BP | MODE_CP
-#define I8RPRP	MODE_AIMMZ | MODE_BP | MODE_CP
-#define I8RPKP	MODE_AIMMZ | MODE_BP | MODE_CKP
-
-#define CIRR	MODE_ACMP | MODE_BI | MODE_CI
-#define CIRK	MODE_ACMP | MODE_BI | MODE_CKI
-#define CIKR	MODE_ACMP | MODE_BKI | MODE_CI
-#define CFRR	MODE_ACMP | MODE_BF | MODE_CF
-#define CFRK	MODE_ACMP | MODE_BF | MODE_CKF
-#define CFKR	MODE_ACMP | MODE_BKF | MODE_CF
-#define CVRR	MODE_ACMP | MODE_BV | MODE_CV
-#define CVRK	MODE_ACMP | MODE_BV | MODE_CKV
-#define CPRR	MODE_ACMP | MODE_BP | MODE_CP
-#define CPRK	MODE_ACMP | MODE_BP | MODE_CKP
-
-const VMOpInfo OpInfo[NUM_OPS] =
-{
-#define xx(op, name, mode)	{ #name, mode }
-#include "vmops.h"
-};
-
-static const char *const FlopNames[] =
-{
-	"abs",
-	"neg",
-	"exp",
-	"log",
-	"log10",
-	"sqrt",
-	"ceil",
-	"floor",
-
-	"acos rad",
-	"asin rad",
-	"atan rad",
-	"cos rad",
-	"sin rad",
-	"tan rad",
-
-	"acos deg",
-	"asin deg",
-	"atan deg",
-	"cos deg",
-	"sin deg",
-	"tan deg",
-
-	"cosh",
-	"sinh",
-	"tanh",
-};
-
-static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func);
-
-static int printf_wrapper(FILE *f, const char *fmt, ...)
-{
-	va_list argptr;
-	int count;
-
-	va_start(argptr, fmt);
-	if (f == NULL)
-	{
-		count = VPrintf(PRINT_HIGH, fmt, argptr);
-	}
-	else
-	{
-		count = vfprintf(f, fmt, argptr);
-	}
-	va_end(argptr);
-	return count;
-}
-
-void VMDumpConstants(FILE *out, const VMScriptFunction *func)
-{
-	char tmp[21];
-	int i, j, k, kk;
-
-	if (func->KonstD != NULL && func->NumKonstD != 0)
-	{
-		printf_wrapper(out, "\nConstant integers:\n");
-		kk = (func->NumKonstD + 3) / 4;
-		for (i = 0; i < kk; ++i)
-		{
-			for (j = 0, k = i; j < 4 && k < func->NumKonstD; j++, k += kk)
-			{
-				mysnprintf(tmp, countof(tmp), "%3d. %d", k, func->KonstD[k]);
-				printf_wrapper(out, "%-20s", tmp);
-			}
-			printf_wrapper(out, "\n");
-		}
-	}
-	if (func->KonstF != NULL && func->NumKonstF != 0)
-	{
-		printf_wrapper(out, "\nConstant floats:\n");
-		kk = (func->NumKonstF + 3) / 4;
-		for (i = 0; i < kk; ++i)
-		{
-			for (j = 0, k = i; j < 4 && k < func->NumKonstF; j++, k += kk)
-			{
-				mysnprintf(tmp, countof(tmp), "%3d. %.16f", k, func->KonstF[k]);
-				printf_wrapper(out, "%-20s", tmp);
-			}
-			printf_wrapper(out, "\n");
-		}
-	}
-	if (func->KonstA != NULL && func->NumKonstA != 0)
-	{
-		printf_wrapper(out, "\nConstant addresses:\n");
-		kk = (func->NumKonstA + 3) / 4;
-		for (i = 0; i < kk; ++i)
-		{
-			for (j = 0, k = i; j < 4 && k < func->NumKonstA; j++, k += kk)
-			{
-				mysnprintf(tmp, countof(tmp), "%3d. %p:%d", k, func->KonstA[k].v, func->KonstATags()[k]);
-				printf_wrapper(out, "%-20s", tmp);
-			}
-			printf_wrapper(out, "\n");
-		}
-	}
-	if (func->KonstS != NULL && func->NumKonstS != 0)
-	{
-		printf_wrapper(out, "\nConstant strings:\n");
-		for (i = 0; i < func->NumKonstS; ++i)
-		{
-			printf_wrapper(out, "%3d. %s\n", i, func->KonstS[i].GetChars());
-		}
-	}
-}
-
-void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction *func)
-{
-	VMFunction *callfunc;
-	const char *callname;
-	const char *name;
-	int col;
-	int mode;
-	int a;
-	bool cmp;
-	char cmpname[8];
-
-	for (int i = 0; i < codesize; ++i)
-	{
-		name = OpInfo[code[i].op].Name;
-		mode = OpInfo[code[i].op].Mode;
-		a = code[i].a;
-		cmp = (mode & MODE_ATYPE) == MODE_ACMP;
-
-		// String comparison encodes everything in a single instruction.
-		if (code[i].op == OP_CMPS)
-		{
-			switch (a & CMP_METHOD_MASK)
-			{
-			case CMP_EQ:	name = "beq";	break;
-			case CMP_LT:	name = "blt";	break;
-			case CMP_LE:	name = "ble";	break;
-			}
-			mode = MODE_AIMMZ;
-			mode |= (a & CMP_BK) ? MODE_BKS : MODE_BS;
-			mode |= (a & CMP_CK) ? MODE_CKS : MODE_CS;
-			a &= CMP_CHECK | CMP_APPROX;
-			cmp = true;
-		}
-		if (cmp)
-		{ // Comparison instruction. Modify name for inverted test.
-			if (!(a & CMP_CHECK))
-			{
-				strcpy(cmpname, name);
-				if (name[1] == 'e')
-				{ // eq -> ne
-					cmpname[1] = 'n', cmpname[2] = 'e';
-				}
-				else if (name[2] == 't')
-				{ // lt -> ge
-					cmpname[1] = 'g', cmpname[2] = 'e';
-				}
-				else
-				{ // le -> gt
-					cmpname[1] = 'g', cmpname[2] = 't';
-				}
-				name = cmpname;
-			}
-		}
-		printf_wrapper(out, "%08x: %02x%02x%02x%02x %-8s", i << 2, code[i].op, code[i].a, code[i].b, code[i].c, name);
-		col = 0;
-		switch (code[i].op)
-		{
-		case OP_JMP:
-		case OP_TRY:
-			col = printf_wrapper(out, "%08x", (i + 1 + code[i].i24) << 2);
-			break;
-
-		case OP_PARAMI:
-			col = printf_wrapper(out, "%d", code[i].i24);
-			break;
-
-		case OP_CALL_K:
-		case OP_TAIL_K:
-			callfunc = (VMFunction *)func->KonstA[code[i].a].o;
-			callname = callfunc->Name != NAME_None ? callfunc->Name : "[anonfunc]";
-			col = printf_wrapper(out, "%.23s,%d", callname, code[i].b);
-			if (code[i].op == OP_CALL_K)
-			{
-				col += printf_wrapper(out, ",%d", code[i].c);
-			}
-			break;
-
-		case OP_RET:
-			if (code[i].b != REGT_NIL)
-			{
-				if (a == RET_FINAL)
-				{
-					col = print_reg(out, 0, code[i].i16u, MODE_PARAM, 16, func);
-				}
-				else
-				{
-					col = print_reg(out, 0, a & ~RET_FINAL, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
-					col += print_reg(out, col, code[i].i16u, MODE_PARAM, 16, func);
-					if (a & RET_FINAL)
-					{
-						col += printf_wrapper(out, " [final]");
-					}
-				}
-			}
-			break;
-
-		case OP_RETI:
-			if (a == RET_FINAL)
-			{
-				col = printf_wrapper(out, "%d", code[i].i16);
-			}
-			else
-			{
-				col = print_reg(out, 0, a & ~RET_FINAL, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
-				col += print_reg(out, col, code[i].i16, MODE_IMMS, 16, func);
-				if (a & RET_FINAL)
-				{
-					col += printf_wrapper(out, " [final]");
-				}
-			}
-			break;
-
-		case OP_FLOP:
-			col = printf_wrapper(out, "f%d,f%d,%d", code[i].a, code[i].b, code[i].c);
-			if (code[i].c < countof(FlopNames))
-			{
-				col += printf_wrapper(out, " [%s]", FlopNames[code[i].c]);
-			}
-			break;
-
-		default:
-			if ((mode & MODE_BCTYPE) == MODE_BCCAST)
-			{
-				switch (code[i].c)
-				{
-				case CAST_I2F:
-					mode = MODE_AF | MODE_BI | MODE_CUNUSED;
-					break;
-				case CAST_I2S:
-					mode = MODE_AS | MODE_BI | MODE_CUNUSED;
-					break;
-				case CAST_F2I:
-					mode = MODE_AI | MODE_BF | MODE_CUNUSED;
-					break;
-				case CAST_F2S:
-					mode = MODE_AS | MODE_BF | MODE_CUNUSED;
-					break;
-				case CAST_P2S:
-					mode = MODE_AS | MODE_BP | MODE_CUNUSED;
-					break;
-				case CAST_S2I:
-					mode = MODE_AI | MODE_BS | MODE_CUNUSED;
-					break;
-				case CAST_S2F:
-					mode = MODE_AF | MODE_BS | MODE_CUNUSED;
-					break;
-				default:
-					mode = MODE_AX | MODE_BX | MODE_CIMMZ;
-					break;
-				}
-			}
-			col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
-			if ((mode & MODE_BCTYPE) == MODE_BCTHROW)
-			{
-				mode = (code[i].a == 0) ? (MODE_BP | MODE_CUNUSED) : (MODE_BKP | MODE_CUNUSED);
-			}
-			else if ((mode & MODE_BCTYPE) == MODE_BCCATCH)
-			{
-				switch (code[i].a)
-				{
-				case 0:
-					mode = MODE_BUNUSED | MODE_CUNUSED;
-					break;
-				case 1:
-					mode = MODE_BUNUSED | MODE_CP;
-					break;
-				case 2:
-					mode = MODE_BP | MODE_CP;
-					break;
-				case 3:
-					mode = MODE_BKP | MODE_CP;
-					break;
-				default:
-					mode = MODE_BIMMZ | MODE_CIMMZ;
-					break;
-				}
-			}
-			if ((mode & (MODE_BTYPE | MODE_CTYPE)) == MODE_BCJOINT)
-			{
-				col += print_reg(out, col, code[i].i16u, (mode & MODE_BCTYPE) >> MODE_BCSHIFT, 16, func);
-			}
-			else
-			{
-				col += print_reg(out, col, code[i].b, (mode & MODE_BTYPE) >> MODE_BSHIFT, 24, func);
-				col += print_reg(out, col, code[i].c, (mode & MODE_CTYPE) >> MODE_CSHIFT, 24, func);
-			}
-			break;
-		}
-		if (cmp && i + 1 < codesize)
-		{
-			if (code[i+1].op != OP_JMP)
-			{ // comparison instructions must be followed by jump
-				col += printf_wrapper(out, " => *!*!*!*\n");
-			}
-			else
-			{ 
-				col += printf_wrapper(out, " => %08x", (i + 2 + code[i+1].i24) << 2);
-			}
-		}
-		if (col > 30)
-		{
-			col = 30;
-		}
-		printf_wrapper(out, "%*c", 30 - col, ';');
-		if (!cmp && (code[i].op == OP_JMP || code[i].op == OP_TRY || code[i].op == OP_PARAMI))
-		{
-			printf_wrapper(out, "%d\n", code[i].i24);
-		}
-		else
-		{
-			printf_wrapper(out, "%d,%d,%d", code[i].a, code[i].b, code[i].c);
-			if (cmp && i + 1 < codesize && code[i+1].op == OP_JMP)
-			{
-				printf_wrapper(out, ",%d\n", code[++i].i24);
-			}
-			else if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K)
-			{
-				printf_wrapper(out, "  [%p]\n", callfunc);
-			}
-			else
-			{
-				printf_wrapper(out, "\n");
-			}
-		}
-	}
-}
-
-static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func)
-{
-	if (mode == MODE_UNUSED || mode == MODE_CMP)
-	{
-		return 0;
-	}
-	if (col > 0)
-	{
-		col = printf_wrapper(out, ",");
-	}
-	switch(mode)
-	{
-	case MODE_I:
-		return col+printf_wrapper(out, "d%d", arg);
-	case MODE_F:
-		return col+printf_wrapper(out, "f%d", arg);
-	case MODE_S:
-		return col+printf_wrapper(out, "s%d", arg);
-	case MODE_P:
-		return col+printf_wrapper(out, "a%d", arg);
-	case MODE_V:
-		return col+printf_wrapper(out, "v%d", arg);
-
-	case MODE_KI:
-		if (func != NULL)
-		{
-			return col+printf_wrapper(out, "%d", func->KonstD[arg]);
-		}
-		return printf_wrapper(out, "kd%d", arg);
-	case MODE_KF:
-		if (func != NULL)
-		{
-			return col+printf_wrapper(out, "%#g", func->KonstF[arg]);
-		}
-		return col+printf_wrapper(out, "kf%d", arg);
-	case MODE_KS:
-		if (func != NULL)
-		{
-			return col+printf_wrapper(out, "\"%.27s\"", func->KonstS[arg].GetChars());
-		}
-		return col+printf_wrapper(out, "ks%d", arg);
-	case MODE_KP:
-		if (func != NULL)
-		{
-			return col+printf_wrapper(out, "%p", func->KonstA[arg]);
-		}
-		return col+printf_wrapper(out, "ka%d", arg);
-	case MODE_KV:
-		if (func != NULL)
-		{
-			return col+printf_wrapper(out, "(%f,%f,%f)", func->KonstF[arg], func->KonstF[arg+1], func->KonstF[arg+2]);
-		}
-		return col+printf_wrapper(out, "kv%d", arg);
-
-	case MODE_IMMS:
-		return col+printf_wrapper(out, "%d", (arg << immshift) >> immshift);
-
-	case MODE_IMMZ:
-		return col+printf_wrapper(out, "%d", arg);
-
-	case MODE_PARAM:
-		{
-			int regtype, regnum;
-#ifdef __BIG_ENDIAN__
-			regtype = (arg >> 8) & 255;
-			regnum = arg & 255;
-#else
-			regtype = arg & 255;
-			regnum = (arg >> 8) & 255;
-#endif
-			switch (regtype & (REGT_TYPE | REGT_KONST | REGT_MULTIREG))
-			{
-			case REGT_INT:
-				return col+printf_wrapper(out, "d%d", regnum);
-			case REGT_FLOAT:
-				return col+printf_wrapper(out, "f%d", regnum);
-			case REGT_STRING:
-				return col+printf_wrapper(out, "s%d", regnum);
-			case REGT_POINTER:
-				return col+printf_wrapper(out, "a%d", regnum);
-			case REGT_FLOAT | REGT_MULTIREG:
-				return col+printf_wrapper(out, "v%d", regnum);
-			case REGT_INT | REGT_KONST:
-				return col+print_reg(out, 0, regnum, MODE_KI, 0, func);
-			case REGT_FLOAT | REGT_KONST:
-				return col+print_reg(out, 0, regnum, MODE_KF, 0, func);
-			case REGT_STRING | REGT_KONST:
-				return col+print_reg(out, 0, regnum, MODE_KS, 0, func);
-			case REGT_POINTER | REGT_KONST:
-				return col+print_reg(out, 0, regnum, MODE_KP, 0, func);
-			case REGT_FLOAT | REGT_MULTIREG | REGT_KONST:
-				return col+print_reg(out, 0, regnum, MODE_KV, 0, func);
-			default:
-				if (regtype == REGT_NIL)
-				{
-					return col+printf_wrapper(out, "nil");
-				}
-				return col+printf_wrapper(out, "param[t=%d,%c,%c,n=%d]",
-					regtype & REGT_TYPE,
-					regtype & REGT_KONST ? 'k' : 'r',
-					regtype & REGT_MULTIREG ? 'm' : 's',
-					regnum);
-			}
-		}
-
-	default:
-		return col+printf_wrapper(out, "$%d", arg);
-	}
-	return col;
-}
--- src/zscript/vmexec.cpp
+++ src/zscript/vmexec.cpp
@@ -1,193 +0,0 @@
-#include <math.h>
-#include "vm.h"
-#include "xs_Float.h"
-#include "math/cmath.h"
-
-#define IMPLEMENT_VMEXEC
-
-#if !defined(COMPGOTO) && defined(__GNUC__)
-#define COMPGOTO 1
-#endif
-
-#if COMPGOTO
-#define OP(x)	x
-#define NEXTOP	do { unsigned op = pc->op; a = pc->a; pc++; goto *ops[op]; } while(0)
-#else
-#define OP(x)	case OP_##x
-#define NEXTOP	break
-#endif
-
-#define luai_nummod(a,b)        ((a) - floor((a)/(b))*(b))
-
-#define A				(pc[-1].a)
-#define B				(pc[-1].b)
-#define C				(pc[-1].c)
-#define Cs				(pc[-1].cs)
-#define BC				(pc[-1].i16u)
-#define BCs				(pc[-1].i16)
-#define ABCs			(pc[-1].i24)
-#define JMPOFS(x)		((x)->i24)
-
-#define KC				(konstd[C])
-#define RC				(reg.d[C])
-
-#define PA				(reg.a[A])
-#define PB				(reg.a[B])
-
-#define ASSERTD(x)		assert((unsigned)(x) < f->NumRegD)
-#define ASSERTF(x)		assert((unsigned)(x) < f->NumRegF)
-#define ASSERTA(x)		assert((unsigned)(x) < f->NumRegA)
-#define ASSERTS(x)		assert((unsigned)(x) < f->NumRegS)
-
-#define ASSERTKD(x)		assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstD)
-#define ASSERTKF(x)		assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstF)
-#define ASSERTKA(x)		assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstA)
-#define ASSERTKS(x)		assert(sfunc != NULL && (unsigned)(x) < sfunc->NumKonstS)
-
-#define THROW(x)
-
-#define CMPJMP(test) \
-	if ((test) == (a & CMP_CHECK)) { \
-		assert(pc->op == OP_JMP); \
-		pc += 1 + JMPOFS(pc); \
-	} else { \
-		pc += 1; \
-	}
-
-enum
-{
-	X_READ_NIL,
-	X_WRITE_NIL,
-	X_TOO_MANY_TRIES,
-	X_ARRAY_OUT_OF_BOUNDS
-};
-
-#define GETADDR(a,o,x) \
-	if (a == NULL) { THROW(x); } \
-	ptr = (VM_SBYTE *)a + o
-
-static const VM_UWORD ZapTable[16] =
-{
-	0x00000000, 0x000000FF, 0x0000FF00, 0x0000FFFF,
-	0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF,
-	0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF,
-	0xFFFF0000, 0xFFFF00FF, 0xFFFFFF00, 0xFFFFFFFF
-};
-
-#ifdef NDEBUG
-#define WAS_NDEBUG 1
-#else
-#define WAS_NDEBUG 0
-#endif
-
-#if WAS_NDEBUG
-#undef NDEBUG
-#endif
-#undef assert
-#include <assert.h>
-struct VMExec_Checked
-{
-#include "vmexec.h"
-};
-#if WAS_NDEBUG
-#define NDEBUG
-#endif
-
-#if !WAS_NDEBUG
-#define NDEBUG
-#endif
-#undef assert
-#include <assert.h>
-struct VMExec_Unchecked
-{
-#include "vmexec.h"
-};
-#if !WAS_NDEBUG
-#undef NDEBUG
-#endif
-#undef assert
-#include <assert.h>
-
-int (*VMExec)(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) =
-#ifdef NDEBUG
-VMExec_Unchecked::Exec
-#else
-VMExec_Checked::Exec
-#endif
-;
-
-//===========================================================================
-//
-// VMSelectEngine
-//
-// Selects the VM engine, either checked or unchecked. Default will decide
-// based on the NDEBUG preprocessor definition.
-//
-//===========================================================================
-
-void VMSelectEngine(EVMEngine engine)
-{
-	switch (engine)
-	{
-	case VMEngine_Default:
-#ifdef NDEBUG
-		VMExec = VMExec_Unchecked::Exec;
-#else
-#endif
-		VMExec = VMExec_Checked::Exec;
-		break;
-	case VMEngine_Unchecked:
-		VMExec = VMExec_Unchecked::Exec;
-		break;
-	case VMEngine_Checked:
-		VMExec = VMExec_Checked::Exec;
-		break;
-	}
-}
-
-//===========================================================================
-//
-// VMFillParams
-//
-// Takes parameters from the parameter stack and stores them in the callee's
-// registers.
-//
-//===========================================================================
-
-void VMFillParams(VMValue *params, VMFrame *callee, int numparam)
-{
-	unsigned int regd, regf, regs, rega;
-	VMScriptFunction *calleefunc = static_cast<VMScriptFunction *>(callee->Func);
-	const VMRegisters calleereg(callee);
-
-	assert(calleefunc != NULL && !calleefunc->Native);
-	assert(numparam == calleefunc->NumArgs);
-	assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3);
-
-	regd = regf = regs = rega = 0;
-	for (int i = 0; i < numparam; ++i)
-	{
-		VMValue &p = params[i];
-		if (p.Type < REGT_STRING)
-		{
-			if (p.Type == REGT_INT)
-			{
-				calleereg.d[regd++] = p.i;
-			}
-			else // p.Type == REGT_FLOAT
-			{
-				calleereg.f[regf++] = p.f;
-			}
-		}
-		else if (p.Type == REGT_STRING)
-		{
-			calleereg.s[regs++] = p.s();
-		}
-		else
-		{
-			assert(p.Type == REGT_POINTER);
-			calleereg.a[rega] = p.a;
-			calleereg.atag[rega++] = p.atag;
-		}
-	}
-}
--- src/zscript/vmexec.h
+++ src/zscript/vmexec.h
@@ -1,1564 +0,0 @@
-#ifndef IMPLEMENT_VMEXEC
-#error vmexec.h must not be #included outside vmexec.cpp. Use vm.h instead.
-#endif
-
-
-static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
-{
-#if COMPGOTO
-	static const void * const ops[256] =
-	{
-#define xx(op,sym,mode) &&op
-#include "vmops.h"
-	};
-#endif
-	const VMOP *exception_frames[MAX_TRY_DEPTH];
-	int try_depth = 0;
-	VMFrame *f = stack->TopFrame();
-	VMScriptFunction *sfunc;
-	const VMRegisters reg(f);
-	const int *konstd;
-	const double *konstf;
-	const FString *konsts;
-	const FVoidObj *konsta;
-	const VM_ATAG *konstatag;
-
-	if (f->Func != NULL && !f->Func->Native)
-	{
-		sfunc = static_cast<VMScriptFunction *>(f->Func);
-		konstd = sfunc->KonstD;
-		konstf = sfunc->KonstF;
-		konsts = sfunc->KonstS;
-		konsta = sfunc->KonstA;
-		konstatag = sfunc->KonstATags();
-	}
-	else
-	{
-		sfunc = NULL;
-		konstd = NULL;
-		konstf = NULL;
-		konsts = NULL;
-		konsta = NULL;
-		konstatag = NULL;
-	}
-
-	void *ptr;
-	double fb, fc;
-	const double *fbp, *fcp;
-	int a, b, c;
-
-begin:
-	try
-	{
-#if !COMPGOTO
-	VM_UBYTE op;
-	for(;;) switch(op = pc->op, a = pc->a, pc++, op)
-#else
-	NEXTOP;
-#endif
-	{
-	OP(LI):
-		ASSERTD(a);
-		reg.d[a] = BCs;
-		NEXTOP;
-	OP(LK):
-		ASSERTD(a); ASSERTKD(BC);
-		reg.d[a] = konstd[BC];
-		NEXTOP;
-	OP(LKF):
-		ASSERTF(a); ASSERTKF(BC);
-		reg.f[a] = konstf[BC];
-		NEXTOP;
-	OP(LKS):
-		ASSERTS(a); ASSERTKS(BC);
-		reg.s[a] = konsts[BC];
-		NEXTOP;
-	OP(LKP):
-		ASSERTA(a); ASSERTKA(BC);
-		reg.a[a] = konsta[BC].v;
-		reg.atag[a] = konstatag[BC];
-		NEXTOP;
-	OP(LFP):
-		ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0);
-		reg.a[a] = f->GetExtra();
-		reg.atag[a] = ATAG_FRAMEPOINTER;
-		NEXTOP;
-
-	OP(LB):
-		ASSERTD(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.d[a] = *(VM_SBYTE *)ptr;
-		NEXTOP;
-	OP(LB_R):
-		ASSERTD(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.d[a] = *(VM_SBYTE *)ptr;
-		NEXTOP;
-	OP(LH):
-		ASSERTD(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.d[a] = *(VM_SHALF *)ptr;
-		NEXTOP;
-	OP(LH_R):
-		ASSERTD(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.d[a] = *(VM_SHALF *)ptr;
-		NEXTOP;
-	OP(LW):
-		ASSERTD(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.d[a] = *(VM_SWORD *)ptr;
-		NEXTOP;
-	OP(LW_R):
-		ASSERTD(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.d[a] = *(VM_SWORD *)ptr;
-		NEXTOP;
-	OP(LBU):
-		ASSERTD(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.d[a] = *(VM_UBYTE *)ptr;
-		NEXTOP;
-	OP(LBU_R):
-		ASSERTD(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.d[a] = *(VM_UBYTE *)ptr;
-		NEXTOP;
-	OP(LHU):
-		ASSERTD(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.d[a] = *(VM_UHALF *)ptr;
-		NEXTOP;
-	OP(LHU_R):
-		ASSERTD(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.d[a] = *(VM_UHALF *)ptr;
-		NEXTOP;
-
-	OP(LSP):
-		ASSERTF(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.f[a] = *(float *)ptr;
-		NEXTOP;
-	OP(LSP_R):
-		ASSERTF(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.f[a] = *(float *)ptr;
-		NEXTOP;
-	OP(LDP):
-		ASSERTF(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.f[a] = *(double *)ptr;
-		NEXTOP;
-	OP(LDP_R):
-		ASSERTF(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.f[a] = *(double *)ptr;
-		NEXTOP;
-
-	OP(LS):
-		ASSERTS(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.s[a] = *(FString *)ptr;
-		NEXTOP;
-	OP(LS_R):
-		ASSERTS(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.s[a] = *(FString *)ptr;
-		NEXTOP;
-	OP(LO):
-		ASSERTA(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.a[a] = *(void **)ptr;
-		reg.atag[a] = ATAG_OBJECT;
-		NEXTOP;
-	OP(LO_R):
-		ASSERTA(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.a[a] = *(void **)ptr;
-		reg.atag[a] = ATAG_OBJECT;
-		NEXTOP;
-	OP(LP):
-		ASSERTA(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		reg.a[a] = *(void **)ptr;
-		reg.atag[a] = ATAG_GENERIC;
-		NEXTOP;
-	OP(LP_R):
-		ASSERTA(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		reg.a[a] = *(void **)ptr;
-		reg.atag[a] = ATAG_GENERIC;
-		NEXTOP;
-	OP(LV):
-		ASSERTF(a+2); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PB,KC,X_READ_NIL);
-		{
-			float *v = (float *)ptr;
-			reg.f[a] = v[0];
-			reg.f[a+1] = v[1];
-			reg.f[a+2] = v[2];
-		}
-		NEXTOP;
-	OP(LV_R):
-		ASSERTF(a+2); ASSERTA(B); ASSERTD(C);
-		GETADDR(PB,RC,X_READ_NIL);
-		{
-			float *v = (float *)ptr;
-			reg.f[a] = v[0];
-			reg.f[a+1] = v[1];
-			reg.f[a+2] = v[2];
-		}
-		NEXTOP;
-	OP(LBIT):
-		ASSERTD(a); ASSERTA(B);
-		GETADDR(PB,0,X_READ_NIL);
-		reg.d[a] = !!(*(VM_UBYTE *)ptr & C);
-		NEXTOP;
-
-	OP(SB):
-		ASSERTA(a); ASSERTD(B); ASSERTKD(C);
-		GETADDR(PA,KC,X_WRITE_NIL);
-		*(VM_SBYTE *)ptr = reg.d[B];
-		NEXTOP;
-	OP(SB_R):
-		ASSERTA(a); ASSERTD(B); ASSERTD(C);
-		GETADDR(PA,RC,X_WRITE_NIL);
-		*(VM_SBYTE *)ptr = reg.d[B];
-		NEXTOP;
-	OP(SH):
-		ASSERTA(a); ASSERTD(B); ASSERTKD(C);
-		GETADDR(PA,KC,X_WRITE_NIL);
-		*(VM_SHALF *)ptr = reg.d[B];
-		NEXTOP;
-	OP(SH_R):
-		ASSERTA(a); ASSERTD(B); ASSERTD(C);
-		GETADDR(PA,RC,X_WRITE_NIL);
-		*(VM_SHALF *)ptr = reg.d[B];
-		NEXTOP;
-	OP(SW):
-		ASSERTA(a); ASSERTD(B); ASSERTKD(C);
-		GETADDR(PA,KC,X_WRITE_NIL);
-		*(VM_SWORD *)ptr = reg.d[B];
-		NEXTOP;
-	OP(SW_R):
-		ASSERTA(a); ASSERTD(B); ASSERTD(C);
-		GETADDR(PA,RC,X_WRITE_NIL);
-		*(VM_SWORD *)ptr = reg.d[B];
-		NEXTOP;
-	OP(SSP):
-		ASSERTA(a); ASSERTF(B); ASSERTKD(C);
-		GETADDR(PA,KC,X_WRITE_NIL);
-		*(float *)ptr = (float)reg.f[B];
-		NEXTOP;
-	OP(SSP_R):
-		ASSERTA(a); ASSERTF(B); ASSERTD(C);
-		GETADDR(PA,RC,X_WRITE_NIL);
-		*(float *)ptr = (float)reg.f[B];
-		NEXTOP;
-	OP(SDP):
-		ASSERTA(a); ASSERTF(B); ASSERTKD(C);
-		GETADDR(PA,KC,X_WRITE_NIL);
-		*(double *)ptr = reg.f[B];
-		NEXTOP;
-	OP(SDP_R):
-		ASSERTA(a); ASSERTF(B); ASSERTD(C);
-		GETADDR(PA,RC,X_WRITE_NIL);
-		*(double *)ptr = reg.f[B];
-		NEXTOP;
-	OP(SS):
-		ASSERTA(a); ASSERTS(B); ASSERTKD(C);
-		GETADDR(PA,KC,X_WRITE_NIL);
-		*(FString *)ptr = reg.s[B];
-		NEXTOP;
-	OP(SS_R):
-		ASSERTA(a); ASSERTS(B); ASSERTD(C);
-		GETADDR(PA,RC,X_WRITE_NIL);
-		*(FString *)ptr = reg.s[B];
-		NEXTOP;
-	OP(SP):
-		ASSERTA(a); ASSERTA(B); ASSERTKD(C);
-		GETADDR(PA,KC,X_WRITE_NIL);
-		*(void **)ptr = reg.a[B];
-		NEXTOP;
-	OP(SP_R):
-		ASSERTA(a); ASSERTA(B); ASSERTD(C);
-		GETADDR(PA,RC,X_WRITE_NIL);
-		*(void **)ptr = reg.a[B];
-		NEXTOP;
-	OP(SV):
-		ASSERTA(a); ASSERTF(B+2); ASSERTKD(C);
-		GETADDR(PA,KC,X_WRITE_NIL);
-		{
-			float *v = (float *)ptr;
-			v[0] = (float)reg.f[B];
-			v[1] = (float)reg.f[B+1];
-			v[2] = (float)reg.f[B+2];
-		}
-		NEXTOP;
-	OP(SV_R):
-		ASSERTA(a); ASSERTF(B+2); ASSERTD(C);
-		GETADDR(PA,RC,X_WRITE_NIL);
-		{
-			float *v = (float *)ptr;
-			v[0] = (float)reg.f[B];
-			v[1] = (float)reg.f[B+1];
-			v[2] = (float)reg.f[B+2];
-		}
-		NEXTOP;
-	OP(SBIT):
-		ASSERTA(a); ASSERTD(B);
-		GETADDR(PA,0,X_WRITE_NIL);
-		if (reg.d[B])
-		{
-			*(VM_UBYTE *)ptr |= C;
-		}
-		else
-		{
-			*(VM_UBYTE *)ptr &= ~C;
-		}
-		NEXTOP;
-
-	OP(MOVE):
-		ASSERTD(a); ASSERTD(B);
-		reg.d[a] = reg.d[B];
-		NEXTOP;
-	OP(MOVEF):
-		ASSERTF(a); ASSERTF(B);
-		reg.f[a] = reg.f[B];
-		NEXTOP;
-	OP(MOVES):
-		ASSERTS(a); ASSERTS(B);
-		reg.s[a] = reg.s[B];
-		NEXTOP;
-	OP(MOVEA):
-		ASSERTA(a); ASSERTA(B);
-		reg.a[a] = reg.a[B];
-		reg.atag[a] = reg.atag[B];
-		NEXTOP;
-	OP(CAST):
-		if (C == CAST_I2F)
-		{
-			ASSERTF(a); ASSERTD(B);
-			reg.f[A] = reg.d[B];
-		}
-		else if (C == CAST_F2I)
-		{
-			ASSERTD(a); ASSERTF(B);
-			reg.d[A] = (int)reg.f[B];
-		}
-		else
-		{
-			DoCast(reg, f, a, B, C);
-		}
-		NEXTOP;
-	OP(DYNCAST_R):
-		// UNDONE
-		NEXTOP;
-	OP(DYNCAST_K):
-		// UNDONE
-		NEXTOP;
-	
-	OP(TEST):
-		ASSERTD(a);
-		if (reg.d[a] != BC)
-		{
-			pc++;
-		}
-		NEXTOP;
-	OP(JMP):
-		pc += JMPOFS(pc - 1);
-		NEXTOP;
-	OP(IJMP):
-		ASSERTD(a);
-		pc += (BCs + reg.d[a]);
-		assert(pc->op == OP_JMP);
-		pc += 1 + JMPOFS(pc);
-		NEXTOP;
-	OP(PARAMI):
-		assert(f->NumParam < sfunc->MaxParam);
-		{
-			VMValue *param = &reg.param[f->NumParam++];
-			::new(param) VMValue(ABCs);
-		}
-		NEXTOP;
-	OP(PARAM):
-		assert(f->NumParam < sfunc->MaxParam);
-		{
-			VMValue *param = &reg.param[f->NumParam++];
-			b = B;
-			if (b == REGT_NIL)
-			{
-				::new(param) VMValue();
-			}
-			else
-			{
-				switch(b & (REGT_TYPE | REGT_KONST | REGT_ADDROF))
-				{
-				case REGT_INT:
-					assert(C < f->NumRegD);
-					::new(param) VMValue(reg.d[C]);
-					break;
-				case REGT_INT | REGT_ADDROF:
-					assert(C < f->NumRegD);
-					::new(param) VMValue(&reg.d[C], ATAG_DREGISTER);
-					break;
-				case REGT_INT | REGT_KONST:
-					assert(C < sfunc->NumKonstD);
-					::new(param) VMValue(konstd[C]);
-					break;
-				case REGT_STRING:
-					assert(C < f->NumRegS);
-					::new(param) VMValue(reg.s[C]);
-					break;
-				case REGT_STRING | REGT_ADDROF:
-					assert(C < f->NumRegS);
-					::new(param) VMValue(&reg.s[C], ATAG_SREGISTER);
-					break;
-				case REGT_STRING | REGT_KONST:
-					assert(C < sfunc->NumKonstS);
-					::new(param) VMValue(konsts[C]);
-					break;
-				case REGT_POINTER:
-					assert(C < f->NumRegA);
-					::new(param) VMValue(reg.a[C], reg.atag[C]);
-					break;
-				case REGT_POINTER | REGT_ADDROF:
-					assert(C < f->NumRegA);
-					::new(param) VMValue(&reg.a[C], ATAG_AREGISTER);
-					break;
-				case REGT_POINTER | REGT_KONST:
-					assert(C < sfunc->NumKonstA);
-					::new(param) VMValue(konsta[C].v, konstatag[C]);
-					break;
-				case REGT_FLOAT:
-					if (b & REGT_MULTIREG)
-					{
-						assert(C < f->NumRegF - 2);
-						assert(f->NumParam < sfunc->MaxParam - 1);
-						::new(param) VMValue(reg.f[C]);
-						::new(param+1) VMValue(reg.f[C+1]);
-						::new(param+2) VMValue(reg.f[C+2]);
-						f->NumParam += 2;
-					}
-					else
-					{
-						assert(C < f->NumRegF);
-						::new(param) VMValue(reg.f[C]);
-					}
-					break;
-				case REGT_FLOAT | REGT_ADDROF:
-					assert(C < f->NumRegF);
-					::new(param) VMValue(&reg.f[C], ATAG_FREGISTER);
-					break;
-				case REGT_FLOAT | REGT_KONST:
-					if (b & REGT_MULTIREG)
-					{
-						assert(C < sfunc->NumKonstF - 2);
-						assert(f->NumParam < sfunc->MaxParam - 1);
-						::new(param) VMValue(konstf[C]);
-						::new(param+1) VMValue(konstf[C+1]);
-						::new(param+2) VMValue(konstf[C+2]);
-						f->NumParam += 2;
-					}
-					else
-					{
-						assert(C < sfunc->NumKonstF);
-						::new(param) VMValue(konstf[C]);
-					}
-					break;
-				default:
-					assert(0);
-					break;
-				}
-			}
-		}
-		NEXTOP;
-	OP(CALL_K):
-		ASSERTKA(a);
-		assert(konstatag[a] == ATAG_OBJECT);
-		ptr = konsta[a].o;
-		goto Do_CALL;
-	OP(CALL):
-		ASSERTA(a);
-		ptr = reg.a[a];
-	Do_CALL:
-		assert(B <= f->NumParam);
-		assert(C <= MAX_RETURNS);
-		{
-			VMFunction *call = (VMFunction *)ptr;
-			VMReturn returns[MAX_RETURNS];
-			int numret;
-
-			FillReturns(reg, f, returns, pc, C);
-			if (call->Native)
-			{
-				numret = static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, B, returns, C);
-			}
-			else
-			{
-				VMScriptFunction *script = static_cast<VMScriptFunction *>(call);
-				VMFrame *newf = stack->AllocFrame(script);
-				VMFillParams(reg.param + f->NumParam - B, newf, B);
-				try
-				{
-					numret = Exec(stack, script->Code, returns, C);
-				}
-				catch(...)
-				{
-					stack->PopFrame();
-					throw;
-				}
-				stack->PopFrame();
-			}
-			assert(numret == C && "Number of parameters returned differs from what was expected by the caller");
-			for (b = B; b != 0; --b)
-			{
-				reg.param[--f->NumParam].~VMValue();
-			}
-			pc += C;			// Skip RESULTs
-		}
-		NEXTOP;
-	OP(TAIL_K):
-		ASSERTKA(a);
-		assert(konstatag[a] == ATAG_OBJECT);
-		ptr = konsta[a].o;
-		goto Do_TAILCALL;
-	OP(TAIL):
-		ASSERTA(a);
-		ptr = reg.a[a];
-	Do_TAILCALL:
-		// Whereas the CALL instruction uses its third operand to specify how many return values
-		// it expects, TAIL ignores its third operand and uses whatever was passed to this Exec call.
-		assert(B <= f->NumParam);
-		assert(C <= MAX_RETURNS);
-		{
-			VMFunction *call = (VMFunction *)ptr;
-
-			if (call->Native)
-			{
-				return static_cast<VMNativeFunction *>(call)->NativeCall(stack, reg.param + f->NumParam - B, B, ret, numret);
-			}
-			else
-			{ // FIXME: Not a true tail call
-				VMScriptFunction *script = static_cast<VMScriptFunction *>(call);
-				VMFrame *newf = stack->AllocFrame(script);
-				VMFillParams(reg.param + f->NumParam - B, newf, B);
-				try
-				{
-					numret = Exec(stack, script->Code, ret, numret);
-				}
-				catch(...)
-				{
-					stack->PopFrame();
-					throw;
-				}
-				stack->PopFrame();
-				return numret;
-			}
-		}
-		NEXTOP;
-	OP(RET):
-		if (B == REGT_NIL)
-		{ // No return values
-			return 0;
-		}
-		assert(ret != NULL || numret == 0);
-		{
-			int retnum = a & ~RET_FINAL;
-			if (retnum < numret)
-			{
-				SetReturn(reg, f, &ret[retnum], B, C);
-			}
-			if (a & RET_FINAL)
-			{
-				return retnum < numret ? retnum + 1 : numret;
-			}
-		}
-		NEXTOP;
-	OP(RETI):
-		assert(ret != NULL || numret == 0);
-		{
-			int retnum = a & ~RET_FINAL;
-			if (retnum < numret)
-			{
-				ret[retnum].SetInt(BCs);
-			}
-			if (a & RET_FINAL)
-			{
-				return retnum < numret ? retnum + 1 : numret;
-			}
-		}
-		NEXTOP;
-	OP(RESULT):
-		// This instruction is just a placeholder to indicate where a return
-		// value should be stored. It does nothing on its own and should not
-		// be executed.
-		assert(0);
-		NEXTOP;
-
-	OP(TRY):
-		assert(try_depth < MAX_TRY_DEPTH);
-		if (try_depth >= MAX_TRY_DEPTH)
-		{
-			THROW(X_TOO_MANY_TRIES);
-		}
-		assert((pc + JMPOFS(pc - 1))->op == OP_CATCH);
-		exception_frames[try_depth++] = pc + JMPOFS(pc - 1);
-		NEXTOP;
-	OP(UNTRY):
-		assert(a <= try_depth);
-		try_depth -= a;
-		NEXTOP;
-	OP(THROW):
-		if (a == 0)
-		{
-			ASSERTA(B);
-			throw((VMException *)reg.a[B]);
-		}
-		else
-		{
-			ASSERTKA(B);
-			assert(konstatag[B] == ATAG_OBJECT);
-			throw((VMException *)konsta[B].o);
-		}
-		NEXTOP;
-	OP(CATCH):
-		// This instruction is handled by our own catch handler and should
-		// not be executed by the normal VM code.
-		assert(0);
-		NEXTOP;
-
-	OP(BOUND):
-		if (reg.d[a] >= BC)
-		{
-			THROW(X_ARRAY_OUT_OF_BOUNDS);
-		}
-		NEXTOP;
-
-	OP(CONCAT):
-		ASSERTS(a); ASSERTS(B); ASSERTS(C);
-		{
-			FString *rB = &reg.s[B];
-			FString *rC = &reg.s[C];
-			FString concat(*rB);
-			for (++rB; rB <= rC; ++rB)
-			{
-				concat += *rB;
-			}
-			reg.s[a] = concat;
-		}
-		NEXTOP;
-	OP(LENS):
-		ASSERTD(a); ASSERTS(B);
-		reg.d[a] = (int)reg.s[B].Len();
-		NEXTOP;
-	
-	OP(CMPS):
-		// String comparison is a fairly expensive operation, so I've
-		// chosen to conserve a few opcodes by condensing all the
-		// string comparisons into a single one.
-		{
-			const FString *b, *c;
-			int test, method;
-			bool cmp;
-
-			if (a & CMP_BK)
-			{
-				ASSERTKS(B);
-				b = &konsts[B];
-			}
-			else
-			{
-				ASSERTS(B);
-				b = &reg.s[B];
-			}
-			if (a & CMP_CK)
-			{
-				ASSERTKS(C);
-				c = &konsts[C];
-			}
-			else
-			{
-				ASSERTS(C);
-				c = &reg.s[C];
-			}
-			test = (a & CMP_APPROX) ? b->CompareNoCase(*c) : b->Compare(*c);
-			method = a & CMP_METHOD_MASK;
-			if (method == CMP_EQ)
-			{
-				cmp = !test;
-			}
-			else if (method == CMP_LT)
-			{
-				cmp = (test < 0);
-			}
-			else
-			{
-				assert(method == CMP_LE);
-				cmp = (test <= 0);
-			}
-			if (cmp == (a & CMP_CHECK))
-			{
-				assert(pc->op == OP_JMP);
-				pc += 1 + JMPOFS(pc);
-			}
-			else
-			{
-				pc += 1;
-			}
-		}
-		NEXTOP;
-
-	OP(SLL_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] << reg.d[C];
-		NEXTOP;
-	OP(SLL_RI):
-		ASSERTD(a); ASSERTD(B); assert(C <= 31);
-		reg.d[a] = reg.d[B] << C;
-		NEXTOP;
-	OP(SLL_KR):
-		ASSERTD(a); ASSERTKD(B); ASSERTD(C);
-		reg.d[a] = konstd[B] << reg.d[C];
-		NEXTOP;
-
-	OP(SRL_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = (unsigned)reg.d[B] >> reg.d[C];
-		NEXTOP;
-	OP(SRL_RI):
-		ASSERTD(a); ASSERTD(B); assert(C <= 31);
-		reg.d[a] = (unsigned)reg.d[B] >> C;
-		NEXTOP;
-	OP(SRL_KR):
-		ASSERTD(a); ASSERTKD(B); ASSERTD(C);
-		reg.d[a] = (unsigned)konstd[B] >> C;
-		NEXTOP;
-
-	OP(SRA_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] >> reg.d[C];
-		NEXTOP;
-	OP(SRA_RI):
-		ASSERTD(a); ASSERTD(B); assert(C <= 31);
-		reg.d[a] = reg.d[B] >> C;
-		NEXTOP;
-	OP(SRA_KR):
-		ASSERTD(a); ASSERTKD(B); ASSERTD(C);
-		reg.d[a] = konstd[B] >> reg.d[C];
-		NEXTOP;
-
-	OP(ADD_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] + reg.d[C];
-		NEXTOP;
-	OP(ADD_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTKD(C);
-		reg.d[a] = reg.d[B] + konstd[C];
-		NEXTOP;
-	OP(ADDI):
-		ASSERTD(a); ASSERTD(B);
-		reg.d[a] = reg.d[B] + Cs;
-		NEXTOP;
-
-	OP(SUB_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] - reg.d[C];
-		NEXTOP;
-	OP(SUB_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTKD(C);
-		reg.d[a] = reg.d[B] - konstd[C];
-		NEXTOP;
-	OP(SUB_KR):
-		ASSERTD(a); ASSERTKD(B); ASSERTD(C);
-		reg.d[a] = konstd[B] - reg.d[C];
-		NEXTOP;
-
-	OP(MUL_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] * reg.d[C];
-		NEXTOP;
-	OP(MUL_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTKD(C);
-		reg.d[a] = reg.d[B] * konstd[C];
-		NEXTOP;
-
-	OP(DIV_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] / reg.d[C];
-		NEXTOP;
-	OP(DIV_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTKD(C);
-		reg.d[a] = reg.d[B] / konstd[C];
-		NEXTOP;
-	OP(DIV_KR):
-		ASSERTD(a); ASSERTKD(B); ASSERTD(C);
-		reg.d[a] = konstd[B] / reg.d[C];
-		NEXTOP;
-
-	OP(MOD_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] % reg.d[C];
-		NEXTOP;
-	OP(MOD_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTKD(C);
-		reg.d[a] = reg.d[B] % konstd[C];
-		NEXTOP;
-	OP(MOD_KR):
-		ASSERTD(a); ASSERTKD(B); ASSERTD(C);
-		reg.d[a] = konstd[B] % reg.d[C];
-		NEXTOP;
-
-	OP(AND_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] & reg.d[C];
-		NEXTOP;
-	OP(AND_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTKD(C);
-		reg.d[a] = reg.d[B] & konstd[C];
-		NEXTOP;
-
-	OP(OR_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] | reg.d[C];
-		NEXTOP;
-	OP(OR_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTKD(C);
-		reg.d[a] = reg.d[B] | konstd[C];
-		NEXTOP;
-
-	OP(XOR_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] ^ reg.d[C];
-		NEXTOP;
-	OP(XOR_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] ^ konstd[C];
-		NEXTOP;
-
-	OP(MIN_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] < reg.d[C] ? reg.d[B] : reg.d[C];
-		NEXTOP;
-	OP(MIN_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTKD(C);
-		reg.d[a] = reg.d[B] < konstd[C] ? reg.d[B] : konstd[C];
-		NEXTOP;
-	OP(MAX_RR):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] > reg.d[C] ? reg.d[B] : reg.d[C];
-		NEXTOP;
-	OP(MAX_RK):
-		ASSERTD(a); ASSERTD(B); ASSERTKD(C);
-		reg.d[a] = reg.d[B] > konstd[C] ? reg.d[B] : konstd[C];
-		NEXTOP;
-
-	OP(ABS):
-		ASSERTD(a); ASSERTD(B);
-		reg.d[a] = abs(reg.d[B]);
-		NEXTOP;
-
-	OP(NEG):
-		ASSERTD(a); ASSERTD(B);
-		reg.d[a] = -reg.d[B];
-		NEXTOP;
-
-	OP(NOT):
-		ASSERTD(a); ASSERTD(B);
-		reg.d[a] = ~reg.d[B];
-		NEXTOP;
-
-	OP(SEXT):
-		ASSERTD(a); ASSERTD(B);
-		reg.d[a] = (VM_SWORD)(reg.d[B] << C) >> C;
-		NEXTOP;
-
-	OP(ZAP_R):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] & ZapTable[(reg.d[C] & 15) ^ 15];
-		NEXTOP;
-	OP(ZAP_I):
-		ASSERTD(a); ASSERTD(B);
-		reg.d[a] = reg.d[B] & ZapTable[(C & 15) ^ 15];
-		NEXTOP;
-	OP(ZAPNOT_R):
-		ASSERTD(a); ASSERTD(B); ASSERTD(C);
-		reg.d[a] = reg.d[B] & ZapTable[reg.d[C] & 15];
-		NEXTOP;
-	OP(ZAPNOT_I):
-		ASSERTD(a); ASSERTD(B);
-		reg.d[a] = reg.d[B] & ZapTable[C & 15];
-		NEXTOP;
-
-	OP(EQ_R):
-		ASSERTD(B); ASSERTD(C);
-		CMPJMP(reg.d[B] == reg.d[C]);
-		NEXTOP;
-	OP(EQ_K):
-		ASSERTD(B); ASSERTKD(C);
-		CMPJMP(reg.d[B] == konstd[C]);
-		NEXTOP;
-	OP(LT_RR):
-		ASSERTD(B); ASSERTD(C);
-		CMPJMP(reg.d[B] < reg.d[C]);
-		NEXTOP;
-	OP(LT_RK):
-		ASSERTD(B); ASSERTKD(C);
-		CMPJMP(reg.d[B] < konstd[C]);
-		NEXTOP;
-	OP(LT_KR):
-		ASSERTKD(B); ASSERTD(C);
-		CMPJMP(konstd[B] < reg.d[C]);
-		NEXTOP;
-	OP(LE_RR):
-		ASSERTD(B); ASSERTD(C);
-		CMPJMP(reg.d[B] <= reg.d[C]);
-		NEXTOP;
-	OP(LE_RK):
-		ASSERTD(B); ASSERTKD(C);
-		CMPJMP(reg.d[B] <= konstd[C]);
-		NEXTOP;
-	OP(LE_KR):
-		ASSERTKD(B); ASSERTD(C);
-		CMPJMP(konstd[B] <= reg.d[C]);
-		NEXTOP;
-	OP(LTU_RR):
-		ASSERTD(B); ASSERTD(C);
-		CMPJMP((VM_UWORD)reg.d[B] < (VM_UWORD)reg.d[C]);
-		NEXTOP;
-	OP(LTU_RK):
-		ASSERTD(B); ASSERTKD(C);
-		CMPJMP((VM_UWORD)reg.d[B] < (VM_UWORD)konstd[C]);
-		NEXTOP;
-	OP(LTU_KR):
-		ASSERTKD(B); ASSERTD(C);
-		CMPJMP((VM_UWORD)konstd[B] < (VM_UWORD)reg.d[C]);
-		NEXTOP;
-	OP(LEU_RR):
-		ASSERTD(B); ASSERTD(C);
-		CMPJMP((VM_UWORD)reg.d[B] <= (VM_UWORD)reg.d[C]);
-		NEXTOP;
-	OP(LEU_RK):
-		ASSERTD(B); ASSERTKD(C);
-		CMPJMP((VM_UWORD)reg.d[B] <= (VM_UWORD)konstd[C]);
-		NEXTOP;
-	OP(LEU_KR):
-		ASSERTKD(B); ASSERTD(C);
-		CMPJMP((VM_UWORD)konstd[B] <= (VM_UWORD)reg.d[C]);
-		NEXTOP;
-
-	OP(ADDF_RR):
-		ASSERTF(a); ASSERTF(B); ASSERTF(C);
-		reg.f[a] = reg.f[B] + reg.f[C];
-		NEXTOP;
-	OP(ADDF_RK):
-		ASSERTF(a); ASSERTF(B); ASSERTKF(C);
-		reg.f[a] = reg.f[B] + konstf[C];
-		NEXTOP;
-
-	OP(SUBF_RR):
-		ASSERTF(a); ASSERTF(B); ASSERTF(C);
-		reg.f[a] = reg.f[B] - reg.f[C];
-		NEXTOP;
-	OP(SUBF_RK):
-		ASSERTF(a); ASSERTF(B); ASSERTKF(C);
-		reg.f[a] = reg.f[B] - konstf[C];
-		NEXTOP;
-	OP(SUBF_KR):
-		ASSERTF(a); ASSERTKF(B); ASSERTF(C);
-		reg.f[a] = konstf[B] - reg.f[C];
-		NEXTOP;
-
-	OP(MULF_RR):
-		ASSERTF(a); ASSERTF(B); ASSERTF(C);
-		reg.f[a] = reg.f[B] * reg.f[C];
-		NEXTOP;
-	OP(MULF_RK):
-		ASSERTF(a); ASSERTF(B); ASSERTKF(C);
-		reg.f[a] = reg.f[B] * konstf[C];
-		NEXTOP;
-
-	OP(DIVF_RR):
-		ASSERTF(a); ASSERTF(B); ASSERTF(C);
-		reg.f[a] = reg.f[B] / reg.f[C];
-		NEXTOP;
-	OP(DIVF_RK):
-		ASSERTF(a); ASSERTF(B); ASSERTKF(C);
-		reg.f[a] = reg.f[B] / konstf[C];
-		NEXTOP;
-	OP(DIVF_KR):
-		ASSERTF(a); ASSERTKF(B); ASSERTF(C);
-		reg.f[a] = konstf[B] / reg.f[C];
-		NEXTOP;
-
-	OP(MODF_RR):
-		ASSERTF(a); ASSERTF(B); ASSERTF(C);
-		fb = reg.f[B]; fc = reg.f[C];
-	Do_MODF:
-		reg.f[a] = luai_nummod(fb, fc);
-		NEXTOP;
-	OP(MODF_RK):
-		ASSERTF(a); ASSERTF(B); ASSERTKF(C);
-		fb = reg.f[B]; fc = konstf[C];
-		goto Do_MODF;
-		NEXTOP;
-	OP(MODF_KR):
-		ASSERTF(a); ASSERTKF(B); ASSERTF(C);
-		fb = konstf[B]; fc = reg.f[C];
-		goto Do_MODF;
-		NEXTOP;
-
-	OP(POWF_RR):
-		ASSERTF(a); ASSERTF(B); ASSERTF(C);
-		reg.f[a] = pow(reg.f[B], reg.f[C]);
-		NEXTOP;
-	OP(POWF_RK):
-		ASSERTF(a); ASSERTF(B); ASSERTKF(C);
-		reg.f[a] = pow(reg.f[B], konstf[C]);
-		NEXTOP;
-	OP(POWF_KR):
-		ASSERTF(a); ASSERTKF(B); ASSERTF(C);
-		reg.f[a] = pow(konstf[B], reg.f[C]);
-		NEXTOP;
-
-	OP(MINF_RR):
-		ASSERTF(a); ASSERTF(B); ASSERTF(C);
-		reg.f[a] = reg.f[B] < reg.f[C] ? reg.f[B] : reg.f[C];
-		NEXTOP;
-	OP(MINF_RK):
-		ASSERTF(a); ASSERTF(B); ASSERTKF(C);
-		reg.f[a] = reg.f[B] < konstf[C] ? reg.f[B] : konstf[C];
-		NEXTOP;
-	OP(MAXF_RR):
-		ASSERTF(a); ASSERTF(B); ASSERTF(C);
-		reg.f[a] = reg.f[B] > reg.f[C] ? reg.f[B] : reg.f[C];
-		NEXTOP;
-	OP(MAXF_RK):
-		ASSERTF(a); ASSERTF(B); ASSERTKF(C);
-		reg.f[a] = reg.f[B] > konstf[C] ? reg.f[B] : konstf[C];
-		NEXTOP;
-
-	OP(ATAN2):
-		ASSERTF(a); ASSERTF(B); ASSERTF(C);
-		reg.f[a] = g_atan2(reg.f[B], reg.f[C]) * (180 / M_PI);
-		NEXTOP;
-
-	OP(FLOP):
-		ASSERTF(a); ASSERTF(B);
-		fb = reg.f[B];
-		reg.f[a] = (C == FLOP_ABS) ? fabs(fb) : (C == FLOP_NEG) ? -fb : DoFLOP(C, fb);
-		NEXTOP;
-	
-	OP(EQF_R):
-		ASSERTF(B); ASSERTF(C);
-		if (a & CMP_APPROX)
-		{
-			CMPJMP(fabs(reg.f[C] - reg.f[B]) < VM_EPSILON);
-		}
-		else
-		{
-			CMPJMP(reg.f[C] == reg.f[B]);
-		}
-		NEXTOP;
-	OP(EQF_K):
-		ASSERTF(B); ASSERTKF(C);
-		if (a & CMP_APPROX)
-		{
-			CMPJMP(fabs(konstf[C] - reg.f[B]) < VM_EPSILON);
-		}
-		else
-		{
-			CMPJMP(konstf[C] == reg.f[B]);
-		}
-		NEXTOP;
-	OP(LTF_RR):
-		ASSERTF(B); ASSERTF(C);
-		if (a & CMP_APPROX)
-		{
-			CMPJMP((reg.f[B] - reg.f[C]) < -VM_EPSILON);
-		}
-		else
-		{
-			CMPJMP(reg.f[B] < reg.f[C]);
-		}
-		NEXTOP;
-	OP(LTF_RK):
-		ASSERTF(B); ASSERTKF(C);
-		if (a & CMP_APPROX)
-		{
-			CMPJMP((reg.f[B] - konstf[C]) < -VM_EPSILON);
-		}
-		else
-		{
-			CMPJMP(reg.f[B] < konstf[C]);
-		}
-		NEXTOP;
-	OP(LTF_KR):
-		ASSERTKF(B); ASSERTF(C);
-		if (a & CMP_APPROX)
-		{
-			CMPJMP((konstf[B] - reg.f[C]) < -VM_EPSILON);
-		}
-		else
-		{
-			CMPJMP(konstf[B] < reg.f[C]);
-		}
-		NEXTOP;
-	OP(LEF_RR):
-		ASSERTF(B); ASSERTF(C);
-		if (a & CMP_APPROX)
-		{
-			CMPJMP((reg.f[B] - reg.f[C]) <= -VM_EPSILON);
-		}
-		else
-		{
-			CMPJMP(reg.f[B] <= reg.f[C]);
-		}
-		NEXTOP;
-	OP(LEF_RK):
-		ASSERTF(B); ASSERTKF(C);
-		if (a & CMP_APPROX)
-		{
-			CMPJMP((reg.f[B] - konstf[C]) <= -VM_EPSILON);
-		}
-		else
-		{
-			CMPJMP(reg.f[B] <= konstf[C]);
-		}
-		NEXTOP;
-	OP(LEF_KR):
-		ASSERTKF(B); ASSERTF(C);
-		if (a & CMP_APPROX)
-		{
-			CMPJMP((konstf[B] - reg.f[C]) <= -VM_EPSILON);
-		}
-		else
-		{
-			CMPJMP(konstf[B] <= reg.f[C]);
-		}
-		NEXTOP;
-
-	OP(NEGV):
-		ASSERTF(a+2); ASSERTF(B+2);
-		reg.f[a] = -reg.f[B];
-		reg.f[a+1] = -reg.f[B+1];
-		reg.f[a+2] = -reg.f[B+2];
-		NEXTOP;
-
-	OP(ADDV_RR):
-		ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2);
-		fcp = &reg.f[C];
-	Do_ADDV:
-		fbp = &reg.f[B];
-		reg.f[a] = fbp[0] + fcp[0];
-		reg.f[a+1] = fbp[1] + fcp[1];
-		reg.f[a+2] = fbp[2] + fcp[2];
-		NEXTOP;
-	OP(ADDV_RK):
-		fcp = &konstf[C];
-		goto Do_ADDV;
-
-	OP(SUBV_RR):
-		ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2);
-		fbp = &reg.f[B];
-		fcp = &reg.f[C];
-	Do_SUBV:
-		reg.f[a] = fbp[0] - fcp[0];
-		reg.f[a+1] = fbp[1] - fcp[1];
-		reg.f[a+2] = fbp[2] - fcp[2];
-		NEXTOP;
-	OP(SUBV_RK):
-		ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2);
-		fbp = &reg.f[B];
-		fcp = &konstf[C];
-		goto Do_SUBV;
-	OP(SUBV_KR):
-		ASSERTF(A+2); ASSERTKF(B+2); ASSERTF(C+2);
-		fbp = &konstf[B];
-		fcp = &reg.f[C];
-		goto Do_SUBV;
-
-	OP(DOTV_RR):
-		ASSERTF(a); ASSERTF(B+2); ASSERTF(C+2);
-		reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1] + reg.f[B+2] * reg.f[C+2];
-		NEXTOP;
-	OP(DOTV_RK):
-		ASSERTF(a); ASSERTF(B+2); ASSERTKF(C+2);
-		reg.f[a] = reg.f[B] * konstf[C] + reg.f[B+1] * konstf[C+1] + reg.f[B+2] * konstf[C+2];
-		NEXTOP;
-
-	OP(CROSSV_RR):
-		ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2);
-		fbp = &reg.f[B];
-		fcp = &reg.f[C];
-	Do_CROSSV:
-		{
-			double t[3];
-			t[2] = fbp[0] * fcp[1] - fbp[1] * fcp[0];
-			t[1] = fbp[2] * fcp[0] - fbp[0] * fcp[2];
-			t[0] = fbp[1] * fcp[2] - fbp[2] * fcp[1];
-			reg.f[a] = t[0]; reg.f[a+1] = t[1]; reg.f[a+2] = t[2];
-		}
-		NEXTOP;
-	OP(CROSSV_RK):
-		ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2);
-		fbp = &reg.f[B];
-		fcp = &konstf[C];
-		goto Do_CROSSV;
-	OP(CROSSV_KR):
-		ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C+2);
-		fbp = &reg.f[B];
-		fcp = &konstf[C];
-		goto Do_CROSSV;
-
-	OP(MULVF_RR):
-		ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C);
-		fc = reg.f[C];
-		fbp = &reg.f[B];
-	Do_MULV:
-		reg.f[a] = fbp[0] * fc;
-		reg.f[a+1] = fbp[1] * fc;
-		reg.f[a+2] = fbp[2] * fc;
-		NEXTOP;
-	OP(MULVF_RK):
-		ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C);
-		fc = konstf[C];
-		fbp = &reg.f[B];
-		goto Do_MULV;
-	OP(MULVF_KR):
-		ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C);
-		fc = reg.f[C];
-		fbp = &konstf[B];
-		goto Do_MULV;
-
-	OP(LENV):
-		ASSERTF(a); ASSERTF(B+2);
-		reg.f[a] = g_sqrt(reg.f[B] * reg.f[B] + reg.f[B+1] * reg.f[B+1] + reg.f[B+2] * reg.f[B+2]);
-		NEXTOP;
-
-	OP(EQV_R):
-		ASSERTF(B+2); ASSERTF(C+2);
-		fcp = &reg.f[C];
-	Do_EQV:
-		if (a & CMP_APPROX)
-		{
-			CMPJMP(fabs(reg.f[B  ] - fcp[0]) < VM_EPSILON &&
-				   fabs(reg.f[B+1] - fcp[1]) < VM_EPSILON &&
-				   fabs(reg.f[B+2] - fcp[2]) < VM_EPSILON);
-		}
-		else
-		{
-			CMPJMP(reg.f[B] == fcp[0] && reg.f[B+1] == fcp[1] && reg.f[B+2] == fcp[2]);
-		}
-		NEXTOP;
-	OP(EQV_K):
-		ASSERTF(B+2); ASSERTKF(C+2);
-		fcp = &konstf[C];
-		goto Do_EQV;
-
-	OP(ADDA_RR):
-		ASSERTA(a); ASSERTA(B); ASSERTD(C);
-		c = reg.d[C];
-	Do_ADDA:
-		if (reg.a[B] == NULL)	// Leave NULL pointers as NULL pointers
-		{
-			c = 0;
-		}
-		reg.a[a] = (VM_UBYTE *)reg.a[B] + c;
-		reg.atag[a] = c == 0 ? reg.atag[B] : (int)ATAG_GENERIC;
-		NEXTOP;
-	OP(ADDA_RK):
-		ASSERTA(a); ASSERTA(B); ASSERTKD(C);
-		c = konstd[C];
-		goto Do_ADDA;
-
-	OP(SUBA):
-		ASSERTD(a); ASSERTA(B); ASSERTA(C);
-		reg.d[a] = (VM_UWORD)((VM_UBYTE *)reg.a[B] - (VM_UBYTE *)reg.a[C]);
-		NEXTOP;
-
-	OP(EQA_R):
-		ASSERTA(B); ASSERTA(C);
-		CMPJMP(reg.a[B] == reg.a[C]);
-		NEXTOP;
-	OP(EQA_K):
-		ASSERTA(B); ASSERTKA(C);
-		CMPJMP(reg.a[B] == konsta[C].v);
-		NEXTOP;
-
-	OP(NOP):
-		NEXTOP;
-	}
-	}
-	catch(VMException *exception)
-	{
-		// Try to find a handler for the exception.
-		PClass *extype = exception->GetClass();
-
-		while(--try_depth >= 0)
-		{
-			pc = exception_frames[try_depth];
-			assert(pc->op == OP_CATCH);
-			while (pc->a > 1)
-			{
-				// CATCH must be followed by JMP if it doesn't terminate a catch chain.
-				assert(pc[1].op == OP_JMP);
-
-				PClass *type;
-				int b = pc->b;
-
-				if (pc->a == 2)
-				{
-					ASSERTA(b);
-					type = (PClass *)reg.a[b];
-				}
-				else
-				{
-					assert(pc->a == 3);
-					ASSERTKA(b);
-					assert(konstatag[b] == ATAG_OBJECT);
-					type = (PClass *)konsta[b].o;
-				}
-				ASSERTA(pc->c);
-				if (type == extype)
-				{
-					// Found a handler. Store the exception in pC, skip the JMP,
-					// and begin executing its code.
-					reg.a[pc->c] = exception;
-					reg.atag[pc->c] = ATAG_OBJECT;
-					pc += 2;
-					goto begin;
-				}
-				// This catch didn't handle it. Try the next one.
-				pc += 1 + JMPOFS(pc + 1);
-				assert(pc->op == OP_CATCH);
-			}
-			if (pc->a == 1)
-			{
-				// Catch any type of VMException. This terminates the chain.
-				ASSERTA(pc->c);
-				reg.a[pc->c] = exception;
-				reg.atag[pc->c] = ATAG_OBJECT;
-				pc += 1;
-				goto begin;
-			}
-			// This frame failed. Try the next one out.
-		}
-		// Nothing caught it. Rethrow and let somebody else deal with it.
-		throw;
-	}
-	return 0;
-}
-
-static double DoFLOP(int flop, double v)
-{
-	switch(flop)
-	{
-	case FLOP_ABS:		return fabs(v);
-	case FLOP_NEG:		return -v;
-	case FLOP_EXP:		return g_exp(v);
-	case FLOP_LOG:		return g_log(v);
-	case FLOP_LOG10:	return g_log10(v);
-	case FLOP_SQRT:		return g_sqrt(v);
-	case FLOP_CEIL:		return ceil(v);
-	case FLOP_FLOOR:	return floor(v);
-
-	case FLOP_ACOS:		return g_acos(v);
-	case FLOP_ASIN:		return g_asin(v);
-	case FLOP_ATAN:		return g_atan(v);
-	case FLOP_COS:		return g_cos(v);
-	case FLOP_SIN:		return g_sin(v);
-	case FLOP_TAN:		return g_tan(v);
-
-	case FLOP_ACOS_DEG:	return g_acos(v) * (180 / M_PI);
-	case FLOP_ASIN_DEG:	return g_asin(v) * (180 / M_PI);
-	case FLOP_ATAN_DEG:	return g_atan(v) * (180 / M_PI);
-	case FLOP_COS_DEG:	return g_cosdeg(v);
-	case FLOP_SIN_DEG:	return g_sindeg(v);
-	case FLOP_TAN_DEG:	return g_tan(v * (M_PI / 180));
-
-	case FLOP_COSH:		return g_cosh(v);
-	case FLOP_SINH:		return g_sinh(v);
-	case FLOP_TANH:		return g_tanh(v);
-	}
-	assert(0);
-	return 0;
-}
-
-static void DoCast(const VMRegisters &reg, const VMFrame *f, int a, int b, int cast)
-{
-	switch (cast)
-	{
-	case CAST_I2F:
-		ASSERTF(a); ASSERTD(b);
-		reg.f[a] = reg.d[b];
-		break;
-	case CAST_I2S:
-		ASSERTS(a); ASSERTD(b);
-		reg.s[a].Format("%d", reg.d[b]);
-		break;
-
-	case CAST_F2I:
-		ASSERTD(a); ASSERTF(b);
-		reg.d[a] = (int)reg.f[b];
-		break;
-	case CAST_F2S:
-		ASSERTS(a); ASSERTD(b);
-		reg.s[a].Format("%.14g", reg.f[b]);
-		break;
-
-	case CAST_P2S:
-		ASSERTS(a); ASSERTA(b);
-		reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? "Object" : "Pointer", reg.a[b]);
-		break;
-
-	case CAST_S2I:
-		ASSERTD(a); ASSERTS(b);
-		reg.d[a] = (VM_SWORD)reg.s[b].ToLong();
-		break;
-	case CAST_S2F:
-		ASSERTF(a); ASSERTS(b);
-		reg.f[a] = reg.s[b].ToDouble();
-		break;
-
-	default:
-		assert(0);
-	}
-}
-
-//===========================================================================
-//
-// FillReturns
-//
-// Fills in an array of pointers to locations to store return values in.
-//
-//===========================================================================
-
-static void FillReturns(const VMRegisters &reg, VMFrame *frame, VMReturn *returns, const VMOP *retval, int numret)
-{
-	int i, type, regnum;
-	VMReturn *ret;
-
-	assert(REGT_INT == 0 && REGT_FLOAT == 1 && REGT_STRING == 2 && REGT_POINTER == 3);
-
-	for (i = 0, ret = returns; i < numret; ++i, ++ret, ++retval)
-	{
-		assert(retval->op == OP_RESULT);				// opcode
-		ret->TagOfs = 0;
-		ret->RegType = type = retval->b;
-		regnum = retval->c;
-		assert(!(type & REGT_KONST));
-		type &= REGT_TYPE;
-		if (type < REGT_STRING)
-		{
-			if (type == REGT_INT)
-			{
-				assert(regnum < frame->NumRegD);
-				ret->Location = &reg.d[regnum];
-			}
-			else // type == REGT_FLOAT
-			{
-				assert(regnum < frame->NumRegF);
-				ret->Location = &reg.f[regnum];
-			}
-		}
-		else if (type == REGT_STRING)
-		{
-			assert(regnum < frame->NumRegS);
-			ret->Location = &reg.s[regnum];
-		}
-		else
-		{
-			assert(type == REGT_POINTER);
-			assert(regnum < frame->NumRegA);
-			ret->Location = &reg.a[regnum];
-			ret->TagOfs = (VM_SHALF)(&frame->GetRegATag()[regnum] - (VM_ATAG *)ret->Location);
-		}
-	}
-}
-
-//===========================================================================
-//
-// SetReturn
-//
-// Used by script code to set a return value.
-//
-//===========================================================================
-
-static void SetReturn(const VMRegisters &reg, VMFrame *frame, VMReturn *ret, VM_UBYTE regtype, int regnum)
-{
-	const void *src;
-	VMScriptFunction *func = static_cast<VMScriptFunction *>(frame->Func);
-
-	assert(func != NULL && !func->Native);
-	assert((regtype & ~REGT_KONST) == ret->RegType);
-
-	switch (regtype & REGT_TYPE)
-	{
-	case REGT_INT:
-		assert(!(regtype & REGT_MULTIREG));
-		if (regtype & REGT_KONST)
-		{
-			assert(regnum < func->NumKonstD);
-			src = &func->KonstD[regnum];
-		}
-		else
-		{
-			assert(regnum < frame->NumRegD);
-			src = &reg.d[regnum];
-		}
-		ret->SetInt(*(int *)src);
-		break;
-
-	case REGT_FLOAT:
-		if (regtype & REGT_KONST)
-		{
-			assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < func->NumKonstF);
-			src = &func->KonstF[regnum];
-		}
-		else
-		{
-			assert(regnum + ((regtype & REGT_KONST) ? 2u : 0u) < frame->NumRegF);
-			src = &reg.f[regnum];
-		}
-		if (regtype & REGT_MULTIREG)
-		{
-			ret->SetVector((double *)src);
-		}
-		else
-		{
-			ret->SetFloat(*(double *)src);
-		}
-		break;
-
-	case REGT_STRING:
-		assert(!(regtype & REGT_MULTIREG));
-		if (regtype & REGT_KONST)
-		{
-			assert(regnum < func->NumKonstS);
-			src = &func->KonstS[regnum];
-		}
-		else
-		{
-			assert(regnum < frame->NumRegS);
-			src = &reg.s[regnum];
-		}
-		ret->SetString(*(const FString *)src);
-		break;
-
-	case REGT_POINTER:
-		assert(!(regtype & REGT_MULTIREG));
-		if (regtype & REGT_KONST)
-		{
-			assert(regnum < func->NumKonstA);
-			ret->SetPointer(func->KonstA[regnum].v, func->KonstATags()[regnum]);
-		}
-		else
-		{
-			assert(regnum < frame->NumRegA);
-			ret->SetPointer(reg.a[regnum], reg.atag[regnum]);
-		}
-		break;
-	}
-}
--- src/zscript/vmframe.cpp
+++ src/zscript/vmframe.cpp
@@ -1,418 +0,0 @@
-#include <new>
-#include "vm.h"
-
-IMPLEMENT_CLASS(VMException)
-IMPLEMENT_ABSTRACT_POINTY_CLASS(VMFunction)
- DECLARE_POINTER(Proto)
-END_POINTERS
-IMPLEMENT_CLASS(VMScriptFunction)
-IMPLEMENT_CLASS(VMNativeFunction)
-
-VMScriptFunction::VMScriptFunction(FName name)
-{
-	Native = false;
-	Name = name;
-	Code = NULL;
-	KonstD = NULL;
-	KonstF = NULL;
-	KonstS = NULL;
-	KonstA = NULL;
-	ExtraSpace = 0;
-	CodeSize = 0;
-	NumRegD = 0;
-	NumRegF = 0;
-	NumRegS = 0;
-	NumRegA = 0;
-	NumKonstD = 0;
-	NumKonstF = 0;
-	NumKonstS = 0;
-	NumKonstA = 0;
-	MaxParam = 0;
-	NumArgs = 0;
-}
-
-VMScriptFunction::~VMScriptFunction()
-{
-	if (Code != NULL)
-	{
-		if (KonstS != NULL)
-		{
-			for (int i = 0; i < NumKonstS; ++i)
-			{
-				KonstS[i].~FString();
-			}
-		}
-		M_Free(Code);
-	}
-}
-
-void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numkonsts, int numkonsta)
-{
-	assert(Code == NULL);
-	assert(numops > 0);
-	assert(numkonstd >= 0 && numkonstd <= 255);
-	assert(numkonstf >= 0 && numkonstf <= 255);
-	assert(numkonsts >= 0 && numkonsts <= 255);
-	assert(numkonsta >= 0 && numkonsta <= 255);
-	void *mem = M_Malloc(numops * sizeof(VMOP) +
-						 numkonstd * sizeof(int) +
-						 numkonstf * sizeof(double) +
-						 numkonsts * sizeof(FString) +
-						 numkonsta * (sizeof(FVoidObj) + 1));
-	Code = (VMOP *)mem;
-	mem = (void *)((VMOP *)mem + numops);
-
-	if (numkonstd > 0)
-	{
-		KonstD = (int *)mem;
-		mem = (void *)((int *)mem + numkonstd);
-	}
-	else
-	{
-		KonstD = NULL;
-	}
-	if (numkonstf > 0)
-	{
-		KonstF = (double *)mem;
-		mem = (void *)((double *)mem + numkonstf);
-	}
-	else
-	{
-		KonstF = NULL;
-	}
-	if (numkonsts > 0)
-	{
-		KonstS = (FString *)mem;
-		for (int i = 0; i < numkonsts; ++i)
-		{
-			::new(&KonstS[i]) FString;
-		}
-		mem = (void *)((FString *)mem + numkonsts);
-	}
-	else
-	{
-		KonstS = NULL;
-	}
-	if (numkonsta > 0)
-	{
-		KonstA = (FVoidObj *)mem;
-	}
-	else
-	{
-		KonstA = NULL;
-	}
-	CodeSize = numops;
-	NumKonstD = numkonstd;
-	NumKonstF = numkonstf;
-	NumKonstS = numkonsts;
-	NumKonstA = numkonsta;
-}
-
-size_t VMScriptFunction::PropagateMark()
-{
-	if (KonstA != NULL)
-	{
-		FVoidObj *konsta = KonstA;
-		VM_UBYTE *atag = KonstATags();
-		for (int count = NumKonstA; count > 0; --count)
-		{
-			if (*atag++ == ATAG_OBJECT)
-			{
-				GC::Mark(konsta->o);
-			}
-			konsta++;
-		}
-	}
-	return NumKonstA * sizeof(void *) + Super::PropagateMark();
-}
-
-//===========================================================================
-//
-// VMFrame :: InitRegS
-//
-// Initialize the string registers of a newly-allocated VMFrame.
-//
-//===========================================================================
-
-void VMFrame::InitRegS()
-{
-	FString *regs = GetRegS();
-	for (int i = 0; i < NumRegS; ++i)
-	{
-		::new(&regs[i]) FString;
-	}
-}
-
-//===========================================================================
-//
-// VMFrameStack - Constructor
-//
-//===========================================================================
-
-VMFrameStack::VMFrameStack()
-{
-	Blocks = NULL;
-	UnusedBlocks = NULL;
-}
-
-//===========================================================================
-//
-// VMFrameStack - Destructor
-//
-//===========================================================================
-
-VMFrameStack::~VMFrameStack()
-{
-	while (PopFrame() != NULL)
-	{ }
-	if (Blocks != NULL)
-	{
-		BlockHeader *block, *next;
-		for (block = Blocks; block != NULL; block = next)
-		{
-			next = block->NextBlock;
-			delete[] (VM_UBYTE *)block;
-		}
-	}
-	if (UnusedBlocks != NULL)
-	{
-		BlockHeader *block, *next;
-		for (block = UnusedBlocks; block != NULL; block = next)
-		{
-			next = block->NextBlock;
-			delete[] (VM_UBYTE *)block;
-		}
-	}
-	Blocks = NULL;
-	UnusedBlocks = NULL;
-}
-
-//===========================================================================
-//
-// VMFrameStack :: AllocFrame
-//
-// Allocates a frame from the stack with the desired number of registers.
-//
-//===========================================================================
-
-VMFrame *VMFrameStack::AllocFrame(int numregd, int numregf, int numregs, int numrega)
-{
-	assert((unsigned)numregd < 255);
-	assert((unsigned)numregf < 255);
-	assert((unsigned)numregs < 255);
-	assert((unsigned)numrega < 255);
-	// To keep the arguments to this function simpler, it assumes that every
-	// register might be used as a parameter for a single call.
-	int numparam = numregd + numregf + numregs + numrega;
-	int size = VMFrame::FrameSize(numregd, numregf, numregs, numrega, numparam, 0);
-	VMFrame *frame = Alloc(size);
-	frame->NumRegD = numregd;
-	frame->NumRegF = numregf;
-	frame->NumRegS = numregs;
-	frame->NumRegA = numrega;
-	frame->MaxParam = numparam;
-	frame->InitRegS();
-	return frame;
-}
-
-//===========================================================================
-//
-// VMFrameStack :: AllocFrame
-//
-// Allocates a frame from the stack suitable for calling a particular
-// function.
-//
-//===========================================================================
-
-VMFrame *VMFrameStack::AllocFrame(VMScriptFunction *func)
-{
-	int size = VMFrame::FrameSize(func->NumRegD, func->NumRegF, func->NumRegS, func->NumRegA,
-		func->MaxParam, func->ExtraSpace);
-	VMFrame *frame = Alloc(size);
-	frame->Func = func;
-	frame->NumRegD = func->NumRegD;
-	frame->NumRegF = func->NumRegF;
-	frame->NumRegS = func->NumRegS;
-	frame->NumRegA = func->NumRegA;
-	frame->MaxParam = func->MaxParam;
-	frame->Func = func;
-	frame->InitRegS();
-	return frame;
-}
-
-//===========================================================================
-//
-// VMFrameStack :: Alloc
-//
-// Allocates space for a frame. Its size will be rounded up to a multiple
-// of 16 bytes.
-//
-//===========================================================================
-
-VMFrame *VMFrameStack::Alloc(int size)
-{
-	BlockHeader *block;
-	VMFrame *frame, *parent;
-
-	size = (size + 15) & ~15;
-	block = Blocks;
-	if (block != NULL)
-	{
-		parent = block->LastFrame;
-	}
-	else
-	{
-		parent = NULL;
-	}
-	if (block == NULL || ((VM_UBYTE *)block + block->BlockSize) < (block->FreeSpace + size))
-	{ // Not enough space. Allocate a new block.
-		int blocksize = ((sizeof(BlockHeader) + 15) & ~15) + size;
-		BlockHeader **blockp;
-		if (blocksize < BLOCK_SIZE)
-		{
-			blocksize = BLOCK_SIZE;
-		}
-		for (blockp = &UnusedBlocks, block = *blockp; block != NULL; block = block->NextBlock)
-		{
-			if (block->BlockSize >= blocksize)
-			{
-				break;
-			}
-		}
-		if (block != NULL)
-		{
-			*blockp = block->NextBlock;
-		}
-		else
-		{
-			block = (BlockHeader *)new VM_UBYTE[blocksize];
-			block->BlockSize = blocksize;
-		}
-		block->InitFreeSpace();
-		block->LastFrame = NULL;
-		block->NextBlock = Blocks;
-		Blocks = block;
-	}
-	frame = (VMFrame *)block->FreeSpace;
-	memset(frame, 0, size);
-	frame->ParentFrame = parent;
-	block->FreeSpace += size;
-	block->LastFrame = frame;
-	return frame;
-}
-
-
-//===========================================================================
-//
-// VMFrameStack :: PopFrame
-//
-// Pops the top frame off the stack, returning a pointer to the new top
-// frame.
-//
-//===========================================================================
-
-VMFrame *VMFrameStack::PopFrame()
-{
-	if (Blocks == NULL)
-	{
-		return NULL;
-	}
-	VMFrame *frame = Blocks->LastFrame;
-	if (frame == NULL)
-	{
-		return NULL;
-	}
-	// Free any string registers this frame had.
-	FString *regs = frame->GetRegS();
-	for (int i = frame->NumRegS; i != 0; --i)
-	{
-		(regs++)->~FString();
-	}
-	// Free any parameters this frame left behind.
-	VMValue *param = frame->GetParam();
-	for (int i = frame->NumParam; i != 0; --i)
-	{
-		(param++)->~VMValue();
-	}
-	VMFrame *parent = frame->ParentFrame;
-	if (parent == NULL)
-	{
-		// Popping the last frame off the stack.
-		if (Blocks != NULL)
-		{
-			assert(Blocks->NextBlock == NULL);
-			Blocks->LastFrame = NULL;
-			Blocks->InitFreeSpace();
-		}
-		return NULL;
-	}
-	if ((VM_UBYTE *)parent < (VM_UBYTE *)Blocks || (VM_UBYTE *)parent >= (VM_UBYTE *)Blocks + Blocks->BlockSize)
-	{ // Parent frame is in a different block, so move this one to the unused list.
-		BlockHeader *next = Blocks->NextBlock;
-		assert(next != NULL);
-		assert((VM_UBYTE *)parent >= (VM_UBYTE *)next && (VM_UBYTE *)parent < (VM_UBYTE *)next + next->BlockSize);
-		Blocks->NextBlock = UnusedBlocks;
-		UnusedBlocks = Blocks;
-		Blocks = next;
-	}
-	else
-	{
-		Blocks->LastFrame = parent;
-		Blocks->FreeSpace = (VM_UBYTE *)frame;
-	}
-	return parent;
-}
-
-//===========================================================================
-//
-// VMFrameStack :: Call
-//
-// Calls a function, either native or scripted. If an exception occurs while
-// executing, the stack is cleaned up. If trap is non-NULL, it is set to the
-// VMException that was caught and the return value is negative. Otherwise,
-// any caught exceptions will be rethrown. Under normal termination, the
-// return value is the number of results from the function.
-//
-//===========================================================================
-
-int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMReturn *results, int numresults, VMException **trap)
-{
-	bool allocated = false;
-	try
-	{
-		if (func->Native)
-		{
-			return static_cast<VMNativeFunction *>(func)->NativeCall(this, params, numparams, results, numresults);
-		}
-		else
-		{
-			AllocFrame(static_cast<VMScriptFunction *>(func));
-			allocated = true;
-			VMFillParams(params, TopFrame(), numparams);
-			int numret = VMExec(this, static_cast<VMScriptFunction *>(func)->Code, results, numresults);
-			PopFrame();
-			return numret;
-		}
-	}
-	catch (VMException *exception)
-	{
-		if (allocated)
-		{
-			PopFrame();
-		}
-		if (trap != NULL)
-		{
-			*trap = exception;
-			return -1;
-		}
-		throw;
-	}
-	catch (...)
-	{
-		if (allocated)
-		{
-			PopFrame();
-		}
-		throw;
-	}
-}
--- src/zscript/vmops.h
+++ src/zscript/vmops.h
@@ -1,214 +0,0 @@
-#ifndef xx
-#define xx(op, name, mode) OP_##op
-#endif
-
-xx(NOP,		nop,	NOP),		// no operation
-
-// Load constants.
-xx(LI,		li,		LI),		// load immediate signed 16-bit constant
-xx(LK,		lk,		LKI),		// load integer constant
-xx(LKF,		lk,		LKF),		// load float constant
-xx(LKS,		lk,		LKS),		// load string constant
-xx(LKP,		lk,		LKP),		// load pointer constant
-xx(LFP,		lf,		LFP),		// load frame pointer
-
-// Load from memory. rA = *(rB + rkC)
-xx(LB,		lb,		RIRPKI),	// load byte
-xx(LB_R,	lb,		RIRPRI),
-xx(LH,		lh,		RIRPKI),	// load halfword
-xx(LH_R,	lh,		RIRPRI),
-xx(LW,		lw,		RIRPKI),	// load word
-xx(LW_R,	lw,		RIRPRI),
-xx(LBU,		lbu,	RIRPKI),	// load byte unsigned
-xx(LBU_R,	lbu,	RIRPRI),
-xx(LHU,		lhu,	RIRPKI),	// load halfword unsigned
-xx(LHU_R,	lhu,	RIRPRI),
-xx(LSP,		lsp,	RFRPKI),	// load single-precision fp
-xx(LSP_R,	lsp,	RFRPRI),
-xx(LDP,		ldp,	RFRPKI),	// load double-precision fp
-xx(LDP_R,	ldp,	RFRPRI),
-xx(LS,		ls,		RSRPKI),	// load string
-xx(LS_R,	ls,		RSRPRI),
-xx(LO,		lo,		RPRPKI),	// load object
-xx(LO_R,	lo,		RPRPRI),
-xx(LP,		lp,		RPRPKI),	// load pointer
-xx(LP_R,	lp,		RPRPRI),
-xx(LV,		lv,		RVRPKI),	// load vector
-xx(LV_R,	lv,		RVRPRI),
-
-xx(LBIT,	lbit,	RIRPI8),	// rA = !!(*rB & C)  -- *rB is a byte
-
-// Store instructions. *(rA + rkC) = rB
-xx(SB,		sb,		RPRIKI),		// store byte
-xx(SB_R,	sb,		RPRIRI),
-xx(SH,		sh,		RPRIKI),		// store halfword
-xx(SH_R,	sh,		RPRIRI),
-xx(SW,		sw,		RPRIKI),		// store word
-xx(SW_R,	sw,		RPRIRI),
-xx(SSP,		ssp,	RPRFKI),		// store single-precision fp
-xx(SSP_R,	ssp,	RPRFRI),
-xx(SDP,		sdp,	RPRFKI),		// store double-precision fp
-xx(SDP_R,	sdp,	RPRFRI),
-xx(SS,		ss,		RPRSKI),		// store string
-xx(SS_R,	ss,		RPRSRI),
-xx(SP,		sp,		RPRPKI),		// store pointer
-xx(SP_R,	sp,		RPRPRI),
-xx(SV,		sv,		RPRVKI),		// store vector
-xx(SV_R,	sv,		RPRVRI),
-
-xx(SBIT,	sbit,	RPRII8),		// *rA |= C if rB is true, *rA &= ~C otherwise
-
-// Move instructions.
-xx(MOVE,		mov,	RIRI),		// dA = dB
-xx(MOVEF,		mov,	RFRF),		// fA = fB
-xx(MOVES,		mov,	RSRS),		// sA = sB
-xx(MOVEA,		mov,	RPRP),		// aA = aB
-xx(CAST,		cast,	CAST),		// xA = xB, conversion specified by C
-xx(DYNCAST_R,	dyncast,RPRPRP),	// aA = aB after casting to rkC (specifying a class)
-xx(DYNCAST_K,	dyncast,RPRPKP),
-
-// Control flow.
-xx(TEST,	test,	RII16),		// if (dA != BC) then pc++
-xx(JMP,		jmp,	I24),		// pc += ABC		-- The ABC fields contain a signed 24-bit offset.
-xx(IJMP,	ijmp,	RII16),		// pc += dA + BC	-- BC is a signed offset. The target instruction must be a JMP.
-xx(PARAM,	param,	__BCP),		// push parameter encoded in BC for function call (B=regtype, C=regnum)
-xx(PARAMI,	parami,	I24),		// push immediate, signed integer for function call
-xx(CALL,	call,	RPI8I8),	// Call function pkA with parameter count B and expected result count C
-xx(CALL_K,	call,	KPI8I8),
-xx(TAIL,	tail,	RPI8),		// Call+Ret in a single instruction
-xx(TAIL_K,	tail,	KPI8),
-xx(RESULT,	result,	__BCP),		// Result should go in register encoded in BC (in caller, after CALL)
-xx(RET,		ret,	I8BCP),		// Copy value from register encoded in BC to return value A, possibly returning
-xx(RETI,	reti,	I8I16),		// Copy immediate from BC to return value A, possibly returning
-xx(TRY,		try,	I24),		// When an exception is thrown, start searching for a handler at pc + ABC
-xx(UNTRY,	untry,	I8),		// Pop A entries off the exception stack
-xx(THROW,	throw,	THROW),		// A == 0: Throw exception object pB
-								// A != 0: Throw exception object pkB
-xx(CATCH,	catch,	CATCH),		// A == 0: continue search on next try
-								// A == 1: continue execution at instruction immediately following CATCH (catches any exception)
-								// A == 2: (pB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
-								// A == 3: (pkB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
-								// for A > 0, exception is stored in pC
-xx(BOUND,	bound,	RII16),		// if rA >= BC, throw exception
-
-// String instructions.
-xx(CONCAT,		concat,	RSRSRS),		// sA = sB.. ... ..sC
-xx(LENS,		lens,	RIRS),			// dA = sB.Length
-xx(CMPS,		cmps,	I8RXRX),		// if ((skB op skC) != (A & 1)) then pc++
-
-// Integer math.
-xx(SLL_RR,		sll,	RIRIRI),		// dA = dkB << diC
-xx(SLL_RI,		sll,	RIRII8),
-xx(SLL_KR,		sll,	RIKIRI),
-xx(SRL_RR,		srl,	RIRIRI),		// dA = dkB >> diC  -- unsigned
-xx(SRL_RI,		srl,	RIRII8),
-xx(SRL_KR,		srl,	RIKIRI),
-xx(SRA_RR,		sra,	RIRIRI),		// dA = dkB >> diC  -- signed
-xx(SRA_RI,		sra,	RIRII8),
-xx(SRA_KR,		sra,	RIKIRI),
-xx(ADD_RR,		add,	RIRIRI),		// dA = dB + dkC
-xx(ADD_RK,		add,	RIRIKI),
-xx(ADDI,		addi,	RIRIIs),		// dA = dB + C		-- C is a signed 8-bit constant
-xx(SUB_RR,		sub,	RIRIRI),		// dA = dkB - dkC
-xx(SUB_RK,		sub,	RIRIKI),
-xx(SUB_KR,		sub,	RIKIRI),
-xx(MUL_RR,		mul,	RIRIRI),		// dA = dB * dkC
-xx(MUL_RK,		mul,	RIRIKI),
-xx(DIV_RR,		div,	RIRIRI),		// dA = dkB / dkC
-xx(DIV_RK,		div,	RIRIKI),
-xx(DIV_KR,		div,	RIKIRI),
-xx(MOD_RR,		mod,	RIRIRI),		// dA = dkB % dkC
-xx(MOD_RK,		mod,	RIRIKI),
-xx(MOD_KR,		mod,	RIKIRI),
-xx(AND_RR,		and,	RIRIRI),		// dA = dB & dkC
-xx(AND_RK,		and,	RIRIKI),
-xx(OR_RR,		or,		RIRIRI),		// dA = dB | dkC
-xx(OR_RK,		or,		RIRIKI),
-xx(XOR_RR,		xor,	RIRIRI),		// dA = dB ^ dkC
-xx(XOR_RK,		xor,	RIRIKI),
-xx(MIN_RR,		min,	RIRIRI),		// dA = min(dB,dkC)
-xx(MIN_RK,		min,	RIRIKI),
-xx(MAX_RR,		max,	RIRIRI),		// dA = max(dB,dkC)
-xx(MAX_RK,		max,	RIRIKI),
-xx(ABS,			abs,	RIRI),			// dA = abs(dB)
-xx(NEG,			neg,	RIRI),			// dA = -dB
-xx(NOT,			not,	RIRI),			// dA = ~dB
-xx(SEXT,		sext,	RIRII8),		// dA = dB, sign extended by shifting left then right by C
-xx(ZAP_R,		zap,	RIRIRI),		// dA = dB, with bytes zeroed where bits in C/dC are one
-xx(ZAP_I,		zap,	RIRII8),
-xx(ZAPNOT_R,	zapnot,	RIRIRI),		// dA = dB, with bytes zeroed where bits in C/dC are zero
-xx(ZAPNOT_I,	zapnot,	RIRII8),
-xx(EQ_R,		beq,	CIRR),			// if ((dB == dkC) != A) then pc++
-xx(EQ_K,		beq,	CIRK),
-xx(LT_RR,		blt,	CIRR),			// if ((dkB < dkC) != A) then pc++
-xx(LT_RK,		blt,	CIRK),
-xx(LT_KR,		blt,	CIKR),
-xx(LE_RR,		ble,	CIRR),			// if ((dkB <= dkC) != A) then pc++
-xx(LE_RK,		ble,	CIRK),
-xx(LE_KR,		ble,	CIKR),
-xx(LTU_RR,		bltu,	CIRR),			// if ((dkB < dkC) != A) then pc++		-- unsigned
-xx(LTU_RK,		bltu,	CIRK),
-xx(LTU_KR,		bltu,	CIKR),	
-xx(LEU_RR,		bleu,	CIRR),			// if ((dkB <= dkC) != A) then pc++		-- unsigned
-xx(LEU_RK,		bleu,	CIRK),
-xx(LEU_KR,		bleu,	CIKR),
-
-// Double-precision floating point math.
-xx(ADDF_RR,		add,	RFRFRF),		// fA = fB + fkC
-xx(ADDF_RK,		add,	RFRFKF),
-xx(SUBF_RR,		sub,	RFRFRF),		// fA = fkB - fkC
-xx(SUBF_RK,		sub,	RFRFKF),
-xx(SUBF_KR,		sub,	RFKFRF),
-xx(MULF_RR,		mul,	RFRFRF),		// fA = fB * fkC
-xx(MULF_RK,		mul,	RFRFKF),
-xx(DIVF_RR,		div,	RFRFRF),		// fA = fkB / fkC
-xx(DIVF_RK,		div,	RFRFKF),
-xx(DIVF_KR,		div,	RFKFRF),
-xx(MODF_RR,		mod,	RFRFRF),		// fA = fkB % fkC
-xx(MODF_RK,		mod,	RFRFKF),
-xx(MODF_KR,		mod,	RFKFRF),
-xx(POWF_RR,		pow,	RFRFRF),		// fA = fkB ** fkC
-xx(POWF_RK,		pow,	RFRFKF),
-xx(POWF_KR,		pow,	RFKFRF),
-xx(MINF_RR,		min,	RFRFRF),		// fA = min(fB),fkC)
-xx(MINF_RK,		min,	RFRFKF),
-xx(MAXF_RR,		max,	RFRFRF),		// fA = max(fB),fkC)
-xx(MAXF_RK,		max,	RFRFKF),
-xx(ATAN2,		atan2,	RFRFRF),		// fA = atan2(fB,fC), result is in degrees
-xx(FLOP,		flop,	RFRFI8),		// fA = f(fB), where function is selected by C
-xx(EQF_R,		beq,	CFRR),			// if ((fB == fkC) != (A & 1)) then pc++
-xx(EQF_K,		beq,	CFRK),
-xx(LTF_RR,		blt,	CFRR),			// if ((fkB < fkC) != (A & 1)) then pc++
-xx(LTF_RK,		blt,	CFRK),
-xx(LTF_KR,		blt,	CFKR),
-xx(LEF_RR,		ble,	CFRR),			// if ((fkb <= fkC) != (A & 1)) then pc++
-xx(LEF_RK,		ble,	CFRK),
-xx(LEF_KR,		ble,	CFKR),
-
-// Vector math.
-xx(NEGV,		negv,	RVRV),			// vA = -vB
-xx(ADDV_RR,		addv,	RVRVRV),		// vA = vB + vkC
-xx(ADDV_RK,		addv,	RVRVKV),
-xx(SUBV_RR,		subv,	RVRVRV),		// vA = vkB - vkC
-xx(SUBV_RK,		subv,	RVRVKV),
-xx(SUBV_KR,		subv,	RVKVRV),
-xx(DOTV_RR,		dotv,	RVRVRV),		// va = vB dot vkC
-xx(DOTV_RK,		dotv,	RVRVKV),
-xx(CROSSV_RR,	crossv,	RVRVRV),		// vA = vkB cross vkC
-xx(CROSSV_RK,	crossv,	RVRVKV),
-xx(CROSSV_KR,	crossv,	RVKVRV),
-xx(MULVF_RR,	mulv,	RVRVRV),		// vA = vkB * fkC
-xx(MULVF_RK,	mulv,	RVRVKV),
-xx(MULVF_KR,	mulv,	RVKVRV),
-xx(LENV,		lenv,	RFRV),			// fA = vB.Length
-xx(EQV_R,		beqv,	CVRR),			// if ((vB == vkC) != A) then pc++ (inexact if A & 32)
-xx(EQV_K,		beqv,	CVRK),
-
-// Pointer math.
-xx(ADDA_RR,		add,	RPRPRI),		// pA = pB + dkC
-xx(ADDA_RK,		add,	RPRPKI),
-xx(SUBA,		sub,	RIRPRP),		// dA = pB - pC
-xx(EQA_R,		beq,	CPRR),			// if ((pB == pkC) != A) then pc++
-xx(EQA_K,		beq,	CPRK),
-
-#undef xx
--- src/zscript/zcc-parse.lemon
+++ src/zscript/zcc-parse.lemon
@@ -1,1483 +0,0 @@
-%include
-{
-// Allocates a new AST node off the parse state's arena.
-#define NEW_AST_NODE(type,name,tok) \
-	ZCC_##type *name = static_cast<ZCC_##type *>(stat->InitNode(sizeof(ZCC_##type), AST_##type)); \
-	SetNodeLine(name, tok)
-
-static void SetNodeLine(ZCC_TreeNode *name, ZCCToken &tok)
-{
-	name->SourceLoc = tok.SourceLoc;
-}
-
-static void SetNodeLine(ZCC_TreeNode *name, ZCC_TreeNode *node)
-{
-	name->SourceLoc = node->SourceLoc;
-}
-
-static void SetNodeLine(ZCC_TreeNode *name, int line)
-{
-	name->SourceLoc = line;
-}
-
-// If a is non-null, appends b to a. Otherwise, sets a to b.
-#define SAFE_APPEND(a,b) \
-	if (a == NULL) a = b; else a->AppendSibling(b);
-
-#define UNARY_EXPR(X,T) NEW_AST_NODE(ExprUnary, expr1, X); expr1->Operation = T; expr1->Operand = X; expr1->Type = NULL
-#define BINARY_EXPR(X,Y,T) NEW_AST_NODE(ExprBinary, expr2, X); expr2->Operation = T; expr2->Type = NULL; expr2->Left = X; expr2->Right = Y
-
-#define NEW_INTCONST_NODE(name,type,val,tok) \
-	NEW_AST_NODE(ExprConstant, name, tok); \
-	name->Operation = PEX_ConstValue; \
-	name->Type = type; \
-	name->IntVal = val
-
-	struct ClassFlagsBlock {
-		VM_UWORD Flags;
-		ZCC_Identifier *Replaces;
-	};
-
-	struct StateOpts {
-		ZCC_Expression *Offset;
-		bool Bright;
-		bool Fast;
-		bool Slow;
-		bool NoDelay;
-		bool CanRaise;
-
-		void Zero() {
-			Offset = NULL;
-			Bright = false;
-			Fast = false;
-			Slow = false;
-			NoDelay = false;
-			CanRaise = false;
-		}
-	};
-
-	struct VarOrFun
-	{
-		ZCC_VarName *VarNames;
-		ZCC_FuncParamDecl *FuncParams;
-		ZCC_CompoundStmt *FuncBody;
-		ENamedName FuncName;
-		int FuncFlags;
-		int SourceLoc;
-	};
-}
-
-%token_prefix ZCC_
-%token_type { ZCCToken }
-%token_destructor {}	// just to avoid a compiler warning
-%name ZCCParse
-%extra_argument { ZCCParseState *stat }
-%syntax_error
-{
-	FString unexpected, expecting;
-
-	int i;
-	int stateno = yypParser->yystack[yypParser->yyidx].stateno;
-
-	unexpected << "Unexpected " << ZCCTokenName(yymajor);
-
-	// Determine all the terminals that the parser would have accepted at this point
-	// (see yy_find_shift_action). This list can get quite long. Is it worthwhile to
-	// print it when not debugging the grammar, or would that be too confusing to
-	// the average user?
-	if (stateno < YY_SHIFT_MAX && (i = yy_shift_ofst[stateno])!=YY_SHIFT_USE_DFLT)
-	{
-		for (int j = 1; j < YYERRORSYMBOL; ++j)
-		{
-			int k = i + j;
-			if (k >= 0 && k < YY_ACTTAB_COUNT && yy_lookahead[k] == j)
-			{
-				expecting << (expecting.IsEmpty() ? "Expecting " : " or ") << ZCCTokenName(j);
-			}
-		}
-	}
-	stat->sc.ScriptMessage("%s\n%s\n", unexpected.GetChars(), expecting.GetChars());
-}
-%parse_accept { stat->sc.ScriptMessage("input accepted\n"); }
-%parse_failure { /**failed = true;*/ }
-
-%nonassoc EQ MULEQ DIVEQ MODEQ ADDEQ SUBEQ LSHEQ RSHEQ ANDEQ OREQ XOREQ.
-%right QUESTION COLON.
-%left OROR.
-%left ANDAND.
-%left EQEQ NEQ APPROXEQ.
-%left LT GT LTEQ GTEQ LTGTEQ IS.
-%left DOTDOT.
-%left OR.		/* Note that this is like the Ruby precedence for these */
-%left XOR.		/* three operators and not the C precedence, since */
-%left AND.		/* they are higher priority than the comparisons. */
-%left LSH RSH.
-%left SUB ADD.
-%left MUL DIV MOD CROSSPROD DOTPROD.
-%left POW.
-%right UNARY ADDADD SUBSUB.
-%left DOT LPAREN LBRACKET.
-%left SCOPE.
-
-%type declarator {ZCC_Declarator *}
-%type declarator_no_fun {ZCC_Declarator *}
-%type opt_func_body {ZCC_CompoundStmt *}
-%type function_body {ZCC_CompoundStmt *}
-
-main ::= translation_unit(A). { stat->TopNode = A; stat->sc.ScriptMessage("Parse complete\n"); }
-
-%type translation_unit {ZCC_TreeNode *}
-translation_unit(X) ::= .												{ X = NULL; }
-translation_unit(X) ::= translation_unit(X) external_declaration(B).	{ SAFE_APPEND(X,B); }
-translation_unit(X) ::= translation_unit(X) EOF.
-translation_unit(X) ::= error.											{ X = NULL; }
-
-%type external_declaration {ZCC_TreeNode *}
-external_declaration(X) ::= class_definition(A).						{ X = A; /*X-overwrites-A*/ }
-external_declaration(X) ::= struct_def(A).								{ X = A; /*X-overwrites-A*/ }
-external_declaration(X) ::= enum_def(A).								{ X = A; /*X-overwrites-A*/ }
-external_declaration(X) ::= const_def(A).								{ X = A; /*X-overwrites-A*/ }
-
-/* Optional bits. */
-opt_semicolon ::= .
-opt_semicolon ::= SEMICOLON.
-
-opt_comma ::= .
-opt_comma ::= COMMA.
-
-%type opt_expr{ZCC_Expression *}
-opt_expr(X) ::= .
-{
-	X = NULL;
-}
-opt_expr(X) ::= expr(X).
-
-
-/************ Class Definition ************/
-/* Can only occur at global scope. */
-
-%type class_definition{ZCC_Class *}
-%type class_head{ZCC_Class *}
-%type class_innards{ZCC_TreeNode *}
-%type class_member{ZCC_TreeNode *}
-%type class_body{ZCC_TreeNode *}
-
-class_definition(X) ::= class_head(A) class_body(B).
-{
-	A->Body = B;
-	X = A; /*X-overwrites-A*/
-}
-
-class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C).
-{
-	NEW_AST_NODE(Class,head,T);
-	head->NodeName = A.Name();
-	head->ParentName = B;
-	head->Flags = C.Flags;
-	head->Replaces = C.Replaces;
-	X = head;
-}
-
-%type class_ancestry{ZCC_Identifier *}
-class_ancestry(X) ::= .						{ X = NULL; }
-class_ancestry(X) ::= COLON dottable_id(A).	{ X = A; /*X-overwrites-A*/ }
-
-%type class_flags{ClassFlagsBlock}
-class_flags(X) ::= .										{ X.Flags = 0; X.Replaces = NULL; }
-class_flags(X) ::= class_flags(A) ABSTRACT.					{ X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; }
-class_flags(X) ::= class_flags(A) NATIVE.					{ X.Flags = A.Flags | 0/*FIXME*/; X.Replaces = A.Replaces; }
-class_flags(X) ::= class_flags(A) REPLACES dottable_id(B).	{ X.Flags = A.Flags; X.Replaces = B; }
-
-/*----- Dottable Identifier -----*/
-// This can be either a single identifier or two identifiers connected by a .
-
-%type dottable_id{ZCC_Identifier *}
-
-dottable_id(X) ::= IDENTIFIER(A).
-{
-	NEW_AST_NODE(Identifier,id,A);
-	id->Id = A.Name();
-	X = id;
-}
-dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B).
-{
-	NEW_AST_NODE(Identifier,id2,A);
-	id2->Id = B.Name();
-	A->AppendSibling(id2);
-	X = A; /*X-overwrites-A*/
-}
-
-/*------ Class Body ------*/
-// Body is a list of:
-//  * variable definitions
-//  * function definitions
-//  * enum definitions
-//  * struct definitions
-//  * state definitions
-//  * constants
-//  * defaults
-
-class_body(X) ::= SEMICOLON class_innards(A) EOF.		{ X = A; /*X-overwrites-A*/ }
-class_body(X) ::= LBRACE class_innards(A) RBRACE.		{ X = A; /*X-overwrites-A*/ }
-
-class_innards(X) ::= .									{ X = NULL; }
-class_innards(X) ::= class_innards(X) class_member(B).	{ SAFE_APPEND(X,B); }
-
-%type struct_def{ZCC_Struct *}
-%type enum_def {ZCC_Enum *}
-%type states_def {ZCC_States *}
-%type const_def {ZCC_ConstantDef *}
-
-class_member(X) ::= declarator(A).						{ X = A; /*X-overwrites-A*/ }
-class_member(X) ::= enum_def(A).						{ X = A; /*X-overwrites-A*/ }
-class_member(X) ::= struct_def(A).						{ X = A; /*X-overwrites-A*/ }
-class_member(X) ::= states_def(A).						{ X = A; /*X-overwrites-A*/ }
-class_member(X) ::= default_def(A).						{ X = A; /*X-overwrites-A*/ }
-class_member(X) ::= const_def(A).						{ X = A; /*X-overwrites-A*/ }
-
-/*----- Struct Definition -----*/
-/* Structs can define variables and enums. */
-
-%type opt_struct_body{ZCC_TreeNode *}
-%type struct_body{ZCC_TreeNode *}
-%type struct_member{ZCC_TreeNode *}
-
-struct_def(X) ::= STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon.
-{
-	NEW_AST_NODE(Struct,def,T);
-	def->NodeName = A.Name();
-	def->Body = B;
-	X = def;
-}
-
-opt_struct_body(X) ::= .								{ X = NULL; }
-opt_struct_body(X) ::= struct_body(X).
-
-struct_body(X) ::= error.								{ X = NULL; }
-struct_body(X) ::= struct_member(X).
-struct_body(X) ::= struct_member(A) struct_body(B).		{ X = A; /*X-overwrites-A*/ X->AppendSibling(B); }
-
-struct_member(X) ::= declarator_no_fun(A).				{ X = A; /*X-overwrites-A*/ }
-struct_member(X) ::= enum_def(A).						{ X = A; /*X-overwrites-A*/ }
-struct_member(X) ::= const_def(A).						{ X = A; /*X-overwrites-A*/ }
-
-/*----- Constant Definition ------*/
-/* Like UnrealScript, a constant's type is implied by its value's type. */
-const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON.
-{
-	NEW_AST_NODE(ConstantDef,def,T);
-	def->NodeName = A.Name();
-	def->Value = B;
-	def->Symbol = NULL;
-	X = def;
-}
-
-
-/*----- Enum Definition -----*/
-/* Enumerators are lists of named integers. */
-
-%type enum_list {ZCC_ConstantDef *}
-%type opt_enum_list {ZCC_ConstantDef *}
-%type enumerator {ZCC_ConstantDef *}
-
-enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRACE(U) opt_semicolon.
-{
-	NEW_AST_NODE(Enum,def,T);
-	def->NodeName = A.Name();
-	def->EnumType = (EZCCBuiltinType)B.Int;
-	def->Elements = C;
-
-	// If the first element does not have an explicit value, make it 0.
-	if (C != NULL)
-	{
-		ZCC_ConstantDef *node = C, *prev = node;
-
-		if (node->Value == NULL)
-		{
-			NEW_INTCONST_NODE(zero, TypeSInt32, 0, C);
-			node->Value = zero;
-		}
-		for (node = static_cast<ZCC_ConstantDef *>(node->SiblingNext);
-			node != C;
-			prev = node, node = static_cast<ZCC_ConstantDef *>(node->SiblingNext))
-		{
-			assert(node->NodeType == AST_ConstantDef);
-			// Leave explicit values alone.
-			if (node->Value != NULL)
-			{
-				continue;
-			}
-			// Compute implicit values by adding one to the preceding value.
-			assert(prev->Value != NULL);
-			// If the preceding node is a constant, then we can do this now.
-			if (prev->Value->Operation == PEX_ConstValue && prev->Value->Type->IsA(RUNTIME_CLASS(PInt)))
-			{
-				NEW_INTCONST_NODE(cval, prev->Value->Type, static_cast<ZCC_ExprConstant *>(prev->Value)->IntVal + 1, node);
-				node->Value = cval;
-			}
-			// Otherwise, create a new addition expression to add 1.
-			else
-			{
-				NEW_INTCONST_NODE(one, TypeSInt32, 1, T);
-				NEW_AST_NODE(ExprID, label, node);
-				label->Operation = PEX_ID;
-				label->Identifier = prev->NodeName;
-				label->Type = NULL;
-
-				BINARY_EXPR(label, one, PEX_Add);
-				node->Value = expr2;
-			}
-		}
-		// Add a new terminating node, to indicate that the ConstantDefs for this enum are done.
-		NEW_AST_NODE(EnumTerminator,term,U);
-		C->AppendSibling(term);
-	}
-	if (C != NULL)
-	{
-		def->AppendSibling(C);
-	}
-	X = def;
-}
-
-enum_type(X) ::= .										{ X.Int = ZCC_IntAuto; X.SourceLoc = stat->sc.GetMessageLine(); }
-enum_type(X) ::= COLON int_type(A).						{ X = A; /*X-overwrites-A*/ }
-
-enum_list(X) ::= error.									{ X = NULL; }
-enum_list(X) ::= enumerator(X).
-enum_list(X) ::= enum_list(A) COMMA enumerator(B).		{ X = A; /*X-overwrites-A*/ X->AppendSibling(B); }
-
-opt_enum_list(X) ::= .									{ X = NULL; }
-opt_enum_list(X) ::= enum_list(X) opt_comma.
-
-enumerator(X) ::= IDENTIFIER(A).
-{
-	NEW_AST_NODE(ConstantDef,node,A);
-	node->NodeName = A.Name();
-	node->Value = NULL;
-	node->Symbol = NULL;
-	X = node;
-}
-enumerator(X) ::= IDENTIFIER(A) EQ expr(B).			/* Expression must be constant. */
-{
-	NEW_AST_NODE(ConstantDef,node,A);
-	node->NodeName = A.Name();
-	node->Value = B;
-	node->Symbol = NULL;
-	X = node;
-}
-
-/************ States ************/
-
-%type states_body {ZCC_StatePart *}
-%type state_line {ZCC_StatePart *}
-%type state_label {ZCC_StatePart *}
-%type state_flow {ZCC_StatePart *}
-%type state_flow_type {ZCC_StatePart *}
-%type state_goto_offset {ZCC_Expression *}
-%type state_action {ZCC_TreeNode *}
-%type state_call {ZCC_ExprFuncCall *}
-%type state_call_params {ZCC_FuncParm *}
-
-%type state_opts {StateOpts}
-
-states_def(X) ::= STATES(T) scanner_mode LBRACE states_body(A) RBRACE.
-{
-	NEW_AST_NODE(States,def,T);
-	def->Body = A;
-	X = def;
-}
-
-/* We use a special scanner mode to allow for sprite names and frame characters
- * to not be quoted even if they contain special characters. The scanner_mode
- * nonterminal is used to enter this mode. The scanner automatically leaves it
- * upon pre-defined conditions. See the comments by FScanner::SetStateMode().
- *
- * Note that rules are reduced *after* one token of lookahead has been
- * consumed, so this nonterminal must be placed one token before we want it to
- * take effect. For example, in states_def above, the scanner mode will be
- * set immediately after LBRACE is consumed, rather than immediately after
- * STATES is consumed.
- */
-scanner_mode ::= . { stat->sc.SetStateMode(true); }
-
-states_body(X) ::= .								{ X = NULL; }
-states_body(X) ::= error.							{ X = NULL; }
-states_body(X) ::= states_body(X) state_line(B).	{ SAFE_APPEND(X,B); }
-states_body(X) ::= states_body(X) state_label(B).	{ SAFE_APPEND(X,B); }
-states_body(X) ::= states_body(X) state_flow(B).	{ SAFE_APPEND(X,B); }
-
-state_label(X) ::= NWS(A) COLON.
-{
-	NEW_AST_NODE(StateLabel, label, A);
-	label->Label = A.Name();
-	X = label;
-}
-
-state_flow(X) ::= state_flow_type(X) scanner_mode SEMICOLON.
-
-state_flow_type(X) ::= STOP(A).			{ NEW_AST_NODE(StateStop, flow, A); X = flow; }
-state_flow_type(X) ::= WAIT(A).			{ NEW_AST_NODE(StateWait, flow, A); X = flow; }
-state_flow_type(X) ::= FAIL(A).			{ NEW_AST_NODE(StateFail, flow, A); X = flow; }
-state_flow_type(X) ::= LOOP(A).			{ NEW_AST_NODE(StateLoop, flow, A); X = flow; }
-state_flow_type(X) ::= GOTO(T) dottable_id(A) state_goto_offset(B).
-{
-	NEW_AST_NODE(StateGoto, flow, T);
-	flow->Label = A;
-	flow->Offset = B;
-	X = flow;
-}
-
-state_goto_offset(X) ::= .				{ X = NULL; }
-state_goto_offset(X) ::= PLUS expr(A).	{ X = A; /*X-overwrites-A*/ }	/* Must evaluate to a non-negative integer constant. */
-
-state_line(X) ::= NWS(A) NWS(B) expr state_opts(C) state_action(D).
-{
-	NEW_AST_NODE(StateLine, line, A);
-	const char *sprite = FName(A.Name()).GetChars();
-	if (strlen(sprite) != 4)
-	{
-		Printf("Sprite name '%s' must be four characters", sprite);
-	}
-	else
-	{
-		memcpy(line->Sprite, sprite, 4);
-	}
-	line->Frames = stat->Strings.Alloc(FName(B.Name()).GetChars());
-	line->bBright = C.Bright;
-	line->bFast = C.Fast;
-	line->bSlow = C.Slow;
-	line->bNoDelay = C.NoDelay;
-	line->bCanRaise = C.CanRaise;
-	line->Offset = C.Offset;
-	line->Action = D;
-	X = line;
-}
-
-state_opts(X) ::= .													{ StateOpts opts; opts.Zero(); X = opts; }
-state_opts(X) ::= state_opts(A) BRIGHT.								{ A.Bright = true; X = A; /*X-overwrites-A*/ }
-state_opts(X) ::= state_opts(A) FAST.								{ A.Fast = true; X = A; /*X-overwrites-A*/ }
-state_opts(X) ::= state_opts(A) SLOW.								{ A.Slow = true; X = A; /*X-overwrites-A*/ }
-state_opts(X) ::= state_opts(A) NODELAY.							{ A.NoDelay = true; X = A; /*X-overwrites-A*/ }
-state_opts(X) ::= state_opts(A) CANRAISE.							{ A.CanRaise = true; X = A; /*X-overwrites-A*/ }
-state_opts(X) ::= state_opts(A) OFFSET LPAREN expr(B) COMMA expr(C) RPAREN.	{ A.Offset = B; B->AppendSibling(C); X = A; /*X-overwrites-A*/ }
-state_opts(X) ::= state_opts(A) LIGHT LPAREN light_list RPAREN.		{ X = A; /*X-overwrites-A*/ }	///FIXME: GZDoom would want to know this
-
-light_list ::= STRCONST.
-light_list ::= light_list COMMA STRCONST.
-
-/* A state action can be either a compound statement or a single action function call. */
-state_action(X) ::= LBRACE statement_list(A) scanner_mode RBRACE.	{ X = A; /*X-overwrites-A*/ }
-state_action(X) ::= LBRACE error scanner_mode RBRACE.				{ X = NULL; }
-state_action(X) ::= state_call(A) scanner_mode SEMICOLON.			{ X = A; /*X-overwrites-A*/ }
-
-state_call(X) ::= .											{ X = NULL; }
-state_call(X) ::= IDENTIFIER(A) state_call_params(B).
-{
-	NEW_AST_NODE(ExprFuncCall, expr, A);
-	NEW_AST_NODE(ExprID, func, A);
-
-	func->Operation = PEX_ID;
-	func->Identifier = A.Name();
-	expr->Operation = PEX_FuncCall;
-	expr->Function = func;
-	expr->Parameters = B;
-	X = expr;
-}
-
-state_call_params(X) ::= .									{ X = NULL; }
-state_call_params(X) ::= LPAREN func_expr_list(A) RPAREN.	{ X = A; /*X-overwrites-A*/ }
-
-/* Definition of a default class instance. */
-%type default_def {ZCC_CompoundStmt *}
-default_def(X) ::= DEFAULT compound_statement(A).			{ X = A; /*X-overwrites-A*/ }
-
-/* Type names */
-%type type_name {ZCC_BasicType *}
-
-int_type(X) ::= SBYTE(T).					{ X.Int = ZCC_SInt8; X.SourceLoc = T.SourceLoc; }
-int_type(X) ::= BYTE(T).					{ X.Int = ZCC_UInt8; X.SourceLoc = T.SourceLoc; }
-int_type(X) ::= SHORT(T).					{ X.Int = ZCC_SInt16; X.SourceLoc = T.SourceLoc; }
-int_type(X) ::= USHORT(T).					{ X.Int = ZCC_UInt16; X.SourceLoc = T.SourceLoc; }
-int_type(X) ::= INT(T).						{ X.Int = ZCC_SInt32; X.SourceLoc = T.SourceLoc; }
-int_type(X) ::= UINT(T).					{ X.Int = ZCC_UInt32; X.SourceLoc = T.SourceLoc; }
-
-type_name1(X) ::= BOOL(T).					{ X.Int = ZCC_Bool; X.SourceLoc = T.SourceLoc; }
-type_name1(X) ::= int_type(X).
-type_name1(X) ::= FLOAT(T).					{ X.Int = ZCC_FloatAuto; X.SourceLoc = T.SourceLoc; }
-type_name1(X) ::= DOUBLE(T).				{ X.Int = ZCC_Float64; X.SourceLoc = T.SourceLoc; }
-type_name1(X) ::= STRING(T).				{ X.Int = ZCC_String; X.SourceLoc = T.SourceLoc; }
-type_name1(X) ::= VECTOR(T) vector_size(A).	{ X.Int = A.Int; X.SourceLoc = T.SourceLoc; }
-type_name1(X) ::= NAME(T).					{ X.Int = ZCC_Name; X.SourceLoc = T.SourceLoc; }
-
-type_name(X) ::= type_name1(A).
-{
-	NEW_AST_NODE(BasicType, type, A);
-	type->Type = (EZCCBuiltinType)A.Int;
-	type->UserType = NULL;
-	X = type;
-}
-type_name(X) ::= IDENTIFIER(A).			/* User-defined type (struct, enum, or class) */
-{
-	NEW_AST_NODE(BasicType, type, A);
-	NEW_AST_NODE(Identifier, id, A);
-	type->Type = ZCC_UserType;
-	type->UserType = id;
-	id->Id = A.Name();
-	X = type;
-}
-type_name(X) ::= DOT dottable_id(A).
-{
-	NEW_AST_NODE(BasicType, type, A);
-	type->Type = ZCC_UserType;
-	type->UserType = A;
-	X = type;
-}
-
-/* Vectors can be 2, 3, or 4 entries long. Default is a 3D vector.
- * (Well, actually, I'm not sure if 4D ones are going to happen
- * straight away.)
- */
-%token_class intconst INTCONST|UINTCONST.
-vector_size(X) ::= .						{ X.Int = ZCC_Vector3; X.SourceLoc = stat->sc.GetMessageLine(); }
-vector_size(X) ::= LT intconst(A) GT.
-{
-	if (A.Int >= 2 && A.Int <= 4)
-	{
-		X.Int = ZCC_Vector2 + A.Int - 2;
-	}
-	else
-	{
-		X.Int = ZCC_Vector3;
-		stat->sc.ScriptMessage("Invalid vector size %d\n", A.Int);
-	}
-	X.SourceLoc = A.SourceLoc;
-}
-
-/* Type names can also be used as identifiers in contexts where type names
- * are not normally allowed. */
-%fallback IDENTIFIER
-	SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR NAME MAP ARRAY VOID.
-
-/* Aggregate types */
-%type aggregate_type {ZCC_Type *}
-%type type {ZCC_Type *}
-%type type_list {ZCC_Type *}
-%type type_list_or_void {ZCC_Type *}
-%type type_or_array {ZCC_Type *}
-%type class_restrictor {ZCC_Identifier *}
-%type array_size{ZCC_Expression *}
-%type array_size_expr{ZCC_Expression *}
-
-aggregate_type(X) ::= MAP(T) LT type_or_array(A) COMMA type_or_array(B) GT.	/* Hash table */
-{
-	NEW_AST_NODE(MapType,map,T);
-	map->KeyType = A;
-	map->ValueType = B;
-	X = map;
-}
-
-aggregate_type(X) ::= ARRAY(T) LT type_or_array(A) GT.							/* TArray<type> */
-{
-	NEW_AST_NODE(DynArrayType,arr,T);
-	arr->ElementType = A;
-	X = arr;
-}
-
-aggregate_type(X) ::= CLASS(T) class_restrictor(A).							/* class<type> */
-{
-	NEW_AST_NODE(ClassType,cls,T);
-	cls->Restriction = A;
-	X = cls;
-}
-class_restrictor(X) ::= .						{ X = NULL; }
-class_restrictor(X) ::= LT dottable_id(A) GT.	{ X = A; /*X-overwrites-A*/ }
-
-type(X) ::= type_name(A).					{ X = A; /*X-overwrites-A*/ X->ArraySize = NULL; }
-type(X) ::= aggregate_type(A).				{ X = A; /*X-overwrites-A*/ X->ArraySize = NULL; }
-
-type_or_array(X) ::= type(X).
-type_or_array(X) ::= type(A) array_size(B).	{ X = A; /*X-overwrites-A*/ X->ArraySize = B; }
-
-type_list(X) ::= type_or_array(X).			/* A comma-separated list of types */
-type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; /*X-overwrites-A*/ X->AppendSibling(B); }
-
-type_list_or_void(X) ::= VOID.				{ X = NULL; }
-type_list_or_void(X) ::= type_list(X).
-
-array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET.
-{
-	if (A == NULL)
-	{
-		NEW_AST_NODE(Expression,nil,A);
-		nil->Operation = PEX_Nil;
-		nil->Type = NULL;
-		X = nil;
-	}
-	else
-	{
-		X = A;
-	}
-}
-array_size(X) ::= array_size_expr(X).
-array_size(X) ::= array_size(A) array_size_expr(B).
-{
-	A->AppendSibling(B);
-	X = A; /*X-overwrites-A*/
-}
-
-%type variables_or_function {VarOrFun}
-
-/* Multiple type names are only valid for functions. */
-declarator(X) ::= decl_flags(A) type_list_or_void(B) variables_or_function(C).
-{
-	if (C.FuncName == NAME_None && C.VarNames == NULL)
-	{ // An error. A message was already printed.
-		X = NULL;
-	}
-	else if (C.FuncName != NAME_None)
-	{ // A function
-		NEW_AST_NODE(FuncDeclarator, decl, A.SourceLoc);
-		decl->Type = B;
-		decl->Params = C.FuncParams;
-		decl->Name = C.FuncName;
-		decl->Flags = A.Int | C.FuncFlags;
-		decl->Body = C.FuncBody;
-		X = decl;
-	}
-	else if (B != NULL && B->SiblingNext == B)
-	{ // A variable
-		NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc);
-		decl->Type = B;
-		decl->Names = C.VarNames;
-		decl->Flags = A.Int;
-		X = decl;
-	}
-	else
-	{ // An invalid
-		if (B == NULL)
-		{
-			stat->sc.ScriptMessage("Variables may not be of type void.\n");
-		}
-		else
-		{
-			stat->sc.ScriptMessage("Variables may be of only one type.\n");
-		}
-		X = NULL;
-	}
-}
-declarator_no_fun(X) ::= decl_flags(A) type(B) variable_list(C) SEMICOLON.
-{
-	NEW_AST_NODE(VarDeclarator, decl, A.SourceLoc ? A.SourceLoc : B->SourceLoc);
-	decl->Type = B;
-	decl->Names = C;
-	decl->Flags = A.Int;
-	X = decl;
-}
-
-// Need to split it up like this to avoid parsing conflicts.
-variables_or_function(X) ::= IDENTIFIER(A) LPAREN func_params(B) RPAREN func_const(C) opt_func_body(D).	/* Function */
-{
-	VarOrFun fun;
-
-	fun.VarNames = NULL;
-	fun.FuncParams = B;
-	fun.FuncFlags = C.Int;
-	fun.FuncName = A.Name();
-	fun.FuncBody = D;
-	fun.SourceLoc = A.SourceLoc;
-	X = fun;
-}
-variables_or_function(X) ::= variable_list(A) SEMICOLON.
-{
-	VarOrFun var;
-
-	var.VarNames = A;
-	var.FuncParams = NULL;
-	var.FuncFlags = 0;
-	var.FuncName = NAME_None;
-	var.FuncBody = NULL;
-	var.SourceLoc = A->SourceLoc;
-	X = var;
-}
-variables_or_function(X) ::= error SEMICOLON(T).
-{
-	VarOrFun bad;
-	bad.VarNames = NULL;
-	bad.FuncParams = NULL;
-	bad.FuncFlags = 0;
-	bad.FuncName = NAME_None;
-	bad.FuncBody = NULL;
-	bad.SourceLoc = T.SourceLoc;
-	X = bad;
-}
-
-/*----- Variable Names -----*/
-
-%type variable_name{ZCC_VarName *}
-%type variable_list{ZCC_VarName *}
-
-variable_name(X) ::= IDENTIFIER(A).
-{
-	NEW_AST_NODE(VarName,var,A);
-	var->Name = ENamedName(A.Int);
-	var->ArraySize = NULL;
-	X = var;
-}
-variable_name(X) ::= IDENTIFIER(A) array_size(B).
-{
-	NEW_AST_NODE(VarName,var,A);
-	var->Name = ENamedName(A.Int);
-	var->ArraySize = B;
-	X = var;
-}
-
-variable_list(X) ::= variable_name(X).
-variable_list(X) ::= variable_list(A) COMMA variable_name(B).
-{
-	A->AppendSibling(B);
-	X = A; /*X-overwrites-A*/
-}
-
-decl_flags(X) ::= .								{ X.Int = 0; X.SourceLoc = 0; }
-decl_flags(X) ::= decl_flags(A) NATIVE(T).		{ X.Int = A.Int | ZCC_Native; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-decl_flags(X) ::= decl_flags(A) STATIC(T).		{ X.Int = A.Int | ZCC_Static; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-decl_flags(X) ::= decl_flags(A) PRIVATE(T).		{ X.Int = A.Int | ZCC_Private; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-decl_flags(X) ::= decl_flags(A) PROTECTED(T).	{ X.Int = A.Int | ZCC_Protected; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-decl_flags(X) ::= decl_flags(A) LATENT(T).		{ X.Int = A.Int | ZCC_Latent; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-decl_flags(X) ::= decl_flags(A) FINAL(T).		{ X.Int = A.Int | ZCC_Final; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-decl_flags(X) ::= decl_flags(A) META(T).		{ X.Int = A.Int | ZCC_Meta; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-decl_flags(X) ::= decl_flags(A) ACTION(T).		{ X.Int = A.Int | ZCC_Action; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-decl_flags(X) ::= decl_flags(A) READONLY(T).	{ X.Int = A.Int | ZCC_ReadOnly; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-decl_flags(X) ::= decl_flags(A) DEPRECATED(T).	{ X.Int = A.Int | ZCC_Deprecated; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-
-func_const(X) ::= .							{ X.Int = 0; X.SourceLoc = stat->sc.GetMessageLine(); }
-func_const(X) ::= CONST(T).					{ X.Int = ZCC_FuncConst; X.SourceLoc = T.SourceLoc; }
-
-opt_func_body(X) ::= SEMICOLON.				{ X = NULL; }
-opt_func_body(X) ::= function_body(X).
-
-%type func_params {ZCC_FuncParamDecl *}
-%type func_param_list {ZCC_FuncParamDecl *}
-%type func_param {ZCC_FuncParamDecl *}
-
-func_params(X) ::= .	/* empty */			{ X = NULL; }
-func_params(X) ::= VOID.					{ X = NULL; }
-func_params(X) ::= func_param_list(X).
-
-func_param_list(X) ::= func_param(X).
-func_param_list(X) ::= func_param_list(A) COMMA func_param(B).	{ X = A; /*X-overwrites-A*/ X->AppendSibling(B); }
-
-func_param(X) ::= func_param_flags(A) type(B) IDENTIFIER(C).
-{
-	NEW_AST_NODE(FuncParamDecl,parm,A.SourceLoc ? A.SourceLoc : B->SourceLoc);
-	parm->Type = B;
-	parm->Name = C.Name();
-	parm->Flags = A.Int;
-	X = parm;
-}
-
-func_param_flags(X) ::= .									{ X.Int = 0; X.SourceLoc = 0; }
-func_param_flags(X) ::= func_param_flags(A) IN(T).			{ X.Int = A.Int | ZCC_In; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-func_param_flags(X) ::= func_param_flags(A) OUT(T).			{ X.Int = A.Int | ZCC_Out; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T).	{ X.Int = A.Int | ZCC_Optional; X.SourceLoc = A.SourceLoc ? A.SourceLoc : T.SourceLoc; }
-
-/************ Expressions ************/
-
-/* We use default to access a class's default instance. */
-%fallback IDENTIFIER
-	DEFAULT.
-
-%type expr{ZCC_Expression *}
-%type primary{ZCC_Expression *}
-%type unary_expr{ZCC_Expression *}
-%type constant{ZCC_ExprConstant *}
-
-/*----- Primary Expressions -----*/
-
-primary(X) ::= IDENTIFIER(A).
-{
-	NEW_AST_NODE(ExprID, expr, A);
-	expr->Operation = PEX_ID;
-	expr->Identifier = A.Name();
-	expr->Type = NULL;
-	X = expr;
-}
-primary(X) ::= SUPER(T).
-{
-	NEW_AST_NODE(Expression, expr, T);
-	expr->Operation = PEX_Super;
-	expr->Type = NULL;
-	X = expr;
-}
-primary(X) ::= constant(A).				{ X = A; /*X-overwrites-A*/ }
-primary(X) ::= SELF(T).
-{
-	NEW_AST_NODE(Expression, expr, T);
-	expr->Operation = PEX_Self;
-	expr->Type = NULL;
-	X = expr;
-}
-primary(X) ::= LPAREN expr(A) RPAREN.
-{
-	X = A; /*X-overwrites-A*/
-}
-primary ::= LPAREN error RPAREN.
-primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT]		// Function call
-{
-	NEW_AST_NODE(ExprFuncCall, expr, A);
-	expr->Operation = PEX_FuncCall;
-	expr->Type = NULL;
-	expr->Function = A;
-	expr->Parameters = B;
-	X = expr;
-}
-primary(X) ::= primary(A) LBRACKET expr(B) RBRACKET. [DOT]				// Array access
-{
-	NEW_AST_NODE(ExprBinary, expr, B);
-	expr->Operation = PEX_ArrayAccess;
-	expr->Type = NULL;
-	expr->Left = A;
-	expr->Right = B;
-	X = expr;
-}
-primary(X) ::= primary(A) DOT IDENTIFIER(B).							// Member access
-{
-	NEW_AST_NODE(ExprMemberAccess, expr, B);
-	expr->Operation = PEX_MemberAccess;
-	expr->Type = NULL;
-	expr->Left = A;
-	expr->Right = ENamedName(B.Int);
-	X = expr;
-}
-primary(X) ::= primary(A) ADDADD.		/* postfix++ */
-{
-	UNARY_EXPR(A,PEX_PostInc);
-	X = expr1;
-}
-primary(X) ::= primary(A) SUBSUB.		/* postfix-- */
-{
-	UNARY_EXPR(A,PEX_PostDec);
-	X = expr1;
-}
-/*
-primary(X) ::= SCOPE primary(B).
-{
-	BINARY_EXPR(NULL,B,PEX_Scope);
-	X = expr2;
-}
-*/
-/*----- Unary Expressions -----*/
-
-unary_expr(X) ::= primary(X).
-unary_expr(X) ::= SUB unary_expr(A). [UNARY]
-{
-	ZCC_ExprConstant *con = static_cast<ZCC_ExprConstant *>(A);
-	if (A->Operation == PEX_ConstValue && (con->Type->IsA(RUNTIME_CLASS(PInt)) || con->Type->IsA(RUNTIME_CLASS(PFloat))))
-	{ // For constants, manipulate the child node directly, and don't create a new node.
-		if (con->Type->IsA(RUNTIME_CLASS(PInt)))
-		{
-			con->IntVal = -con->IntVal;
-		}
-		else
-		{
-			con->DoubleVal = -con->DoubleVal;
-		}
-		X = A;
-	}
-	else
-	{ // For everything else, create a new node and do the negation later.
-		UNARY_EXPR(A,PEX_Negate);
-		X = expr1;
-	}
-}
-unary_expr(X) ::= ADD unary_expr(A). [UNARY]
-{
-	// Even though this is really a no-op, we still need to make a node for
-	// it so we can type check that it is being applied to something numeric.
-	// But we can do that right now for constant numerals.
-	ZCC_ExprConstant *con = static_cast<ZCC_ExprConstant *>(A);
-	if (A->Operation != PEX_ConstValue || (!con->Type->IsA(RUNTIME_CLASS(PInt)) && !con->Type->IsA(RUNTIME_CLASS(PFloat))))
-	{
-		UNARY_EXPR(A,PEX_AntiNegate);
-		X = expr1;
-	}
-	else
-	{
-		X = A;
-	}
-}
-unary_expr(X) ::= SUBSUB unary_expr(A). [UNARY]
-{
-	UNARY_EXPR(A,PEX_PreDec);
-	X = expr1;
-}
-unary_expr(X) ::= ADDADD unary_expr(A). [UNARY]
-{
-	UNARY_EXPR(A,PEX_PreInc);
-	X = expr1;
-}
-unary_expr(X) ::= TILDE unary_expr(A). [UNARY]
-{
-	UNARY_EXPR(A,PEX_BitNot);
-	X = expr1;
-}
-unary_expr(X) ::= BANG unary_expr(A). [UNARY]
-{
-	UNARY_EXPR(A,PEX_BoolNot);
-	X = expr1;
-}
-unary_expr(X) ::= SIZEOF unary_expr(A). [UNARY]
-{
-	UNARY_EXPR(A,PEX_SizeOf);
-	X = expr1;
-}
-unary_expr(X) ::= ALIGNOF unary_expr(A). [UNARY]
-{
-	UNARY_EXPR(A,PEX_AlignOf);
-	X = expr1;
-}
-
-/* Due to parsing conflicts, C-style casting is not supported. You
- * must use C++ function call-style casting instead.
- */
-
-/*----- Binary Expressions -----*/
-
-expr(X) ::= unary_expr(X).
-expr(X) ::= expr(A) ADD expr(B).		/* a + b */
-{
-	BINARY_EXPR(A,B,PEX_Add);
-	X = expr2;
-}
-expr(X) ::= expr(A) SUB expr(B).		/* a - b */
-{
-	BINARY_EXPR(A,B,PEX_Sub);
-	X = expr2;
-}
-expr(X) ::= expr(A) MUL expr(B).		/* a * b */
-{
-	BINARY_EXPR(A,B,PEX_Mul);
-	X = expr2;
-}
-expr(X) ::= expr(A) DIV expr(B).		/* a / b */
-{
-	BINARY_EXPR(A,B,PEX_Div);
-	X = expr2;
-}
-expr(X) ::= expr(A) MOD expr(B).		/* a % b */
-{
-	BINARY_EXPR(A,B,PEX_Mod);
-	X = expr2;
-}
-expr(X) ::= expr(A) POW expr(B).		/* a ** b */
-{
-	BINARY_EXPR(A,B,PEX_Pow);
-	X = expr2;
-}
-expr(X) ::= expr(A) CROSSPROD expr(B).	/* a cross b */
-{
-	BINARY_EXPR(A,B,PEX_CrossProduct);
-	X = expr2;
-}
-expr(X) ::= expr(A) DOTPROD expr(B).	/* a dot b */
-{
-	BINARY_EXPR(A,B,PEX_DotProduct);
-	X = expr2;
-}
-expr(X) ::= expr(A) LSH expr(B).		/* a << b */
-{
-	BINARY_EXPR(A,B,PEX_LeftShift);
-	X = expr2;
-}
-expr(X) ::= expr(A) RSH expr(B).		/* a >> b */
-{
-	BINARY_EXPR(A,B,PEX_RightShift);
-	X = expr2;
-}
-expr(X) ::= expr(A) DOTDOT expr(B).		/* a .. b */
-{
-	BINARY_EXPR(A,B,PEX_Concat);
-	X = expr2;
-}
-
-expr(X) ::= expr(A) LT expr(B).			/* a < b */
-{
-	BINARY_EXPR(A,B,PEX_LT);
-	X = expr2;
-}
-expr(X) ::= expr(A) GT expr(B).			/* a > b */
-{
-	BINARY_EXPR(A,B,PEX_LTEQ);
-	UNARY_EXPR(expr2,PEX_BoolNot);
-	X = expr1;
-}
-expr(X) ::= expr(A) LTEQ expr(B).		/* a <= b */
-{
-	BINARY_EXPR(A,B,PEX_LTEQ);
-	X = expr2;
-}
-expr(X) ::= expr(A) GTEQ expr(B).		/* a >= b */
-{
-	BINARY_EXPR(A,B,PEX_LT);
-	UNARY_EXPR(expr1,PEX_BoolNot);
-	X = expr1;
-}
-expr(X) ::= expr(A) LTGTEQ expr(B).		/* a <>= b */
-{
-	BINARY_EXPR(A,B,PEX_LTGTEQ);
-	X = expr2;
-}
-expr(X) ::= expr(A) IS expr(B).			/* a is b */
-{
-	BINARY_EXPR(A,B,PEX_Is);
-	X = expr2;
-}
-
-expr(X) ::= expr(A) EQEQ expr(B).		/* a == b */
-{
-	BINARY_EXPR(A,B,PEX_EQEQ);
-	X = expr2;
-}
-expr(X) ::= expr(A) NEQ expr(B).		/* a != b */
-{
-	BINARY_EXPR(A,B,PEX_EQEQ);
-	UNARY_EXPR(expr2,PEX_BoolNot);
-	X = expr1;
-}
-expr(X) ::= expr(A) APPROXEQ expr(B).	/* a ~== b */
-{
-	BINARY_EXPR(A,B,PEX_APREQ);
-	X = expr2;
-}
-
-expr(X) ::= expr(A) AND expr(B).		/* a & b */
-{
-	BINARY_EXPR(A,B,PEX_BitAnd);
-	X = expr2;
-}
-expr(X) ::= expr(A) XOR expr(B).		/* a ^ b */
-{
-	BINARY_EXPR(A,B,PEX_BitXor);
-	X = expr2;
-}
-expr(X) ::= expr(A) OR expr(B).			/* a | b */
-{
-	BINARY_EXPR(A,B,PEX_BitOr);
-	X = expr2;
-}
-expr(X) ::= expr(A) ANDAND expr(B).		/* a && b */
-{
-	BINARY_EXPR(A,B,PEX_BoolAnd);
-	X = expr2;
-}
-expr(X) ::= expr(A) OROR expr(B).		/* a || b */
-{
-	BINARY_EXPR(A,B,PEX_BoolOr);
-	X = expr2;
-}
-
-expr(X) ::= expr(A) SCOPE expr(B).
-{
-	BINARY_EXPR(A,B,PEX_Scope);
-	X = expr2;
-}
-
-/*----- Trinary Expression -----*/
-
-expr(X) ::= expr(A) QUESTION expr(B) COLON expr(C).
-{
-	NEW_AST_NODE(ExprTrinary, expr, A);
-	expr->Operation = PEX_Trinary;
-	expr->Type = NULL;
-	expr->Test = A;
-	expr->Left = B;
-	expr->Right = C;
-	X = expr;
-}
-
-/************ Expression Lists ***********/ 
-
-%type expr_list{ZCC_Expression *}
-
-expr_list(X) ::= expr(X).
-expr_list(X) ::= expr_list(A) COMMA expr(B).
-{
-	X = A;	/*X-overwrites-A*/
-	X->AppendSibling(B);
-}
-
-/*----- Function argument lists -----*/
-
-/* A function expression list can also specify a parameter's name,
- * but once you do that, all remaining parameters must also be named.
- * We let higher-level code handle this to keep this file simpler. */
-%type func_expr_list{ZCC_FuncParm *}
-%type func_expr_item{ZCC_FuncParm *}
-%type named_expr{ZCC_FuncParm *}
-
-func_expr_list(X) ::= func_expr_item(X).
-func_expr_list(X) ::= func_expr_list(A) COMMA(T) func_expr_item(B).
-{
-	// Omitted parameters still need to appear as nodes in the list.
-	if (A == NULL)
-	{
-		NEW_AST_NODE(FuncParm,nil_a,T);
-		nil_a->Value = NULL;
-		nil_a->Label = NAME_None;
-		A = nil_a;
-	}
-	if (B == NULL)
-	{
-		NEW_AST_NODE(FuncParm,nil_b,T);
-		nil_b->Value = NULL;
-		nil_b->Label = NAME_None;
-		B = nil_b;
-	}
-	X = A;	/*X-overwrites-A*/
-	X->AppendSibling(B);
-}
-
-func_expr_item(X) ::= .
-{
-	X = NULL;
-}
-func_expr_item(X) ::= named_expr(X).
-
-named_expr(X) ::= IDENTIFIER(A) COLON expr(B).
-{
-	NEW_AST_NODE(FuncParm, parm, A);
-	parm->Value = B;
-	parm->Label = ENamedName(A.Int);
-	X = parm;
-}
-named_expr(X) ::= expr(B).
-{
-	NEW_AST_NODE(FuncParm, parm, B);
-	parm->Value = B;
-	parm->Label = NAME_None;
-	X = parm;
-}
-
-/************ Constants ************/
-
-/* Allow C-like concatenation of adjacent string constants. */
-%type string_constant{ZCC_ExprConstant *}
-
-string_constant(X) ::= STRCONST(A).
-{
-	NEW_AST_NODE(ExprConstant, strconst, A);
-	strconst->Operation = PEX_ConstValue;
-	strconst->Type = TypeString;
-	strconst->StringVal = A.String;
-	X = strconst;
-}
-string_constant(X) ::= string_constant(A) STRCONST(B).
-{
-	NEW_AST_NODE(ExprConstant, strconst, A);
-	strconst->Operation = PEX_ConstValue;
-	strconst->Type = TypeString;
-	strconst->StringVal = stat->Strings.Alloc(*(A->StringVal) + *(B.String));
-	X = strconst;
-}
-
-constant(X) ::= string_constant(X).
-constant(X) ::= INTCONST(A).
-{
-	NEW_INTCONST_NODE(intconst, TypeSInt32, A.Int, A);
-	X = intconst;
-}
-constant(X) ::= UINTCONST(A).
-{
-	NEW_INTCONST_NODE(intconst, TypeUInt32, A.Int, A);
-	X = intconst;
-}
-constant(X) ::= FLOATCONST(A).
-{
-	NEW_AST_NODE(ExprConstant, floatconst, A);
-	floatconst->Operation = PEX_ConstValue;
-	floatconst->Type = TypeFloat64;
-	floatconst->DoubleVal = A.Float;
-	X = floatconst;
-}
-constant(X) ::= NAMECONST(A).
-{
-	NEW_AST_NODE(ExprConstant, floatconst, A);
-	floatconst->Operation = PEX_ConstValue;
-	floatconst->Type = TypeName;
-	floatconst->IntVal = A.Int;
-	X = floatconst;
-}
-constant(X) ::= FALSE(A).
-{
-	NEW_INTCONST_NODE(boolconst, TypeBool, false, A);
-	X = boolconst;
-}
-constant(X) ::= TRUE(A).
-{
-	NEW_INTCONST_NODE(boolconst, TypeBool, true, A);
-	X = boolconst;
-}
-
-/************ Statements ************/
-
-function_body(X) ::= compound_statement(X).
-
-%type statement{ZCC_Statement *}
-statement(X) ::= SEMICOLON.							{ X = NULL; }
-statement(X) ::= labeled_statement(A).				{ X = A; /*X-overwrites-A*/ }
-statement(X) ::= compound_statement(A).				{ X = A; /*X-overwrites-A*/ }
-statement(X) ::= expression_statement(A) SEMICOLON.	{ X = A; /*X-overwrites-A*/ }
-statement(X) ::= selection_statement(X).
-statement(X) ::= iteration_statement(X).
-statement(X) ::= jump_statement(X).
-statement(X) ::= assign_statement(A) SEMICOLON.		{ X = A; /*X-overwrites-A*/ }
-statement(X) ::= local_var(A) SEMICOLON.			{ X = A; /*X-overwrites-A*/ }
-statement(X) ::= error SEMICOLON.					{ X = NULL; }
-
-/*----- Jump Statements -----*/
-
-%type jump_statement{ZCC_Statement *}
-
-jump_statement(A) ::= CONTINUE(T) SEMICOLON.
-{
-	NEW_AST_NODE(ContinueStmt, stmt, T);
-	A = stmt;
-}
-jump_statement(A) ::= BREAK(T) SEMICOLON.
-{
-	NEW_AST_NODE(BreakStmt, stmt, T);
-	A = stmt;
-}
-jump_statement(A) ::= RETURN(T) SEMICOLON.
-{
-	NEW_AST_NODE(ReturnStmt, stmt, T);
-	stmt->Values = NULL;
-	A = stmt;
-}
-jump_statement(A) ::= RETURN(T) expr_list(X) SEMICOLON.
-{
-	NEW_AST_NODE(ReturnStmt, stmt, T);
-	stmt->Values = X;
-	A = stmt;
-}
-
-/*----- Compound Statements -----*/
-
-%type compound_statement{ZCC_CompoundStmt *}
-%type statement_list{ZCC_Statement *}
-
-compound_statement(X) ::= LBRACE(T) RBRACE.
-{
-	NEW_AST_NODE(CompoundStmt,stmt,T);
-	stmt->Content = NULL;
-	X = stmt;
-}
-compound_statement(X) ::= LBRACE(T) statement_list(A) RBRACE.
-{
-	NEW_AST_NODE(CompoundStmt,stmt,T);
-	stmt->Content = A;
-	X = stmt;
-}
-compound_statement(X) ::= LBRACE(T) error RBRACE.
-{
-	NEW_AST_NODE(CompoundStmt,stmt,T);
-	stmt->Content = NULL;
-	X = stmt;
-}
-
-statement_list(X) ::= statement(A).
-{
-	X = A; /*X-overwrites-A*/
-}
-statement_list(X) ::= statement_list(X) statement(B).
-{
-	SAFE_APPEND(X,B);
-}
-
-/*----- Expression Statements -----*/
-
-%type expression_statement{ZCC_ExpressionStmt *}
-
-expression_statement(X) ::= expr(A).
-{
-	NEW_AST_NODE(ExpressionStmt, stmt, A);
-	stmt->Expression = A;
-	X = stmt;
-}
-
-/*----- Iteration Statements -----*/
-
-%type iteration_statement{ZCC_Statement *}
-
-// while/until (expr) statement
-iteration_statement(X) ::= while_or_until(TY) LPAREN expr(EX) RPAREN statement(ST).
-{
-	NEW_AST_NODE(IterationStmt, iter, TY);
-	if (TY.Int == ZCC_UNTIL)
-	{ // Negate the loop condition
-		UNARY_EXPR(EX,PEX_BoolNot);
-		iter->LoopCondition = expr1;
-	}
-	else
-	{
-		iter->LoopCondition = EX;
-	}
-	iter->LoopStatement = ST;
-	iter->LoopBumper = NULL;
-	iter->CheckAt = ZCC_IterationStmt::Start;
-	X = iter;
-}
-// do statement while/until (expr)
-iteration_statement(X) ::= DO(T) statement(ST) while_or_until(TY) LPAREN expr(EX) RPAREN.
-{
-	NEW_AST_NODE(IterationStmt, iter, T);
-	if (TY.Int == ZCC_UNTIL)
-	{ // Negate the loop condition
-		UNARY_EXPR(EX,PEX_BoolNot);
-		iter->LoopCondition = expr1;
-	}
-	else
-	{
-		iter->LoopCondition = EX;
-	}
-	iter->LoopStatement = ST;
-	iter->LoopBumper = NULL;
-	iter->CheckAt = ZCC_IterationStmt::End;
-	X = iter;
-}
-// for (init; cond; bump) statement
-iteration_statement(X) ::= FOR(T) LPAREN for_init(IN) SEMICOLON opt_expr(EX) SEMICOLON for_bump(DO) RPAREN statement(ST).
-{
-	NEW_AST_NODE(IterationStmt, iter, T);
-	iter->LoopCondition = EX;
-	iter->LoopStatement = ST;
-	iter->LoopBumper = DO;
-	iter->CheckAt = ZCC_IterationStmt::Start;
-	// The initialization expression appears outside the loop
-	// for_init may be NULL if there is no initialization.
-	SAFE_APPEND(IN, iter);
-	// And the whole thing gets wrapped inside a compound statement in case the loop
-	// initializer defined any variables.
-	NEW_AST_NODE(CompoundStmt, wrap, T);
-	wrap->Content = IN;
-	X = wrap;
-}
-
-while_or_until(X) ::= WHILE(T).
-{
-	X.Int = ZCC_WHILE;
-	X.SourceLoc = T.SourceLoc;
-}
-while_or_until(X) ::= UNTIL(T).
-{
-	X.Int = ZCC_UNTIL;
-	X.SourceLoc = T.SourceLoc;
-}
-
-%type for_init{ZCC_Statement *}
-for_init(X) ::= local_var(A).						{ X = A /*X-overwrites-A*/; }
-for_init(X) ::= for_bump(A).						{ X = A /*X-overwrites-A*/; }
-
-%type for_bump{ZCC_Statement *}
-for_bump(X) ::= .									{ X = NULL; }
-for_bump(X) ::= expression_statement(A).			{ X = A; /*X-overwrites-A*/ }
-for_bump(X) ::= assign_statement(A).				{ X = A; /*X-overwrites-A*/ }
-
-/*----- If Statements -----*/
-
-/* Resolve the shift-reduce conflict here in favor of the shift.
- * This is the default behavior, but using precedence symbols
- * lets us do it without warnings.
- */
-%left IF.
-%left ELSE.
-%type selection_statement{ZCC_Statement *}
-%type if_front{ZCC_IfStmt *}
-
-selection_statement(X) ::= if_front(A). [IF]
-{
-	X = A; /*X-overwrites-A*/
-}
-selection_statement(X) ::= if_front(A) ELSE statement(B). [ELSE]
-{
-	A->FalsePath = B;
-	X = A; /*X-overwrites-A*/
-}
-
-if_front(X) ::= IF(T) LPAREN expr(A) RPAREN statement(B).
-{
-	NEW_AST_NODE(IfStmt,stmt,T);
-	stmt->Condition = A;
-	stmt->TruePath = B;
-	stmt->FalsePath = NULL;
-	X = stmt;
-}
-
-/*----- Switch Statements -----*/
-
-selection_statement(X) ::= SWITCH(T) LPAREN expr(A) RPAREN statement(B).
-{
-	NEW_AST_NODE(SwitchStmt,stmt,T);
-	stmt->Condition = A;
-	stmt->Content = B;
-	X = stmt;
-}
-
-/*----- Case Label "Statements" -----*/
-
-%type labeled_statement{ZCC_CaseStmt *}
-
-labeled_statement(X) ::= CASE(T) expr(A) COLON.
-{
-	NEW_AST_NODE(CaseStmt,stmt,T);
-	stmt->Condition = A;
-	X = stmt;
-}
-labeled_statement(X) ::= DEFAULT(T) COLON.
-{
-	NEW_AST_NODE(CaseStmt,stmt,T);
-	stmt->Condition = NULL;
-	X = stmt;
-}
-
-/*----- Assignment Statements -----*/
-
-%type assign_statement{ZCC_AssignStmt *}
-
-assign_statement(X) ::= expr_list(A) assign_op(OP) expr_list(B). [EQ]
-{
-	NEW_AST_NODE(AssignStmt,stmt,OP);
-	stmt->AssignOp = OP.Int;
-	stmt->Dests = A;
-	stmt->Sources = B;
-	X = stmt;
-}
-
-assign_op(X) ::= EQ(T).			{ X.Int = ZCC_EQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= MULEQ(T).		{ X.Int = ZCC_MULEQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= DIVEQ(T).		{ X.Int = ZCC_DIVEQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= MODEQ(T).		{ X.Int = ZCC_MODEQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= ADDEQ(T).		{ X.Int = ZCC_ADDEQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= SUBEQ(T).		{ X.Int = ZCC_SUBEQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= LSHEQ(T).		{ X.Int = ZCC_LSHEQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= RSHEQ(T).		{ X.Int = ZCC_RSHEQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= ANDEQ(T).		{ X.Int = ZCC_ANDEQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= OREQ(T).		{ X.Int = ZCC_OREQ; X.SourceLoc = T.SourceLoc; }
-assign_op(X) ::= XOREQ(T).		{ X.Int = ZCC_XOREQ; X.SourceLoc = T.SourceLoc; }
-
-/*----- Local Variable Definition "Statements" -----*/
-
-%type local_var{ZCC_LocalVarStmt *}
-
-local_var(X) ::= type(A) variable_list(B) var_init(C).
-{
-	NEW_AST_NODE(LocalVarStmt,vardef,A);
-	vardef->Type = A;
-	vardef->Vars = B;
-	vardef->Inits = C;
-	X = vardef;
-}
-
-%type var_init{ZCC_Expression *}
-var_init(X) ::= .						{ X = NULL; }
-var_init(X) ::= EQ expr_list(A).		{ X = A; /*X-overwrites-A*/ }
--- src/zscript/zcc_compile.cpp
+++ src/zscript/zcc_compile.cpp
@@ -1,642 +0,0 @@
-#include "dobject.h"
-#include "sc_man.h"
-#include "c_console.h"
-#include "c_dispatch.h"
-#include "w_wad.h"
-#include "cmdlib.h"
-#include "m_alloc.h"
-#include "zcc_parser.h"
-#include "zcc_compile.h"
-#include "v_text.h"
-#include "gdtoa.h"
-
-#define DEFINING_CONST ((PSymbolConst *)(void *)1)
-
-//==========================================================================
-//
-// ZCCCompiler Constructor
-//
-//==========================================================================
-
-ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols)
-: Outer(_outer), Symbols(&_symbols), AST(ast), ErrorCount(0), WarnCount(0)
-{
-	// Group top-level nodes by type
-	if (ast.TopNode != NULL)
-	{
-		ZCC_TreeNode *node = ast.TopNode;
-		do
-		{
-			switch (node->NodeType)
-			{
-			case AST_Class:
-			case AST_Struct:
-			case AST_ConstantDef:
-				if (AddNamedNode(static_cast<ZCC_NamedNode *>(node)))
-				{
-					switch (node->NodeType)
-					{
-					case AST_Class:			Classes.Push(static_cast<ZCC_Class *>(node));			break;
-					case AST_Struct:		Structs.Push(static_cast<ZCC_Struct *>(node));			break;
-					case AST_ConstantDef:	Constants.Push(static_cast<ZCC_ConstantDef *>(node));	break;
-					default: assert(0 && "Default case is just here to make GCC happy. It should never be reached");
-					}
-				}
-				break;
-
-			case AST_Enum:			break;
-			case AST_EnumTerminator:break;
-
-			default:
-				assert(0 && "Unhandled AST node type");
-				break;
-			}
-			node = node->SiblingNext;
-		}
-		while (node != ast.TopNode);
-	}
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: AddNamedNode
-//
-// Keeps track of definition nodes by their names. Ensures that all names
-// in this scope are unique.
-//
-//==========================================================================
-
-bool ZCCCompiler::AddNamedNode(ZCC_NamedNode *node)
-{
-	FName name = node->NodeName;
-	PSymbol *check = Symbols->FindSymbol(name, false);
-	if (check != NULL)
-	{
-		assert(check->IsA(RUNTIME_CLASS(PSymbolTreeNode)));
-		Error(node, "Attempt to redefine '%s'", name.GetChars());
-		Error(static_cast<PSymbolTreeNode *>(check)->Node, " Original definition is here");
-		return false;
-	}
-	else
-	{
-		Symbols->AddSymbol(new PSymbolTreeNode(name, node));
-		return true;
-	}
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: Warn
-//
-// Prints a warning message, and increments WarnCount.
-//
-//==========================================================================
-
-void ZCCCompiler::Warn(ZCC_TreeNode *node, const char *msg, ...)
-{
-	va_list argptr;
-	va_start(argptr, msg);
-	MessageV(node, TEXTCOLOR_ORANGE, msg, argptr);
-	va_end(argptr);
-
-	WarnCount++;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: Error
-//
-// Prints an error message, and increments ErrorCount.
-//
-//==========================================================================
-
-void ZCCCompiler::Error(ZCC_TreeNode *node, const char *msg, ...)
-{
-	va_list argptr;
-	va_start(argptr, msg);
-	MessageV(node, TEXTCOLOR_RED, msg, argptr);
-	va_end(argptr);
-
-	ErrorCount++;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: MessageV
-//
-// Prints a message, annotated with the source location for the tree node.
-//
-//==========================================================================
-
-void ZCCCompiler::MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr)
-{
-	FString composed;
-
-	composed.Format("%s%s, line %d: ", txtcolor, node->SourceName->GetChars(), node->SourceLoc);
-	composed.VAppendFormat(msg, argptr);
-	composed += '\n';
-	PrintString(PRINT_HIGH, composed);
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: Compile
-//
-// Compile everything defined at this level.
-//
-//==========================================================================
-
-int ZCCCompiler::Compile()
-{
-	CompileConstants(Constants);
-	return ErrorCount;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: CompileConstants
-//
-// Make symbols from every constant defined at this level.
-//
-//==========================================================================
-
-void ZCCCompiler::CompileConstants(const TArray<ZCC_ConstantDef *> &defs)
-{
-	for (unsigned i = 0; i < defs.Size(); ++i)
-	{
-		ZCC_ConstantDef *def = defs[i];
-		if (def->Symbol == NULL)
-		{
-			PSymbolConst *sym = CompileConstant(def);
-		}
-	}
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: CompileConstant
-//
-// For every constant definition, evaluate its value (which should result
-// in a constant), and create a symbol for it. Simplify() uses recursion
-// to resolve constants used before their declarations.
-//
-//==========================================================================
-
-PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def)
-{
-	assert(def->Symbol == NULL);
-
-	def->Symbol = DEFINING_CONST;	// avoid recursion
-	ZCC_Expression *val = Simplify(def->Value);
-	def->Value = val;
-	PSymbolConst *sym = NULL;
-	if (val->NodeType == AST_ExprConstant)
-	{
-		ZCC_ExprConstant *cval = static_cast<ZCC_ExprConstant *>(val);
-		if (cval->Type == TypeString)
-		{
-			sym = new PSymbolConstString(def->NodeName, *(cval->StringVal));
-		}
-		else if (cval->Type->IsA(RUNTIME_CLASS(PInt)))
-		{
-			sym = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->IntVal);
-		}
-		else if (cval->Type->IsA(RUNTIME_CLASS(PFloat)))
-		{
-			sym = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->DoubleVal);
-		}
-		else
-		{
-			Error(def->Value, "Bad type for constant definiton");
-		}
-	}
-	else
-	{
-		Error(def->Value, "Constant definition requires a constant value");
-	}
-	if (sym == NULL)
-	{
-		// Create a dummy constant so we don't make any undefined value warnings.
-		sym = new PSymbolConstNumeric(def->NodeName, TypeError, 0);
-	}
-	def->Symbol = sym;
-	Symbols->ReplaceSymbol(sym);
-	return sym;
-}
-
-
-//==========================================================================
-//
-// ZCCCompiler :: Simplify
-//
-// For an expression,
-//   Evaluate operators whose arguments are both constants, replacing it
-//     with a new constant.
-//   For a binary operator with one constant argument, put it on the right-
-//     hand operand, where permitted.
-//   Perform automatic type promotion.
-//
-//==========================================================================
-
-ZCC_Expression *ZCCCompiler::Simplify(ZCC_Expression *root)
-{
-	if (root->NodeType == AST_ExprUnary)
-	{
-		return SimplifyUnary(static_cast<ZCC_ExprUnary *>(root));
-	}
-	else if (root->NodeType == AST_ExprBinary)
-	{
-		return SimplifyBinary(static_cast<ZCC_ExprBinary *>(root));
-	}
-	else if (root->Operation == PEX_ID)
-	{
-		return IdentifyIdentifier(static_cast<ZCC_ExprID *>(root));
-	}
-	else if (root->Operation == PEX_MemberAccess)
-	{
-		return SimplifyMemberAccess(static_cast<ZCC_ExprMemberAccess *>(root));
-	}
-	else if (root->Operation == PEX_FuncCall)
-	{
-		return SimplifyFunctionCall(static_cast<ZCC_ExprFuncCall *>(root));
-	}
-	return root;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: SimplifyUnary
-//
-//==========================================================================
-
-ZCC_Expression *ZCCCompiler::SimplifyUnary(ZCC_ExprUnary *unary)
-{
-	unary->Operand = Simplify(unary->Operand);
-	ZCC_OpProto *op = PromoteUnary(unary->Operation, unary->Operand);
-	if (op == NULL)
-	{ // Oh, poo!
-		unary->Type = TypeError;
-	}
-	else if (unary->Operand->Operation == PEX_ConstValue)
-	{
-		return op->EvalConst1(static_cast<ZCC_ExprConstant *>(unary->Operand));
-	}
-	return unary;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: SimplifyBinary
-//
-//==========================================================================
-
-ZCC_Expression *ZCCCompiler::SimplifyBinary(ZCC_ExprBinary *binary)
-{
-	binary->Left = Simplify(binary->Left);
-	binary->Right = Simplify(binary->Right);
-	ZCC_OpProto *op = PromoteBinary(binary->Operation, binary->Left, binary->Right);
-	if (op == NULL)
-	{
-		binary->Type = TypeError;
-	}
-	else if (binary->Left->Operation == PEX_ConstValue &&
-		binary->Right->Operation == PEX_ConstValue)
-	{
-		return op->EvalConst2(static_cast<ZCC_ExprConstant *>(binary->Left),
-							  static_cast<ZCC_ExprConstant *>(binary->Right), AST.Strings);
-	}
-	return binary;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: SimplifyMemberAccess
-//
-//==========================================================================
-
-ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop)
-{
-	dotop->Left = Simplify(dotop->Left);
-
-	if (dotop->Left->Operation == PEX_TypeRef)
-	{ // Type refs can be evaluated now.
-		PType *ref = static_cast<ZCC_ExprTypeRef *>(dotop->Left)->RefType;
-		PSymbolTable *symtable;
-		PSymbol *sym = ref->Symbols.FindSymbolInTable(dotop->Right, symtable);
-		if (sym == NULL)
-		{
-			Error(dotop, "'%s' is not a valid member", FName(dotop->Right).GetChars());
-		}
-		else
-		{
-			ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable);
-			if (expr == NULL)
-			{
-				Error(dotop, "Unhandled symbol type encountered");
-			}
-			else
-			{
-				return expr;
-			}
-		}
-	}
-	return dotop;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: SimplifyFunctionCall
-//
-// This may replace a function call with cast(s), since they look like the
-// same thing to the parser.
-//
-//==========================================================================
-
-ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop)
-{
-	ZCC_FuncParm *parm;
-	int parmcount = 0;
-
-	callop->Function = Simplify(callop->Function);
-	parm = callop->Parameters;
-	if (parm != NULL)
-	{
-		do
-		{
-			parmcount++;
-			assert(parm->NodeType == AST_FuncParm);
-			parm->Value = Simplify(parm->Value);
-			parm = static_cast<ZCC_FuncParm *>(parm->SiblingNext);
-		}
-		while (parm != callop->Parameters);
-	}
-	// If the left side is a type ref, then this is actually a cast
-	// and not a function call.
-	if (callop->Function->Operation == PEX_TypeRef)
-	{
-		if (parmcount != 1)
-		{
-			Error(callop, "Type cast requires one parameter");
-			callop->ToErrorNode();
-		}
-		else
-		{
-			PType *dest = static_cast<ZCC_ExprTypeRef *>(callop->Function)->RefType;
-			const PType::Conversion *route[CONVERSION_ROUTE_SIZE];
-			int routelen = parm->Value->Type->FindConversion(dest, route, countof(route));
-			if (routelen < 0)
-			{
-				///FIXME: Need real type names
-				Error(callop, "Cannot convert type 1 to type 2");
-				callop->ToErrorNode();
-			}
-			else
-			{
-				ZCC_Expression *val = ApplyConversion(parm->Value, route, routelen);
-				assert(val->Type == dest);
-				return val;
-			}
-		}
-	}
-	return callop;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: PromoteUnary
-//
-// Converts the operand into a format preferred by the operator.
-//
-//==========================================================================
-
-ZCC_OpProto *ZCCCompiler::PromoteUnary(EZCCExprType op, ZCC_Expression *&expr)
-{
-	if (expr->Type == TypeError)
-	{
-		return NULL;
-	}
-	const PType::Conversion *route[CONVERSION_ROUTE_SIZE];
-	int routelen = countof(route);
-	ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(expr->Type, route, routelen);
-
-	if (proto != NULL)
-	{
-		expr = ApplyConversion(expr, route, routelen);
-	}
-	return proto;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: PromoteBinary
-//
-// Converts the operands into a format (hopefully) compatible with the
-// operator.
-//
-//==========================================================================
-
-ZCC_OpProto *ZCCCompiler::PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right)
-{
-	// If either operand is of type 'error', the result is also 'error'
-	if (left->Type == TypeError || right->Type == TypeError)
-	{
-		return NULL;
-	}
-	const PType::Conversion *route1[CONVERSION_ROUTE_SIZE], *route2[CONVERSION_ROUTE_SIZE];
-	int route1len = countof(route1), route2len = countof(route2);
-	ZCC_OpProto *proto = ZCC_OpInfo[op].FindBestProto(left->Type, route1, route1len, right->Type, route2, route2len);
-	if (proto != NULL)
-	{
-		left = ApplyConversion(left, route1, route1len);
-		right = ApplyConversion(right, route2, route2len);
-	}
-	return proto;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: ApplyConversion
-//
-//==========================================================================
-
-ZCC_Expression *ZCCCompiler::ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen)
-{
-	for (int i = 0; i < routelen; ++i)
-	{
-		if (expr->Operation != PEX_ConstValue)
-		{
-			expr = AddCastNode(route[i]->TargetType, expr);
-		}
-		else
-		{
-			route[i]->ConvertConstant(static_cast<ZCC_ExprConstant *>(expr), AST.Strings);
-		}
-	}
-	return expr;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: AddCastNode
-//
-//==========================================================================
-
-ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr)
-{
-	assert(expr->Operation != PEX_ConstValue && "Expression must not be constant");
-	// TODO: add a node here
-	return expr;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: IdentifyIdentifier
-//
-// Returns a node that represents what the identifer stands for.
-//
-//==========================================================================
-
-ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode)
-{
-	// Check the symbol table for the identifier.
-	PSymbolTable *table;
-	PSymbol *sym = Symbols->FindSymbolInTable(idnode->Identifier, table);
-	if (sym != NULL)
-	{
-		ZCC_Expression *node = NodeFromSymbol(sym, idnode, table);
-		if (node != NULL)
-		{
-			return node;
-		}
-	}
-	else
-	{
-		Error(idnode, "Unknown identifier '%s'", FName(idnode->Identifier).GetChars());
-	}
-	// Identifier didn't refer to anything good, so type error it.
-	idnode->ToErrorNode();
-	return idnode;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: CompileNode
-//
-//==========================================================================
-
-PSymbol *ZCCCompiler::CompileNode(ZCC_NamedNode *node)
-{
-	assert(node != NULL);
-	if (node->NodeType == AST_ConstantDef)
-	{
-		ZCC_ConstantDef *def = static_cast<ZCC_ConstantDef *>(node);
-		PSymbolConst *sym = def->Symbol;
-
-		if (sym == DEFINING_CONST)
-		{
-			Error(node, "Definition of '%s' is infinitely recursive", FName(node->NodeName).GetChars());
-			sym = NULL;
-		}
-		else
-		{
-			assert(sym == NULL);
-			sym = CompileConstant(def);
-		}
-		return sym;
-	}
-	else if (node->NodeType == AST_Struct)
-	{
-
-	}
-	return NULL;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: NodeFromSymbol
-//
-//==========================================================================
-
-ZCC_Expression *ZCCCompiler::NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table)
-{
-	assert(sym != NULL);
-	if (sym->IsA(RUNTIME_CLASS(PSymbolTreeNode)))
-	{
-		PSymbolTable *prevtable = Symbols;
-		Symbols = table;
-		sym = CompileNode(static_cast<PSymbolTreeNode *>(sym)->Node);
-		Symbols = prevtable;
-		if (sym == NULL)
-		{
-			return NULL;
-		}
-	}
-	if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
-	{
-		return NodeFromSymbolConst(static_cast<PSymbolConst *>(sym), source);
-	}
-	else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolType)))
-	{
-		return NodeFromSymbolType(static_cast<PSymbolType *>(sym), source);
-	}
-	return NULL;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: NodeFromSymbolConst
-//
-// Returns a new AST constant node with the symbol's content.
-//
-//==========================================================================
-
-ZCC_ExprConstant *ZCCCompiler::NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode)
-{
-	ZCC_ExprConstant *val = static_cast<ZCC_ExprConstant *>(AST.InitNode(sizeof(*val), AST_ExprConstant, idnode));
-	val->Operation = PEX_ConstValue;
-	if (sym == NULL)
-	{
-		val->Type = TypeError;
-		val->IntVal = 0;
-	}
-	else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConstString)))
-	{
-		val->StringVal = AST.Strings.Alloc(static_cast<PSymbolConstString *>(sym)->Str);
-		val->Type = TypeString;
-	}
-	else
-	{
-		val->Type = sym->ValueType;
-		if (val->Type != TypeError)
-		{
-			assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
-			if (sym->ValueType->IsKindOf(RUNTIME_CLASS(PInt)))
-			{
-				val->IntVal = static_cast<PSymbolConstNumeric *>(sym)->Value;
-			}
-			else
-			{
-				assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat)));
-				val->DoubleVal = static_cast<PSymbolConstNumeric *>(sym)->Float;
-			}
-		}
-	}
-	return val;
-}
-
-//==========================================================================
-//
-// ZCCCompiler :: NodeFromSymbolType
-//
-// Returns a new AST type ref node with the symbol's content.
-//
-//==========================================================================
-
-ZCC_ExprTypeRef *ZCCCompiler::NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode)
-{
-	ZCC_ExprTypeRef *ref = static_cast<ZCC_ExprTypeRef *>(AST.InitNode(sizeof(*ref), AST_ExprTypeRef, idnode));
-	ref->Operation = PEX_TypeRef;
-	ref->RefType = sym->Type;
-	ref->Type = NewClassPointer(RUNTIME_CLASS(PType));
-	return ref;
-}
--- src/zscript/zcc_compile.h
+++ src/zscript/zcc_compile.h
@@ -1,56 +0,0 @@
-#ifndef ZCC_COMPILE_H
-#define ZCC_COMPILE_H
-
-class ZCCCompiler
-{
-public:
-	ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols);
-	int Compile();
-
-private:
-	void CompileConstants(const TArray<ZCC_ConstantDef *> &defs);
-	PSymbolConst *CompileConstant(ZCC_ConstantDef *def);
-
-	TArray<ZCC_ConstantDef *> Constants;
-	TArray<ZCC_Struct *> Structs;
-	TArray<ZCC_Class *> Classes;
-
-	bool AddNamedNode(ZCC_NamedNode *node);
-
-	ZCC_Expression *Simplify(ZCC_Expression *root);
-	ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary);
-	ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary);
-	ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop);
-	ZCC_Expression *SimplifyFunctionCall(ZCC_ExprFuncCall *callop);
-	ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr);
-	ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right);
-
-	void PromoteToInt(ZCC_Expression *&expr);
-	void PromoteToUInt(ZCC_Expression *&expr);
-	void PromoteToDouble(ZCC_Expression *&expr);
-	void PromoteToString(ZCC_Expression *&expr);
-
-	ZCC_Expression *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen);
-	ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr);
-
-	ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode);
-	ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table);
-	ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode);
-	ZCC_ExprTypeRef *NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode);
-	PSymbol *CompileNode(ZCC_NamedNode *node);
-
-
-	void Warn(ZCC_TreeNode *node, const char *msg, ...);
-	void Error(ZCC_TreeNode *node, const char *msg, ...);
-	void MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr);
-
-	DObject *Outer;
-	PSymbolTable *Symbols;
-	ZCC_AST &AST;
-	int ErrorCount;
-	int WarnCount;
-};
-
-void ZCC_InitConversions();
-
-#endif
--- src/zscript/zcc_expr.cpp
+++ src/zscript/zcc_expr.cpp
@@ -1,484 +0,0 @@
-#include <math.h>
-#include "dobject.h"
-#include "sc_man.h"
-#include "c_console.h"
-#include "c_dispatch.h"
-#include "w_wad.h"
-#include "cmdlib.h"
-#include "m_alloc.h"
-#include "zcc_parser.h"
-#include "templates.h"
-
-#define luai_nummod(a,b)        ((a) - floor((a)/(b))*(b))
-
-static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena);
-
-ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] =
-{
-#define xx(a,z)	{ #a, NULL },
-#include "zcc_exprlist.h"
-};
-
-// Structures used for initializing operator overloads
-struct OpProto1
-{
-	EZCCExprType Op;
-	PType **Type;
-	EvalConst1op EvalConst;
-};
-
-struct OpProto2
-{
-	EZCCExprType Op;
-	PType **Res, **Ltype, **Rtype;
-	EvalConst2op EvalConst;
-};
-
-static struct FreeOpInfoProtos
-{
-	~FreeOpInfoProtos()
-	{
-		for (size_t i = 0; i < countof(ZCC_OpInfo); ++i)
-		{
-			ZCC_OpInfo[i].FreeAllProtos();
-		}
-	}
-} ProtoFreeer;
-
-void ZCC_OpInfoType::FreeAllProtos()
-{
-	for (ZCC_OpProto *proto = Protos, *next = NULL; proto != NULL; proto = next)
-	{
-		next = proto->Next;
-		delete proto;
-	}
-	Protos = NULL;
-}
-
-void ZCC_OpInfoType::AddProto(PType *res, PType *optype, EvalConst1op evalconst)
-{
-	ZCC_OpProto *proto = new ZCC_OpProto(res, optype, NULL);
-	proto->EvalConst1 = evalconst;
-	proto->Next = Protos;
-	Protos = proto;
-}
-
-void ZCC_OpInfoType::AddProto(PType *res, PType *ltype, PType *rtype, EvalConst2op evalconst)
-{
-	assert(ltype != NULL);
-	ZCC_OpProto *proto = new ZCC_OpProto(res, ltype, rtype);
-	proto->EvalConst2 = evalconst;
-	proto->Next = Protos;
-	Protos = proto;
-}
-
-//==========================================================================
-//
-// ZCC_OpInfoType :: FindBestProto (Unary)
-//
-// Finds the "best" prototype for this operand type. Best is defined as the
-// one that requires the fewest conversions. Also returns the conversion
-// route necessary to get from the input type to the desired type.
-//
-//==========================================================================
-
-ZCC_OpProto *ZCC_OpInfoType::FindBestProto(PType *optype, const PType::Conversion **route, int &numslots)
-{
-	assert(optype != NULL);
-
-	const PType::Conversion *routes[2][CONVERSION_ROUTE_SIZE];
-	const PType::Conversion **best_route = NULL;
-	int cur_route = 0;
-	ZCC_OpProto *best_proto = NULL;
-	int best_dist = INT_MAX;
-
-	// Find the best prototype.
-	for (ZCC_OpProto *proto = Protos; best_dist != 0 && proto != NULL; proto = proto->Next)
-	{
-		if (proto->Type2 != NULL)
-		{ // Not a unary prototype.
-			continue;
-		}
-		int dist = optype->FindConversion(proto->Type1, routes[cur_route], CONVERSION_ROUTE_SIZE);
-		if (dist >= 0 && dist < best_dist)
-		{
-			best_dist = dist;
-			best_proto = proto;
-			best_route = routes[cur_route];
-			cur_route ^= 1;
-		}
-	}
-	// Copy best conversion route to the caller's array.
-	if (best_route != NULL && route != NULL && numslots > 0)
-	{
-		numslots = MIN(numslots, best_dist);
-		if (numslots > 0)
-		{
-			memcpy(route, best_route, sizeof(*route) * numslots);
-		}
-	}
-	return best_proto;
-}
-
-//==========================================================================
-//
-// ZCC_OpInfoType :: FindBestProto (Binary)
-//
-// Finds the "best" prototype for the given operand types. Here, best is
-// defined as the one that requires the fewest conversions for *one* of the
-// operands. For prototypes with matching distances, the first one found
-// is used. ZCC_InitOperators() initializes the prototypes in order such
-// that this will result in the precedences: double > uint > int
-//
-//==========================================================================
-
-ZCC_OpProto *ZCC_OpInfoType::FindBestProto(
-	PType *left, const PType::Conversion **route1, int &numslots1,
-	PType *right, const PType::Conversion **route2, int &numslots2)
-{
-	assert(left != NULL && right != NULL);
-
-	const PType::Conversion *routes[2][2][CONVERSION_ROUTE_SIZE];
-	const PType::Conversion **best_route1 = NULL, **best_route2 = NULL;
-	int cur_route1 = 0, cur_route2 = 0;
-	int best_dist1 = INT_MAX, best_dist2 = INT_MAX;
-
-	ZCC_OpProto *best_proto = NULL;
-	int best_low_dist = INT_MAX;
-
-	for (ZCC_OpProto *proto = Protos; best_low_dist != 0 && proto != NULL; proto = proto->Next)
-	{
-		if (proto->Type2 == NULL)
-		{ // Not a binary prototype
-			continue;
-		}
-		int dist1 = left->FindConversion(proto->Type1, routes[0][cur_route1], CONVERSION_ROUTE_SIZE);
-		int dist2 = right->FindConversion(proto->Type2, routes[1][cur_route2], CONVERSION_ROUTE_SIZE);
-		if (dist1 < 0 || dist2 < 0)
-		{ // one or both operator types are unreachable
-			continue;
-		}
-		// Do not count F32->F64 conversions in the distance comparisons. If we do, then
-		// [[float32 (op) int]] will choose the integer version instead of the floating point
-		// version, which we do not want.
-		int test_dist1 = dist1, test_dist2 = dist2;
-		if (routes[0][cur_route1][0]->ConvertConstant == FtoD)
-		{
-			test_dist1--;
-		}
-		if (routes[1][cur_route2][0]->ConvertConstant == FtoD)
-		{
-			test_dist2--;
-		}
-		int dist = MIN(test_dist1, test_dist2);
-		if (dist < best_low_dist)
-		{
-			best_low_dist = dist;
-			best_proto = proto;
-			best_dist1 = dist1;
-			best_dist2 = dist2;
-			best_route1 = routes[0][cur_route1];
-			best_route2 = routes[1][cur_route2];
-			cur_route1 ^= 1;
-			cur_route2 ^= 1;
-		}
-	}
-	// Copy best conversion route to the caller's arrays.
-	if (best_route1 != NULL && route1 != NULL && numslots1 > 0)
-	{
-		numslots1 = MIN(numslots1, best_dist1);
-		if (numslots1 > 0)
-		{
-			memcpy(route1, best_route1, sizeof(*route1) * numslots1);
-		}
-	}
-	if (best_route2 != NULL && route2 != NULL && numslots2 > 0)
-	{
-		numslots2 = MIN(numslots2, best_dist2);
-		if (numslots2 > 0)
-		{
-			memcpy(route2, best_route2, sizeof(*route2) * numslots2);
-		}
-	}
-	return best_proto;
-}
-
-static ZCC_ExprConstant *EvalIdentity(ZCC_ExprConstant *val)
-{
-	return val;
-}
-
-
-static ZCC_ExprConstant *EvalConcat(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &strings)
-{
-	FString str = *l->StringVal + *r->StringVal;
-	l->StringVal = strings.Alloc(str);
-	return l;
-}
-
-static ZCC_ExprConstant *EvalLTGTEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
-{
-	l->IntVal = l->IntVal < r->IntVal ? -1 : l->IntVal == r->IntVal ? 0 : 1;
-	return l;
-}
-
-static ZCC_ExprConstant *EvalLTGTEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
-{
-	l->IntVal = l->UIntVal < r->UIntVal ? -1 : l->UIntVal == r->UIntVal ? 0 : 1;
-	l->Type = TypeSInt32;
-	return l;
-}
-
-static ZCC_ExprConstant *EvalLTGTEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
-{
-	l->IntVal = l->DoubleVal < r->DoubleVal ? -1 : l->DoubleVal == r->DoubleVal ? 0 : 1;
-	l->Type = TypeSInt32;
-	return l;
-}
-
-void ZCC_InitOperators()
-{
-	// Prototypes are added from lowest to highest conversion precedence.
-
-	// Unary operators
-	static const OpProto1 UnaryOpInit[] =
-	{
-		{ PEX_PostInc	 , (PType **)&TypeSInt32,  EvalIdentity },
-		{ PEX_PostInc	 , (PType **)&TypeUInt32,  EvalIdentity },
-		{ PEX_PostInc	 , (PType **)&TypeFloat64, EvalIdentity },
-
-		{ PEX_PostDec	 , (PType **)&TypeSInt32,  EvalIdentity },
-		{ PEX_PostDec	 , (PType **)&TypeUInt32,  EvalIdentity },
-		{ PEX_PostDec	 , (PType **)&TypeFloat64, EvalIdentity },
-
-		{ PEX_PreInc	 , (PType **)&TypeSInt32,  [](auto *val) { val->IntVal += 1; return val; } },
-		{ PEX_PreInc	 , (PType **)&TypeUInt32,  [](auto *val) { val->UIntVal += 1; return val; } },
-		{ PEX_PreInc	 , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal += 1; return val; } },
-
-		{ PEX_PreDec	 , (PType **)&TypeSInt32,  [](auto *val) { val->IntVal -= 1; return val; } },
-		{ PEX_PreDec	 , (PType **)&TypeUInt32,  [](auto *val) { val->UIntVal -= 1; return val; } },
-		{ PEX_PreDec	 , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal -= 1; return val; } },
-
-		{ PEX_Negate	 , (PType **)&TypeSInt32,  [](auto *val) { val->IntVal = -val->IntVal; return val; } },
-		{ PEX_Negate	 , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal = -val->DoubleVal; return val; } },
-
-		{ PEX_AntiNegate , (PType **)&TypeSInt32,  EvalIdentity },
-		{ PEX_AntiNegate , (PType **)&TypeUInt32,  EvalIdentity },
-		{ PEX_AntiNegate , (PType **)&TypeFloat64, EvalIdentity },
-
-		{ PEX_BitNot	 , (PType **)&TypeSInt32,  [](auto *val) { val->IntVal = ~val->IntVal; return val; } },
-		{ PEX_BitNot	 , (PType **)&TypeUInt32,  [](auto *val) { val->UIntVal = ~val->UIntVal; return val; } },
-
-		{ PEX_BoolNot	 , (PType **)&TypeBool,    [](auto *val) { val->IntVal = !val->IntVal; return val; } },
-	};
-	for (size_t i = 0; i < countof(UnaryOpInit); ++i)
-	{
-		ZCC_OpInfo[UnaryOpInit[i].Op].AddProto(*UnaryOpInit[i].Type, *UnaryOpInit[i].Type, UnaryOpInit[i].EvalConst);
-	}
-
-	// Binary operators
-	static const OpProto2 BinaryOpInit[] =
-	{
-		{ PEX_Add		 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal += r->IntVal; return l; } },
-		{ PEX_Add		 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal += r->UIntVal; return l; } },
-		{ PEX_Add		 , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal += r->DoubleVal; return l; } },
-
-		{ PEX_Sub		 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal -= r->IntVal; return l; } },
-		{ PEX_Sub		 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal -= r->UIntVal; return l; } },
-		{ PEX_Sub		 , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal -= r->DoubleVal; return l; } },
-
-		{ PEX_Mul		 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal *= r->IntVal; return l; } },
-		{ PEX_Mul		 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal *= r->UIntVal; return l; } },
-		{ PEX_Mul		 , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal *= r->DoubleVal; return l; } },
-
-		{ PEX_Div		 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal /= r->IntVal; return l; } },
-		{ PEX_Div		 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal /= r->UIntVal; return l; } },
-		{ PEX_Div		 , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal /= r->DoubleVal; return l; } },
-
-		{ PEX_Mod		 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal %= r->IntVal; return l; } },
-		{ PEX_Mod		 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal %= r->UIntVal; return l; } },
-		{ PEX_Mod		 , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = luai_nummod(l->DoubleVal, r->DoubleVal); return l; } },
-
-		{ PEX_Pow		 , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = pow(l->DoubleVal, r->DoubleVal); return l; } },
-
-		{ PEX_Concat	 , (PType **)&TypeString,  (PType **)&TypeString,  (PType **)&TypeString,  EvalConcat },
-
-		{ PEX_BitAnd	 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal &= r->IntVal; return l; } },
-		{ PEX_BitAnd	 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal &= r->UIntVal; return l; } },
-
-		{ PEX_BitOr		 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal |= r->IntVal; return l; } },
-		{ PEX_BitOr		 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal |= r->UIntVal; return l; } },
-
-		{ PEX_BitXor	 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal ^= r->IntVal; return l; } },
-		{ PEX_BitXor	 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal ^= r->UIntVal; return l; } },
-
-		{ PEX_BoolAnd	 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal && r->IntVal; l->Type = TypeBool; return l; } },
-		{ PEX_BoolAnd	 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal && r->UIntVal; l->Type = TypeBool; return l;  } },
-
-		{ PEX_BoolOr	 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal || r->IntVal; l->Type = TypeBool; return l; } },
-		{ PEX_BoolOr	 , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal || r->UIntVal; l->Type = TypeBool; return l; } },
-
-		{ PEX_LeftShift  , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->IntVal <<= r->UIntVal; return l; } },
-		{ PEX_LeftShift  , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal <<= r->UIntVal; return l; } },
-
-		{ PEX_RightShift , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->IntVal >>= r->UIntVal; return l; } },
-		{ PEX_RightShift , (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->UIntVal >>= r->UIntVal; return l; } },
-
-		{ PEX_LT		 , (PType **)&TypeBool,    (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal < r->IntVal; l->Type = TypeBool; return l; } },
-		{ PEX_LT		 , (PType **)&TypeBool,    (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal < r->UIntVal; l->Type = TypeBool; return l; } },
-		{ PEX_LT		 , (PType **)&TypeBool,    (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal < r->DoubleVal; l->Type = TypeBool; return l; } },
-
-		{ PEX_LTEQ		 , (PType **)&TypeBool,    (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal <= r->IntVal; l->Type = TypeBool; return l; } },
-		{ PEX_LTEQ		 , (PType **)&TypeBool,    (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal <= r->UIntVal; l->Type = TypeBool; return l; } },
-		{ PEX_LTEQ		 , (PType **)&TypeBool,    (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal <= r->DoubleVal; l->Type = TypeBool; return l; } },
-
-		{ PEX_EQEQ		 , (PType **)&TypeBool,    (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal == r->IntVal; l->Type = TypeBool; return l; } },
-		{ PEX_EQEQ		 , (PType **)&TypeBool,    (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal == r->UIntVal; l->Type = TypeBool; return l; } },
-		{ PEX_EQEQ		 , (PType **)&TypeBool,    (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal == r->DoubleVal; l->Type = TypeBool; return l; } },
-
-		{ PEX_LTGTEQ	 , (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  (PType **)&TypeSInt32,  EvalLTGTEQSInt32 },
-		{ PEX_LTGTEQ	 , (PType **)&TypeSInt32,  (PType **)&TypeUInt32,  (PType **)&TypeUInt32,  EvalLTGTEQUInt32 },
-		{ PEX_LTGTEQ	 , (PType **)&TypeSInt32,  (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTGTEQFloat64 },
-	};
-	for (size_t i = 0; i < countof(BinaryOpInit); ++i)
-	{
-		ZCC_OpInfo[BinaryOpInit[i].Op].AddProto(*BinaryOpInit[i].Res, *BinaryOpInit[i].Ltype, *BinaryOpInit[i].Rtype, BinaryOpInit[i].EvalConst);
-	}
-}
-
-static void IntToS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	// Integers always fill out the full sized 32-bit field, so converting
-	// from a smaller sized integer to a 32-bit one is as simple as changing
-	// the type field.
-	expr->Type = TypeSInt32;
-}
-
-static void S32toS8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	expr->IntVal = ((expr->IntVal << 24) >> 24);
-	expr->Type = TypeSInt8;
-}
-
-static void S32toS16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	expr->IntVal = ((expr->IntVal << 16) >> 16);
-	expr->Type = TypeSInt16;
-}
-
-static void S32toU8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	expr->IntVal &= 0xFF;
-	expr->Type = TypeUInt8;
-}
-
-static void S32toU16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	expr->IntVal &= 0xFFFF;
-	expr->Type = TypeUInt16;
-}
-
-static void S32toU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	expr->Type = TypeUInt32;
-}
-
-static void S32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	expr->DoubleVal = expr->IntVal;
-	expr->Type = TypeFloat64;
-}
-
-static void DtoS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	expr->IntVal = (int)expr->DoubleVal;
-	expr->Type = TypeSInt32;
-}
-
-static void U32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	expr->DoubleVal = expr->UIntVal;
-	expr->Type = TypeFloat64;
-}
-
-static void DtoU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	expr->UIntVal = (unsigned int)expr->DoubleVal;
-	expr->Type = TypeUInt32;
-}
-
-static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	// Constant single precision numbers are stored as doubles.
-	assert(expr->Type == TypeFloat32);
-	expr->Type = TypeFloat64;
-}
-
-static void DtoF(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	// Truncate double precision to single precision.
-	float poop = (float)expr->DoubleVal;
-	expr->DoubleVal = poop;
-	expr->Type = TypeFloat32;
-}
-
-static void S32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	char str[16];
-	int len = mysnprintf(str, countof(str), "%i", expr->IntVal);
-	expr->StringVal = str_arena.Alloc(str, len);
-	expr->Type = TypeString;
-}
-
-static void U32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	char str[16];
-	int len = mysnprintf(str, countof(str), "%u", expr->UIntVal);
-	expr->StringVal = str_arena.Alloc(str, len);
-	expr->Type = TypeString;
-}
-
-static void DtoS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
-{
-	// Convert to a string with enough precision such that converting
-	// back to a double will not lose any data.
-	char str[64];
-	IGNORE_FORMAT_PRE
-	int len = mysnprintf(str, countof(str), "%H", expr->DoubleVal);
-	IGNORE_FORMAT_POST
-	expr->StringVal = str_arena.Alloc(str, len);
-	expr->Type = TypeString;
-}
-
-//==========================================================================
-//
-// ZCC_InitConversions
-//
-//==========================================================================
-
-void ZCC_InitConversions()
-{
-	TypeUInt8->AddConversion(TypeSInt32, IntToS32);
-	TypeSInt8->AddConversion(TypeSInt32, IntToS32);
-	TypeUInt16->AddConversion(TypeSInt32, IntToS32);
-	TypeSInt16->AddConversion(TypeSInt32, IntToS32);
-
-	TypeUInt32->AddConversion(TypeSInt32, IntToS32);
-	TypeUInt32->AddConversion(TypeFloat64, U32toD);
-	TypeUInt32->AddConversion(TypeString, U32toS);
-
-	TypeSInt32->AddConversion(TypeUInt8, S32toU8);
-	TypeSInt32->AddConversion(TypeSInt8, S32toS8);
-	TypeSInt32->AddConversion(TypeSInt16, S32toS16);
-	TypeSInt32->AddConversion(TypeUInt16, S32toU16);
-	TypeSInt32->AddConversion(TypeUInt32, S32toU32);
-	TypeSInt32->AddConversion(TypeFloat64, S32toD);
-	TypeSInt32->AddConversion(TypeString, S32toS);
-
-	TypeFloat32->AddConversion(TypeFloat64, FtoD);
-
-	TypeFloat64->AddConversion(TypeUInt32, DtoU32);
-	TypeFloat64->AddConversion(TypeSInt32, DtoS32);
-	TypeFloat64->AddConversion(TypeFloat32, DtoF);
-	TypeFloat64->AddConversion(TypeString, DtoS);
-}
--- src/zscript/zcc_exprlist.h
+++ src/zscript/zcc_exprlist.h
@@ -1,57 +0,0 @@
-// Name				n-ary
-xx(Nil,				)
-
-xx(ID,				)
-xx(Super,			)
-xx(Self,			)
-xx(ConstValue,		)
-xx(FuncCall,		)
-xx(ArrayAccess,		)
-xx(MemberAccess,	)
-xx(TypeRef,			)
-
-xx(PostInc,			)
-xx(PostDec,			)
-
-xx(PreInc,			)
-xx(PreDec,			)
-xx(Negate,			)
-xx(AntiNegate,		)
-xx(BitNot,			)
-xx(BoolNot,			)
-xx(SizeOf,			)
-xx(AlignOf,			)
-
-xx(Add,				)
-xx(Sub,				)
-xx(Mul,				)
-xx(Div,				)
-xx(Mod,				)
-xx(Pow,				)
-xx(CrossProduct,	)
-xx(DotProduct,		)
-xx(LeftShift,		)
-xx(RightShift,		)
-xx(Concat,			)
-
-xx(LT,				)
-xx(LTEQ,			)
-xx(LTGTEQ,			)
-xx(Is,				)
-
-xx(EQEQ,			)
-xx(APREQ,			)
-
-xx(BitAnd,			)
-xx(BitOr,			)
-xx(BitXor,			)
-xx(BoolAnd,			)
-xx(BoolOr,			)
-
-xx(Scope,			)
-
-xx(Trinary,			)
-
-xx(Cast,			)
-
-#undef xx
--- src/zscript/zcc_parser.cpp
+++ src/zscript/zcc_parser.cpp
@@ -1,338 +0,0 @@
-#include "dobject.h"
-#include "sc_man.h"
-#include "c_console.h"
-#include "c_dispatch.h"
-#include "w_wad.h"
-#include "cmdlib.h"
-#include "m_alloc.h"
-#include "zcc_parser.h"
-#include "zcc_compile.h"
-
-static FString ZCCTokenName(int terminal);
-
-#include "zcc-parse.h"
-#include "zcc-parse.c"
-
-struct TokenMapEntry
-{
-	SWORD TokenType;
-	WORD TokenName;
-	TokenMapEntry(SWORD a, WORD b)
-	: TokenType(a), TokenName(b)
-	{ }
-};
-static TMap<SWORD, TokenMapEntry> TokenMap;
-static SWORD BackTokenMap[YYERRORSYMBOL];	// YYERRORSYMBOL immediately follows the terminals described by the grammar
-
-#define TOKENDEF2(sc, zcc, name)	{ TokenMapEntry tme(zcc, name); TokenMap.Insert(sc, tme); } BackTokenMap[zcc] = sc
-#define TOKENDEF(sc, zcc)			TOKENDEF2(sc, zcc, NAME_None)
-
-static void InitTokenMap()
-{
-	TOKENDEF ('=',				ZCC_EQ);
-	TOKENDEF (TK_MulEq,			ZCC_MULEQ);
-	TOKENDEF (TK_DivEq,			ZCC_DIVEQ);
-	TOKENDEF (TK_ModEq,			ZCC_MODEQ);
-	TOKENDEF (TK_AddEq,			ZCC_ADDEQ);
-	TOKENDEF (TK_SubEq,			ZCC_SUBEQ);
-	TOKENDEF (TK_LShiftEq,		ZCC_LSHEQ);
-	TOKENDEF (TK_RShiftEq,		ZCC_RSHEQ);
-	TOKENDEF (TK_AndEq,			ZCC_ANDEQ);
-	TOKENDEF (TK_OrEq,			ZCC_OREQ);
-	TOKENDEF (TK_XorEq,			ZCC_XOREQ);
-	TOKENDEF ('?',				ZCC_QUESTION);
-	TOKENDEF (':',				ZCC_COLON);
-	TOKENDEF (TK_OrOr,			ZCC_OROR);
-	TOKENDEF (TK_AndAnd,		ZCC_ANDAND);
-	TOKENDEF (TK_Eq,			ZCC_EQEQ);
-	TOKENDEF (TK_Neq,			ZCC_NEQ);
-	TOKENDEF (TK_ApproxEq,		ZCC_APPROXEQ);
-	TOKENDEF ('<',				ZCC_LT);
-	TOKENDEF ('>',				ZCC_GT);
-	TOKENDEF (TK_Leq,			ZCC_LTEQ);
-	TOKENDEF (TK_Geq,			ZCC_GTEQ);
-	TOKENDEF (TK_LtGtEq,		ZCC_LTGTEQ);
-	TOKENDEF (TK_Is,			ZCC_IS);
-	TOKENDEF (TK_DotDot,		ZCC_DOTDOT);
-	TOKENDEF ('|',				ZCC_OR);
-	TOKENDEF ('^',				ZCC_XOR);
-	TOKENDEF ('&',				ZCC_AND);
-	TOKENDEF (TK_LShift,		ZCC_LSH);
-	TOKENDEF (TK_RShift,		ZCC_RSH);
-	TOKENDEF ('-',				ZCC_SUB);
-	TOKENDEF ('+',				ZCC_ADD);
-	TOKENDEF ('*',				ZCC_MUL);
-	TOKENDEF ('/',				ZCC_DIV);
-	TOKENDEF ('%',				ZCC_MOD);
-	TOKENDEF (TK_Cross,			ZCC_CROSSPROD);
-	TOKENDEF (TK_Dot,			ZCC_DOTPROD);
-	TOKENDEF (TK_MulMul,		ZCC_POW);
-	TOKENDEF (TK_Incr,			ZCC_ADDADD);
-	TOKENDEF (TK_Decr,			ZCC_SUBSUB);
-	TOKENDEF ('.',				ZCC_DOT);
-	TOKENDEF ('(',				ZCC_LPAREN);
-	TOKENDEF (')',				ZCC_RPAREN);
-	TOKENDEF (TK_ColonColon,	ZCC_SCOPE);
-	TOKENDEF (';',				ZCC_SEMICOLON);
-	TOKENDEF (',',				ZCC_COMMA);
-	TOKENDEF (TK_Class,			ZCC_CLASS);
-	TOKENDEF (TK_Abstract,		ZCC_ABSTRACT);
-	TOKENDEF (TK_Native,		ZCC_NATIVE);
-	TOKENDEF (TK_Replaces,		ZCC_REPLACES);
-	TOKENDEF (TK_Static,		ZCC_STATIC);
-	TOKENDEF (TK_Private,		ZCC_PRIVATE);
-	TOKENDEF (TK_Protected,		ZCC_PROTECTED);
-	TOKENDEF (TK_Latent,		ZCC_LATENT);
-	TOKENDEF (TK_Final,			ZCC_FINAL);
-	TOKENDEF (TK_Meta,			ZCC_META);
-	TOKENDEF (TK_Deprecated,	ZCC_DEPRECATED);
-	TOKENDEF (TK_ReadOnly,		ZCC_READONLY);
-	TOKENDEF ('{',				ZCC_LBRACE);
-	TOKENDEF ('}',				ZCC_RBRACE);
-	TOKENDEF (TK_Struct,		ZCC_STRUCT);
-	TOKENDEF (TK_Enum,			ZCC_ENUM);
-	TOKENDEF2(TK_SByte,			ZCC_SBYTE,		NAME_sByte);
-	TOKENDEF2(TK_Byte,			ZCC_BYTE,		NAME_Byte);
-	TOKENDEF2(TK_Short,			ZCC_SHORT,		NAME_Short);
-	TOKENDEF2(TK_UShort,		ZCC_USHORT,		NAME_uShort);
-	TOKENDEF2(TK_Int,			ZCC_INT,		NAME_Int);
-	TOKENDEF2(TK_UInt,			ZCC_UINT,		NAME_uInt);
-	TOKENDEF2(TK_Bool,			ZCC_BOOL,		NAME_Bool);
-	TOKENDEF2(TK_Float,			ZCC_FLOAT,		NAME_Float);
-	TOKENDEF2(TK_Double,		ZCC_DOUBLE,		NAME_Double);
-	TOKENDEF2(TK_String,		ZCC_STRING,		NAME_String);
-	TOKENDEF2(TK_Vector,		ZCC_VECTOR,		NAME_Vector);
-	TOKENDEF2(TK_Name,			ZCC_NAME,		NAME_Name);
-	TOKENDEF2(TK_Map,			ZCC_MAP,		NAME_Map);
-	TOKENDEF2(TK_Array,			ZCC_ARRAY,		NAME_Array);
-	TOKENDEF (TK_Void,			ZCC_VOID);
-	TOKENDEF (TK_True,			ZCC_TRUE);
-	TOKENDEF (TK_False,			ZCC_FALSE);
-	TOKENDEF ('[',				ZCC_LBRACKET);
-	TOKENDEF (']',				ZCC_RBRACKET);
-	TOKENDEF (TK_In,			ZCC_IN);
-	TOKENDEF (TK_Out,			ZCC_OUT);
-	TOKENDEF (TK_Optional,		ZCC_OPTIONAL);
-	TOKENDEF (TK_Super,			ZCC_SUPER);
-	TOKENDEF (TK_Self,			ZCC_SELF);
-	TOKENDEF ('~',				ZCC_TILDE);
-	TOKENDEF ('!',				ZCC_BANG);
-	TOKENDEF (TK_SizeOf,		ZCC_SIZEOF);
-	TOKENDEF (TK_AlignOf,		ZCC_ALIGNOF);
-	TOKENDEF (TK_Continue,		ZCC_CONTINUE);
-	TOKENDEF (TK_Break,			ZCC_BREAK);
-	TOKENDEF (TK_Return,		ZCC_RETURN);
-	TOKENDEF (TK_Do,			ZCC_DO);
-	TOKENDEF (TK_For,			ZCC_FOR);
-	TOKENDEF (TK_While,			ZCC_WHILE);
-	TOKENDEF (TK_Until,			ZCC_UNTIL);
-	TOKENDEF (TK_If,			ZCC_IF);
-	TOKENDEF (TK_Else,			ZCC_ELSE);
-	TOKENDEF (TK_Switch,		ZCC_SWITCH);
-	TOKENDEF (TK_Case,			ZCC_CASE);
-	TOKENDEF2(TK_Default,		ZCC_DEFAULT,	NAME_Default);
-	TOKENDEF (TK_Const,			ZCC_CONST);
-	TOKENDEF (TK_Stop,			ZCC_STOP);
-	TOKENDEF (TK_Wait,			ZCC_WAIT);
-	TOKENDEF (TK_Fail,			ZCC_FAIL);
-	TOKENDEF (TK_Loop,			ZCC_LOOP);
-	TOKENDEF (TK_Goto,			ZCC_GOTO);
-	TOKENDEF (TK_States,		ZCC_STATES);
-
-	TOKENDEF (TK_Identifier,	ZCC_IDENTIFIER);
-	TOKENDEF (TK_StringConst,	ZCC_STRCONST);
-	TOKENDEF (TK_NameConst,		ZCC_NAMECONST);
-	TOKENDEF (TK_IntConst,		ZCC_INTCONST);
-	TOKENDEF (TK_UIntConst,		ZCC_UINTCONST);
-	TOKENDEF (TK_FloatConst,	ZCC_FLOATCONST);
-	TOKENDEF (TK_NonWhitespace,	ZCC_NWS);
-
-	TOKENDEF (TK_Bright,		ZCC_BRIGHT);
-	TOKENDEF (TK_Slow,			ZCC_SLOW);
-	TOKENDEF (TK_Fast,			ZCC_FAST);
-	TOKENDEF (TK_NoDelay,		ZCC_NODELAY);
-	TOKENDEF (TK_Offset,		ZCC_OFFSET);
-	TOKENDEF (TK_CanRaise,		ZCC_CANRAISE);
-	TOKENDEF (TK_Light,			ZCC_CANRAISE);
-
-	ZCC_InitOperators();
-	ZCC_InitConversions();
-}
-#undef TOKENDEF
-#undef TOKENDEF2
-
-static void DoParse(const char *filename)
-{
-	if (TokenMap.CountUsed() == 0)
-	{
-		InitTokenMap();
-	}
-
-	FScanner sc;
-	void *parser;
-	int tokentype;
-	int lump;
-	bool failed;
-	ZCCToken value;
-
-	lump = Wads.CheckNumForFullName(filename, true);
-	if (lump >= 0)
-	{
-		sc.OpenLumpNum(lump);
-	}
-	else if (FileExists(filename))
-	{
-		sc.OpenFile(filename);
-	}
-	else
-	{
-		Printf("Could not find script lump '%s'\n", filename);
-		return;
-	}
-	
-	parser = ZCCParseAlloc(malloc);
-	failed = false;
-#ifdef _DEBUG
-	FILE *f = fopen("trace.txt", "w");
-	char prompt = '\0';
-	ZCCParseTrace(f, &prompt);
-#endif
-	ZCCParseState state(sc);
-
-	while (sc.GetToken())
-	{
-		value.SourceLoc = sc.GetMessageLine();
-		switch (sc.TokenType)
-		{
-		case TK_StringConst:
-			value.String = state.Strings.Alloc(sc.String, sc.StringLen);
-			tokentype = ZCC_STRCONST;
-			break;
-
-		case TK_NameConst:
-			value.Int = sc.Name;
-			tokentype = ZCC_NAMECONST;
-			break;
-
-		case TK_IntConst:
-			value.Int = sc.Number;
-			tokentype = ZCC_INTCONST;
-			break;
-
-		case TK_UIntConst:
-			value.Int = sc.Number;
-			tokentype = ZCC_UINTCONST;
-			break;
-
-		case TK_FloatConst:
-			value.Float = sc.Float;
-			tokentype = ZCC_FLOATCONST;
-			break;
-
-		case TK_Identifier:
-			value.Int = FName(sc.String);
-			tokentype = ZCC_IDENTIFIER;
-			break;
-
-		case TK_NonWhitespace:
-			value.Int = FName(sc.String);
-			tokentype = ZCC_NWS;
-			break;
-
-		default:
-			TokenMapEntry *zcctoken = TokenMap.CheckKey(sc.TokenType);
-			if (zcctoken != NULL)
-			{
-				tokentype = zcctoken->TokenType;
-				value.Int = zcctoken->TokenName;
-			}
-			else
-			{
-				sc.ScriptMessage("Unexpected token %s.\n", sc.TokenName(sc.TokenType).GetChars());
-				goto parse_end;
-			}
-			break;
-		}
-		ZCCParse(parser, tokentype, value, &state);
-		if (failed)
-		{
-			sc.ScriptMessage("Parse failed\n");
-			goto parse_end;
-		}
-	}
-parse_end:
-	value.Int = -1;
-	ZCCParse(parser, ZCC_EOF, value, &state);
-	ZCCParse(parser, 0, value, &state);
-	ZCCParseFree(parser, free);
-
-	PSymbolTable symbols(&GlobalSymbols);
-	ZCCCompiler cc(state, NULL, symbols);
-	cc.Compile();
-#ifdef _DEBUG
-	if (f != NULL)
-	{
-		fclose(f);
-	}
-	FString ast = ZCC_PrintAST(state.TopNode);
-	FString astfile = ExtractFileBase(filename, false);
-	astfile << ".ast";
-	f = fopen(astfile, "w");
-	if (f != NULL)
-	{
-		fputs(ast.GetChars(), f);
-		fclose(f);
-	}
-#endif
-}
-
-CCMD(parse)
-{
-	if (argv.argc() == 2)
-	{
-		DoParse(argv[1]);
-	}
-}
-
-static FString ZCCTokenName(int terminal)
-{
-	if (terminal == ZCC_EOF)
-	{
-		return "end of file";
-	}
-	int sc_token;
-	if (terminal > 0 && terminal < (int)countof(BackTokenMap))
-	{
-		sc_token = BackTokenMap[terminal];
-		if (sc_token == 0)
-		{ // This token was not initialized. Whoops!
-			sc_token = -terminal;
-		}
-	}
-	else
-	{ // This should never happen.
-		sc_token = -terminal;
-	}
-	return FScanner::TokenName(sc_token);
-}
-
-ZCC_TreeNode *ZCC_AST::InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode *basis)
-{
-	ZCC_TreeNode *node = (ZCC_TreeNode *)SyntaxArena.Alloc(size);
-	node->SiblingNext = node;
-	node->SiblingPrev = node;
-	node->NodeType = type;
-	if (basis != NULL)
-	{
-		node->SourceName = basis->SourceName;
-		node->SourceLoc = basis->SourceLoc;
-	}
-	return node;
-}
-
-ZCC_TreeNode *ZCCParseState::InitNode(size_t size, EZCCTreeNodeType type)
-{
-	ZCC_TreeNode *node = ZCC_AST::InitNode(size, type, NULL);
-	node->SourceName = Strings.Alloc(sc.ScriptName);
-	return node;
-}
--- src/zscript/zcc_parser.h
+++ src/zscript/zcc_parser.h
@@ -1,523 +0,0 @@
-#ifndef ZCC_PARSER_H
-#define ZCC_PARSER_H
-
-#include "memarena.h"
-
-struct ZCCToken
-{
-	union
-	{
-		int Int;
-		double Float;
-		FString *String;
-	};
-	int SourceLoc;
-
-	ENamedName Name() { return ENamedName(Int); }
-};
-
-// Variable / Function modifiers
-enum
-{
-	ZCC_Native			= 1 << 0,
-	ZCC_Static			= 1 << 1,
-	ZCC_Private			= 1 << 2,
-	ZCC_Protected		= 1 << 3,
-	ZCC_Latent			= 1 << 4,
-	ZCC_Final			= 1 << 5,
-	ZCC_Meta			= 1 << 6,
-	ZCC_Action			= 1 << 7,
-	ZCC_Deprecated		= 1 << 8,
-	ZCC_ReadOnly		= 1 << 9,
-	ZCC_FuncConst		= 1 << 10,
-};
-
-// Function parameter modifiers
-enum
-{
-	ZCC_In				= 1 << 0,
-	ZCC_Out				= 1 << 1,
-	ZCC_Optional		= 1 << 2,
-};
-
-
-
-// Syntax tree structures.
-enum EZCCTreeNodeType
-{
-	AST_Identifier,
-	AST_Class,
-	AST_Struct,
-	AST_Enum,
-	AST_EnumTerminator,
-	AST_States,
-	AST_StatePart,
-	AST_StateLabel,
-	AST_StateStop,
-	AST_StateWait,
-	AST_StateFail,
-	AST_StateLoop,
-	AST_StateGoto,
-	AST_StateLine,
-	AST_VarName,
-	AST_Type,
-	AST_BasicType,
-	AST_MapType,
-	AST_DynArrayType,
-	AST_ClassType,
-	AST_Expression,
-	AST_ExprID,
-	AST_ExprTypeRef,
-	AST_ExprConstant,
-	AST_ExprFuncCall,
-	AST_ExprMemberAccess,
-	AST_ExprUnary,
-	AST_ExprBinary,
-	AST_ExprTrinary,
-	AST_FuncParm,
-	AST_Statement,
-	AST_CompoundStmt,
-	AST_ContinueStmt,
-	AST_BreakStmt,
-	AST_ReturnStmt,
-	AST_ExpressionStmt,
-	AST_IterationStmt,
-	AST_IfStmt,
-	AST_SwitchStmt,
-	AST_CaseStmt,
-	AST_AssignStmt,
-	AST_LocalVarStmt,
-	AST_FuncParamDecl,
-	AST_ConstantDef,
-	AST_Declarator,
-	AST_VarDeclarator,
-	AST_FuncDeclarator,
-
-	NUM_AST_NODE_TYPES
-};
-
-enum EZCCBuiltinType
-{
-	ZCC_SInt8,
-	ZCC_UInt8,
-	ZCC_SInt16,
-	ZCC_UInt16,
-	ZCC_SInt32,
-	ZCC_UInt32,
-	ZCC_IntAuto,	// for enums, autoselect appropriately sized int
-
-	ZCC_Bool,
-	ZCC_Float32,
-	ZCC_Float64,
-	ZCC_FloatAuto,	// 32-bit in structs/classes, 64-bit everywhere else
-	ZCC_String,
-	ZCC_Vector2,
-	ZCC_Vector3,
-	ZCC_Vector4,
-	ZCC_Name,
-	ZCC_UserType,
-
-	ZCC_NUM_BUILT_IN_TYPES
-};
-
-enum EZCCExprType
-{
-#define xx(a,z)	PEX_##a,
-#include "zcc_exprlist.h"
-
-	PEX_COUNT_OF
-};
-
-struct ZCC_TreeNode
-{
-	// This tree node's siblings are stored in a circular linked list.
-	// When you get back to this node, you know you've been through
-	// the whole list.
-	ZCC_TreeNode *SiblingNext;
-	ZCC_TreeNode *SiblingPrev;
-
-	// can't use FScriptPosition, because the string wouldn't have a chance to
-	// destruct if we did that.
-	FString *SourceName;
-	int SourceLoc;
-
-	// Node type is one of the node types above, which corresponds with
-	// one of the structures below.
-	EZCCTreeNodeType NodeType;
-
-	// Appends a sibling to this node's sibling list.
-	void AppendSibling(ZCC_TreeNode *sibling)
-	{
-		if (sibling == NULL)
-		{
-			return;
-		}
-
-		// Check integrity of our sibling list.
-		assert(SiblingPrev->SiblingNext == this);
-		assert(SiblingNext->SiblingPrev == this);
-
-		// Check integrity of new sibling list.
-		assert(sibling->SiblingPrev->SiblingNext == sibling);
-		assert(sibling->SiblingNext->SiblingPrev == sibling);
-
-		ZCC_TreeNode *siblingend = sibling->SiblingPrev;
-		SiblingPrev->SiblingNext = sibling;
-		sibling->SiblingPrev = SiblingPrev;
-		SiblingPrev = siblingend;
-		siblingend->SiblingNext = this;
-	}
-};
-
-struct ZCC_Identifier : ZCC_TreeNode
-{
-	ENamedName Id;
-};
-
-struct ZCC_NamedNode : ZCC_TreeNode
-{
-	ENamedName NodeName;
-};
-
-struct ZCC_Class : ZCC_NamedNode
-{
-	ZCC_Identifier *ParentName;
-	ZCC_Identifier *Replaces;
-	VM_UWORD Flags;
-	ZCC_TreeNode *Body;
-};
-
-struct ZCC_Struct : ZCC_NamedNode
-{
-	ZCC_TreeNode *Body;
-};
-
-struct ZCC_Enum : ZCC_NamedNode
-{
-	EZCCBuiltinType EnumType;
-	struct ZCC_ConstantDef *Elements;
-};
-
-struct ZCC_EnumTerminator : ZCC_TreeNode
-{
-};
-
-struct ZCC_States : ZCC_TreeNode
-{
-	struct ZCC_StatePart *Body;
-};
-
-struct ZCC_StatePart : ZCC_TreeNode
-{
-};
-
-struct ZCC_StateLabel : ZCC_StatePart
-{
-	ENamedName Label;
-};
-
-struct ZCC_StateStop : ZCC_StatePart
-{
-};
-
-struct ZCC_StateWait : ZCC_StatePart
-{
-};
-
-struct ZCC_StateFail : ZCC_StatePart
-{
-};
-
-struct ZCC_StateLoop : ZCC_StatePart
-{
-};
-
-struct ZCC_Expression : ZCC_TreeNode
-{
-	EZCCExprType Operation;
-	PType *Type;
-
-	// Repurposes this node as an error node
-	void ToErrorNode()
-	{
-		Type = TypeError;
-		Operation = PEX_Nil;
-		NodeType = AST_Expression;
-	}
-};
-
-struct ZCC_StateGoto : ZCC_StatePart
-{
-	ZCC_Identifier *Label;
-	ZCC_Expression *Offset;
-};
-
-struct ZCC_StateLine : ZCC_StatePart
-{
-	char Sprite[4];
-	BITFIELD bBright : 1;
-	BITFIELD bFast : 1;
-	BITFIELD bSlow : 1;
-	BITFIELD bNoDelay : 1;
-	BITFIELD bCanRaise : 1;
-	FString *Frames;
-	ZCC_Expression *Offset;
-	ZCC_TreeNode *Action;
-};
-
-struct ZCC_VarName : ZCC_TreeNode
-{
-	ENamedName Name;
-	ZCC_Expression *ArraySize;	// NULL if not an array
-};
-
-struct ZCC_Type : ZCC_TreeNode
-{
-	ZCC_Expression *ArraySize;	// NULL if not an array
-};
-
-struct ZCC_BasicType : ZCC_Type
-{
-	EZCCBuiltinType	Type;
-	ZCC_Identifier *UserType;
-};
-
-struct ZCC_MapType : ZCC_Type
-{
-	ZCC_Type *KeyType;
-	ZCC_Type *ValueType;
-};
-
-struct ZCC_DynArrayType : ZCC_Type
-{
-	ZCC_Type *ElementType;
-};
-
-struct ZCC_ClassType : ZCC_Type
-{
-	ZCC_Identifier *Restriction;
-};
-
-struct ZCC_ExprID : ZCC_Expression
-{
-	ENamedName Identifier;
-};
-
-struct ZCC_ExprTypeRef : ZCC_Expression
-{
-	PType *RefType;
-};
-
-struct ZCC_ExprConstant : ZCC_Expression
-{
-	union
-	{
-		FString *StringVal;
-		int IntVal;
-		unsigned int UIntVal;
-		double DoubleVal;
-	};
-};
-
-struct ZCC_FuncParm : ZCC_TreeNode
-{
-	ZCC_Expression *Value;
-	ENamedName Label;
-};
-
-struct ZCC_ExprFuncCall : ZCC_Expression
-{
-	ZCC_Expression *Function;
-	ZCC_FuncParm *Parameters;
-};
-
-struct ZCC_ExprMemberAccess : ZCC_Expression
-{
-	ZCC_Expression *Left;
-	ENamedName Right;
-};
-
-struct ZCC_ExprUnary : ZCC_Expression
-{
-	ZCC_Expression *Operand;
-};
-
-struct ZCC_ExprBinary : ZCC_Expression
-{
-	ZCC_Expression *Left;
-	ZCC_Expression *Right;
-};
-
-struct ZCC_ExprTrinary : ZCC_Expression
-{
-	ZCC_Expression *Test;
-	ZCC_Expression *Left;
-	ZCC_Expression *Right;
-};
-
-struct ZCC_Statement : ZCC_TreeNode
-{
-};
-
-struct ZCC_CompoundStmt : ZCC_Statement
-{
-	ZCC_Statement *Content;
-};
-
-struct ZCC_ContinueStmt : ZCC_Statement
-{
-};
-
-struct ZCC_BreakStmt : ZCC_Statement
-{
-};
-
-struct ZCC_ReturnStmt : ZCC_Statement
-{
-	ZCC_Expression *Values;
-};
-
-struct ZCC_ExpressionStmt : ZCC_Statement
-{
-	ZCC_Expression *Expression;
-};
-
-struct ZCC_IterationStmt : ZCC_Statement
-{
-	ZCC_Expression *LoopCondition;
-	ZCC_Statement *LoopStatement;
-	ZCC_Statement *LoopBumper;
-
-	// Should the loop condition be checked at the
-	// start of the loop (before the LoopStatement)
-	// or at the end (after the LoopStatement)?
-	enum { Start, End } CheckAt;
-};
-
-struct ZCC_IfStmt : ZCC_Statement
-{
-	ZCC_Expression *Condition;
-	ZCC_Statement *TruePath;
-	ZCC_Statement *FalsePath;
-};
-
-struct ZCC_SwitchStmt : ZCC_Statement
-{
-	ZCC_Expression *Condition;
-	ZCC_Statement *Content;
-};
-
-struct ZCC_CaseStmt : ZCC_Statement
-{
-	// A NULL Condition represents the default branch
-	ZCC_Expression *Condition;
-};
-
-struct ZCC_AssignStmt : ZCC_Statement
-{
-	ZCC_Expression *Dests;
-	ZCC_Expression *Sources;
-	int AssignOp;
-};
-
-struct ZCC_LocalVarStmt : ZCC_Statement
-{
-	ZCC_Type *Type;
-	ZCC_VarName *Vars;
-	ZCC_Expression *Inits;
-};
-
-struct ZCC_FuncParamDecl : ZCC_TreeNode
-{
-	ZCC_Type *Type;
-	ENamedName Name;
-	int Flags;
-};
-
-struct ZCC_ConstantDef : ZCC_NamedNode
-{
-	ZCC_Expression *Value;
-	PSymbolConst *Symbol;
-};
-
-struct ZCC_Declarator : ZCC_TreeNode
-{
-	ZCC_Type *Type;
-	int Flags;
-};
-
-// A variable in a class or struct.
-struct ZCC_VarDeclarator : ZCC_Declarator
-{
-	ZCC_VarName *Names;
-};
-
-// A function in a class.
-struct ZCC_FuncDeclarator : ZCC_Declarator
-{
-	ZCC_FuncParamDecl *Params;
-	ENamedName Name;
-	ZCC_Statement *Body;
-};
-
-typedef ZCC_ExprConstant *(*EvalConst1op)(ZCC_ExprConstant *);
-typedef ZCC_ExprConstant *(*EvalConst2op)(ZCC_ExprConstant *, ZCC_ExprConstant *, FSharedStringArena &);
-
-struct ZCC_OpProto
-{
-	ZCC_OpProto *Next;
-	PType *ResType;
-	PType *Type1;
-	PType *Type2;
-	union
-	{
-		EvalConst1op EvalConst1;
-		EvalConst2op EvalConst2;
-	};
-
-	ZCC_OpProto(PType *res, PType *t1, PType *t2)
-		: ResType(res), Type1(t1), Type2(t2) {}
-};
-
-struct ZCC_OpInfoType
-{
-	const char *OpName;
-	ZCC_OpProto *Protos;
-
-	void AddProto(PType *res, PType *optype, EvalConst1op evalconst);
-	void AddProto(PType *res, PType *left, PType *right, EvalConst2op evalconst);
-
-	ZCC_OpProto *FindBestProto(PType *optype, const PType::Conversion **route, int &numslots);
-	ZCC_OpProto *FindBestProto(PType *left, const PType::Conversion **route1, int &numslots,
-		PType *right, const PType::Conversion **route2, int &numslots2);
-
-	void FreeAllProtos();
-};
-
-#define CONVERSION_ROUTE_SIZE	8
-
-FString ZCC_PrintAST(ZCC_TreeNode *root);
-
-void ZCC_InitOperators();
-
-extern ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF];
-
-struct ZCC_AST
-{
-	ZCC_AST() : TopNode(NULL) {}
-	ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode *basis);
-
-	FSharedStringArena Strings;
-	FMemArena SyntaxArena;
-	struct ZCC_TreeNode *TopNode;
-};
-
-struct ZCCParseState : public ZCC_AST
-{
-	ZCCParseState(FScanner &scanner) : sc(scanner) {}
-	ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type);
-
-	FScanner &sc;
-};
-
-#endif
--- tools/lemon/lemon.c
+++ tools/lemon/lemon.c
@@ -6,9 +6,9 @@
 **
 ** The author of this program disclaims copyright.
 **
-** This file is based on version 1.69 of lemon.c from the SQLite
-** CVS, with modifications to make it work nicer when run
-** from Developer Studio.
+** This file is based on version 1.43 of lemon.c from the SQLite
+** source tree, with modifications to make it work nicer when run
+** by Developer Studio.
 */
 #include <stdio.h>
 #include <stdarg.h>
@@ -17,14 +17,6 @@
 #include <stdlib.h>
 #include <assert.h>
 
-#define ISSPACE(X) isspace((unsigned char)(X))
-#define ISDIGIT(X) isdigit((unsigned char)(X))
-#define ISALNUM(X) isalnum((unsigned char)(X))
-#define ISALPHA(X) isalpha((unsigned char)(X))
-#define ISUPPER(X) isupper((unsigned char)(X))
-#define ISLOWER(X) islower((unsigned char)(X))
-
-
 #ifndef __WIN32__
 #   if defined(_WIN32) || defined(WIN32)
 #	define __WIN32__
@@ -32,13 +24,7 @@
 #endif
 
 #ifdef __WIN32__
-#ifdef __cplusplus
-extern "C" {
-#endif
-extern int access(char *path, int mode);
-#ifdef __cplusplus
-}
-#endif
+extern int access();
 #else
 #include <unistd.h>
 #endif
@@ -52,21 +38,8 @@ extern int access(char *path, int mode);
 #define MAXRHS 1000
 #endif
 
-static int showPrecedenceConflict = 0;
 static void *msort(void *list, void *next, int (*cmp)());
 
-/*
-** Compilers are getting increasingly pedantic about type conversions
-** as C evolves ever closer to Ada.... To work around the latest problems
-** we have to define the following variant of strlen().
-*/
-#define lemonStrlen(X)   ((int)strlen(X))
-
-/* a few forward declarations... */
-struct rule;
-struct lemon;
-struct action;
-
 /******** From the file "action.h" *************************************/
 static struct action *Action_new(void);
 static struct action *Action_sort(struct action *);
@@ -80,58 +53,59 @@ void FindFollowSets();
 void FindActions();
 
 /********* From the file "configlist.h" *********************************/
-void Configlist_init(void);
-struct config *Configlist_add(struct rule *, int);
-struct config *Configlist_addbasis(struct rule *, int);
-void Configlist_closure(struct lemon *);
-void Configlist_sort(void);
-void Configlist_sortbasis(void);
-struct config *Configlist_return(void);
-struct config *Configlist_basis(void);
-void Configlist_eat(struct config *);
-void Configlist_reset(void);
+void Configlist_init(/* void */);
+struct config *Configlist_add(/* struct rule *, int */);
+struct config *Configlist_addbasis(/* struct rule *, int */);
+void Configlist_closure(/* void */);
+void Configlist_sort(/* void */);
+void Configlist_sortbasis(/* void */);
+struct config *Configlist_return(/* void */);
+struct config *Configlist_basis(/* void */);
+void Configlist_eat(/* struct config * */);
+void Configlist_reset(/* void */);
 
 /********* From the file "error.h" ***************************************/
 void ErrorMsg(const char *, int,const char *, ...);
 
 /****** From the file "option.h" ******************************************/
-enum option_type { OPT_FLAG=1,  OPT_INT,  OPT_DBL,  OPT_STR,
-         OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR};
 struct s_options {
-  enum option_type type;
-  const char *label;
+  enum { OPT_FLAG=1,  OPT_INT,  OPT_DBL,  OPT_STR,
+         OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR} type;
+  char *label;
   char *arg;
-  const char *message;
+  char *message;
 };
-int    OptInit(char**,struct s_options*,FILE*);
-int    OptNArgs(void);
-char  *OptArg(int);
-void   OptErr(int);
-void   OptPrint(void);
+int    OptInit(/* char**,struct s_options*,FILE* */);
+int    OptNArgs(/* void */);
+char  *OptArg(/* int */);
+void   OptErr(/* int */);
+void   OptPrint(/* void */);
 
 /******** From the file "parse.h" *****************************************/
-void Parse(struct lemon *lemp);
+void Parse(/* struct lemon *lemp */);
 
 /********* From the file "plink.h" ***************************************/
-struct plink *Plink_new(void);
-void Plink_add(struct plink **, struct config *);
-void Plink_copy(struct plink **, struct plink *);
-void Plink_delete(struct plink *);
+struct plink *Plink_new(/* void */);
+void Plink_add(/* struct plink **, struct config * */);
+void Plink_copy(/* struct plink **, struct plink * */);
+void Plink_delete(/* struct plink * */);
 
 /********** From the file "report.h" *************************************/
-void Reprint(struct lemon *);
-void ReportOutput(struct lemon *);
-void ReportTable(struct lemon *, int);
-void ReportHeader(struct lemon *);
-void CompressTables(struct lemon *);
-void ResortStates(struct lemon *);
+void Reprint(/* struct lemon * */);
+void ReportOutput(/* struct lemon * */);
+void ReportTable(/* struct lemon * */);
+void ReportHeader(/* struct lemon * */);
+void CompressTables(/* struct lemon * */);
+void ResortStates(/* struct lemon * */);
 
 /********** From the file "set.h" ****************************************/
-void  SetSize(int);             /* All sets will be of size N */
-char *SetNew(void);               /* A new set for element 0..N */
-void  SetFree(char*);             /* Deallocate a set */
-int SetAdd(char*,int);            /* Add element to a set */
-int SetUnion(char *,char *);    /* A <- A U B, thru element N */
+void  SetSize(/* int N */);             /* All sets will be of size N */
+char *SetNew(/* void */);               /* A new set for element 0..N */
+void  SetFree(/* char* */);             /* Deallocate a set */
+
+int SetAdd(/* char*,int */);            /* Add element to a set */
+int SetUnion(/* char *A,char *B */);    /* A <- A U B, thru element N */
+
 #define SetFind(X,Y) (X[Y])       /* True if Y is in set X */
 
 /********** From the file "struct.h" *************************************/
@@ -143,31 +117,29 @@ typedef enum {LEMON_FALSE=0, LEMON_TRUE}
 
 /* Symbols (terminals and nonterminals) of the grammar are stored
 ** in the following: */
-enum symbol_type {
-  TERMINAL,
-  NONTERMINAL,
-  MULTITERMINAL
-};
-enum e_assoc {
-    LEFT,
-    RIGHT,
-    NONE,
-    UNK
-};
 struct symbol {
-  const char *name;        /* Name of the symbol */
+  char *name;              /* Name of the symbol */
   int index;               /* Index number for this symbol */
-  enum symbol_type type;   /* Symbols are all either TERMINALS or NTs */
+  enum {
+    TERMINAL,
+    NONTERMINAL,
+    MULTITERMINAL
+  } type;                  /* Symbols are all either TERMINALS or NTs */
   struct rule *rule;       /* Linked list of rules of this (if an NT) */
   struct symbol *fallback; /* fallback token in case this token doesn't parse */
   int prec;                /* Precedence if defined (-1 otherwise) */
-  enum e_assoc assoc;      /* Associativity if precedence is defined */
+  enum e_assoc {
+    LEFT,
+    RIGHT,
+    NONE,
+    UNK
+  } assoc;                 /* Associativity if predecence is defined */
   char *firstset;          /* First-set for all rules of this symbol */
   Boolean lambda;          /* True if NT and can generate an empty string */
   int useCnt;              /* Number of times used */
   char *destructor;        /* Code which executes whenever this symbol is
                            ** popped from the stack during error processing */
-  int destLineno;          /* Line number for start of destructor */
+  int destructorln;        /* Line number of destructor code */
   char *datatype;          /* The data type of information held by this
                            ** object. Only used if type==NONTERMINAL */
   int dtnum;               /* The data type number.  In the parser, the value
@@ -182,19 +154,16 @@ struct symbol {
 ** structure.  */
 struct rule {
   struct symbol *lhs;      /* Left-hand side of the rule */
-  const char *lhsalias;    /* Alias for the LHS (NULL if none) */
+  char *lhsalias;          /* Alias for the LHS (NULL if none) */
   int lhsStart;            /* True if left-hand side is the start symbol */
   int ruleline;            /* Line number for the rule */
   int nrhs;                /* Number of RHS symbols */
   struct symbol **rhs;     /* The RHS symbols */
-  const char **rhsalias;   /* An alias for each RHS symbol (NULL if none) */
+  char **rhsalias;         /* An alias for each RHS symbol (NULL if none) */
   int line;                /* Line number at which code begins */
-  const char *code;        /* The code executed when this rule is reduced */
-  const char *codePrefix;  /* Setup code before code[] above */
-  const char *codeSuffix;  /* Breakdown code after code[] above */
+  char *code;              /* The code executed when this rule is reduced */
   struct symbol *precsym;  /* Precedence symbol for this rule */
   int index;               /* An index number for this rule */
-  int iRule;               /* Rule number as used in the generated tables */
   Boolean canReduce;       /* True if this rule is ever reduced */
   struct rule *nextlhs;    /* Next rule with the same LHS */
   struct rule *next;       /* Next rule in the global list */
@@ -205,10 +174,6 @@ struct rule {
 ** Configurations also contain a follow-set which is a list of terminal
 ** symbols which are allowed to immediately follow the end of the rule.
 ** Every configuration is recorded as an instance of the following: */
-enum cfgstatus {
-  COMPLETE,
-  INCOMPLETE
-};
 struct config {
   struct rule *rp;         /* The rule upon which the configuration is based */
   int dot;                 /* The parse point */
@@ -216,29 +181,29 @@ struct config {
   struct plink *fplp;      /* Follow-set forward propagation links */
   struct plink *bplp;      /* Follow-set backwards propagation links */
   struct state *stp;       /* Pointer to state which contains this */
-  enum cfgstatus status;   /* used during followset and shift computations */
+  enum {
+    COMPLETE,              /* The status is used during followset and */
+    INCOMPLETE             /*    shift computations */
+  } status;
   struct config *next;     /* Next configuration in the state */
   struct config *bp;       /* The next basis configuration */
 };
 
-enum e_action {
-  SHIFT,
-  ACCEPT,
-  REDUCE,
-  ERROR,
-  SSCONFLICT,              /* A shift/shift conflict */
-  SRCONFLICT,              /* Was a reduce, but part of a conflict */
-  RRCONFLICT,              /* Was a reduce, but part of a conflict */
-  SH_RESOLVED,             /* Was a shift.  Precedence resolved conflict */
-  RD_RESOLVED,             /* Was reduce.  Precedence resolved conflict */
-  NOT_USED,                /* Deleted by compression */
-  SHIFTREDUCE              /* Shift first, then reduce */
-};
-
 /* Every shift or reduce operation is stored as one of the following */
 struct action {
   struct symbol *sp;       /* The look-ahead symbol */
-  enum e_action type;
+  enum e_action {
+    SHIFT,
+    ACCEPT,
+    REDUCE,
+    ERROR,
+    SSCONFLICT,              /* A shift/shift conflict */
+    SRCONFLICT,              /* Was a reduce, but part of a conflict */
+    RRCONFLICT,              /* Was a reduce, but part of a conflict */
+    SH_RESOLVED,             /* Was a shift.  Precedence resolved conflict */
+    RD_RESOLVED,             /* Was reduce.  Precedence resolved conflict */
+    NOT_USED                 /* Deleted by compression */
+  } type;
   union {
     struct state *stp;     /* The new state, if a shift */
     struct rule *rp;       /* The rule, if a reduce */
@@ -252,13 +217,11 @@ struct action {
 struct state {
   struct config *bp;       /* The basis configurations for this state */
   struct config *cfp;      /* All configurations in this set */
-  int statenum;            /* Sequential number for this state */
+  int statenum;            /* Sequencial number for this state */
   struct action *ap;       /* Array of actions for this state */
   int nTknAct, nNtAct;     /* Number of actions on terminals and nonterminals */
   int iTknOfst, iNtOfst;   /* yy_action[] offset for terminals and nonterms */
-  int iDfltReduce;         /* Default action is to REDUCE by this rule */
-  struct rule *pDfltReduce;/* The default REDUCE rule. */
-  int autoReduce;          /* True if this is an auto-reduce state */
+  int iDflt;               /* Default action */
 };
 #define NO_OFFSET (-2147483647)
 
@@ -273,13 +236,11 @@ struct plink {
 /* The state vector for the entire parser generator is recorded as
 ** follows.  (LEMON uses no global variables and makes little use of
 ** static variables.  Fields in the following structure can be thought
-** of as being global variables in the program.) */
+** of as begin global variables in the program.) */
 struct lemon {
   struct state **sorted;   /* Table of states sorted by state number */
   struct rule *rule;       /* List of all rules */
-  struct rule *startRule;  /* First rule */
   int nstate;              /* Number of states */
-  int nxstate;             /* nstate with tail degenerate states removed */
   int nrule;               /* Number of rules */
   int nsymbol;             /* Number of terminal and nonterminal symbols */
   int nterminal;           /* Number of terminal symbols */
@@ -294,23 +255,28 @@ struct lemon {
   char *start;             /* Name of the start symbol for the grammar */
   char *stacksize;         /* Size of the parser stack */
   char *include;           /* Code to put at the start of the C file */
+  int  includeln;          /* Line number for start of include code */
   char *error;             /* Code to execute when an error is seen */
+  int  errorln;            /* Line number for start of error code */
   char *overflow;          /* Code to execute on a stack overflow */
+  int  overflowln;         /* Line number for start of overflow code */
   char *failure;           /* Code to execute on parser failure */
+  int  failureln;          /* Line number for start of failure code */
   char *accept;            /* Code to execute when the parser excepts */
+  int  acceptln;           /* Line number for the start of accept code */
   char *extracode;         /* Code appended to the generated file */
+  int  extracodeln;        /* Line number for the start of the extra code */
   char *tokendest;         /* Code to execute to destroy token data */
+  int  tokendestln;        /* Line number for token destroyer code */
   char *vardest;           /* Code for the default non-terminal destructor */
+  int  vardestln;          /* Line number for default non-term destructor code*/
   char *filename;          /* Name of the input file */
-  char *outbasefilename;   /* Name of the input file, with the output dir's path */
   char *outname;           /* Name of the current output file */
   char *tokenprefix;       /* A prefix added to token names in the .h file */
   int nconflict;           /* Number of parsing conflicts */
-  int nactiontab;          /* Number of entries in the yy_action[] table */
-  int tablesize;           /* Total table size of all tables in bytes */
+  int tablesize;           /* Size of the parse tables */
   int basisflag;           /* Print only basis configurations */
-  int has_fallback;        /* True if any %fallback is seen in the grammar */
-  int nolinenosflag;       /* True if #line statements should not be printed */
+  int has_fallback;        /* True if any %fallback is seen in the grammer */
   char *argv0;             /* Name of the program */
 };
 
@@ -331,41 +297,41 @@ struct lemon {
 /*
 ** Code for processing tables in the LEMON parser generator.
 */
+
 /* Routines for handling a strings */
 
-const char *Strsafe(const char *);
+char *Strsafe();
 
-void Strsafe_init(void);
-int Strsafe_insert(const char *);
-const char *Strsafe_find(const char *);
+void Strsafe_init(/* void */);
+int Strsafe_insert(/* char * */);
+char *Strsafe_find(/* char * */);
 
 /* Routines for handling symbols of the grammar */
 
-struct symbol *Symbol_new(const char *);
-int Symbolcmpp(const void *, const void *);
-void Symbol_init(void);
-int Symbol_insert(struct symbol *, const char *);
-struct symbol *Symbol_find(const char *);
-struct symbol *Symbol_Nth(int);
-int Symbol_count(void);
-struct symbol **Symbol_arrayof(void);
+struct symbol *Symbol_new();
+int Symbolcmpp(/* struct symbol **, struct symbol ** */);
+void Symbol_init(/* void */);
+int Symbol_insert(/* struct symbol *, char * */);
+struct symbol *Symbol_find(/* char * */);
+struct symbol *Symbol_Nth(/* int */);
+int Symbol_count(/*  */);
+struct symbol **Symbol_arrayof(/*  */);
 
 /* Routines to manage the state table */
 
-int Configcmp(const char *, const char *);
-struct state *State_new(void);
-void State_init(void);
-int State_insert(struct state *, struct config *);
-struct state *State_find(struct config *);
+int Configcmp(/* struct config *, struct config * */);
+struct state *State_new();
+void State_init(/* void */);
+int State_insert(/* struct state *, struct config * */);
+struct state *State_find(/* struct config * */);
 struct state **State_arrayof(/*  */);
 
 /* Routines used for efficiency in Configlist_add */
 
-void Configtable_init(void);
-int Configtable_insert(struct config *);
-struct config *Configtable_find(struct config *);
-void Configtable_clear(int(*)(struct config *));
-
+void Configtable_init(/* void */);
+int Configtable_insert(/* struct config * */);
+struct config *Configtable_find(/* struct config * */);
+void Configtable_clear(/* int(*)(struct config *) */);
 /****************** From the file "action.c" *******************************/
 /*
 ** Routines processing parser actions in the LEMON parser generator.
@@ -374,7 +340,7 @@ void Configtable_clear(int(*)(struct con
 /* Allocate a new parser action */
 static struct action *Action_new(void){
   static struct action *freelist = 0;
-  struct action *newaction;
+  struct action *new;
 
   if( freelist==0 ){
     int i;
@@ -387,9 +353,9 @@ static struct action *Action_new(void){
     for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1];
     freelist[amt-1].next = 0;
   }
-  newaction = freelist;
+  new = freelist;
   freelist = freelist->next;
-  return newaction;
+  return new;
 }
 
 /* Compare two actions for sorting purposes.  Return negative, zero, or
@@ -405,12 +371,9 @@ struct action *ap2;
   if( rc==0 ){
     rc = (int)ap1->type - (int)ap2->type;
   }
-  if( rc==0 && (ap1->type==REDUCE || ap1->type==SHIFTREDUCE) ){
+  if( rc==0 && ap1->type==REDUCE ){
     rc = ap1->x.rp->index - ap2->x.rp->index;
   }
-  if( rc==0 ){
-    rc = ap2 - ap1;
-  }
   return rc;
 }
 
@@ -421,22 +384,22 @@ static struct action *Action_sort(struct
   return ap;
 }
 
-void Action_add(
-  struct action **app,
-  enum e_action type,
-  struct symbol *sp,
-  char *arg
-){
-  struct action *newaction;
-  newaction = Action_new();
-  newaction->next = *app;
-  *app = newaction;
-  newaction->type = type;
-  newaction->sp = sp;
+void Action_add(app,type,sp,arg)
+struct action **app;
+enum e_action type;
+struct symbol *sp;
+char *arg;
+{
+  struct action *new;
+  new = Action_new();
+  new->next = *app;
+  *app = new;
+  new->type = type;
+  new->sp = sp;
   if( type==SHIFT ){
-    newaction->x.stp = (struct state *)arg;
+    new->x.stp = (struct state *)arg;
   }else{
-    newaction->x.rp = (struct rule *)arg;
+    new->x.rp = (struct rule *)arg;
   }
 }
 /********************** New code to implement the "acttab" module ***********/
@@ -446,34 +409,16 @@ void Action_add(
 
 /*
 ** The state of the yy_action table under construction is an instance of
-** the following structure.
-**
-** The yy_action table maps the pair (state_number, lookahead) into an
-** action_number.  The table is an array of integers pairs.  The state_number
-** determines an initial offset into the yy_action array.  The lookahead
-** value is then added to this initial offset to get an index X into the
-** yy_action array. If the aAction[X].lookahead equals the value of the
-** of the lookahead input, then the value of the action_number output is
-** aAction[X].action.  If the lookaheads do not match then the
-** default action for the state_number is returned.
-**
-** All actions associated with a single state_number are first entered
-** into aLookahead[] using multiple calls to acttab_action().  Then the 
-** actions for that single state_number are placed into the aAction[] 
-** array with a single call to acttab_insert().  The acttab_insert() call
-** also resets the aLookahead[] array in preparation for the next
-** state number.
-*/
-struct lookahead_action {
-  int lookahead;             /* Value of the lookahead token */
-  int action;                /* Action to take on the given lookahead */
-};
+** the following structure
+*/
 typedef struct acttab acttab;
 struct acttab {
   int nAction;                 /* Number of used slots in aAction[] */
   int nActionAlloc;            /* Slots allocated for aAction[] */
-  struct lookahead_action
-    *aAction,                  /* The yy_action[] table under construction */
+  struct {
+    int lookahead;             /* Value of the lookahead token */
+    int action;                /* Action to take on the given lookahead */
+  } *aAction,                  /* The yy_action[] table under construction */
     *aLookahead;               /* A single new transaction set */
   int mnLookahead;             /* Minimum aLookahead[].lookahead */
   int mnAction;                /* Action associated with mnLookahead */
@@ -501,7 +446,7 @@ void acttab_free(acttab **pp){
 
 /* Allocate a new acttab structure */
 acttab *acttab_alloc(void){
-  acttab *p = (acttab *) calloc( 1, sizeof(*p) );
+  acttab *p = calloc( 1, sizeof(*p) );
   if( p==0 ){
     fprintf(stderr,"Unable to allocate memory for a new acttab.");
     exit(1);
@@ -510,15 +455,12 @@ acttab *acttab_alloc(void){
   return p;
 }
 
-/* Add a new action to the current transaction set.  
-**
-** This routine is called once for each lookahead for a particular
-** state.
+/* Add a new action to the current transaction set
 */
 void acttab_action(acttab *p, int lookahead, int action){
   if( p->nLookahead>=p->nLookaheadAlloc ){
     p->nLookaheadAlloc += 25;
-    p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead,
+    p->aLookahead = realloc( p->aLookahead,
                              sizeof(p->aLookahead[0])*p->nLookaheadAlloc );
     if( p->aLookahead==0 ){
       fprintf(stderr,"malloc failed\n");
@@ -560,7 +502,7 @@ int acttab_insert(acttab *p){
   if( p->nAction + n >= p->nActionAlloc ){
     int oldAlloc = p->nActionAlloc;
     p->nActionAlloc = p->nAction + n + p->nActionAlloc + 20;
-    p->aAction = (struct lookahead_action *) realloc( p->aAction,
+    p->aAction = realloc( p->aAction,
                           sizeof(p->aAction[0])*p->nActionAlloc);
     if( p->aAction==0 ){
       fprintf(stderr,"malloc failed\n");
@@ -572,16 +514,28 @@ int acttab_insert(acttab *p){
     }
   }
 
-  /* Scan the existing action table looking for an offset that is a 
-  ** duplicate of the current transaction set.  Fall out of the loop
-  ** if and when the duplicate is found.
+  /* Scan the existing action table looking for an offset where we can
+  ** insert the current transaction set.  Fall out of the loop when that
+  ** offset is found.  In the worst case, we fall out of the loop when
+  ** i reaches p->nAction, which means we append the new transaction set.
   **
   ** i is the index in p->aAction[] where p->mnLookahead is inserted.
   */
-  for(i=p->nAction-1; i>=0; i--){
-    if( p->aAction[i].lookahead==p->mnLookahead ){
-      /* All lookaheads and actions in the aLookahead[] transaction
-      ** must match against the candidate aAction[i] entry. */
+  for(i=0; i<p->nAction+p->mnLookahead; i++){
+    if( p->aAction[i].lookahead<0 ){
+      for(j=0; j<p->nLookahead; j++){
+        k = p->aLookahead[j].lookahead - p->mnLookahead + i;
+        if( k<0 ) break;
+        if( p->aAction[k].lookahead>=0 ) break;
+      }
+      if( j<p->nLookahead ) continue;
+      for(j=0; j<p->nAction; j++){
+        if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break;
+      }
+      if( j==p->nAction ){
+        break;  /* Fits in empty slots */
+      }
+    }else if( p->aAction[i].lookahead==p->mnLookahead ){
       if( p->aAction[i].action!=p->mnAction ) continue;
       for(j=0; j<p->nLookahead; j++){
         k = p->aLookahead[j].lookahead - p->mnLookahead + i;
@@ -590,43 +544,13 @@ int acttab_insert(acttab *p){
         if( p->aLookahead[j].action!=p->aAction[k].action ) break;
       }
       if( j<p->nLookahead ) continue;
-
-      /* No possible lookahead value that is not in the aLookahead[]
-      ** transaction is allowed to match aAction[i] */
       n = 0;
       for(j=0; j<p->nAction; j++){
         if( p->aAction[j].lookahead<0 ) continue;
         if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++;
       }
       if( n==p->nLookahead ){
-        break;  /* An exact match is found at offset i */
-      }
-    }
-  }
-
-  /* If no existing offsets exactly match the current transaction, find an
-  ** an empty offset in the aAction[] table in which we can add the
-  ** aLookahead[] transaction.
-  */
-  if( i<0 ){
-    /* Look for holes in the aAction[] table that fit the current
-    ** aLookahead[] transaction.  Leave i set to the offset of the hole.
-    ** If no holes are found, i is left at p->nAction, which means the
-    ** transaction will be appended. */
-    for(i=0; i<p->nActionAlloc - p->mxLookahead; i++){
-      if( p->aAction[i].lookahead<0 ){
-        for(j=0; j<p->nLookahead; j++){
-          k = p->aLookahead[j].lookahead - p->mnLookahead + i;
-          if( k<0 ) break;
-          if( p->aAction[k].lookahead>=0 ) break;
-        }
-        if( j<p->nLookahead ) continue;
-        for(j=0; j<p->nAction; j++){
-          if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break;
-        }
-        if( j==p->nAction ){
-          break;  /* Fits in empty slots */
-        }
+        break;  /* Same as a prior transaction set */
       }
     }
   }
@@ -658,7 +582,8 @@ int acttab_insert(acttab *p){
 ** are not RHS symbols with a defined precedence, the precedence
 ** symbol field is left blank.
 */
-void FindRulePrecedences(struct lemon *xp)
+void FindRulePrecedences(xp)
+struct lemon *xp;
 {
   struct rule *rp;
   for(rp=xp->rule; rp; rp=rp->next){
@@ -687,7 +612,8 @@ void FindRulePrecedences(struct lemon *x
 ** The first set is the set of all terminal symbols which can begin
 ** a string generated by that nonterminal.
 */
-void FindFirstSets(struct lemon *lemp)
+void FindFirstSets(lemp)
+struct lemon *lemp;
 {
   int i, j;
   struct rule *rp;
@@ -707,8 +633,7 @@ void FindFirstSets(struct lemon *lemp)
       if( rp->lhs->lambda ) continue;
       for(i=0; i<rp->nrhs; i++){
          struct symbol *sp = rp->rhs[i];
-         assert( sp->type==NONTERMINAL || sp->lambda==LEMON_FALSE );
-         if( sp->lambda==LEMON_FALSE ) break;
+         if( sp->type!=TERMINAL || sp->lambda==LEMON_FALSE ) break;
       }
       if( i==rp->nrhs ){
         rp->lhs->lambda = LEMON_TRUE;
@@ -749,8 +674,9 @@ void FindFirstSets(struct lemon *lemp)
 ** are added to between some states so that the LR(1) follow sets
 ** can be computed later.
 */
-PRIVATE struct state *getstate(struct lemon *);  /* forward reference */
-void FindStates(struct lemon *lemp)
+PRIVATE struct state *getstate(/* struct lemon * */);  /* forward reference */
+void FindStates(lemp)
+struct lemon *lemp;
 {
   struct symbol *sp;
   struct rule *rp;
@@ -764,12 +690,12 @@ void FindStates(struct lemon *lemp)
       ErrorMsg(lemp->filename,0,
 "The specified start symbol \"%s\" is not \
 in a nonterminal of the grammar.  \"%s\" will be used as the start \
-symbol instead.",lemp->start,lemp->startRule->lhs->name);
+symbol instead.",lemp->start,lemp->rule->lhs->name);
       lemp->errorcnt++;
-      sp = lemp->startRule->lhs;
+      sp = lemp->rule->lhs;
     }
   }else{
-    sp = lemp->startRule->lhs;
+    sp = lemp->rule->lhs;
   }
 
   /* Make sure the start symbol doesn't occur on the right-hand side of
@@ -808,8 +734,9 @@ does not work properly.",sp->name);
 /* Return a pointer to a state which is described by the configuration
 ** list which has been built from calls to Configlist_add.
 */
-PRIVATE void buildshifts(struct lemon *, struct state *); /* Forwd ref */
-PRIVATE struct state *getstate(struct lemon *lemp)
+PRIVATE void buildshifts(/* struct lemon *, struct state * */); /* Forwd ref */
+PRIVATE struct state *getstate(lemp)
+struct lemon *lemp;
 {
   struct config *cfp, *bp;
   struct state *stp;
@@ -853,7 +780,9 @@ PRIVATE struct state *getstate(struct le
 /*
 ** Return true if two symbols are the same.
 */
-int same_symbol(struct symbol *a, struct symbol *b)
+int same_symbol(a,b)
+struct symbol *a;
+struct symbol *b;
 {
   int i;
   if( a==b ) return 1;
@@ -869,11 +798,13 @@ int same_symbol(struct symbol *a, struct
 /* Construct all successor states to the given state.  A "successor"
 ** state is any state which can be reached by a shift action.
 */
-PRIVATE void buildshifts(struct lemon *lemp, struct state *stp)
+PRIVATE void buildshifts(lemp,stp)
+struct lemon *lemp;
+struct state *stp;     /* The state from which successors are computed */
 {
   struct config *cfp;  /* For looping thru the config closure of "stp" */
   struct config *bcfp; /* For the inner loop on config closure of "stp" */
-  struct config *newcfg;  /* */
+  struct config *new;  /* */
   struct symbol *sp;   /* Symbol following the dot in configuration "cfp" */
   struct symbol *bsp;  /* Symbol following the dot in configuration "bcfp" */
   struct state *newstp; /* A pointer to a successor state */
@@ -898,8 +829,8 @@ PRIVATE void buildshifts(struct lemon *l
       bsp = bcfp->rp->rhs[bcfp->dot];           /* Get symbol after dot */
       if( !same_symbol(bsp,sp) ) continue;      /* Must be same as for "cfp" */
       bcfp->status = COMPLETE;                  /* Mark this config as used */
-      newcfg = Configlist_addbasis(bcfp->rp,bcfp->dot+1);
-      Plink_add(&newcfg->bplp,bcfp);
+      new = Configlist_addbasis(bcfp->rp,bcfp->dot+1);
+      Plink_add(&new->bplp,bcfp);
     }
 
     /* Get a pointer to the state described by the basis configuration set
@@ -922,7 +853,8 @@ PRIVATE void buildshifts(struct lemon *l
 /*
 ** Construct the propagation links
 */
-void FindLinks(struct lemon *lemp)
+void FindLinks(lemp)
+struct lemon *lemp;
 {
   int i;
   struct config *cfp, *other;
@@ -957,7 +889,8 @@ void FindLinks(struct lemon *lemp)
 ** A followset is the set of all symbols which can come immediately
 ** after a configuration.
 */
-void FindFollowSets(struct lemon *lemp)
+void FindFollowSets(lemp)
+struct lemon *lemp;
 {
   int i;
   struct config *cfp;
@@ -989,11 +922,12 @@ void FindFollowSets(struct lemon *lemp)
   }while( progress );
 }
 
-static int resolve_conflict(struct action *,struct action *);
+static int resolve_conflict();
 
 /* Compute the reduce actions, and resolve conflicts.
 */
-void FindActions(struct lemon *lemp)
+void FindActions(lemp)
+struct lemon *lemp;
 {
   int i,j;
   struct config *cfp;
@@ -1023,9 +957,9 @@ void FindActions(struct lemon *lemp)
   /* Add the accepting token */
   if( lemp->start ){
     sp = Symbol_find(lemp->start);
-    if( sp==0 ) sp = lemp->startRule->lhs;
+    if( sp==0 ) sp = lemp->rule->lhs;
   }else{
-    sp = lemp->startRule->lhs;
+    sp = lemp->rule->lhs;
   }
   /* Add to the first state (which is always the starting state of the
   ** finite state machine) an action to ACCEPT if the lookahead is the
@@ -1043,7 +977,7 @@ void FindActions(struct lemon *lemp)
       for(nap=ap->next; nap && nap->sp==ap->sp; nap=nap->next){
          /* The two actions "ap" and "nap" have the same lookahead.
          ** Figure out which one should be used */
-         lemp->nconflict += resolve_conflict(ap,nap);
+         lemp->nconflict += resolve_conflict(ap,nap,lemp->errsym);
       }
     }
   }
@@ -1064,7 +998,7 @@ void FindActions(struct lemon *lemp)
 }
 
 /* Resolve a conflict between the two given actions.  If the
-** conflict can't be resolved, return non-zero.
+** conflict can't be resolve, return non-zero.
 **
 ** NO LONGER TRUE:
 **   To resolve a conflict, first look to see if either action
@@ -1076,10 +1010,11 @@ void FindActions(struct lemon *lemp)
 ** If either action is a SHIFT, then it must be apx.  This
 ** function won't work if apx->type==REDUCE and apy->type==SHIFT.
 */
-static int resolve_conflict(
-  struct action *apx,
-  struct action *apy
-){
+static int resolve_conflict(apx,apy,errsym)
+struct action *apx;
+struct action *apy;
+struct symbol *errsym;   /* The error symbol (if defined.  NULL otherwise) */
+{
   struct symbol *spx, *spy;
   int errcnt = 0;
   assert( apx->sp==apy->sp );  /* Otherwise there would be no conflict */
@@ -1094,7 +1029,7 @@ static int resolve_conflict(
       /* Not enough precedence information. */
       apy->type = SRCONFLICT;
       errcnt++;
-    }else if( spx->prec>spy->prec ){    /* higher precedence wins */
+    }else if( spx->prec>spy->prec ){    /* Lower precedence wins */
       apy->type = RD_RESOLVED;
     }else if( spx->prec<spy->prec ){
       apx->type = SH_RESOLVED;
@@ -1104,7 +1039,8 @@ static int resolve_conflict(
       apx->type = SH_RESOLVED;
     }else{
       assert( spx->prec==spy->prec && spx->assoc==NONE );
-      apy->type = ERROR;
+      apy->type = SRCONFLICT;
+      errcnt++;
     }
   }else if( apx->type==REDUCE && apy->type==REDUCE ){
     spx = apx->x.rp->precsym;
@@ -1151,7 +1087,7 @@ static struct config **basisend = 0;    
 
 /* Return a pointer to a new configuration */
 PRIVATE struct config *newconfig(){
-  struct config *newcfg;
+  struct config *new;
   if( freelist==0 ){
     int i;
     int amt = 3;
@@ -1163,13 +1099,14 @@ PRIVATE struct config *newconfig(){
     for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1];
     freelist[amt-1].next = 0;
   }
-  newcfg = freelist;
+  new = freelist;
   freelist = freelist->next;
-  return newcfg;
+  return new;
 }
 
 /* The configuration "old" is no longer used */
-PRIVATE void deleteconfig(struct config *old)
+PRIVATE void deleteconfig(old)
+struct config *old;
 {
   old->next = freelist;
   freelist = old;
@@ -1196,10 +1133,10 @@ void Configlist_reset(){
 }
 
 /* Add another configuration to the configuration list */
-struct config *Configlist_add(
-  struct rule *rp,    /* The rule */
-  int dot             /* Index into the RHS of the rule where the dot goes */
-){
+struct config *Configlist_add(rp,dot)
+struct rule *rp;    /* The rule */
+int dot;            /* Index into the RHS of the rule where the dot goes */
+{
   struct config *cfp, model;
 
   assert( currentend!=0 );
@@ -1223,7 +1160,9 @@ struct config *Configlist_add(
 }
 
 /* Add a basis configuration to the configuration list */
-struct config *Configlist_addbasis(struct rule *rp, int dot)
+struct config *Configlist_addbasis(rp,dot)
+struct rule *rp;
+int dot;
 {
   struct config *cfp, model;
 
@@ -1251,7 +1190,8 @@ struct config *Configlist_addbasis(struc
 }
 
 /* Compute the closure of the configuration list */
-void Configlist_closure(struct lemon *lemp)
+void Configlist_closure(lemp)
+struct lemon *lemp;
 {
   struct config *cfp, *newcfp;
   struct rule *rp, *newrp;
@@ -1297,16 +1237,14 @@ void Configlist_closure(struct lemon *le
 
 /* Sort the configuration list */
 void Configlist_sort(){
-  current = (struct config*)msort((char*)current,(char**)&(current->next),
-                                  Configcmp);
+  current = (struct config *)msort(current,&(current->next),Configcmp);
   currentend = 0;
   return;
 }
 
 /* Sort the basis configuration list */
 void Configlist_sortbasis(){
-  basis = (struct config *)msort((char*)current,(char**)&(current->bp),
-                                 Configcmp);
+  basis = (struct config *)msort(current,&(current->bp),Configcmp);
   basisend = 0;
   return;
 }
@@ -1332,7 +1270,8 @@ struct config *Configlist_basis(){
 }
 
 /* Free all elements of the given configuration list */
-void Configlist_eat(struct config *cfp)
+void Configlist_eat(cfp)
+struct config *cfp;
 {
   struct config *nextcfp;
   for(; cfp; cfp=nextcfp){
@@ -1349,26 +1288,84 @@ void Configlist_eat(struct config *cfp)
 ** Code for printing error message.
 */
 
+/* Find a good place to break "msg" so that its length is at least "min"
+** but no more than "max".  Make the point as close to max as possible.
+*/
+static int findbreak(msg,min,max)
+char *msg;
+int min;
+int max;
+{
+  int i,spot;
+  char c;
+  for(i=spot=min; i<=max; i++){
+    c = msg[i];
+    if( c=='\t' ) msg[i] = ' ';
+    if( c=='\n' ){ msg[i] = ' '; spot = i; break; }
+    if( c==0 ){ spot = i; break; }
+    if( c=='-' && i<max-1 ) spot = i+1;
+    if( c==' ' ) spot = i;
+  }
+  return spot;
+}
+
+/*
+** The error message is split across multiple lines if necessary.  The
+** splits occur at a space, if there is a space available near the end
+** of the line.
+*/
+#define ERRMSGSIZE  10000 /* Hope this is big enough.  No way to error check */
+#if _MSC_VER
+#define LINEWIDTH   10000 /* Max width of any output line */
+#else
+#define LINEWIDTH      79 /* Max width of any output line */
+#endif
+#define PREFIXLIMIT  3000 /* Max width of the prefix on each line */
 void ErrorMsg(const char *filename, int lineno, const char *format, ...){
+  char errmsg[ERRMSGSIZE];
+  char prefix[PREFIXLIMIT+10];
+  size_t errmsgsize;
+  size_t prefixsize;
+  size_t availablewidth;
   va_list ap;
+  int end, restart, base;
 
+  va_start(ap, format);
+  /* Prepare a prefix to be prepended to every output line */
 #if _MSC_VER
   if( lineno>0 ){
-    fprintf(stderr,"%s(%d) : error : ",filename,lineno);
+	sprintf(prefix,"%.*s(%d) : error : ",PREFIXLIMIT-10,filename,lineno);
   }else{
-    fprintf(stderr,"%s : error : ",filename);
+	sprintf(prefix,"%.*s : error : ",PREFIXLIMIT-10,filename);
   }
 #else
   if( lineno>0 ){
-    fprintf(stderr,"%s:%d: ",filename,lineno);
+    sprintf(prefix,"%.*s:%d: ",PREFIXLIMIT-10,filename,lineno);
   }else{
-    fprintf(stderr,"%s: ",filename);
+    sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename);
   }
 #endif
-  va_start(ap, format);
-  vfprintf(stderr,format,ap);
+  prefixsize = strlen(prefix);
+  availablewidth = LINEWIDTH - prefixsize;
+
+  /* Generate the error message */
+  vsprintf(errmsg,format,ap);
   va_end(ap);
-  fprintf(stderr, "\n");
+  errmsgsize = strlen(errmsg);
+  /* Remove trailing '\n's from the error message. */
+  while( errmsgsize>0 && errmsg[errmsgsize-1]=='\n' ){
+     errmsg[--errmsgsize] = 0;
+  }
+
+  /* Print the error message */
+  base = 0;
+  while( errmsg[base]!=0 ){
+    end = restart = findbreak(&errmsg[base],0,availablewidth);
+    restart += base;
+    while( errmsg[restart]==' ' ) restart++;
+    fprintf(stdout,"%s%.*s\n",prefix,end,&errmsg[base]);
+    base = restart;
+  }
 }
 /**************** From the file "main.c" ************************************/
 /*
@@ -1392,13 +1389,13 @@ static char **azDefine = 0;  /* Name of 
 static void handle_D_option(char *z){
   char **paz;
   nDefine++;
-  azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine);
+  azDefine = realloc(azDefine, sizeof(azDefine[0])*nDefine);
   if( azDefine==0 ){
     fprintf(stderr,"out of memory\n");
     exit(1);
   }
   paz = &azDefine[nDefine-1];
-  *paz = (char *) malloc( lemonStrlen(z)+1 );
+  *paz = malloc( strlen(z)+1 );
   if( *paz==0 ){
     fprintf(stderr,"out of memory\n");
     exit(1);
@@ -1408,143 +1405,11 @@ static void handle_D_option(char *z){
   *z = 0;
 }
 
-static char *user_templatename = NULL;
-static void handle_T_option(char *z){
-  user_templatename = (char *) malloc( lemonStrlen(z)+1 );
-  if( user_templatename==0 ){
-    memory_error();
-  }
-  strcpy(user_templatename, z);
-}
-
-/* Routines for routing output to a different directory than the one
-** the source file resides in.
-*/
-static char *output_dir = NULL;
-
-static inline Boolean is_seperator(int c)
-{
-  if (c == '/')
-    return LEMON_TRUE;
-#if defined(_WIN32) || defined(DOS)
-  if (c == '\\' || c == ':')
-    return LEMON_TRUE;
-#endif
-  return LEMON_FALSE;
-}
-
-/* Returns the file part of a pathname.
-*/
-const char *file_base(const char *path)
-{
-  const char *src = path + strlen(path) - 1;
-  if( src >= path ){
-    // back up until a / or the start
-    while (src != path && !is_seperator(*(src - 1)))
-      src--;
-
-    // Check for files with drive specification but no path
-#if defined(_WIN32) || defined(DOS)
-    if( src == path && src[0] != 0 ){
-      if( src[1] == ':' )
-        src += 2;
-    }
-#endif
-    return src;
-  }
-  return NULL;
-}
-
-static char *stitch_outdir(char *path)
-{
-  if( output_dir ){
-    const char *base = file_base(path);
-    char *newpath = (char *) malloc( lemonStrlen(output_dir) + lemonStrlen(path) + 1 );
-    if( newpath==0 ){
-      memory_error();
-    }
-    strcpy(newpath, output_dir);
-    strcat(newpath, base);
-    return newpath;
-  }
-  return path;
-}
-
-static void handle_C_option(char *z){
-  int len = lemonStrlen(z);
-  output_dir = (char *) malloc( len+2 );
-  if( output_dir==0 ){
-    memory_error();
-  }
-  strcpy(output_dir, z);
-  if( !is_seperator(output_dir[len-1]) ){
-    output_dir[len] = '/';
-    output_dir[len+1] = '\0';
-  }
-}
-
-/* Merge together to lists of rules order by rule.iRule */
-static struct rule *Rule_merge(struct rule *pA, struct rule *pB){
-  struct rule *pFirst = 0;
-  struct rule **ppPrev = &pFirst;
-  while( pA && pB ){
-    if( pA->iRule<pB->iRule ){
-      *ppPrev = pA;
-      ppPrev = &pA->next;
-      pA = pA->next;
-    }else{
-      *ppPrev = pB;
-      ppPrev = &pB->next;
-      pB = pB->next;
-    }
-  }
-  if( pA ){
-    *ppPrev = pA;
-  }else{
-    *ppPrev = pB;
-  }
-  return pFirst;
-}
-
-/*
-** Sort a list of rules in order of increasing iRule value
-*/
-static struct rule *Rule_sort(struct rule *rp){
-  int i;
-  struct rule *pNext;
-  struct rule *x[32];
-  memset(x, 0, sizeof(x));
-  while( rp ){
-    pNext = rp->next;
-    rp->next = 0;
-    for(i=0; i<sizeof(x)/sizeof(x[0]) && x[i]; i++){
-      rp = Rule_merge(x[i], rp);
-      x[i] = 0;
-    }
-    x[i] = rp;
-    rp = pNext;
-  }
-  rp = 0;
-  for(i=0; i<sizeof(x)/sizeof(x[0]); i++){
-    rp = Rule_merge(x[i], rp);
-  }
-  return rp;
-}
-
-/* forward reference */
-static const char *minimum_size_type(int lwr, int upr, int *pnByte);
-
-/* Print a single line of the "Parser Stats" output
-*/
-static void stats_line(const char *zLabel, int iValue){
-  int nLabel = lemonStrlen(zLabel);
-  printf("  %s%.*s %5d\n", zLabel,
-         35-nLabel, "................................",
-         iValue);
-}
 
 /* The main program.  Parse the command line and do it... */
-int main(int argc, char **argv)
+int main(argc,argv)
+int argc;
+char **argv;
 {
   static int version = 0;
   static int rpflag = 0;
@@ -1553,33 +1418,20 @@ int main(int argc, char **argv)
   static int quiet = 0;
   static int statistics = 0;
   static int mhflag = 0;
-  static int nolinenosflag = 0;
-  static int noResort = 0;
   static struct s_options options[] = {
     {OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."},
     {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."},
-    {OPT_FSTR, "C", (char*)handle_C_option, "Write output files to a different directory."},
     {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."},
-    {OPT_FSTR, "f", 0, "Ignored.  (Placeholder for -f compiler options.)"},
     {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."},
-    {OPT_FSTR, "I", 0, "Ignored.  (Placeholder for '-I' compiler options.)"},
-    {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file."},
-    {OPT_FLAG, "l", (char*)&nolinenosflag, "Do not print #line statements."},
-    {OPT_FSTR, "O", 0, "Ignored.  (Placeholder for '-O' compiler options.)"},
-    {OPT_FLAG, "p", (char*)&showPrecedenceConflict,
-                    "Show conflicts resolved by precedence rules"},
+    {OPT_FLAG, "m", (char*)&mhflag, "Output a makeheaders compatible file"},
     {OPT_FLAG, "q", (char*)&quiet, "(Quiet) Don't print the report file."},
-    {OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"},
     {OPT_FLAG, "s", (char*)&statistics,
                                    "Print parser stats to standard output."},
     {OPT_FLAG, "x", (char*)&version, "Print the version number."},
-    {OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."},
-    {OPT_FSTR, "W", 0, "Ignored.  (Placeholder for '-W' compiler options.)"},
     {OPT_FLAG,0,0,0}
   };
   int i;
   struct lemon lem;
-  struct rule *rp;
 
   OptInit(argv,options,stderr);
   if( version ){
@@ -1599,9 +1451,7 @@ int main(int argc, char **argv)
   State_init();
   lem.argv0 = argv[0];
   lem.filename = OptArg(0);
-  lem.outbasefilename = stitch_outdir(lem.filename);
   lem.basisflag = basisflag;
-  lem.nolinenosflag = nolinenosflag;
   Symbol_new("$");
   lem.errsym = Symbol_new("error");
   lem.errsym->useCnt = 0;
@@ -1615,28 +1465,16 @@ int main(int argc, char **argv)
   }
 
   /* Count and index the symbols of the grammar */
-  Symbol_new("{default}");
   lem.nsymbol = Symbol_count();
+  Symbol_new("{default}");
   lem.symbols = Symbol_arrayof();
-  for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i;
-  qsort(lem.symbols,lem.nsymbol,sizeof(struct symbol*), Symbolcmpp);
-  for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i;
-  while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; }
-  assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 );
-  lem.nsymbol = i - 1;
-  for(i=1; ISUPPER(lem.symbols[i]->name[0]); i++);
+  for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
+  qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*),
+        (int(*)(const void*, const void*))Symbolcmpp);
+  for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
+  for(i=1; isupper(lem.symbols[i]->name[0]); i++);
   lem.nterminal = i;
 
-  /* Assign sequential rule numbers */
-  for(i=0, rp=lem.rule; rp; rp=rp->next){
-    rp->iRule = rp->code ? i++ : -1;
-  }
-  for(rp=lem.rule; rp; rp=rp->next){
-    if( rp->iRule<0 ) rp->iRule = i++;
-  }
-  lem.startRule = lem.rule;
-  lem.rule = Rule_sort(lem.rule);
-
   /* Generate a reprint of the grammar, if requested on the command line */
   if( rpflag ){
     Reprint(&lem);
@@ -1670,9 +1508,8 @@ int main(int argc, char **argv)
     if( compress==0 ) CompressTables(&lem);
 
     /* Reorder and renumber the states so that states with fewer choices
-    ** occur at the end.  This is an optimization that helps make the
-    ** generated parser tables smaller. */
-    if( noResort==0 ) ResortStates(&lem);
+    ** occur at the end. */
+    ResortStates(&lem);
 
     /* Generate a report of the parser generated.  (the "y.output" file) */
     if( !quiet ) ReportOutput(&lem);
@@ -1686,15 +1523,10 @@ int main(int argc, char **argv)
     if( !mhflag ) ReportHeader(&lem);
   }
   if( statistics ){
-    printf("Parser statistics:\n");
-    stats_line("terminal symbols", lem.nterminal);
-    stats_line("non-terminal symbols", lem.nsymbol - lem.nterminal);
-    stats_line("total symbols", lem.nsymbol);
-    stats_line("rules", lem.nrule);
-    stats_line("states", lem.nxstate);
-    stats_line("conflicts", lem.nconflict);
-    stats_line("action table entries", lem.nactiontab);
-    stats_line("total table size (bytes)", lem.tablesize);
+    printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n",
+      lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule);
+    printf("                   %d states, %d parser table entries, %d conflicts\n",
+      lem.nstate, lem.tablesize, lem.nconflict);
   }
   if( lem.nconflict ){
     fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict);
@@ -1755,7 +1587,7 @@ static void *merge(void *a,void *b,int (
   }else if( b==0 ){
     head = a;
   }else{
-    if( (*cmp)(a,b)<=0 ){
+    if( (*cmp)(a,b)<0 ){
       ptr = a;
       a = NEXT(a);
     }else{
@@ -1764,7 +1596,7 @@ static void *merge(void *a,void *b,int (
     }
     head = ptr;
     while( a && b ){
-      if( (*cmp)(a,b)<=0 ){
+      if( (*cmp)(a,b)<0 ){
         NEXT(ptr) = a;
         ptr = a;
         a = NEXT(a);
@@ -1813,7 +1645,7 @@ static void *msort(void *list,void *next
     set[i] = ep;
   }
   ep = 0;
-  for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(set[i],ep,cmp,offset);
+  for(i=0; i<LISTSIZE; i++) if( set[i] ) ep = merge(ep,set[i],cmp,offset);
   return ep;
 }
 /************************ From the file "option.c" **************************/
@@ -1827,15 +1659,18 @@ static FILE *errstream;
 ** Print the command line with a carrot pointing to the k-th character
 ** of the n-th field.
 */
-static void errline(int n, int k, FILE *err)
+static void errline(n,k,err)
+int n;
+int k;
+FILE *err;
 {
   int i;
   size_t spcnt;
   if( argv[0] ) fprintf(err,"%s",argv[0]);
-  spcnt = lemonStrlen(argv[0]) + 1;
+  spcnt = strlen(argv[0]) + 1;
   for(i=1; i<n && argv[i]; i++){
     fprintf(err," %s",argv[i]);
-    spcnt += lemonStrlen(argv[i])+1;
+    spcnt += strlen(argv[i])+1;
   }
   spcnt += k;
   for(; argv[i]; i++) fprintf(err," %s",argv[i]);
@@ -1850,7 +1685,8 @@ static void errline(int n, int k, FILE *
 ** Return the index of the N-th non-switch argument.  Return -1
 ** if N is out of range.
 */
-static int argindex(int n)
+static int argindex(n)
+int n;
 {
   int i;
   int dashdash = 0;
@@ -1871,13 +1707,15 @@ static char emsg[] = "Command line synta
 /*
 ** Process a flag command line argument.
 */
-static int handleflags(int i, FILE *err)
+static int handleflags(i,err)
+int i;
+FILE *err;
 {
   int v;
   int errcnt = 0;
   int j;
   for(j=0; op[j].label; j++){
-    if( strncmp(&argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break;
+    if( strncmp(&argv[i][1],op[j].label,strlen(op[j].label))==0 ) break;
   }
   v = argv[i][0]=='-' ? 1 : 0;
   if( op[j].label==0 ){
@@ -1886,14 +1724,12 @@ static int handleflags(int i, FILE *err)
       errline(i,1,err);
     }
     errcnt++;
-  }else if( op[j].arg==0 ){
-    /* Ignore this option */
   }else if( op[j].type==OPT_FLAG ){
     *((int*)op[j].arg) = v;
   }else if( op[j].type==OPT_FFLAG ){
-    (*(void(*)(int))(op[j].arg))(v);
+    (*(void(*)())(op[j].arg))(v);
   }else if( op[j].type==OPT_FSTR ){
-    (*(void(*)(char *))(op[j].arg))(&argv[i][2]);
+    (*(void(*)())(op[j].arg))(&argv[i][2]);
   }else{
     if( err ){
       fprintf(err,"%smissing argument on switch.\n",emsg);
@@ -1907,7 +1743,9 @@ static int handleflags(int i, FILE *err)
 /*
 ** Process a command line switch which has an argument.
 */
-static int handleswitch(int i, FILE *err)
+static int handleswitch(i,err)
+int i;
+FILE *err;
 {
   int lv = 0;
   double dv = 0.0;
@@ -1944,8 +1782,7 @@ static int handleswitch(int i, FILE *err
         dv = strtod(cp,&end);
         if( *end ){
           if( err ){
-            fprintf(err,
-               "%sillegal character in floating-point argument.\n",emsg);
+            fprintf(err,"%sillegal character in floating-point argument.\n",emsg);
             errline(i,((size_t)end)-(size_t)argv[i],err);
           }
           errcnt++;
@@ -1975,26 +1812,29 @@ static int handleswitch(int i, FILE *err
         *(double*)(op[j].arg) = dv;
         break;
       case OPT_FDBL:
-        (*(void(*)(double))(op[j].arg))(dv);
+        (*(void(*)())(op[j].arg))(dv);
         break;
       case OPT_INT:
         *(int*)(op[j].arg) = lv;
         break;
       case OPT_FINT:
-        (*(void(*)(int))(op[j].arg))((int)lv);
+        (*(void(*)())(op[j].arg))((int)lv);
         break;
       case OPT_STR:
         *(char**)(op[j].arg) = sv;
         break;
       case OPT_FSTR:
-        (*(void(*)(char *))(op[j].arg))(sv);
+        (*(void(*)())(op[j].arg))(sv);
         break;
     }
   }
   return errcnt;
 }
 
-int OptInit(char **a, struct s_options *o, FILE *err)
+int OptInit(a,o,err)
+char **a;
+struct s_options *o;
+FILE *err;
 {
   int errcnt = 0;
   argv = a;
@@ -2031,14 +1871,16 @@ int OptNArgs(){
   return cnt;
 }
 
-char *OptArg(int n)
+char *OptArg(n)
+int n;
 {
   int i;
   i = argindex(n);
   return i>=0 ? argv[i] : 0;
 }
 
-void OptErr(int n)
+void OptErr(n)
+int n;
 {
   int i;
   i = argindex(n);
@@ -2050,7 +1892,7 @@ void OptPrint(){
   size_t max, len;
   max = 0;
   for(i=0; op[i].label; i++){
-    len = lemonStrlen(op[i].label) + 1;
+    len = strlen(op[i].label) + 1;
     switch( op[i].type ){
       case OPT_FLAG:
       case OPT_FFLAG:
@@ -2078,18 +1920,18 @@ void OptPrint(){
         break;
       case OPT_INT:
       case OPT_FINT:
-        fprintf(errstream,"  -%s<integer>%*s  %s\n",op[i].label,
-          (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message);
+        fprintf(errstream,"  %s=<integer>%*s  %s\n",op[i].label,
+          (int)(max-strlen(op[i].label)-9),"",op[i].message);
         break;
       case OPT_DBL:
       case OPT_FDBL:
-        fprintf(errstream,"  -%s<real>%*s  %s\n",op[i].label,
-          (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message);
+        fprintf(errstream,"  %s=<real>%*s  %s\n",op[i].label,
+          (int)(max-strlen(op[i].label)-6),"",op[i].message);
         break;
       case OPT_STR:
       case OPT_FSTR:
-        fprintf(errstream,"  -%s<string>%*s  %s\n",op[i].label,
-          (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message);
+        fprintf(errstream,"  %s=<string>%*s  %s\n",op[i].label,
+          (int)(max-strlen(op[i].label)-8),"",op[i].message);
         break;
     }
   }
@@ -2100,49 +1942,44 @@ void OptPrint(){
 */
 
 /* The state of the parser */
-enum e_state {
-  INITIALIZE,
-  WAITING_FOR_DECL_OR_RULE,
-  WAITING_FOR_DECL_KEYWORD,
-  WAITING_FOR_DECL_ARG,
-  WAITING_FOR_PRECEDENCE_SYMBOL,
-  WAITING_FOR_ARROW,
-  IN_RHS,
-  LHS_ALIAS_1,
-  LHS_ALIAS_2,
-  LHS_ALIAS_3,
-  RHS_ALIAS_1,
-  RHS_ALIAS_2,
-  PRECEDENCE_MARK_1,
-  PRECEDENCE_MARK_2,
-  RESYNC_AFTER_RULE_ERROR,
-  RESYNC_AFTER_DECL_ERROR,
-  WAITING_FOR_DESTRUCTOR_SYMBOL,
-  WAITING_FOR_DATATYPE_SYMBOL,
-  WAITING_FOR_FALLBACK_ID,
-  WAITING_FOR_WILDCARD_ID,
-  WAITING_FOR_CLASS_ID,
-  WAITING_FOR_CLASS_TOKEN
-};
 struct pstate {
   char *filename;       /* Name of the input file */
   int tokenlineno;      /* Linenumber at which current token starts */
   int errorcnt;         /* Number of errors so far */
   char *tokenstart;     /* Text of current token */
   struct lemon *gp;     /* Global state vector */
-  enum e_state state;        /* The state of the parser */
+  enum e_state {
+    INITIALIZE,
+    WAITING_FOR_DECL_OR_RULE,
+    WAITING_FOR_DECL_KEYWORD,
+    WAITING_FOR_DECL_ARG,
+    WAITING_FOR_PRECEDENCE_SYMBOL,
+    WAITING_FOR_ARROW,
+    IN_RHS,
+    LHS_ALIAS_1,
+    LHS_ALIAS_2,
+    LHS_ALIAS_3,
+    RHS_ALIAS_1,
+    RHS_ALIAS_2,
+    PRECEDENCE_MARK_1,
+    PRECEDENCE_MARK_2,
+    RESYNC_AFTER_RULE_ERROR,
+    RESYNC_AFTER_DECL_ERROR,
+    WAITING_FOR_DESTRUCTOR_SYMBOL,
+    WAITING_FOR_DATATYPE_SYMBOL,
+    WAITING_FOR_FALLBACK_ID,
+	WAITING_FOR_WILDCARD_ID
+  } state;                   /* The state of the parser */
   struct symbol *fallback;   /* The fallback token */
-  struct symbol *tkclass;    /* Token class symbol */
   struct symbol *lhs;        /* Left-hand side of current rule */
-  const char *lhsalias;      /* Alias for the LHS */
+  char *lhsalias;            /* Alias for the LHS */
   int nrhs;                  /* Number of right-hand side symbols seen */
   struct symbol *rhs[MAXRHS];  /* RHS symbols */
-  const char *alias[MAXRHS];   /* Aliases for each RHS symbol (or NULL) */
+  char *alias[MAXRHS];       /* Aliases for each RHS symbol (or NULL) */
   struct rule *prevrule;     /* Previous rule parsed */
-  const char *declkeyword;   /* Keyword of a declaration */
+  char *declkeyword;         /* Keyword of a declaration */
   char **declargslot;        /* Where the declaration argument should be put */
-  int insertLineMacro;       /* Add #line before declaration insert */
-  int *decllinenoslot;       /* Where to write declaration line number */
+  int *decllnslot;           /* Where the declaration linenumber is put */
   enum e_assoc declassoc;    /* Assign this association to decl arguments */
   int preccounter;           /* Assign this precedence to decl arguments */
   struct rule *firstrule;    /* Pointer to first rule in the grammar */
@@ -2150,9 +1987,10 @@ struct pstate {
 };
 
 /* Parse a single token */
-static void parseonetoken(struct pstate *psp)
+static void parseonetoken(psp)
+struct pstate *psp;
 {
-  const char *x;
+  char *x;
   x = Strsafe(psp->tokenstart);     /* Save the token permanently */
 #if 0
   printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno,
@@ -2168,7 +2006,7 @@ static void parseonetoken(struct pstate 
     case WAITING_FOR_DECL_OR_RULE:
       if( x[0]=='%' ){
         psp->state = WAITING_FOR_DECL_KEYWORD;
-      }else if( ISLOWER(x[0]) ){
+      }else if( islower(x[0]) ){
         psp->lhs = Symbol_new(x);
         psp->nrhs = 0;
         psp->lhsalias = 0;
@@ -2176,7 +2014,7 @@ static void parseonetoken(struct pstate 
       }else if( x[0]=='{' ){
         if( psp->prevrule==0 ){
           ErrorMsg(psp->filename,psp->tokenlineno,
-"There is no prior rule upon which to attach the code \
+"There is not prior rule opon which to attach the code \
 fragment which begins on this line.");
           psp->errorcnt++;
 	}else if( psp->prevrule->code!=0 ){
@@ -2198,7 +2036,7 @@ to follow the previous rule.");
       }
       break;
     case PRECEDENCE_MARK_1:
-      if( !ISUPPER(x[0]) ){
+      if( !isupper(x[0]) ){
         ErrorMsg(psp->filename,psp->tokenlineno,
           "The precedence symbol must be a terminal.");
         psp->errorcnt++;
@@ -2238,7 +2076,7 @@ to follow the previous rule.");
       }
       break;
     case LHS_ALIAS_1:
-      if( ISALPHA(x[0]) ){
+      if( isalpha(x[0]) ){
         psp->lhsalias = x;
         psp->state = LHS_ALIAS_2;
       }else{
@@ -2284,7 +2122,7 @@ to follow the previous rule.");
           int i;
           rp->ruleline = psp->tokenlineno;
           rp->rhs = (struct symbol**)&rp[1];
-          rp->rhsalias = (const char**)&(rp->rhs[psp->nrhs]);
+          rp->rhsalias = (char**)&(rp->rhs[psp->nrhs]);
           for(i=0; i<psp->nrhs; i++){
             rp->rhs[i] = psp->rhs[i];
             rp->rhsalias[i] = psp->alias[i];
@@ -2303,11 +2141,11 @@ to follow the previous rule.");
 	  }else{
             psp->lastrule->next = rp;
             psp->lastrule = rp;
-          }
+	  }
           psp->prevrule = rp;
-        }
+	}
         psp->state = WAITING_FOR_DECL_OR_RULE;
-      }else if( ISALPHA(x[0]) ){
+      }else if( isalpha(x[0]) ){
         if( psp->nrhs>=MAXRHS ){
           ErrorMsg(psp->filename,psp->tokenlineno,
             "Too many symbols on RHS of rule beginning at \"%s\".",
@@ -2323,19 +2161,18 @@ to follow the previous rule.");
         struct symbol *msp = psp->rhs[psp->nrhs-1];
         if( msp->type!=MULTITERMINAL ){
           struct symbol *origsp = msp;
-          msp = (struct symbol *) calloc(1,sizeof(*msp));
+          msp = calloc(1,sizeof(*msp));
           msp->type = MULTITERMINAL;
           msp->nsubsym = 1;
-          msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*));
+          msp->subsym = calloc(1,sizeof(struct symbol*));
           msp->subsym[0] = origsp;
           msp->name = origsp->name;
           psp->rhs[psp->nrhs-1] = msp;
         }
         msp->nsubsym++;
-        msp->subsym = (struct symbol **) realloc(msp->subsym,
-          sizeof(struct symbol*)*msp->nsubsym);
+        msp->subsym = realloc(msp->subsym, sizeof(struct symbol*)*msp->nsubsym);
         msp->subsym[msp->nsubsym-1] = Symbol_new(&x[1]);
-        if( ISLOWER(x[1]) || ISLOWER(msp->subsym[0]->name[0]) ){
+        if( islower(x[1]) || islower(msp->subsym[0]->name[0]) ){
           ErrorMsg(psp->filename,psp->tokenlineno,
             "Cannot form a compound containing a non-terminal");
           psp->errorcnt++;
@@ -2350,7 +2187,7 @@ to follow the previous rule.");
       }
       break;
     case RHS_ALIAS_1:
-      if( ISALPHA(x[0]) ){
+      if( isalpha(x[0]) ){
         psp->alias[psp->nrhs-1] = x;
         psp->state = RHS_ALIAS_2;
       }else{
@@ -2372,49 +2209,49 @@ to follow the previous rule.");
       }
       break;
     case WAITING_FOR_DECL_KEYWORD:
-      if( ISALPHA(x[0]) ){
+      if( isalpha(x[0]) ){
         psp->declkeyword = x;
         psp->declargslot = 0;
-        psp->decllinenoslot = 0;
-        psp->insertLineMacro = 1;
+        psp->decllnslot = 0;
         psp->state = WAITING_FOR_DECL_ARG;
         if( strcmp(x,"name")==0 ){
           psp->declargslot = &(psp->gp->name);
-          psp->insertLineMacro = 0;
 	}else if( strcmp(x,"include")==0 ){
           psp->declargslot = &(psp->gp->include);
+          psp->decllnslot = &psp->gp->includeln;
 	}else if( strcmp(x,"code")==0 ){
           psp->declargslot = &(psp->gp->extracode);
+          psp->decllnslot = &psp->gp->extracodeln;
 	}else if( strcmp(x,"token_destructor")==0 ){
           psp->declargslot = &psp->gp->tokendest;
+          psp->decllnslot = &psp->gp->tokendestln;
 	}else if( strcmp(x,"default_destructor")==0 ){
           psp->declargslot = &psp->gp->vardest;
+          psp->decllnslot = &psp->gp->vardestln;
 	}else if( strcmp(x,"token_prefix")==0 ){
           psp->declargslot = &psp->gp->tokenprefix;
-          psp->insertLineMacro = 0;
 	}else if( strcmp(x,"syntax_error")==0 ){
           psp->declargslot = &(psp->gp->error);
+          psp->decllnslot = &psp->gp->errorln;
 	}else if( strcmp(x,"parse_accept")==0 ){
           psp->declargslot = &(psp->gp->accept);
+          psp->decllnslot = &psp->gp->acceptln;
 	}else if( strcmp(x,"parse_failure")==0 ){
           psp->declargslot = &(psp->gp->failure);
+          psp->decllnslot = &psp->gp->failureln;
 	}else if( strcmp(x,"stack_overflow")==0 ){
           psp->declargslot = &(psp->gp->overflow);
+          psp->decllnslot = &psp->gp->overflowln;
         }else if( strcmp(x,"extra_argument")==0 ){
           psp->declargslot = &(psp->gp->arg);
-          psp->insertLineMacro = 0;
         }else if( strcmp(x,"token_type")==0 ){
           psp->declargslot = &(psp->gp->tokentype);
-          psp->insertLineMacro = 0;
         }else if( strcmp(x,"default_type")==0 ){
           psp->declargslot = &(psp->gp->vartype);
-          psp->insertLineMacro = 0;
         }else if( strcmp(x,"stack_size")==0 ){
           psp->declargslot = &(psp->gp->stacksize);
-          psp->insertLineMacro = 0;
         }else if( strcmp(x,"start_symbol")==0 ){
           psp->declargslot = &(psp->gp->start);
-          psp->insertLineMacro = 0;
         }else if( strcmp(x,"left")==0 ){
           psp->preccounter++;
           psp->declassoc = LEFT;
@@ -2436,8 +2273,6 @@ to follow the previous rule.");
           psp->state = WAITING_FOR_FALLBACK_ID;
         }else if( strcmp(x,"wildcard")==0 ){
           psp->state = WAITING_FOR_WILDCARD_ID;
-        }else if( strcmp(x,"token_class")==0 ){
-          psp->state = WAITING_FOR_CLASS_ID;
         }else{
           ErrorMsg(psp->filename,psp->tokenlineno,
             "Unknown declaration keyword: \"%%%s\".",x);
@@ -2452,7 +2287,7 @@ to follow the previous rule.");
       }
       break;
     case WAITING_FOR_DESTRUCTOR_SYMBOL:
-      if( !ISALPHA(x[0]) ){
+      if( !isalpha(x[0]) ){
         ErrorMsg(psp->filename,psp->tokenlineno,
           "Symbol name missing after %%destructor keyword");
         psp->errorcnt++;
@@ -2460,38 +2295,27 @@ to follow the previous rule.");
       }else{
         struct symbol *sp = Symbol_new(x);
         psp->declargslot = &sp->destructor;
-		psp->decllinenoslot = &sp->destLineno;
-        psp->insertLineMacro = 1;
+        psp->decllnslot = &sp->destructorln;
         psp->state = WAITING_FOR_DECL_ARG;
       }
       break;
     case WAITING_FOR_DATATYPE_SYMBOL:
-      if( !ISALPHA(x[0]) ){
+      if( !isalpha(x[0]) ){
         ErrorMsg(psp->filename,psp->tokenlineno,
-          "Symbol name missing after %%type keyword");
+          "Symbol name missing after %%destructor keyword");
         psp->errorcnt++;
         psp->state = RESYNC_AFTER_DECL_ERROR;
       }else{
-        struct symbol *sp = Symbol_find(x);
-        if((sp) && (sp->datatype)){
-          ErrorMsg(psp->filename,psp->tokenlineno,
-            "Symbol %%type \"%s\" already defined", x);
-          psp->errorcnt++;
-          psp->state = RESYNC_AFTER_DECL_ERROR;
-        }else{
-          if (!sp){
-            sp = Symbol_new(x);
-          }
-          psp->declargslot = &sp->datatype;
-          psp->insertLineMacro = 0;
-          psp->state = WAITING_FOR_DECL_ARG;
-        }
+        struct symbol *sp = Symbol_new(x);
+        psp->declargslot = &sp->datatype;
+        psp->decllnslot = 0;
+        psp->state = WAITING_FOR_DECL_ARG;
       }
       break;
     case WAITING_FOR_PRECEDENCE_SYMBOL:
       if( x[0]=='.' ){
         psp->state = WAITING_FOR_DECL_OR_RULE;
-      }else if( ISUPPER(x[0]) ){
+      }else if( isupper(x[0]) ){
         struct symbol *sp;
         sp = Symbol_new(x);
         if( sp->prec>=0 ){
@@ -2509,57 +2333,18 @@ to follow the previous rule.");
       }
       break;
     case WAITING_FOR_DECL_ARG:
-      if( x[0]=='{' || x[0]=='\"' || ISALNUM(x[0]) ){
-        const char *zOld, *zNew;
-        char *zBuf, *z;
-        int nOld, n, nLine, nNew, nBack;
-		int addLineMacro;
-        char zLine[50];
-        zNew = x;
-        if( zNew[0]=='"' || zNew[0]=='{' ) zNew++;
-        nNew = lemonStrlen(zNew);
-        if( *psp->declargslot ){
-          zOld = *psp->declargslot;
-        }else{
-          zOld = "";
-        }
-        nOld = lemonStrlen(zOld);
-        n = nOld + nNew + 20;
-		addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro &&
-			            (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0);
-		if( addLineMacro ){
-          for(z=psp->filename, nBack=0; *z; z++){
-            if( *z=='\\' ) nBack++;
-          }
-          sprintf(zLine, "#line %d ", psp->tokenlineno);
-          nLine = lemonStrlen(zLine);
-          n += nLine + lemonStrlen(psp->filename) + nBack;
-        }
-        *psp->declargslot = (char *) realloc(*psp->declargslot, n);
-        zBuf = *psp->declargslot + nOld;
-        if( addLineMacro ){
-          if( nOld && zBuf[-1]!='\n' ){
-            *(zBuf++) = '\n';
-          }
-          memcpy(zBuf, zLine, nLine);
-          zBuf += nLine;
-          *(zBuf++) = '"';
-          for(z=psp->filename; *z; z++){
-            if( *z=='\\' ){
-              *(zBuf++) = '\\';
-            }
-            *(zBuf++) = *z;
-          }
-          *(zBuf++) = '"';
-          *(zBuf++) = '\n';
-        }
-		if( psp->decllinenoslot && psp->decllinenoslot[0]==0 ){
-		  psp->decllinenoslot[0] = psp->tokenlineno;
-		}
-        memcpy(zBuf, zNew, nNew);
-        zBuf += nNew;
-        *zBuf = 0;
-        psp->state = WAITING_FOR_DECL_OR_RULE;
+      if( (x[0]=='{' || x[0]=='\"' || isalnum(x[0])) ){
+        if( *(psp->declargslot)!=0 ){
+          ErrorMsg(psp->filename,psp->tokenlineno,
+            "The argument \"%s\" to declaration \"%%%s\" is not the first.",
+            x[0]=='\"' ? &x[1] : x,psp->declkeyword);
+          psp->errorcnt++;
+          psp->state = RESYNC_AFTER_DECL_ERROR;
+	}else{
+          *(psp->declargslot) = (x[0]=='\"' || x[0]=='{') ? &x[1] : x;
+          if( psp->decllnslot ) *psp->decllnslot = psp->tokenlineno;
+          psp->state = WAITING_FOR_DECL_OR_RULE;
+	}
       }else{
         ErrorMsg(psp->filename,psp->tokenlineno,
           "Illegal argument to %%%s: %s",psp->declkeyword,x);
@@ -2570,7 +2355,7 @@ to follow the previous rule.");
     case WAITING_FOR_FALLBACK_ID:
       if( x[0]=='.' ){
         psp->state = WAITING_FOR_DECL_OR_RULE;
-      }else if( !ISUPPER(x[0]) ){
+      }else if( !isupper(x[0]) ){
         ErrorMsg(psp->filename, psp->tokenlineno,
           "%%fallback argument \"%s\" should be a token", x);
         psp->errorcnt++;
@@ -2591,7 +2376,7 @@ to follow the previous rule.");
     case WAITING_FOR_WILDCARD_ID:
       if( x[0]=='.' ){
         psp->state = WAITING_FOR_DECL_OR_RULE;
-      }else if( !ISUPPER(x[0]) ){
+      }else if( !isupper(x[0]) ){
         ErrorMsg(psp->filename, psp->tokenlineno,
           "%%wildcard argument \"%s\" should be a token", x);
         psp->errorcnt++;
@@ -2606,40 +2391,6 @@ to follow the previous rule.");
         }
       }
       break;
-    case WAITING_FOR_CLASS_ID:
-      if( !ISLOWER(x[0]) ){
-        ErrorMsg(psp->filename, psp->tokenlineno,
-          "%%token_class must be followed by an identifier: ", x);
-        psp->errorcnt++;
-        psp->state = RESYNC_AFTER_DECL_ERROR;
-     }else if( Symbol_find(x) ){
-        ErrorMsg(psp->filename, psp->tokenlineno,
-          "Symbol \"%s\" already used", x);
-        psp->errorcnt++;
-        psp->state = RESYNC_AFTER_DECL_ERROR;
-      }else{
-        psp->tkclass = Symbol_new(x);
-        psp->tkclass->type = MULTITERMINAL;
-        psp->state = WAITING_FOR_CLASS_TOKEN;
-      }
-      break;
-    case WAITING_FOR_CLASS_TOKEN:
-      if( x[0]=='.' ){
-        psp->state = WAITING_FOR_DECL_OR_RULE;
-      }else if( ISUPPER(x[0]) || ((x[0]=='|' || x[0]=='/') && ISUPPER(x[1])) ){
-        struct symbol *msp = psp->tkclass;
-        msp->nsubsym++;
-        msp->subsym = (struct symbol **) realloc(msp->subsym,
-          sizeof(struct symbol*)*msp->nsubsym);
-        if( !ISUPPER(x[0]) ) x++;
-        msp->subsym[msp->nsubsym-1] = Symbol_new(x);
-      }else{
-        ErrorMsg(psp->filename, psp->tokenlineno,
-          "%%token_class argument \"%s\" should be a token", x);
-        psp->errorcnt++;
-        psp->state = RESYNC_AFTER_DECL_ERROR;
-      }
-      break;
     case RESYNC_AFTER_RULE_ERROR:
 /*      if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
 **      break; */
@@ -2650,7 +2401,7 @@ to follow the previous rule.");
   }
 }
 
-/* Run the preprocessor over the input file text.  The global variables
+/* Run the proprocessor over the input file text.  The global variables
 ** azDefine[0] through azDefine[nDefine-1] contains the names of all defined
 ** macros.  This routine looks for "%ifdef" and "%ifndef" and "%endif" and
 ** comments them out.  Text in between is also commented out as appropriate.
@@ -2664,7 +2415,7 @@ static void preprocess_input(char *z){
   for(i=0; z[i]; i++){
     if( z[i]=='\n' ) lineno++;
     if( z[i]!='%' || (i>0 && z[i-1]!='\n') ) continue;
-    if( strncmp(&z[i],"%endif",6)==0 && ISSPACE(z[i+6]) ){
+    if( strncmp(&z[i],"%endif",6)==0 && isspace(z[i+6]) ){
       if( exclude ){
         exclude--;
         if( exclude==0 ){
@@ -2672,16 +2423,16 @@ static void preprocess_input(char *z){
         }
       }
       for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
-    }else if( (strncmp(&z[i],"%ifdef",6)==0 && ISSPACE(z[i+6]))
-          || (strncmp(&z[i],"%ifndef",7)==0 && ISSPACE(z[i+7])) ){
+    }else if( (strncmp(&z[i],"%ifdef",6)==0 && isspace(z[i+6]))
+          || (strncmp(&z[i],"%ifndef",7)==0 && isspace(z[i+7])) ){
       if( exclude ){
         exclude++;
       }else{
-        for(j=i+7; ISSPACE(z[j]); j++){}
-        for(n=0; z[j+n] && !ISSPACE(z[j+n]); n++){}
+        for(j=i+7; isspace(z[j]); j++){}
+        for(n=0; z[j+n] && !isspace(z[j+n]); n++){}
         exclude = 1;
         for(k=0; k<nDefine; k++){
-          if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){
+          if( strncmp(azDefine[k],&z[j],n)==0 && strlen(azDefine[k])==n ){
             exclude = 0;
             break;
           }
@@ -2723,7 +2474,8 @@ int filesize;
 ** token is passed to the function "parseonetoken" which builds all
 ** the appropriate data structures in the global state vector "gp".
 */
-void Parse(struct lemon *gp)
+void Parse(gp)
+struct lemon *gp;
 {
   struct pstate ps;
   FILE *fp;
@@ -2751,8 +2503,9 @@ void Parse(struct lemon *gp)
   filesize = ftell(fp);
   rewind(fp);
   filebuf = (char *)malloc( filesize+1 );
-  if( filesize>100000000 || filebuf==0 ){
-    ErrorMsg(ps.filename,0,"Input file too large.");
+  if( filebuf==0 ){
+    ErrorMsg(ps.filename,0,"Can't allocate %d of memory to hold this file.",
+      filesize+1);
     gp->errorcnt++;
     fclose(fp);
     return;
@@ -2761,8 +2514,8 @@ void Parse(struct lemon *gp)
     ErrorMsg(ps.filename,0,"Can't read in all %d bytes of this file.",
       filesize);
     free(filebuf);
-    gp->errorcnt++;
     fclose(fp);
+    gp->errorcnt++;
     return;
   }
   fclose(fp);
@@ -2776,7 +2529,7 @@ void Parse(struct lemon *gp)
   lineno = 1;
   for(cp=filebuf; (c= *cp)!=0; ){
     if( c=='\n' ) lineno++;              /* Keep track of the line number */
-    if( ISSPACE(c) ){ cp++; continue; }  /* Skip all white space */
+    if( isspace(c) ){ cp++; continue; }  /* Skip all white space */
     if( c=='/' && cp[1]=='/' ){          /* Skip C++ style comments */
       cp+=2;
       while( (c= *cp)!=0 && c!='\n' ) cp++;
@@ -2846,15 +2599,15 @@ void Parse(struct lemon *gp)
       }else{
         nextcp = cp+1;
       }
-    }else if( ISALNUM(c) ){          /* Identifiers */
-      while( (c= *cp)!=0 && (ISALNUM(c) || c=='_') ) cp++;
+    }else if( isalnum(c) ){          /* Identifiers */
+      while( (c= *cp)!=0 && (isalnum(c) || c=='_') ) cp++;
       nextcp = cp;
     }else if( c==':' && cp[1]==':' && cp[2]=='=' ){ /* The operator "::=" */
       cp += 3;
       nextcp = cp;
-    }else if( (c=='/' || c=='|') && ISALPHA(cp[1]) ){
+    }else if( (c=='/' || c=='|') && isalpha(cp[1]) ){
       cp += 2;
-      while( (c = *cp)!=0 && (ISALNUM(c) || c=='_') ) cp++;
+      while( (c = *cp)!=0 && (isalnum(c) || c=='_') ) cp++;
       nextcp = cp;
     }else{                          /* All other (one character) operators */
       cp++;
@@ -2879,7 +2632,7 @@ static struct plink *plink_freelist = 0;
 
 /* Allocate a new plink */
 struct plink *Plink_new(){
-  struct plink *newlink;
+  struct plink *new;
 
   if( plink_freelist==0 ){
     int i;
@@ -2893,23 +2646,27 @@ struct plink *Plink_new(){
     for(i=0; i<amt-1; i++) plink_freelist[i].next = &plink_freelist[i+1];
     plink_freelist[amt-1].next = 0;
   }
-  newlink = plink_freelist;
+  new = plink_freelist;
   plink_freelist = plink_freelist->next;
-  return newlink;
+  return new;
 }
 
 /* Add a plink to a plink list */
-void Plink_add(struct plink **plpp, struct config *cfp)
-{
-  struct plink *newlink;
-  newlink = Plink_new();
-  newlink->next = *plpp;
-  *plpp = newlink;
-  newlink->cfp = cfp;
+void Plink_add(plpp,cfp)
+struct plink **plpp;
+struct config *cfp;
+{
+  struct plink *new;
+  new = Plink_new();
+  new->next = *plpp;
+  *plpp = new;
+  new->cfp = cfp;
 }
 
 /* Transfer every plink on the list "from" to the list "to" */
-void Plink_copy(struct plink **to, struct plink *from)
+void Plink_copy(to,from)
+struct plink **to;
+struct plink *from;
 {
   struct plink *nextpl;
   while( from ){
@@ -2921,7 +2678,8 @@ void Plink_copy(struct plink **to, struc
 }
 
 /* Delete every plink on the list */
-void Plink_delete(struct plink *plp)
+void Plink_delete(plp)
+struct plink *plp;
 {
   struct plink *nextpl;
 
@@ -2941,17 +2699,19 @@ void Plink_delete(struct plink *plp)
 ** name comes from malloc() and must be freed by the calling
 ** function.
 */
-PRIVATE char *file_makename(struct lemon *lemp, const char *suffix)
+PRIVATE char *file_makename(lemp,suffix)
+struct lemon *lemp;
+char *suffix;
 {
   char *name;
   char *cp;
 
-  name = (char*)malloc( lemonStrlen(lemp->outbasefilename) + lemonStrlen(suffix) + 5 );
+  name = malloc( strlen(lemp->filename) + strlen(suffix) + 5 );
   if( name==0 ){
     fprintf(stderr,"Can't allocate space for a filename.\n");
     exit(1);
   }
-  strcpy(name,lemp->outbasefilename);
+  strcpy(name,lemp->filename);
   cp = strrchr(name,'.');
   if( cp ) *cp = 0;
   strcat(name,suffix);
@@ -2961,11 +2721,11 @@ PRIVATE char *file_makename(struct lemon
 /* Open a file with a name based on the name of the input file,
 ** but with a different (specified) suffix, and return a pointer
 ** to the stream */
-PRIVATE FILE *file_open(
-  struct lemon *lemp,
-  const char *suffix,
-  const char *mode
-){
+PRIVATE FILE *file_open(lemp,suffix,mode)
+struct lemon *lemp;
+char *suffix;
+char *mode;
+{
   FILE *fp;
 
   if( lemp->outname ) free(lemp->outname);
@@ -2981,7 +2741,8 @@ PRIVATE FILE *file_open(
 
 /* Duplicate the input file without comments and without actions 
 ** on rules */
-void Reprint(struct lemon *lemp)
+void Reprint(lemp)
+struct lemon *lemp;
 {
   struct rule *rp;
   struct symbol *sp;
@@ -2990,7 +2751,7 @@ void Reprint(struct lemon *lemp)
   maxlen = 10;
   for(i=0; i<lemp->nsymbol; i++){
     sp = lemp->symbols[i];
-    len = lemonStrlen(sp->name);
+    len = (int)strlen(sp->name);
     if( len>maxlen ) maxlen = len;
   }
   ncolumns = 76/(maxlen+5);
@@ -3011,13 +2772,11 @@ void Reprint(struct lemon *lemp)
     printf(" ::=");
     for(i=0; i<rp->nrhs; i++){
       sp = rp->rhs[i];
+      printf(" %s", sp->name);
       if( sp->type==MULTITERMINAL ){
-        printf(" %s", sp->subsym[0]->name);
         for(j=1; j<sp->nsubsym; j++){
           printf("|%s", sp->subsym[j]->name);
         }
-      }else{
-        printf(" %s", sp->name);
       }
       /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */
     }
@@ -3028,33 +2787,28 @@ void Reprint(struct lemon *lemp)
   }
 }
 
-/* Print a single rule.
-*/
-void RulePrint(FILE *fp, struct rule *rp, int iCursor){
+void ConfigPrint(fp,cfp)
+FILE *fp;
+struct config *cfp;
+{
+  struct rule *rp;
   struct symbol *sp;
   int i, j;
+  rp = cfp->rp;
   fprintf(fp,"%s ::=",rp->lhs->name);
   for(i=0; i<=rp->nrhs; i++){
-    if( i==iCursor ) fprintf(fp," *");
+    if( i==cfp->dot ) fprintf(fp," *");
     if( i==rp->nrhs ) break;
     sp = rp->rhs[i];
+    fprintf(fp," %s", sp->name);
     if( sp->type==MULTITERMINAL ){
-      fprintf(fp," %s", sp->subsym[0]->name);
       for(j=1; j<sp->nsubsym; j++){
         fprintf(fp,"|%s",sp->subsym[j]->name);
       }
-    }else{
-      fprintf(fp," %s", sp->name);
     }
   }
 }
 
-/* Print the rule for a configuration.
-*/
-void ConfigPrint(FILE *fp, struct config *cfp){
-  RulePrint(fp, cfp->rp, cfp->dot);
-}
-
 /* #define TEST */
 #if 0
 /* Print a set */
@@ -3094,30 +2848,15 @@ char *tag;
 /* Print an action to the given file descriptor.  Return FALSE if
 ** nothing was actually printed.
 */
-int PrintAction(
-  struct action *ap,          /* The action to print */
-  FILE *fp,                   /* Print the action here */
-  int indent                  /* Indent by this amount */
-){
+int PrintAction(struct action *ap, FILE *fp, int indent){
   int result = 1;
   switch( ap->type ){
-    case SHIFT: {
-      struct state *stp = ap->x.stp;
-      fprintf(fp,"%*s shift        %-7d",indent,ap->sp->name,stp->statenum);
+    case SHIFT:
+      fprintf(fp,"%*s shift  %d",indent,ap->sp->name,ap->x.stp->statenum);
       break;
-    }
-    case REDUCE: {
-      struct rule *rp = ap->x.rp;
-      fprintf(fp,"%*s reduce       %-7d",indent,ap->sp->name,rp->iRule);
-      RulePrint(fp, rp, -1);
+    case REDUCE:
+      fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index);
       break;
-    }
-    case SHIFTREDUCE: {
-      struct rule *rp = ap->x.rp;
-      fprintf(fp,"%*s shift-reduce %-7d",indent,ap->sp->name,rp->iRule);
-      RulePrint(fp, rp, -1);
-      break;
-    }
     case ACCEPT:
       fprintf(fp,"%*s accept",indent,ap->sp->name);
       break;
@@ -3126,29 +2865,15 @@ int PrintAction(
       break;
     case SRCONFLICT:
     case RRCONFLICT:
-      fprintf(fp,"%*s reduce       %-7d ** Parsing conflict **",
-        indent,ap->sp->name,ap->x.rp->iRule);
+      fprintf(fp,"%*s reduce %-3d ** Parsing conflict **",
+        indent,ap->sp->name,ap->x.rp->index);
       break;
     case SSCONFLICT:
-      fprintf(fp,"%*s shift        %-7d ** Parsing conflict **", 
+      fprintf(fp,"%*s shift  %d ** Parsing conflict **", 
         indent,ap->sp->name,ap->x.stp->statenum);
       break;
     case SH_RESOLVED:
-      if( showPrecedenceConflict ){
-        fprintf(fp,"%*s shift        %-7d -- dropped by precedence",
-                indent,ap->sp->name,ap->x.stp->statenum);
-      }else{
-        result = 0;
-      }
-      break;
     case RD_RESOLVED:
-      if( showPrecedenceConflict ){
-        fprintf(fp,"%*s reduce %-7d -- dropped by precedence",
-                indent,ap->sp->name,ap->x.rp->iRule);
-      }else{
-        result = 0;
-      }
-      break;
     case NOT_USED:
       result = 0;
       break;
@@ -3156,8 +2881,9 @@ int PrintAction(
   return result;
 }
 
-/* Generate the "*.out" log file */
-void ReportOutput(struct lemon *lemp)
+/* Generate the "y.output" log file */
+void ReportOutput(lemp)
+struct lemon *lemp;
 {
   int i;
   struct state *stp;
@@ -3167,7 +2893,7 @@ void ReportOutput(struct lemon *lemp)
 
   fp = file_open(lemp,".out","wb");
   if( fp==0 ) return;
-  for(i=0; i<lemp->nxstate; i++){
+  for(i=0; i<lemp->nstate; i++){
     stp = lemp->sorted[i];
     fprintf(fp,"State %d:\n",stp->statenum);
     if( lemp->basisflag ) cfp=stp->bp;
@@ -3175,7 +2901,7 @@ void ReportOutput(struct lemon *lemp)
     while( cfp ){
       char buf[20];
       if( cfp->dot==cfp->rp->nrhs ){
-        sprintf(buf,"(%d)",cfp->rp->iRule);
+        sprintf(buf,"(%d)",cfp->rp->index);
         fprintf(fp,"    %5s ",buf);
       }else{
         fprintf(fp,"          ");
@@ -3223,16 +2949,17 @@ void ReportOutput(struct lemon *lemp)
 
 /* Search for the file "name" which is in the same directory as
 ** the exacutable */
-PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
+PRIVATE char *pathsearch(argv0,name,modemask)
+char *argv0;
+char *name;
+int modemask;
 {
-  const char *pathlist;
-  char *pathbufptr;
-  char *pathbuf;
+  char *pathlist;
   char *path,*cp;
   char c;
 
 #ifdef __WIN32__
-  for (cp = argv0 + lemonStrlen(argv0); cp-- > argv0; )
+  for (cp = argv0 + strlen(argv0); cp-- > argv0; )
   {
     if( *cp == '\\' || *cp == '/' )
       break;
@@ -3243,29 +2970,26 @@ PRIVATE char *pathsearch(char *argv0, ch
   if( cp ){
     c = *cp;
     *cp = 0;
-    path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 );
+    path = (char *)malloc( strlen(argv0) + strlen(name) + 2 );
     if( path ) sprintf(path,"%s/%s",argv0,name);
     *cp = c;
   }else{
+    extern char *getenv();
     pathlist = getenv("PATH");
     if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
-    pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 );
-    path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 );
-    if( (pathbuf != 0) && (path!=0) ){
-      pathbufptr = pathbuf;
-      strcpy(pathbuf, pathlist);
-      while( *pathbuf ){
-        cp = strchr(pathbuf,':');
-        if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)];
+    path = (char *)malloc( strlen(pathlist)+strlen(name)+2 );
+    if( path!=0 ){
+      while( *pathlist ){
+        cp = strchr(pathlist,':');
+        if( cp==0 ) cp = &pathlist[strlen(pathlist)];
         c = *cp;
         *cp = 0;
-        sprintf(path,"%s/%s",pathbuf,name);
+        sprintf(path,"%s/%s",pathlist,name);
         *cp = c;
-        if( c==0 ) pathbuf[0] = 0;
-        else pathbuf = &cp[1];
+        if( c==0 ) pathlist = "";
+        else pathlist = &cp[1];
         if( access(path,modemask)==0 ) break;
       }
-      free(pathbufptr);
     }
   }
   return path;
@@ -3275,15 +2999,16 @@ PRIVATE char *pathsearch(char *argv0, ch
 ** which is to be put in the action table of the generated machine.
 ** Return negative if no action should be generated.
 */
-PRIVATE int compute_action(struct lemon *lemp, struct action *ap)
+PRIVATE int compute_action(lemp,ap)
+struct lemon *lemp;
+struct action *ap;
 {
   int act;
   switch( ap->type ){
-    case SHIFT:  act = ap->x.stp->statenum;                        break;
-    case SHIFTREDUCE: act = ap->x.rp->iRule + lemp->nstate;        break;
-    case REDUCE: act = ap->x.rp->iRule + lemp->nstate+lemp->nrule; break;
-    case ERROR:  act = lemp->nstate + lemp->nrule*2;               break;
-    case ACCEPT: act = lemp->nstate + lemp->nrule*2 + 1;           break;
+    case SHIFT:  act = ap->x.stp->statenum;            break;
+    case REDUCE: act = ap->x.rp->index + lemp->nstate; break;
+    case ERROR:  act = lemp->nstate + lemp->nrule;     break;
+    case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break;
     default:     act = -1; break;
   }
   return act;
@@ -3299,7 +3024,11 @@ PRIVATE int compute_action(struct lemon 
 ** if name!=0, then any word that begin with "Parse" is changed to
 ** begin with *name instead.
 */
-PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno)
+PRIVATE void tplt_xfer(name,in,out,lineno)
+char *name;
+FILE *in;
+FILE *out;
+int *lineno;
 {
   int i, iStart;
   char line[LINESIZE];
@@ -3309,7 +3038,7 @@ PRIVATE void tplt_xfer(char *name, FILE 
     if( name ){
       for(i=0; line[i]; i++){
         if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0
-          && (i==0 || !ISALPHA(line[i-1]))
+          && (i==0 || !isalpha(line[i-1]))
         ){
           if( i>iStart ) fprintf(out,"%.*s",i-iStart,&line[iStart]);
           fprintf(out,"%s",name);
@@ -3324,7 +3053,8 @@ PRIVATE void tplt_xfer(char *name, FILE 
 
 /* The next function finds the template file and opens it, returning
 ** a pointer to the opened file. */
-PRIVATE FILE *tplt_open(struct lemon *lemp)
+PRIVATE FILE *tplt_open(lemp)
+struct lemon *lemp;
 {
   static char templatename[] = "lempar.c";
   char buf[1000];
@@ -3333,24 +3063,6 @@ PRIVATE FILE *tplt_open(struct lemon *le
   char *cp;
   Boolean tpltnameinbuf;
 
-  /* first, see if user specified a template filename on the command line. */
-  if (user_templatename != 0) {
-    if( access(user_templatename,004)==-1 ){
-      fprintf(stderr,"Can't find the parser driver template file \"%s\".\n",
-        user_templatename);
-      lemp->errorcnt++;
-      return 0;
-    }
-    in = fopen(user_templatename,"rb");
-    if( in==0 ){
-      fprintf(stderr,"Can't open the template file \"%s\".\n",
-              user_templatename);
-      lemp->errorcnt++;
-      return 0;
-    }
-    return in;
-  }
-
   cp = strrchr(lemp->filename,'.');
   if( cp ){
     sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename);
@@ -3385,7 +3097,10 @@ PRIVATE FILE *tplt_open(struct lemon *le
 }
 
 /* Print a #line directive line to the output file. */
-PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename)
+PRIVATE void tplt_linedir(out,lineno,filename)
+FILE *out;
+int lineno;
+char *filename;
 {
   fprintf(out,"#line %d \"",lineno);
   while( *filename ){
@@ -3397,9 +3112,16 @@ PRIVATE void tplt_linedir(FILE *out, int
 }
 
 /* Print a string to the file and keep the linenumber up to date */
-PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno)
+PRIVATE void tplt_print(out,lemp,str,strln,lineno)
+FILE *out;
+struct lemon *lemp;
+char *str;
+int strln;
+int *lineno;
 {
   if( str==0 ) return;
+  tplt_linedir(out,strln,lemp->filename);
+  (*lineno)++;
   while( *str ){
     if( *str=='\n' ) (*lineno)++;
     putc(*str,out);
@@ -3409,10 +3131,8 @@ PRIVATE void tplt_print(FILE *out, struc
     putc('\n',out);
     (*lineno)++;
   }
-  if (!lemp->nolinenosflag) {
-	(*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
-  }
-
+  tplt_linedir(out,*lineno+1,lemp->outname); 
+  (*lineno)+=1;
   return;
 }
 
@@ -3420,29 +3140,29 @@ PRIVATE void tplt_print(FILE *out, struc
 ** The following routine emits code for the destructor for the
 ** symbol sp
 */
-void emit_destructor_code(
-  FILE *out,
-  struct symbol *sp,
-  struct lemon *lemp,
-  int *lineno
-){
+void emit_destructor_code(out,sp,lemp,lineno)
+FILE *out;
+struct symbol *sp;
+struct lemon *lemp;
+int *lineno;
+{
  char *cp = 0;
 
+ int linecnt = 0;
  if( sp->type==TERMINAL ){
    cp = lemp->tokendest;
    if( cp==0 ) return;
-   fprintf(out,"{\n"); (*lineno)++;
+   tplt_linedir(out,lemp->tokendestln,lemp->filename);
+   fprintf(out,"{");
  }else if( sp->destructor ){
    cp = sp->destructor;
-   fprintf(out,"{\n"); (*lineno)++;
-   if( !lemp->nolinenosflag ){
-     (*lineno)++;
-     tplt_linedir(out,sp->destLineno,lemp->filename);
-   }
+   tplt_linedir(out,sp->destructorln,lemp->filename);
+   fprintf(out,"{");
  }else if( lemp->vardest ){
    cp = lemp->vardest;
    if( cp==0 ) return;
-   fprintf(out,"{\n"); (*lineno)++;
+   tplt_linedir(out,lemp->vardestln,lemp->filename);
+   fprintf(out,"{");
  }else{
    assert( 0 );  /* Cannot happen */
  }
@@ -3452,21 +3172,21 @@ void emit_destructor_code(
      cp++;
      continue;
    }
-   if( *cp=='\n' ) (*lineno)++;
+   if( *cp=='\n' ) linecnt++;
    fputc(*cp,out);
  }
- fprintf(out,"\n"); (*lineno)++;
- if (!lemp->nolinenosflag) {
-   (*lineno)++; tplt_linedir(out,*lineno,lemp->outname);
- }
- fprintf(out,"}\n"); (*lineno)++;
+ (*lineno) += 3 + linecnt;
+ fprintf(out,"}\n");
+ tplt_linedir(out,*lineno,lemp->outname);
  return;
 }
 
 /*
 ** Return TRUE (non-zero) if the given symbol has a destructor.
 */
-int has_destructor(struct symbol *sp, struct lemon *lemp)
+int has_destructor(sp, lemp)
+struct symbol *sp;
+struct lemon *lemp;
 {
   int ret;
   if( sp->type==TERMINAL ){
@@ -3489,15 +3209,14 @@ int has_destructor(struct symbol *sp, st
 **
 ** If n==-1, then the previous character is overwritten.
 */
-PRIVATE char *append_str(const char *zText, int n, int p1, int p2, int bNoSubst){
-  static char empty[1] = { 0 };
+PRIVATE char *append_str(char *zText, int n, int p1, int p2, int bNoSubst){
   static char *z = 0;
   static int alloced = 0;
   static int used = 0;
   int c;
   char zInt[40];
+
   if( zText==0 ){
-    if( used==0 && z!=0 ) z[0] = 0;
     used = 0;
     return z;
   }
@@ -3506,20 +3225,20 @@ PRIVATE char *append_str(const char *zTe
       used += n;
       assert( used>=0 );
     }
-    n = lemonStrlen(zText);
+    n = (int)strlen(zText);
   }
   if( n+sizeof(zInt)*2+used >= (size_t)alloced ){
     alloced = n + sizeof(zInt)*2 + used + 200;
-    z = (char *) realloc(z,  alloced);
+    z = realloc(z,  alloced);
   }
-  if( z==0 ) return empty;
+  if( z==0 ) return "";
   while( n-- > 0 ){
     c = *(zText++);
     if( !bNoSubst && c=='%' && n>0 && zText[0]=='d' ){
       sprintf(zInt, "%d", p1);
       p1 = p2;
       strcpy(&z[used], zInt);
-      used += lemonStrlen(&z[used]);
+      used += (int)strlen(&z[used]);
       zText++;
       n--;
     }else{
@@ -3534,106 +3253,36 @@ PRIVATE char *append_str(const char *zTe
 ** zCode is a string that is the action associated with a rule.  Expand
 ** the symbols in this string so that the refer to elements of the parser
 ** stack.
-**
-** Return 1 if the expanded code requires that "yylhsminor" local variable
-** to be defined.
 */
-PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
+PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
   char *cp, *xp;
   int i;
-  int rc = 0;            /* True if yylhsminor is used */
-  int dontUseRhs0 = 0;   /* If true, use of left-most RHS label is illegal */
-  const char *zSkip = 0; /* The zOvwrt comment within rp->code, or NULL */
-  char lhsused = 0;      /* True if the LHS element has been used */
-  char lhsdirect;        /* True if LHS writes directly into stack */
-  char used[MAXRHS];     /* True for each RHS element which is used */
-  char zLhs[50];         /* Convert the LHS symbol into this string */
-  char zOvwrt[900];      /* Comment that to allow LHS to overwrite RHS */
+  char lhsused = 0;    /* True if the LHS element has been used */
+  char used[MAXRHS];   /* True for each RHS element which is used */
 
   for(i=0; i<rp->nrhs; i++) used[i] = 0;
   lhsused = 0;
 
   if( rp->code==0 ){
-    static char newlinestr[2] = { '\n', '\0' };
-    rp->code = newlinestr;
-    rp->line = rp->ruleline;
-  }
-
-  if( rp->lhsalias==0 ){
-    /* There is no LHS value symbol. */
-    lhsdirect = 1;
-  }else if( rp->nrhs==0 ){
-    /* If there are no RHS symbols, then writing directly to the LHS is ok */
-    lhsdirect = 1;
-  }else if( rp->rhsalias[0]==0 ){
-    /* The left-most RHS symbol has not value.  LHS direct is ok.  But
-    ** we have to call the distructor on the RHS symbol first. */
-    lhsdirect = 1;
-    if( has_destructor(rp->rhs[0],lemp) ){
-      append_str(0,0,0,0,0);
-      append_str("  yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0,
-                 rp->rhs[0]->index,1-rp->nrhs,0);
-      rp->codePrefix = Strsafe(append_str(0,0,0,0,0));
-    }
-  }else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){
-    /* The LHS symbol and the left-most RHS symbol are the same, so 
-    ** direct writing is allowed */
-    lhsdirect = 1;
-    lhsused = 1;
-    used[0] = 1;
-    if( rp->lhs->dtnum!=rp->rhs[0]->dtnum ){
-      ErrorMsg(lemp->filename,rp->ruleline,
-        "%s(%s) and %s(%s) share the same label but have "
-        "different datatypes.",
-        rp->lhs->name, rp->lhsalias, rp->rhs[0]->name, rp->rhsalias[0]);
-      lemp->errorcnt++;
-    }
-  }else{
-    sprintf(zOvwrt, "/*%s-overwrites-%s*/", rp->lhsalias, rp->rhsalias[0]);
-    zSkip = strstr(rp->code, zOvwrt);
-    if( zSkip!=0 ){
-      /* The code contains a special comment that indicates that it is safe
-      ** for the LHS label to overwrite left-most RHS label. */
-      lhsdirect = 1;
-    }else{
-      lhsdirect = 0;
-    }
-  }
-  if( lhsdirect ){
-    sprintf(zLhs, "yymsp[%d].minor.yy%d",1-rp->nrhs,rp->lhs->dtnum);
-  }else{
-    rc = 1;
-    sprintf(zLhs, "yylhsminor.yy%d",rp->lhs->dtnum);
+    rp->code = "\n";
+	rp->line = rp->ruleline;
   }
 
   append_str(0,0,0,0,0);
-
-  /* This const cast is wrong but harmless, if we're careful. */
-  for(cp=(char *)rp->code; *cp; cp++){
-    if( cp==zSkip ){
-      append_str(zOvwrt,0,0,0,0);
-      cp += lemonStrlen(zOvwrt)-1;
-      dontUseRhs0 = 1;
-      continue;
-    }
-    if( ISALPHA(*cp) && (cp==rp->code || (!ISALNUM(cp[-1]) && cp[-1]!='_')) ){
+  for(cp=rp->code; *cp; cp++){
+    if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){
       char saved;
-      for(xp= &cp[1]; ISALNUM(*xp) || *xp=='_'; xp++);
+      for(xp= &cp[1]; isalnum(*xp) || *xp=='_'; xp++);
       saved = *xp;
       *xp = 0;
       if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){
-        append_str(zLhs,0,0,0,0);
+        append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0,0);
         cp = xp;
         lhsused = 1;
       }else{
         for(i=0; i<rp->nrhs; i++){
           if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){
-            if( i==0 && dontUseRhs0 ){
-              ErrorMsg(lemp->filename,rp->ruleline,
-                 "Label %s used after '%s'.",
-                 rp->rhsalias[0], zOvwrt);
-              lemp->errorcnt++;
-            }else if( cp!=rp->code && cp[-1]=='@' ){
+            if( cp!=rp->code && cp[-1]=='@' ){
               /* If the argument is of the form @X then substituted
               ** the token number of X, not the value of X */
               append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0,0);
@@ -3658,11 +3307,6 @@ PRIVATE int translate_code(struct lemon 
     append_str(cp, 1, 0, 0, 1);
   } /* End loop */
 
-  /* Main code generation completed */
-  cp = append_str(0,0,0,0,0);
-  if( cp && cp[0] ) rp->code = Strsafe(cp);
-  append_str(0,0,0,0,0);
-
   /* Check to make sure the LHS has been used */
   if( rp->lhsalias && !lhsused ){
     ErrorMsg(lemp->filename,rp->ruleline,
@@ -3671,99 +3315,53 @@ PRIVATE int translate_code(struct lemon 
     lemp->errorcnt++;
   }
 
-  /* Generate destructor code for RHS minor values which are not referenced.
-  ** Generate error messages for unused labels and duplicate labels.
-  */
+  /* Generate destructor code for RHS symbols which are not used in the
+  ** reduce code */
   for(i=0; i<rp->nrhs; i++){
-    if( rp->rhsalias[i] ){
-      if( i>0 ){
-        int j;
-        if( rp->lhsalias && strcmp(rp->lhsalias,rp->rhsalias[i])==0 ){
-          ErrorMsg(lemp->filename,rp->ruleline,
-            "%s(%s) has the same label as the LHS but is not the left-most "
-           "symbol on the RHS.",
-            rp->rhs[i]->name, rp->rhsalias);
-          lemp->errorcnt++;
-        }
-        for(j=0; j<i; j++){
-          if( rp->rhsalias[j] && strcmp(rp->rhsalias[j],rp->rhsalias[i])==0 ){
-            ErrorMsg(lemp->filename,rp->ruleline,
-              "Label %s used for multiple symbols on the RHS of a rule.",
-              rp->rhsalias[i]);
-            lemp->errorcnt++;
-            break;
-          }
-        }
-      }
-      if( !used[i] ){
-        ErrorMsg(lemp->filename,rp->ruleline,
-          "Label %s for \"%s(%s)\" is never used.",
-          rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]);
-        lemp->errorcnt++;
+    if( rp->rhsalias[i] && !used[i] ){
+      ErrorMsg(lemp->filename,rp->ruleline,
+        "Label %s for \"%s(%s)\" is never used.",
+        rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]);
+      lemp->errorcnt++;
+    }else if( rp->rhsalias[i]==0 ){
+      if( has_destructor(rp->rhs[i],lemp) ){
+        append_str("  yy_destructor(%d,&yymsp[%d].minor);\n", 0,
+           rp->rhs[i]->index,i-rp->nrhs+1,0);
+      }else{
+        /* No destructor defined for this term */
       }
-    }else if( i>0 && has_destructor(rp->rhs[i],lemp) ){
-      append_str("  yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0,
-         rp->rhs[i]->index,i-rp->nrhs+1,0);
     }
   }
-
-  /* If unable to write LHS values directly into the stack, write the
-  ** saved LHS value now. */
-  if( lhsdirect==0 ){
-    append_str("  yymsp[%d].minor.yy%d = ", 0, 1-rp->nrhs, rp->lhs->dtnum, 0);
-    append_str(zLhs, 0, 0, 0, 0);
-    append_str(";\n", 0, 0, 0, 0);
+  if( rp->code ){
+    cp = append_str(0,0,0,0,0);
+    rp->code = Strsafe(cp?cp:"");
   }
-
-  /* Suffix code generation complete */
-  cp = append_str(0,0,0,0,0);
-  if( cp ) rp->codeSuffix = Strsafe(cp);
-
-  return rc;
 }
 
 /* 
 ** Generate code which executes when the rule "rp" is reduced.  Write
 ** the code to "out".  Make sure lineno stays up-to-date.
 */
-PRIVATE void emit_code(
-  FILE *out,
-  struct rule *rp,
-  struct lemon *lemp,
-  int *lineno
-){
- const char *cp;
-
- /* Setup code prior to the #line directive */
- if( rp->codePrefix && rp->codePrefix[0] ){
-   fprintf(out, "{%s", rp->codePrefix);
-   for(cp=rp->codePrefix; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
- }
+PRIVATE void emit_code(out,rp,lemp,lineno)
+FILE *out;
+struct rule *rp;
+struct lemon *lemp;
+int *lineno;
+{
+ char *cp;
+ int linecnt = 0;
 
  /* Generate code to do the reduce action */
  if( rp->code ){
-   if( !lemp->nolinenosflag ){
-     (*lineno)++;
-     tplt_linedir(out,rp->line,lemp->filename);
-   }
+   tplt_linedir(out,rp->line,lemp->filename);
    fprintf(out,"{%s",rp->code);
-   for(cp=rp->code; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
-   fprintf(out,"}\n"); (*lineno)++;
-   if( !lemp->nolinenosflag ){
-     (*lineno)++;
-     tplt_linedir(out,*lineno,lemp->outname);
-   }
- }
-
- /* Generate breakdown code that occurs after the #line directive */
- if( rp->codeSuffix && rp->codeSuffix[0] ){
-   fprintf(out, "%s", rp->codeSuffix);
-   for(cp=rp->codeSuffix; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
- }
-
- if( rp->codePrefix ){
-   fprintf(out, "}\n"); (*lineno)++;
- }
+   for(cp=rp->code; *cp; cp++){
+     if( *cp=='\n' ) linecnt++;
+   } /* End loop */
+   (*lineno) += 3 + linecnt;
+   fprintf(out,"}\n");
+   tplt_linedir(out,*lineno,lemp->outname);
+ } /* End if( rp->code ) */
 
  return;
 }
@@ -3775,37 +3373,33 @@ PRIVATE void emit_code(
 ** union, also set the ".dtnum" field of every terminal and nonterminal
 ** symbol.
 */
-void print_stack_union(
-  FILE *out,                  /* The output stream */
-  struct lemon *lemp,         /* The main info structure for this parser */
-  int *plineno,               /* Pointer to the line number */
-  int mhflag                  /* True if generating makeheaders output */
-){
+void print_stack_union(out,lemp,plineno,mhflag)
+FILE *out;                  /* The output stream */
+struct lemon *lemp;         /* The main info structure for this parser */
+int *plineno;               /* Pointer to the line number */
+int mhflag;                 /* True if generating makeheaders output */
+{
   int lineno = *plineno;    /* The line number of the output */
   char **types;             /* A hash table of datatypes */
   int arraysize;            /* Size of the "types" array */
   int maxdtlength;          /* Maximum length of any ".datatype" field. */
   char *stddt;              /* Standardized name for a datatype */
   int i,j;                  /* Loop counters */
-  unsigned hash;            /* For hashing the name of a type */
-  const char *name;         /* Name of the parser */
+  int hash;                 /* For hashing the name of a type */
+  char *name;               /* Name of the parser */
 
   /* Allocate and initialize types[] and allocate stddt[] */
   arraysize = lemp->nsymbol * 2;
   types = (char**)calloc( arraysize, sizeof(char*) );
-  if( types==0 ){
-    fprintf(stderr,"Out of memory.\n");
-    exit(1);
-  }
   maxdtlength = 0;
   if( lemp->vartype ){
-    maxdtlength = lemonStrlen(lemp->vartype);
+    maxdtlength = (int)strlen(lemp->vartype);
   }
   for(i=0; i<lemp->nsymbol; i++){
     int len;
     struct symbol *sp = lemp->symbols[i];
     if( sp->datatype==0 ) continue;
-    len = lemonStrlen(sp->datatype);
+    len = (int)strlen(sp->datatype);
     if( len>maxdtlength ) maxdtlength = len;
   }
   stddt = (char*)malloc( maxdtlength*2 + 1 );
@@ -3834,14 +3428,10 @@ void print_stack_union(
     cp = sp->datatype;
     if( cp==0 ) cp = lemp->vartype;
     j = 0;
-    while( ISSPACE(*cp) ) cp++;
+    while( isspace(*cp) ) cp++;
     while( *cp ) stddt[j++] = *cp++;
-    while( j>0 && ISSPACE(stddt[j-1]) ) j--;
+    while( j>0 && isspace(stddt[j-1]) ) j--;
     stddt[j] = 0;
-    if( lemp->tokentype && strcmp(stddt, lemp->tokentype)==0 ){
-      sp->dtnum = 0;
-      continue;
-    }
     hash = 0;
     for(j=0; stddt[j]; j++){
       hash = hash*53 + stddt[j];
@@ -3853,11 +3443,11 @@ void print_stack_union(
         break;
       }
       hash++;
-      if( hash>=(unsigned)arraysize ) hash = 0;
+      if( hash>=arraysize ) hash = 0;
     }
     if( types[hash]==0 ){
       sp->dtnum = hash + 1;
-      types[hash] = (char*)malloc( lemonStrlen(stddt)+1 );
+      types[hash] = (char*)malloc( strlen(stddt)+1 );
       if( types[hash]==0 ){
         fprintf(stderr,"Out of memory.\n");
         exit(1);
@@ -3874,7 +3464,6 @@ void print_stack_union(
     lemp->tokentype?lemp->tokentype:"void*");  lineno++;
   if( mhflag ){ fprintf(out,"#endif\n"); lineno++; }
   fprintf(out,"typedef union {\n"); lineno++;
-  fprintf(out,"  int yyinit;\n"); lineno++;
   fprintf(out,"  %sTOKENTYPE yy0;\n",name); lineno++;
   for(i=0; i<arraysize; i++){
     if( types[i]==0 ) continue;
@@ -3892,32 +3481,24 @@ void print_stack_union(
 
 /*
 ** Return the name of a C datatype able to represent values between
-** lwr and upr, inclusive.  If pnByte!=NULL then also write the sizeof
-** for that type (1, 2, or 4) into *pnByte.
+** lwr and upr, inclusive.
 */
-static const char *minimum_size_type(int lwr, int upr, int *pnByte){
-  const char *zType = "int";
-  int nByte = 4;
+static const char *minimum_size_type(int lwr, int upr){
   if( lwr>=0 ){
     if( upr<=255 ){
-      zType = "unsigned char";
-      nByte = 1;
+      return "unsigned char";
     }else if( upr<65535 ){
-      zType = "unsigned short int";
-      nByte = 2;
+      return "unsigned short int";
     }else{
-      zType = "unsigned int";
-      nByte = 4;
+      return "unsigned int";
     }
   }else if( lwr>=-127 && upr<=127 ){
-    zType = "signed char";
-    nByte = 1;
+    return "signed char";
   }else if( lwr>=-32767 && upr<32767 ){
-    zType = "short";
-    nByte = 2;
+    return "short";
+  }else{
+    return "int";
   }
-  if( pnByte ) *pnByte = nByte;
-  return zType;
 }
 
 /*
@@ -3930,7 +3511,6 @@ struct axset {
   struct state *stp;   /* A pointer to a state */
   int isTkn;           /* True to use tokens.  False for non-terminals */
   int nAction;         /* Number of actions */
-  int iOrder;          /* Original order of action sets */
 };
 
 /*
@@ -3939,13 +3519,7 @@ struct axset {
 static int axset_compare(const void *a, const void *b){
   struct axset *p1 = (struct axset*)a;
   struct axset *p2 = (struct axset*)b;
-  int c;
-  c = p2->nAction - p1->nAction;
-  if( c==0 ){
-    c = p1->iOrder - p2->iOrder;
-  }
-  assert( c!=0 || p1==p2 );
-  return c;
+  return p2->nAction - p1->nAction;
 }
 
 /*
@@ -3956,11 +3530,9 @@ static void writeRuleText(FILE *out, str
   fprintf(out,"%s ::=", rp->lhs->name);
   for(j=0; j<rp->nrhs; j++){
     struct symbol *sp = rp->rhs[j];
-    if( sp->type!=MULTITERMINAL ){
-      fprintf(out," %s", sp->name);
-    }else{
+    fprintf(out," %s", sp->name);
+    if( sp->type==MULTITERMINAL ){
       int k;
-      fprintf(out," %s", sp->subsym[0]->name);
       for(k=1; k<sp->nsubsym; k++){
         fprintf(out,"|%s",sp->subsym[k]->name);
       }
@@ -3970,10 +3542,10 @@ static void writeRuleText(FILE *out, str
 
 
 /* Generate C source code for the parser */
-void ReportTable(
-  struct lemon *lemp,
-  int mhflag     /* Output in makeheaders format if true */
-){
+void ReportTable(lemp, mhflag)
+struct lemon *lemp;
+int mhflag;     /* Output in makeheaders format if true */
+{
   FILE *out, *in;
   char line[LINESIZE];
   int  lineno;
@@ -3981,10 +3553,8 @@ void ReportTable(
   struct action *ap;
   struct rule *rp;
   struct acttab *pActtab;
-  int i, j, n, sz;
-  int szActionType;     /* sizeof(YYACTIONTYPE) */
-  int szCodeType;       /* sizeof(YYCODETYPE) */
-  const char *name;
+  int i, j, n;
+  char *name;
   int mnTknOfst, mxTknOfst;
   int mnNtOfst, mxNtOfst;
   struct axset *ax;
@@ -4000,7 +3570,7 @@ void ReportTable(
   tplt_xfer(lemp->name,in,out,&lineno);
 
   /* Generate the include code, if any */
-  tplt_print(out,lemp,lemp->include,&lineno);
+  tplt_print(out,lemp,lemp->include,lemp->includeln,&lineno);
   if( mhflag ){
     char *name = file_makename(lemp, ".h");
     fprintf(out,"#include \"%s\"\n", name); lineno++;
@@ -4010,7 +3580,7 @@ void ReportTable(
 
   /* Generate #defines for all tokens */
   if( mhflag ){
-    const char *prefix;
+    char *prefix;
     fprintf(out,"#if INTERFACE\n"); lineno++;
     if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
     else                    prefix = "";
@@ -4024,10 +3594,10 @@ void ReportTable(
 
   /* Generate the defines */
   fprintf(out,"#define YYCODETYPE %s\n",
-    minimum_size_type(0, lemp->nsymbol+1, &szCodeType)); lineno++;
+    minimum_size_type(0, lemp->nsymbol+5)); lineno++;
   fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1);  lineno++;
   fprintf(out,"#define YYACTIONTYPE %s\n",
-    minimum_size_type(0,lemp->nstate+lemp->nrule*2+5,&szActionType)); lineno++;
+    minimum_size_type(0, lemp->nstate+lemp->nrule+5));  lineno++;
   if( lemp->wildcard ){
     fprintf(out,"#define YYWILDCARD %d\n",
        lemp->wildcard->index); lineno++;
@@ -4046,9 +3616,9 @@ void ReportTable(
   name = lemp->name ? lemp->name : "Parse";
   if( lemp->arg && lemp->arg[0] ){
     size_t i;
-    i = lemonStrlen(lemp->arg);
-    while( i>=1 && ISSPACE(lemp->arg[i-1]) ) i--;
-    while( i>=1 && (ISALNUM(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--;
+    i = strlen(lemp->arg);
+    while( i>=1 && isspace(lemp->arg[i-1]) ) i--;
+    while( i>=1 && (isalnum(lemp->arg[i-1]) || lemp->arg[i-1]=='_') ) i--;
     fprintf(out,"#define %sARG_SDECL %s;\n",name,lemp->arg);  lineno++;
     fprintf(out,"#define %sARG_PDECL ,%s\n",name,lemp->arg);  lineno++;
     fprintf(out,"#define %sARG_FETCH %s = yypParser->%s\n",
@@ -4064,24 +3634,36 @@ void ReportTable(
   if( mhflag ){
     fprintf(out,"#endif\n"); lineno++;
   }
+  fprintf(out,"#define YYNSTATE %d\n",lemp->nstate);  lineno++;
+  fprintf(out,"#define YYNRULE %d\n",lemp->nrule);  lineno++;
   if( lemp->errsym->useCnt ){
-    fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
-    fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
+    fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index);  lineno++;
+    fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum);  lineno++;
   }
   if( lemp->has_fallback ){
     fprintf(out,"#define YYFALLBACK 1\n");  lineno++;
   }
+  tplt_xfer(lemp->name,in,out,&lineno);
 
-  /* Compute the action table, but do not output it yet.  The action
-  ** table must be computed before generating the YYNSTATE macro because
-  ** we need to know how many states can be eliminated.
+  /* Generate the action table and its associates:
+  **
+  **  yy_action[]        A single table containing all actions.
+  **  yy_lookahead[]     A table containing the lookahead for each entry in
+  **                     yy_action.  Used to detect hash collisions.
+  **  yy_shift_ofst[]    For each state, the offset into yy_action for
+  **                     shifting terminals.
+  **  yy_reduce_ofst[]   For each state, the offset into yy_action for
+  **                     shifting non-terminals after a reduce.
+  **  yy_default[]       Default action for each state.
   */
-  ax = (struct axset *) calloc(lemp->nxstate*2 , sizeof(ax[0]));
+
+  /* Compute the actions on all states and count them up */
+  ax = calloc(lemp->nstate*2 , sizeof(ax[0]));
   if( ax==0 ){
     fprintf(stderr,"malloc failed\n");
     exit(1);
   }
-  for(i=0; i<lemp->nxstate; i++){
+  for(i=0; i<lemp->nstate; i++){
     stp = lemp->sorted[i];
     ax[i*2].stp = stp;
     ax[i*2].isTkn = 1;
@@ -4092,12 +3674,14 @@ void ReportTable(
   }
   mxTknOfst = mnTknOfst = 0;
   mxNtOfst = mnNtOfst = 0;
-  /* In an effort to minimize the action table size, use the heuristic
-  ** of placing the largest action sets first */
-  for(i=0; i<lemp->nxstate*2; i++) ax[i].iOrder = i;
-  qsort(ax, lemp->nxstate*2, sizeof(ax[0]), axset_compare);
+
+  /* Compute the action table.  In order to try to keep the size of the
+  ** action table to a minimum, the heuristic of placing the largest action
+  ** sets first is used.
+  */
+  qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare);
   pActtab = acttab_alloc();
-  for(i=0; i<lemp->nxstate*2 && ax[i].nAction>0; i++){
+  for(i=0; i<lemp->nstate*2 && ax[i].nAction>0; i++){
     stp = ax[i].stp;
     if( ax[i].isTkn ){
       for(ap=stp->ap; ap; ap=ap->next){
@@ -4123,52 +3707,12 @@ void ReportTable(
       if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst;
       if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst;
     }
-#if 0  /* Uncomment for a trace of how the yy_action[] table fills out */
-    { int jj, nn;
-      for(jj=nn=0; jj<pActtab->nAction; jj++){
-        if( pActtab->aAction[jj].action<0 ) nn++;
-      }
-      printf("%4d: State %3d %s n: %2d size: %5d freespace: %d\n",
-             i, stp->statenum, ax[i].isTkn ? "Token" : "Var  ",
-             ax[i].nAction, pActtab->nAction, nn);
-    }
-#endif
   }
   free(ax);
 
-  /* Finish rendering the constants now that the action table has
-  ** been computed */
-  fprintf(out,"#define YYNSTATE             %d\n",lemp->nxstate);  lineno++;
-  fprintf(out,"#define YYNRULE              %d\n",lemp->nrule);  lineno++;
-  fprintf(out,"#define YY_MAX_SHIFT         %d\n",lemp->nxstate-1); lineno++;
-  fprintf(out,"#define YY_MIN_SHIFTREDUCE   %d\n",lemp->nstate); lineno++;
-  i = lemp->nstate + lemp->nrule;
-  fprintf(out,"#define YY_MAX_SHIFTREDUCE   %d\n", i-1); lineno++;
-  fprintf(out,"#define YY_MIN_REDUCE        %d\n", i); lineno++;
-  i = lemp->nstate + lemp->nrule*2;
-  fprintf(out,"#define YY_MAX_REDUCE        %d\n", i-1); lineno++;
-  fprintf(out,"#define YY_ERROR_ACTION      %d\n", i); lineno++;
-  fprintf(out,"#define YY_ACCEPT_ACTION     %d\n", i+1); lineno++;
-  fprintf(out,"#define YY_NO_ACTION         %d\n", i+2); lineno++;
-  tplt_xfer(lemp->name,in,out,&lineno);
-
-  /* Now output the action table and its associates:
-  **
-  **  yy_action[]        A single table containing all actions.
-  **  yy_lookahead[]     A table containing the lookahead for each entry in
-  **                     yy_action.  Used to detect hash collisions.
-  **  yy_shift_ofst[]    For each state, the offset into yy_action for
-  **                     shifting terminals.
-  **  yy_reduce_ofst[]   For each state, the offset into yy_action for
-  **                     shifting non-terminals after a reduce.
-  **  yy_default[]       Default action for each state.
-  */
-
   /* Output the yy_action table */
-  lemp->nactiontab = n = acttab_size(pActtab);
-  lemp->tablesize += n*szActionType;
-  fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++;
   fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++;
+  n = acttab_size(pActtab);
   for(i=j=0; i<n; i++){
     int action = acttab_yyaction(pActtab, i);
     if( action<0 ) action = lemp->nstate + lemp->nrule + 2;
@@ -4184,7 +3728,6 @@ void ReportTable(
   fprintf(out, "};\n"); lineno++;
 
   /* Output the yy_lookahead table */
-  lemp->tablesize += n*szCodeType;
   fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++;
   for(i=j=0; i<n; i++){
     int la = acttab_yylookahead(pActtab, i);
@@ -4202,14 +3745,11 @@ void ReportTable(
 
   /* Output the yy_shift_ofst[] table */
   fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
-  n = lemp->nxstate;
+  n = lemp->nstate;
   while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--;
-  fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++;
-  fprintf(out, "#define YY_SHIFT_MIN   (%d)\n", mnTknOfst); lineno++;
-  fprintf(out, "#define YY_SHIFT_MAX   (%d)\n", mxTknOfst); lineno++;
+  fprintf(out, "#define YY_SHIFT_MAX %d\n", n-1); lineno++;
   fprintf(out, "static const %s yy_shift_ofst[] = {\n", 
-          minimum_size_type(mnTknOfst-1, mxTknOfst, &sz)); lineno++;
-  lemp->tablesize += n*sz;
+          minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
   for(i=j=0; i<n; i++){
     int ofst;
     stp = lemp->sorted[i];
@@ -4228,14 +3768,11 @@ void ReportTable(
 
   /* Output the yy_reduce_ofst[] table */
   fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
-  n = lemp->nxstate;
+  n = lemp->nstate;
   while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--;
-  fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++;
-  fprintf(out, "#define YY_REDUCE_MIN   (%d)\n", mnNtOfst); lineno++;
-  fprintf(out, "#define YY_REDUCE_MAX   (%d)\n", mxNtOfst); lineno++;
+  fprintf(out, "#define YY_REDUCE_MAX %d\n", n-1); lineno++;
   fprintf(out, "static const %s yy_reduce_ofst[] = {\n", 
-          minimum_size_type(mnNtOfst-1, mxNtOfst, &sz)); lineno++;
-  lemp->tablesize += n*sz;
+          minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
   for(i=j=0; i<n; i++){
     int ofst;
     stp = lemp->sorted[i];
@@ -4254,12 +3791,11 @@ void ReportTable(
 
   /* Output the default action table */
   fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++;
-  n = lemp->nxstate;
-  lemp->tablesize += n*szActionType;
+  n = lemp->nstate;
   for(i=j=0; i<n; i++){
     stp = lemp->sorted[i];
     if( j==0 ) fprintf(out," /* %5d */ ", i);
-    fprintf(out, " %4d,", stp->iDfltReduce+lemp->nstate+lemp->nrule);
+    fprintf(out, " %4d,", stp->iDflt);
     if( j==9 || i==n-1 ){
       fprintf(out, "\n"); lineno++;
       j = 0;
@@ -4273,10 +3809,7 @@ void ReportTable(
   /* Generate the table of fallback tokens.
   */
   if( lemp->has_fallback ){
-    int mx = lemp->nterminal - 1;
-    while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; }
-    lemp->tablesize += (mx+1)*szCodeType;
-    for(i=0; i<=mx; i++){
+    for(i=0; i<lemp->nterminal; i++){
       struct symbol *p = lemp->symbols[i];
       if( p->fallback==0 ){
         fprintf(out, "    0,  /* %10s => nothing */\n", p->name);
@@ -4300,11 +3833,11 @@ void ReportTable(
   tplt_xfer(lemp->name,in,out,&lineno);
 
   /* Generate a table containing a text string that describes every
-  ** rule in the rule set of the grammar.  This information is used
+  ** rule in the rule set of the grammer.  This information is used
   ** when tracing REDUCE actions.
   */
   for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
-    assert( rp->iRule==i );
+    assert( rp->index==i );
     fprintf(out," /* %3d */ \"", i);
     writeRuleText(out, rp);
     fprintf(out,"\",\n"); lineno++;
@@ -4316,15 +3849,11 @@ void ReportTable(
   ** (In other words, generate the %destructor actions)
   */
   if( lemp->tokendest ){
-    int once = 1;
     for(i=0; i<lemp->nsymbol; i++){
       struct symbol *sp = lemp->symbols[i];
       if( sp==0 || sp->type!=TERMINAL ) continue;
-	  if( once ){
-		fprintf(out, "      /* TERMINAL Destructor */\n"); lineno++;
-		once = 0;
-	  }
-	  fprintf(out,"    case %d: /* %s */\n", sp->index, sp->name); lineno++;
+      fprintf(out,"    case %d: /* %s */\n",
+              sp->index, sp->name); lineno++;
     }
     for(i=0; i<lemp->nsymbol && lemp->symbols[i]->type!=TERMINAL; i++);
     if( i<lemp->nsymbol ){
@@ -4334,27 +3863,24 @@ void ReportTable(
   }
   if( lemp->vardest ){
     struct symbol *dflt_sp = 0;
-	int once = 1;
     for(i=0; i<lemp->nsymbol; i++){
       struct symbol *sp = lemp->symbols[i];
       if( sp==0 || sp->type==TERMINAL ||
           sp->index<=0 || sp->destructor!=0 ) continue;
-	  if( once ){
-		fprintf(out, "      /* Default NON-TERMINAL Destructor */\n"); lineno++;
-		once = 0;
-	  }
-	  fprintf(out,"    case %d: /* %s */\n", sp->index, sp->name); lineno++;
+      fprintf(out,"    case %d: /* %s */\n",
+              sp->index, sp->name); lineno++;
       dflt_sp = sp;
     }
     if( dflt_sp!=0 ){
       emit_destructor_code(out,dflt_sp,lemp,&lineno);
+      fprintf(out,"      break;\n"); lineno++;
     }
-    fprintf(out,"      break;\n"); lineno++;
   }
   for(i=0; i<lemp->nsymbol; i++){
     struct symbol *sp = lemp->symbols[i];
     if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
-    fprintf(out,"    case %d: /* %s */\n", sp->index, sp->name); lineno++;
+    fprintf(out,"    case %d: /* %s */\n",
+            sp->index, sp->name); lineno++;
 
     /* Combine duplicate destructors into a single case */
     for(j=i+1; j<lemp->nsymbol; j++){
@@ -4374,7 +3900,7 @@ void ReportTable(
   tplt_xfer(lemp->name,in,out,&lineno);
 
   /* Generate code which executes whenever the parser stack overflows */
-  tplt_print(out,lemp,lemp->overflow,&lineno);
+  tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
   tplt_xfer(lemp->name,in,out,&lineno);
 
   /* Generate the table of rule information 
@@ -4388,60 +3914,42 @@ void ReportTable(
   tplt_xfer(lemp->name,in,out,&lineno);
 
   /* Generate code which executes during each REDUCE action */
-  i = 0;
   for(rp=lemp->rule; rp; rp=rp->next){
-    i += translate_code(lemp, rp);
+    translate_code(lemp, rp);
   }
-  if( i ){
-    fprintf(out,"        YYMINORTYPE yylhsminor;\n"); lineno++;
-   }
-  /* First output rules other than the default: rule */
   for(rp=lemp->rule; rp; rp=rp->next){
-    struct rule *rp2;               /* Other rules with the same action */
+    struct rule *rp2;
     if( rp->code==0 ) continue;
-    if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */
-    fprintf(out,"      case %d: /* ",rp->iRule);
+    fprintf(out,"      case %d: /* ",rp->index);
     writeRuleText(out, rp);
-    fprintf(out," */\n"); lineno++;
+    fprintf(out, " */\n"); lineno++;
     for(rp2=rp->next; rp2; rp2=rp2->next){
       if( rp2->code==rp->code ){
-        fprintf(out,"      case %d: /*",rp2->iRule);
+        fprintf(out,"      case %d: /*",rp2->index);
         writeRuleText(out, rp2);
-        fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp2->iRule); lineno++;
+        fprintf(out," */\n"); lineno++;
         rp2->code = 0;
       }
     }
     emit_code(out,rp,lemp,&lineno);
     fprintf(out,"        break;\n"); lineno++;
-	rp->code = 0;
-  }
-  /* Finally, output the default: rule.  We choose as the default: all
-  ** empty actions. */
-  fprintf(out,"      default:\n"); lineno++;
-  for(rp=lemp->rule; rp; rp=rp->next){
-    if( rp->code==0 ) continue;
-    assert( rp->code[0]=='\n' && rp->code[1]==0 );
-    fprintf(out,"      /* (%d) ", rp->iRule);
-    writeRuleText(out, rp);
-    fprintf(out," */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++;
   }
-  fprintf(out,"       break;\n"); lineno++;
   tplt_xfer(lemp->name,in,out,&lineno);
 
   /* Generate code which executes if a parse fails */
-  tplt_print(out,lemp,lemp->failure,&lineno);
+  tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno);
   tplt_xfer(lemp->name,in,out,&lineno);
 
   /* Generate code which executes when a syntax error occurs */
-  tplt_print(out,lemp,lemp->error,&lineno);
+  tplt_print(out,lemp,lemp->error,lemp->errorln,&lineno);
   tplt_xfer(lemp->name,in,out,&lineno);
 
   /* Generate code which executes when the parser accepts its input */
-  tplt_print(out,lemp,lemp->accept,&lineno);
+  tplt_print(out,lemp,lemp->accept,lemp->acceptln,&lineno);
   tplt_xfer(lemp->name,in,out,&lineno);
 
   /* Append any addition code the user desires */
-  tplt_print(out,lemp,lemp->extracode,&lineno);
+  tplt_print(out,lemp,lemp->extracode,lemp->extracodeln,&lineno);
 
   acttab_free(&pActtab);
   fclose(in);
@@ -4450,10 +3958,11 @@ void ReportTable(
 }
 
 /* Generate a header file for the parser */
-void ReportHeader(struct lemon *lemp)
+void ReportHeader(lemp)
+struct lemon *lemp;
 {
   FILE *out, *in;
-  const char *prefix;
+  char *prefix;
   char line[LINESIZE];
   char pattern[LINESIZE];
   int i;
@@ -4462,15 +3971,12 @@ void ReportHeader(struct lemon *lemp)
   else                    prefix = "";
   in = file_open(lemp,".h","rb");
   if( in ){
-    int nextChar;
     for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){
-      sprintf(pattern,"#define %s%-30s %2d\n",
-              prefix,lemp->symbols[i]->name,i);
+      sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
       if( strcmp(line,pattern) ) break;
     }
-    nextChar = fgetc(in);
     fclose(in);
-    if( i==lemp->nterminal && nextChar==EOF ){
+    if( i==lemp->nterminal ){
       /* No change in the file.  Don't rewrite it. */
       /* (not the best idea if you use make tools that check the date! */
       /*return;*/
@@ -4479,7 +3985,7 @@ void ReportHeader(struct lemon *lemp)
   out = file_open(lemp,".h","wb");
   if( out ){
     for(i=1; i<lemp->nterminal; i++){
-      fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i);
+      fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
     }
     fclose(out);  
   }
@@ -4493,7 +3999,8 @@ void ReportHeader(struct lemon *lemp)
 ** it the default.  Except, there is no default if the wildcard token
 ** is a possible look-ahead.
 */
-void CompressTables(struct lemon *lemp)
+void CompressTables(lemp)
+struct lemon *lemp;
 {
   struct state *stp;
   struct action *ap, *ap2;
@@ -4531,7 +4038,7 @@ void CompressTables(struct lemon *lemp)
 
     /* Do not make a default if the number of rules to default
     ** is not at least 1 or if the wildcard token is a possbile
-    ** lookahead.
+    ** lookahed.
     */
     if( nbest<1 || usesWildcard ) continue;
 
@@ -4546,32 +4053,6 @@ void CompressTables(struct lemon *lemp)
       if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED;
     }
     stp->ap = Action_sort(stp->ap);
-
-    for(ap=stp->ap; ap; ap=ap->next){
-      if( ap->type==SHIFT ) break;
-      if( ap->type==REDUCE && ap->x.rp!=rbest ) break;
-    }
-    if( ap==0 ){
-      stp->autoReduce = 1;
-      stp->pDfltReduce = rbest;
-    }
-  }
-
-  /* Make a second pass over all states and actions.  Convert
-  ** every action that is a SHIFT to an autoReduce state into
-  ** a SHIFTREDUCE action.
-  */
-  for(i=0; i<lemp->nstate; i++){
-    stp = lemp->sorted[i];
-    for(ap=stp->ap; ap; ap=ap->next){
-      struct state *pNextState;
-      if( ap->type!=SHIFT ) continue;
-      pNextState = ap->x.stp;
-      if( pNextState->autoReduce && pNextState->pDfltReduce!=0 ){
-        ap->type = SHIFTREDUCE;
-        ap->x.rp = pNextState->pDfltReduce;
-      }
-    }
   }
 }
 
@@ -4590,11 +4071,7 @@ static int stateResortCompare(const void
   n = pB->nNtAct - pA->nNtAct;
   if( n==0 ){
     n = pB->nTknAct - pA->nTknAct;
-    if( n==0 ){
-      n = pB->statenum - pA->statenum;
-    }
   }
-  assert( n!=0 );
   return n;
 }
 
@@ -4603,7 +4080,8 @@ static int stateResortCompare(const void
 ** Renumber and resort states so that states with fewer choices
 ** occur at the end.  Except, keep state 0 as the first state.
 */
-void ResortStates(struct lemon *lemp)
+void ResortStates(lemp)
+struct lemon *lemp;
 {
   int i;
   struct state *stp;
@@ -4612,19 +4090,17 @@ void ResortStates(struct lemon *lemp)
   for(i=0; i<lemp->nstate; i++){
     stp = lemp->sorted[i];
     stp->nTknAct = stp->nNtAct = 0;
-    stp->iDfltReduce = lemp->nrule;  /* Init dflt action to "syntax error" */
+    stp->iDflt = lemp->nstate + lemp->nrule;
     stp->iTknOfst = NO_OFFSET;
     stp->iNtOfst = NO_OFFSET;
     for(ap=stp->ap; ap; ap=ap->next){
-      int iAction = compute_action(lemp,ap);
-      if( iAction>=0 ){
+      if( compute_action(lemp,ap)>=0 ){
         if( ap->sp->index<lemp->nterminal ){
           stp->nTknAct++;
         }else if( ap->sp->index<lemp->nsymbol ){
           stp->nNtAct++;
         }else{
-          assert( stp->autoReduce==0 || stp->pDfltReduce==ap->x.rp );
-          stp->iDfltReduce = iAction - lemp->nstate - lemp->nrule;
+          stp->iDflt = compute_action(lemp, ap);
         }
       }
     }
@@ -4634,10 +4110,6 @@ void ResortStates(struct lemon *lemp)
   for(i=0; i<lemp->nstate; i++){
     lemp->sorted[i]->statenum = i;
   }
-  lemp->nxstate = lemp->nstate;
-  while( lemp->nxstate>1 && lemp->sorted[lemp->nxstate-1]->autoReduce ){
-    lemp->nxstate--;
-  }
 }
 
 
@@ -4649,7 +4121,8 @@ void ResortStates(struct lemon *lemp)
 static int size = 0;
 
 /* Set the set size */
-void SetSize(int n)
+void SetSize(n)
+int n;
 {
   size = n+1;
 }
@@ -4666,14 +4139,17 @@ char *SetNew(){
 }
 
 /* Deallocate a set */
-void SetFree(char *s)
+void SetFree(s)
+char *s;
 {
   free(s);
 }
 
 /* Add a new element to the set.  Return TRUE if the element was added
 ** and FALSE if it was already there. */
-int SetAdd(char *s, int e)
+int SetAdd(s,e)
+char *s;
+int e;
 {
   int rv;
   assert( e>=0 && e<size );
@@ -4683,7 +4159,9 @@ int SetAdd(char *s, int e)
 }
 
 /* Add every element of s2 to s1.  Return TRUE if s1 changes. */
-int SetUnion(char *s1, char *s2)
+int SetUnion(s1,s2)
+char *s1;
+char *s2;
 {
   int i, progress;
   progress = 0;
@@ -4709,10 +4187,11 @@ int SetUnion(char *s1, char *s2)
 ** Code for processing tables in the LEMON parser generator.
 */
 
-PRIVATE unsigned strhash(const char *x)
+PRIVATE int strhash(x)
+char *x;
 {
-  unsigned h = 0;
-  while( *x ) h = h*13 + *(x++);
+  int h = 0;
+  while( *x) h = h*13 + *(x++);
   return h;
 }
 
@@ -4720,16 +4199,15 @@ PRIVATE unsigned strhash(const char *x)
 ** keep strings in a table so that the same string is not in more
 ** than one place.
 */
-const char *Strsafe(const char *y)
+char *Strsafe(y)
+char *y;
 {
-  const char *z;
-  char *cpy;
+  char *z;
 
   if( y==0 ) return 0;
   z = Strsafe_find(y);
-  if( z==0 && (cpy=(char *)malloc( lemonStrlen(y)+1 ))!=0 ){
-    strcpy(cpy,y);
-    z = cpy;
+  if( z==0 && (z=malloc( strlen(y)+1 ))!=0 ){
+    strcpy(z,y);
     Strsafe_insert(z);
   }
   MemoryCheck(z);
@@ -4752,7 +4230,7 @@ struct s_x1 {
 ** in an associative array of type "x1".
 */
 typedef struct s_x1node {
-  const char *data;        /* The data */
+  char *data;                  /* The data */
   struct s_x1node *next;   /* Next entry with the same hash */
   struct s_x1node **from;  /* Previous link */
 } x1node;
@@ -4767,7 +4245,8 @@ void Strsafe_init(){
   if( x1a ){
     x1a->size = 1024;
     x1a->count = 0;
-    x1a->tbl = (x1node*)calloc(1024, sizeof(x1node) + sizeof(x1node*));
+    x1a->tbl = (x1node*)malloc( 
+      (sizeof(x1node) + sizeof(x1node*))*1024 );
     if( x1a->tbl==0 ){
       free(x1a);
       x1a = 0;
@@ -4780,11 +4259,12 @@ void Strsafe_init(){
 }
 /* Insert a new record into the array.  Return TRUE if successful.
 ** Prior data with the same key is NOT overwritten */
-int Strsafe_insert(const char *data)
+int Strsafe_insert(data)
+char *data;
 {
   x1node *np;
-  unsigned h;
-  unsigned ph;
+  int h;
+  int ph;
 
   if( x1a==0 ) return 0;
   ph = strhash(data);
@@ -4804,7 +4284,8 @@ int Strsafe_insert(const char *data)
     struct s_x1 array;
     array.size = size = x1a->size*2;
     array.count = x1a->count;
-    array.tbl = (x1node*)calloc(size, sizeof(x1node) + sizeof(x1node*));
+    array.tbl = (x1node*)malloc(
+      (sizeof(x1node) + sizeof(x1node*))*size );
     if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
     array.ht = (x1node**)&(array.tbl[size]);
     for(i=0; i<size; i++) array.ht[i] = 0;
@@ -4835,9 +4316,10 @@ int Strsafe_insert(const char *data)
 
 /* Return a pointer to data assigned to the given key.  Return NULL
 ** if no such key. */
-const char *Strsafe_find(const char *key)
+char *Strsafe_find(key)
+char *key;
 {
-  unsigned h;
+  int h;
   x1node *np;
 
   if( x1a==0 ) return 0;
@@ -4853,7 +4335,8 @@ const char *Strsafe_find(const char *key
 /* Return a pointer to the (terminal or nonterminal) symbol "x".
 ** Create a new symbol if this is the first time "x" has been seen.
 */
-struct symbol *Symbol_new(const char *x)
+struct symbol *Symbol_new(x)
+char *x;
 {
   struct symbol *sp;
 
@@ -4862,7 +4345,7 @@ struct symbol *Symbol_new(const char *x)
     sp = (struct symbol *)calloc(1, sizeof(struct symbol) );
     MemoryCheck(sp);
     sp->name = Strsafe(x);
-    sp->type = ISUPPER(*x) ? TERMINAL : NONTERMINAL;
+    sp->type = isupper(*x) ? TERMINAL : NONTERMINAL;
     sp->rule = 0;
     sp->fallback = 0;
     sp->prec = -1;
@@ -4870,7 +4353,6 @@ struct symbol *Symbol_new(const char *x)
     sp->firstset = 0;
     sp->lambda = LEMON_FALSE;
     sp->destructor = 0;
-	sp->destLineno = 0;
     sp->datatype = 0;
 	sp->useCnt = 0;
     Symbol_insert(sp,sp->name);
@@ -4879,27 +4361,20 @@ struct symbol *Symbol_new(const char *x)
   return sp;
 }
 
-/* Compare two symbols for sorting purposes.  Return negative,
-** zero, or positive if a is less then, equal to, or greater
-** than b.
+/* Compare two symbols for working purposes
 **
 ** Symbols that begin with upper case letters (terminals or tokens)
 ** must sort before symbols that begin with lower case letters
-** (non-terminals).  And MULTITERMINAL symbols (created using the
-** %token_class directive) must sort at the very end. Other than
-** that, the order does not matter.
+** (non-terminals).  Other than that, the order does not matter.
 **
 ** We find experimentally that leaving the symbols in their original
 ** order (the order they appeared in the grammar file) gives the
 ** smallest parser tables in SQLite.
 */
-int Symbolcmpp(const void *_a, const void *_b)
-{
-  const struct symbol *a = *(const struct symbol **) _a;
-  const struct symbol *b = *(const struct symbol **) _b;
-  int i1 = a->type==MULTITERMINAL ? 3 : a->name[0]>'Z' ? 2 : 1;
-  int i2 = b->type==MULTITERMINAL ? 3 : b->name[0]>'Z' ? 2 : 1;
-  return i1==i2 ? a->index - b->index : i1 - i2;
+int Symbolcmpp(struct symbol **a, struct symbol **b){
+  int i1 = (**a).index + 10000000*((**a).name[0]>'Z');
+  int i2 = (**b).index + 10000000*((**b).name[0]>'Z');
+  return i1-i2;
 }
 
 /* There is one instance of the following structure for each
@@ -4918,8 +4393,8 @@ struct s_x2 {
 ** in an associative array of type "x2".
 */
 typedef struct s_x2node {
-  struct symbol *data;     /* The data */
-  const char *key;         /* The key */
+  struct symbol *data;                  /* The data */
+  char *key;                   /* The key */
   struct s_x2node *next;   /* Next entry with the same hash */
   struct s_x2node **from;  /* Previous link */
 } x2node;
@@ -4934,7 +4409,8 @@ void Symbol_init(){
   if( x2a ){
     x2a->size = 128;
     x2a->count = 0;
-    x2a->tbl = (x2node*)calloc(128, sizeof(x2node) + sizeof(x2node*));
+    x2a->tbl = (x2node*)malloc( 
+      (sizeof(x2node) + sizeof(x2node*))*128 );
     if( x2a->tbl==0 ){
       free(x2a);
       x2a = 0;
@@ -4947,11 +4423,13 @@ void Symbol_init(){
 }
 /* Insert a new record into the array.  Return TRUE if successful.
 ** Prior data with the same key is NOT overwritten */
-int Symbol_insert(struct symbol *data, const char *key)
+int Symbol_insert(data,key)
+struct symbol *data;
+char *key;
 {
   x2node *np;
-  unsigned h;
-  unsigned ph;
+  int h;
+  int ph;
 
   if( x2a==0 ) return 0;
   ph = strhash(key);
@@ -4971,7 +4449,8 @@ int Symbol_insert(struct symbol *data, c
     struct s_x2 array;
     array.size = size = x2a->size*2;
     array.count = x2a->count;
-    array.tbl = (x2node*)calloc(size, sizeof(x2node) + sizeof(x2node*));
+    array.tbl = (x2node*)malloc(
+      (sizeof(x2node) + sizeof(x2node*))*size );
     if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
     array.ht = (x2node**)&(array.tbl[size]);
     for(i=0; i<size; i++) array.ht[i] = 0;
@@ -5004,9 +4483,10 @@ int Symbol_insert(struct symbol *data, c
 
 /* Return a pointer to data assigned to the given key.  Return NULL
 ** if no such key. */
-struct symbol *Symbol_find(const char *key)
+struct symbol *Symbol_find(key)
+char *key;
 {
-  unsigned h;
+  int h;
   x2node *np;
 
   if( x2a==0 ) return 0;
@@ -5020,7 +4500,8 @@ struct symbol *Symbol_find(const char *k
 }
 
 /* Return the n-th data.  Return NULL if n is out of range. */
-struct symbol *Symbol_Nth(int n)
+struct symbol *Symbol_Nth(n)
+int n;
 {
   struct symbol *data;
   if( x2a && n>0 && n<=x2a->count ){
@@ -5054,10 +4535,10 @@ struct symbol **Symbol_arrayof()
 }
 
 /* Compare two configurations */
-int Configcmp(const char *_a,const char *_b)
+int Configcmp(a,b)
+struct config *a;
+struct config *b;
 {
-  const struct config *a = (struct config *) _a;
-  const struct config *b = (struct config *) _b;
   int x;
   x = a->rp->index - b->rp->index;
   if( x==0 ) x = a->dot - b->dot;
@@ -5065,7 +4546,9 @@ int Configcmp(const char *_a,const char 
 }
 
 /* Compare two states */
-PRIVATE int statecmp(struct config *a, struct config *b)
+PRIVATE int statecmp(a,b)
+struct config *a;
+struct config *b;
 {
   int rc;
   for(rc=0; rc==0 && a && b;  a=a->bp, b=b->bp){
@@ -5080,9 +4563,10 @@ PRIVATE int statecmp(struct config *a, s
 }
 
 /* Hash a state */
-PRIVATE unsigned statehash(struct config *a)
+PRIVATE int statehash(a)
+struct config *a;
 {
-  unsigned h=0;
+  int h=0;
   while( a ){
     h = h*571 + a->rp->index*37 + a->dot;
     a = a->bp;
@@ -5093,10 +4577,10 @@ PRIVATE unsigned statehash(struct config
 /* Allocate a new state structure */
 struct state *State_new()
 {
-  struct state *newstate;
-  newstate = (struct state *)calloc(1, sizeof(struct state) );
-  MemoryCheck(newstate);
-  return newstate;
+  struct state *new;
+  new = (struct state *)calloc(1, sizeof(struct state) );
+  MemoryCheck(new);
+  return new;
 }
 
 /* There is one instance of the following structure for each
@@ -5131,7 +4615,8 @@ void State_init(){
   if( x3a ){
     x3a->size = 128;
     x3a->count = 0;
-    x3a->tbl = (x3node*)calloc(128, sizeof(x3node) + sizeof(x3node*));
+    x3a->tbl = (x3node*)malloc( 
+      (sizeof(x3node) + sizeof(x3node*))*128 );
     if( x3a->tbl==0 ){
       free(x3a);
       x3a = 0;
@@ -5144,11 +4629,13 @@ void State_init(){
 }
 /* Insert a new record into the array.  Return TRUE if successful.
 ** Prior data with the same key is NOT overwritten */
-int State_insert(struct state *data, struct config *key)
+int State_insert(data,key)
+struct state *data;
+struct config *key;
 {
   x3node *np;
-  unsigned h;
-  unsigned ph;
+  int h;
+  int ph;
 
   if( x3a==0 ) return 0;
   ph = statehash(key);
@@ -5168,7 +4655,8 @@ int State_insert(struct state *data, str
     struct s_x3 array;
     array.size = size = x3a->size*2;
     array.count = x3a->count;
-    array.tbl = (x3node*)calloc(size, sizeof(x3node) + sizeof(x3node*));
+    array.tbl = (x3node*)malloc(
+      (sizeof(x3node) + sizeof(x3node*))*size );
     if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
     array.ht = (x3node**)&(array.tbl[size]);
     for(i=0; i<size; i++) array.ht[i] = 0;
@@ -5201,9 +4689,10 @@ int State_insert(struct state *data, str
 
 /* Return a pointer to data assigned to the given key.  Return NULL
 ** if no such key. */
-struct state *State_find(struct config *key)
+struct state *State_find(key)
+struct config *key;
 {
-  unsigned h;
+  int h;
   x3node *np;
 
   if( x3a==0 ) return 0;
@@ -5225,7 +4714,7 @@ struct state **State_arrayof()
   int i,size;
   if( x3a==0 ) return 0;
   size = x3a->count;
-  array = (struct state **)calloc(size, sizeof(struct state *));
+  array = (struct state **)malloc( sizeof(struct state *)*size );
   if( array ){
     for(i=0; i<size; i++) array[i] = x3a->tbl[i].data;
   }
@@ -5233,9 +4722,10 @@ struct state **State_arrayof()
 }
 
 /* Hash a configuration */
-PRIVATE unsigned confighash(struct config *a)
+PRIVATE int confighash(a)
+struct config *a;
 {
-  unsigned h=0;
+  int h=0;
   h = h*571 + a->rp->index*37 + a->dot;
   return h;
 }
@@ -5271,7 +4761,8 @@ void Configtable_init(){
   if( x4a ){
     x4a->size = 64;
     x4a->count = 0;
-    x4a->tbl = (x4node*)calloc(64, sizeof(x4node) + sizeof(x4node*));
+    x4a->tbl = (x4node*)malloc( 
+      (sizeof(x4node) + sizeof(x4node*))*64 );
     if( x4a->tbl==0 ){
       free(x4a);
       x4a = 0;
@@ -5284,18 +4775,19 @@ void Configtable_init(){
 }
 /* Insert a new record into the array.  Return TRUE if successful.
 ** Prior data with the same key is NOT overwritten */
-int Configtable_insert(struct config *data)
+int Configtable_insert(data)
+struct config *data;
 {
   x4node *np;
-  unsigned h;
-  unsigned ph;
+  int h;
+  int ph;
 
   if( x4a==0 ) return 0;
   ph = confighash(data);
   h = ph & (x4a->size-1);
   np = x4a->ht[h];
   while( np ){
-    if( Configcmp((const char *) np->data,(const char *) data)==0 ){
+    if( Configcmp(np->data,data)==0 ){
       /* An existing entry with the same key is found. */
       /* Fail because overwrite is not allows. */
       return 0;
@@ -5308,7 +4800,8 @@ int Configtable_insert(struct config *da
     struct s_x4 array;
     array.size = size = x4a->size*2;
     array.count = x4a->count;
-    array.tbl = (x4node*)calloc(size, sizeof(x4node) + sizeof(x4node*));
+    array.tbl = (x4node*)malloc(
+      (sizeof(x4node) + sizeof(x4node*))*size );
     if( array.tbl==0 ) return 0;  /* Fail due to malloc failure */
     array.ht = (x4node**)&(array.tbl[size]);
     for(i=0; i<size; i++) array.ht[i] = 0;
@@ -5339,7 +4832,8 @@ int Configtable_insert(struct config *da
 
 /* Return a pointer to data assigned to the given key.  Return NULL
 ** if no such key. */
-struct config *Configtable_find(struct config *key)
+struct config *Configtable_find(key)
+struct config *key;
 {
   int h;
   x4node *np;
@@ -5348,7 +4842,7 @@ struct config *Configtable_find(struct c
   h = confighash(key) & (x4a->size-1);
   np = x4a->ht[h];
   while( np ){
-    if( Configcmp((const char *) np->data,(const char *) key)==0 ) break;
+    if( Configcmp(np->data,key)==0 ) break;
     np = np->next;
   }
   return np ? np->data : 0;
@@ -5356,7 +4850,8 @@ struct config *Configtable_find(struct c
 
 /* Remove all data from the table.  Pass each data to the function "f"
 ** as it is removed.  ("f" may be null to avoid this step.) */
-void Configtable_clear(int(*f)(struct config *))
+void Configtable_clear(f)
+int(*f)(/* struct config * */);
 {
   int i;
   if( x4a==0 || x4a->count==0 ) return;
--- tools/lemon/lempar.c
+++ tools/lemon/lempar.c
@@ -1,27 +1,8 @@
-/*
-** 2000-05-29
-**
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
-**
-**    May you do good and not evil.
-**    May you find forgiveness for yourself and forgive others.
-**    May you share freely, never taking more than you give.
-**
-*************************************************************************
-** Driver template for the LEMON parser generator.
-**
-** The "lemon" program processes an LALR(1) input grammar file, then uses
-** this template to construct a parser.  The "lemon" program inserts text
-** at each "%%" line.  Also, any "P-a-r-s-e" identifer prefix (without the
-** interstitial "-" characters) contained in this template is changed into
-** the value of the %name directive from the grammar.  Otherwise, the content
-** of this template is copied straight through into the generate parser
-** source file.
-**
-** The following is the concatenation of all %include directives from the
-** input grammar file:
+/* Driver template for the LEMON parser generator.
+** The author disclaims copyright to this source code.
 */
+/* First off, code is included which follows the "include" declaration
+** in the input file. */
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
@@ -32,85 +13,63 @@
 #define CDECL
 #endif
 
-/************ Begin %include sections from the grammar ************************/
 %%
-/**************** End of %include directives **********************************/
-/* These constants specify the various numeric values for terminal symbols
-** in a format understandable to "makeheaders".  This section is blank unless
-** "lemon" is run with the "-m" command-line option.
-***************** Begin makeheaders token definitions *************************/
+/* Next is all token values, in a form suitable for use by makeheaders.
+** This section will be null unless lemon is run with the -m switch.
+*/
+/* 
+** These constants (all generated automatically by the parser generator)
+** specify the various kinds of tokens (terminals) that the parser
+** understands. 
+**
+** Each symbol here is a terminal symbol in the grammar.
+*/
 %%
-/**************** End makeheaders token definitions ***************************/
-/* The next section is a series of control #defines.
+/* Make sure the INTERFACE macro is defined.
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/* The next thing included is series of defines which control
 ** various aspects of the generated parser.
-**    YYCODETYPE         is the data type used to store the integer codes
-**                       that represent terminal and non-terminal symbols.
-**                       "unsigned char" is used if there are fewer than
-**                       256 symbols.  Larger types otherwise.
-**    YYNOCODE           is a number of type YYCODETYPE that is not used for
-**                       any terminal or nonterminal symbol.
+**    YYCODETYPE         is the data type used for storing terminal
+**                       and nonterminal numbers.  "unsigned char" is
+**                       used if there are fewer than 250 terminals
+**                       and nonterminals.  "int" is used otherwise.
+**    YYNOCODE           is a number of type YYCODETYPE which corresponds
+**                       to no legal terminal or nonterminal number.  This
+**                       number is used to fill in empty slots of the hash 
+**                       table.
 **    YYFALLBACK         If defined, this indicates that one or more tokens
 **                       have fall-back values which should be used if the
 **                       original value of the token will not parse.
-**                       (also known as: "terminal symbols") have fall-back
-**                       values which should be used if the original symbol
-**                       would not parse.  This permits keywords to sometimes
-**                       be used as identifiers, for example.
-**    YYACTIONTYPE       is the data type used for "action codes" - numbers
-**                       that indicate what to do in response to the next
-**                       token.
-**    ParseTOKENTYPE     is the data type used for minor type for terminal
-**                       symbols.  Background: A "minor type" is a semantic
-**                       value associated with a terminal or non-terminal
-**                       symbols.  For example, for an "ID" terminal symbol,
-**                       the minor type might be the name of the identifier.
-**                       Each non-terminal can have a different minor type.
-**                       Terminal symbols all have the same minor type, though.
-**                       This macros defines the minor type for terminal 
-**                       symbols.
-**    YYMINORTYPE        is the data type used for all minor types.
+**    YYACTIONTYPE       is the data type used for storing terminal
+**                       and nonterminal numbers.  "unsigned char" is
+**                       used if there are fewer than 250 rules and
+**                       states combined.  "int" is used otherwise.
+**    ParseTOKENTYPE     is the data type used for minor tokens given 
+**                       directly to the parser from the tokenizer.
+**    YYMINORTYPE        is the data type used for all minor tokens.
 **                       This is typically a union of many types, one of
 **                       which is ParseTOKENTYPE.  The entry in the union
-**                       for terminal symbols is called "yy0".
+**                       for base tokens is called "yy0".
 **    YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
 **                       zero the stack is dynamically sized using realloc()
 **    ParseARG_SDECL     A static variable declaration for the %extra_argument
 **    ParseARG_PDECL     A parameter declaration for the %extra_argument
 **    ParseARG_STORE     Code to store %extra_argument into yypParser
 **    ParseARG_FETCH     Code to extract %extra_argument from yypParser
-**    YYERRORSYMBOL      is the code number of the error symbol.  If not
-**                       defined, then do no error processing.
 **    YYNSTATE           the combined number of states.
 **    YYNRULE            the number of rules in the grammar
-**    YY_MAX_SHIFT       Maximum value for shift actions
-**    YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
-**    YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
-**    YY_MIN_REDUCE      Maximum value for reduce actions
-**    YY_ERROR_ACTION    The yy_action[] code for syntax error
-**    YY_ACCEPT_ACTION   The yy_action[] code for accept
-**    YY_NO_ACTION       The yy_action[] code for no-op
+**    YYERRORSYMBOL      is the code number of the error symbol.  If not
+**                       defined, then do no error processing.
 */
-#ifndef INTERFACE
-# define INTERFACE 1
-#endif
-/************* Begin control #defines *****************************************/
 %%
-/************* End control #defines *******************************************/
+#define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
+#define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
+#define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
 
-/* Define the yytestcase() macro to be a no-op if is not already defined
-** otherwise.
-**
-** Applications can choose to define yytestcase() in the %include section
-** to a macro that can assist in verifying code coverage.  For production
-** code the yytestcase() macro should be turned off.  But it is useful
-** for testing.
-*/
-#ifndef yytestcase
-# define yytestcase(X)
-#endif
-
-
-/* Next are the tables used to determine what action to take based on the
+/* Next are that tables used to determine what action to take based on the
 ** current state and lookahead token.  These tables are used to implement
 ** functions that take a state number and lookahead value and return an
 ** action integer.  
@@ -118,20 +77,16 @@
 ** Suppose the action integer is N.  Then the action is determined as
 ** follows
 **
-**   0 <= N <= YY_MAX_SHIFT             Shift N.  That is, push the lookahead
+**   0 <= N < YYNSTATE                  Shift N.  That is, push the lookahead
 **                                      token onto the stack and goto state N.
 **
-**   N between YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
-**     and YY_MAX_SHIFTREDUCE           reduce by rule N-YY_MIN_SHIFTREDUCE.
+**   YYNSTATE <= N < YYNSTATE+YYNRULE   Reduce by rule N-YYNSTATE.
 **
-**   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
-**     and YY_MAX_REDUCE
-
-**   N == YY_ERROR_ACTION               A syntax error has occurred.
+**   N == YYNSTATE+YYNRULE              A syntax error has occurred.
 **
-**   N == YY_ACCEPT_ACTION              The parser accepts its input.
+**   N == YYNSTATE+YYNRULE+1            The parser accepts its input.
 **
-**   N == YY_NO_ACTION                  No such action.  Denotes unused
+**   N == YYNSTATE+YYNRULE+2            No such action.  Denotes unused
 **                                      slots in the yy_action[] table.
 **
 ** The action table is constructed as a single large table named yy_action[].
@@ -160,24 +115,19 @@
 **  yy_reduce_ofst[]   For each state, the offset into yy_action for
 **                     shifting non-terminals after a reduce.
 **  yy_default[]       Default action for each state.
-**
-*********** Begin parsing tables **********************************************/
+*/
 %%
-/********** End of lemon-generated parsing tables *****************************/
+#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
 
-/* The next table maps tokens (terminal symbols) into fallback tokens.  
-** If a construct like the following:
+/* The next table maps tokens into fallback tokens.  If a construct
+** like the following:
 ** 
 **      %fallback ID X Y Z.
 **
-** appears in the grammar, then ID becomes a fallback token for X, Y,
+** appears in the grammer, then ID becomes a fallback token for X, Y,
 ** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
 ** but it does not parse, the type of the token is changed to ID and
 ** the parse is retried before an error is thrown.
-**
-** This feature can be used, for example, to cause some keywords in a language
-** to revert to identifiers if they keyword does not apply in the context where
-** it appears.
 */
 #ifdef YYFALLBACK
 static const YYCODETYPE yyFallback[] = {
@@ -196,17 +146,13 @@ static const YYCODETYPE yyFallback[] = {
 **   +  The semantic value stored at this level of the stack.  This is
 **      the information used by the action routines in the grammar.
 **      It is sometimes called the "minor" token.
-**
-** After the "shift" half of a SHIFTREDUCE action, the stateno field
-** actually contains the reduce action for the second half of the
-** SHIFTREDUCE.
 */
 struct yyStackEntry {
-  YYACTIONTYPE stateno;  /* The state-number, or reduce action in SHIFTREDUCE */
-  YYCODETYPE major;      /* The major token value.  This is the code
-                         ** number for the token at this stack level */
-  YYMINORTYPE minor;     /* The user-supplied minor token value.  This
-                         ** is the value of the token  */
+  int stateno;       /* The state-number */
+  int major;         /* The major token value.  This is the code
+                     ** number for the token at this stack level */
+  YYMINORTYPE minor; /* The user-supplied minor token value.  This
+                     ** is the value of the token  */
 };
 typedef struct yyStackEntry yyStackEntry;
 
@@ -214,12 +160,7 @@ typedef struct yyStackEntry yyStackEntry
 ** the following structure */
 struct yyParser {
   int yyidx;                    /* Index of top element in stack */
-#ifdef YYTRACKMAXSTACKDEPTH
-  int yyidxMax;                 /* Maximum value of yyidx */
-#endif
-#ifndef YYNOERRORRECOVERY
   int yyerrcnt;                 /* Shifts left before out of the error */
-#endif
   ParseARG_SDECL                /* A place to hold %extra_argument */
 #if YYSTACKDEPTH<=0
   int yystksz;                  /* Current side of the stack */
@@ -301,15 +242,6 @@ static void yyGrowStack(yyParser *p){
 }
 #endif
 
-/* Datatype of the argument to the memory allocated passed as the
-** second argument to ParseAlloc() below.  This can be changed by
-** putting an appropriate #define in the %include section of the input
-** grammar.
-*/
-#ifndef YYMALLOCARGTYPE
-# define YYMALLOCARGTYPE size_t
-#endif
-
 /* 
 ** This function allocates a new parser.
 ** The only argument is a pointer to a function which works like
@@ -322,36 +254,24 @@ static void yyGrowStack(yyParser *p){
 ** A pointer to a parser.  This pointer is used in subsequent calls
 ** to Parse and ParseFree.
 */
-void *ParseAlloc(void *(CDECL *mallocProc)(YYMALLOCARGTYPE)){
+void *ParseAlloc(void *(CDECL *mallocProc)(size_t)){
   yyParser *pParser;
-  pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
+  pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
   if( pParser ){
     pParser->yyidx = -1;
-#ifdef YYTRACKMAXSTACKDEPTH
-    pParser->yyidxMax = 0;
-#endif
 #if YYSTACKDEPTH<=0
-    pParser->yystack = NULL;
-    pParser->yystksz = 0;
     yyGrowStack(pParser);
 #endif
   }
   return pParser;
 }
 
-/* The following function deletes the "minor type" or semantic value
-** associated with a symbol.  The symbol can be either a terminal
-** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
-** a pointer to the value to be deleted.  The code used to do the 
-** deletions is derived from the %destructor and/or %token_destructor
-** directives of the input grammar.
-*/
-static void yy_destructor(
-  yyParser *yypParser,    /* The parser */
-  YYCODETYPE yymajor,     /* Type code for object to destroy */
-  YYMINORTYPE *yypminor   /* The object to be destroyed */
-){
-  ParseARG_FETCH;
+/* The following function deletes the value associated with a
+** symbol.  The symbol can be either a terminal or nonterminal.
+** "yymajor" is the symbol code, and "yypminor" is a pointer to
+** the value.
+*/
+static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
   switch( yymajor ){
     /* Here is inserted the actions which take place when a
     ** terminal or non-terminal is destroyed.  This can happen
@@ -360,12 +280,10 @@ static void yy_destructor(
     ** being destroyed before it is finished parsing.
     **
     ** Note: during a reduce, the only symbols destroyed are those
-    ** which appear on the RHS of the rule, but which are *not* used
+    ** which appear on the RHS of the rule, but which are not used
     ** inside the C code.
     */
-/********* Begin destructor definitions ***************************************/
 %%
-/********* End destructor definitions *****************************************/
     default:  break;   /* If no destructor action specified: do nothing */
   }
 }
@@ -375,37 +293,45 @@ static void yy_destructor(
 **
 ** If there is a destructor routine associated with the token which
 ** is popped from the stack, then call it.
+**
+** Return the major token number for the symbol popped.
 */
-static void yy_pop_parser_stack(yyParser *pParser){
-  yyStackEntry *yytos;
-  assert( pParser->yyidx>=0 );
-  yytos = &pParser->yystack[pParser->yyidx--];
+static int yy_pop_parser_stack(yyParser *pParser){
+  YYCODETYPE yymajor;
+  yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
+
+  if( pParser->yyidx<0 ) return 0;
 #ifndef NDEBUG
-  if( yyTraceFILE ){
+  if( yyTraceFILE && pParser->yyidx>=0 ){
     fprintf(yyTraceFILE,"%sPopping %s\n",
       yyTracePrompt,
       yyTokenName[yytos->major]);
   }
 #endif
-  yy_destructor(pParser, yytos->major, &yytos->minor);
+  yymajor = yytos->major;
+  yy_destructor( yymajor, &yytos->minor);
+  pParser->yyidx--;
+  return yymajor;
 }
 
-/*
-** Deallocate and destroy a parser.  Destructors are called for
+/* 
+** Deallocate and destroy a parser.  Destructors are all called for
 ** all stack elements before shutting the parser down.
-*
-** If the YYPARSEFREENEVERNULL macro exists (for example because it
-** is defined in a %include section of the input grammar) then it is
-** assumed that the input pointer is never NULL.
+**
+** Inputs:
+** <ul>
+** <li>  A pointer to the parser.  This should be a pointer
+**       obtained from ParseAlloc.
+** <li>  A pointer to a function used to reclaim memory obtained
+**       from malloc.
+** </ul>
 */
 void ParseFree(
   void *p,                    /* The parser to be deleted */
   void (CDECL *freeProc)(void*)     /* Function used to reclaim memory */
 ){
   yyParser *pParser = (yyParser*)p;
-#ifndef YYPARSEFREENEVERNULL
   if( pParser==0 ) return;
-#endif
   while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
 #if YYSTACKDEPTH<=0
   free(pParser->yystack);
@@ -414,116 +340,93 @@ void ParseFree(
 }
 
 /*
-** Return the peak depth of the stack for a parser.
-*/
-#ifdef YYTRACKMAXSTACKDEPTH
-int ParseStackPeak(void *p){
-  yyParser *pParser = (yyParser*)p;
-  return pParser->yyidxMax;
-}
-#endif
-
-/*
 ** Find the appropriate action for a parser given the terminal
 ** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead.  If it is, return the action, otherwise
+** return YY_NO_ACTION.
 */
-static unsigned int yy_find_shift_action(
+static int yy_find_shift_action(
   yyParser *pParser,        /* The parser */
   YYCODETYPE iLookAhead     /* The look-ahead token */
 ){
   int i;
   int stateno = pParser->yystack[pParser->yyidx].stateno;
  
-  if( stateno>=YY_MIN_REDUCE ) return stateno;
-  assert( stateno <= YY_SHIFT_COUNT );
-  do{
-    i = yy_shift_ofst[stateno];
-    if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno];
-    assert( iLookAhead!=YYNOCODE );
-    i += iLookAhead;
-    if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
-      if( iLookAhead>0 ){
+  if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
+    return yy_default[stateno];
+  }
+  assert( iLookAhead!=YYNOCODE );
+  i += iLookAhead;
+  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
+    if( iLookAhead>0 ){
 #ifdef YYFALLBACK
-        YYCODETYPE iFallback;            /* Fallback token */
-        if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
-               && (iFallback = yyFallback[iLookAhead])!=0 ){
+      int iFallback;            /* Fallback token */
+      if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+             && (iFallback = yyFallback[iLookAhead])!=0 ){
 #ifndef NDEBUG
-          if( yyTraceFILE ){
-            fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
-               yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
-          }
-#endif
-          assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
-          iLookAhead = iFallback;
-          continue;
+        if( yyTraceFILE ){
+          fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+             yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
         }
 #endif
+        return yy_find_shift_action(pParser, iFallback);
+      }
+#endif
 #ifdef YYWILDCARD
-        {
-          int j = i - iLookAhead + YYWILDCARD;
-          if( 
-#if YY_SHIFT_MIN+YYWILDCARD<0
-            j>=0 &&
-#endif
-#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
-            j<YY_ACTTAB_COUNT &&
-#endif
-            yy_lookahead[j]==YYWILDCARD
-          ){
-#ifndef NDEBUG
-            if( yyTraceFILE ){
-              fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
-                 yyTracePrompt, yyTokenName[iLookAhead],
-                 yyTokenName[YYWILDCARD]);
-            }
-#endif /* NDEBUG */
-            return yy_action[j];
+      {
+        int j = i - iLookAhead + YYWILDCARD;
+        if( j>=0 && j<YY_SZ_ACTTAB && yy_lookahead[j]==YYWILDCARD ){
+#ifndef NDEBUG
+          if( yyTraceFILE ){
+            fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+               yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]);
           }
+#endif /* NDEBUG */
+          return yy_action[j];
         }
-#endif /* YYWILDCARD */
       }
-      return yy_default[stateno];
-    }else{
-      return yy_action[i];
+#endif /* YYWILDCARD */
     }
-  }while(1);
+    return yy_default[stateno];
+  }else{
+    return yy_action[i];
+  }
 }
 
 /*
 ** Find the appropriate action for a parser given the non-terminal
 ** look-ahead token iLookAhead.
+**
+** If the look-ahead token is YYNOCODE, then check to see if the action is
+** independent of the look-ahead.  If it is, return the action, otherwise
+** return YY_NO_ACTION.
 */
 static int yy_find_reduce_action(
   int stateno,              /* Current state number */
   YYCODETYPE iLookAhead     /* The look-ahead token */
 ){
   int i;
-#ifdef YYERRORSYMBOL
-  if( stateno>YY_REDUCE_COUNT ){
+  if( stateno>YY_REDUCE_MAX ||
+	  (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){
 	return yy_default[stateno];
   }
-#else
-  assert( stateno<=YY_REDUCE_COUNT );
-#endif
-  i = yy_reduce_ofst[stateno];
   assert( i!=YY_REDUCE_USE_DFLT );
   assert( iLookAhead!=YYNOCODE );
   i += iLookAhead;
-#ifdef YYERRORSYMBOL
-  if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+  if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
     return yy_default[stateno];
+  }else{
+	return yy_action[i];
   }
-#else
-  assert( i>=0 && i<YY_ACTTAB_COUNT );
-  assert( yy_lookahead[i]==iLookAhead );
-#endif
   return yy_action[i];
 }
 
 /*
 ** The following routine is called if the stack overflows.
 */
-static void yyStackOverflow(yyParser *yypParser){
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
    ParseARG_FETCH;
    yypParser->yyidx--;
 #ifndef NDEBUG
@@ -533,68 +436,50 @@ static void yyStackOverflow(yyParser *yy
 #endif
    while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
    /* Here code is inserted which will execute if the parser
-   ** stack ever overflows */
-/******** Begin %stack_overflow code ******************************************/
+   ** stack every overflows */
 %%
-/******** End %stack_overflow code ********************************************/
    ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
 }
 
 /*
-** Print tracing information for a SHIFT action
-*/
-#ifndef NDEBUG
-static void yyTraceShift(yyParser *yypParser, int yyNewState){
-  if( yyTraceFILE ){
-    if( yyNewState<YYNSTATE ){
-      fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n",
-         yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major],
-         yyNewState);
-    }else{
-      fprintf(yyTraceFILE,"%sShift '%s'\n",
-         yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major]);
-    }
-  }
-}
-#else
-# define yyTraceShift(X,Y)
-#endif
-
-/*
 ** Perform a shift action.
 */
 static void yy_shift(
   yyParser *yypParser,          /* The parser to be shifted */
   int yyNewState,               /* The new state to shift in */
   int yyMajor,                  /* The major token to shift in */
-  ParseTOKENTYPE yyMinor        /* The minor token to shift in */
+  YYMINORTYPE *yypMinor         /* Pointer ot the minor token to shift in */
 ){
   yyStackEntry *yytos;
   yypParser->yyidx++;
-#ifdef YYTRACKMAXSTACKDEPTH
-  if( yypParser->yyidx>yypParser->yyidxMax ){
-    yypParser->yyidxMax = yypParser->yyidx;
-  }
-#endif
 #if YYSTACKDEPTH>0
   if( yypParser->yyidx>=YYSTACKDEPTH ){
-    yyStackOverflow(yypParser);
+    yyStackOverflow(yypParser, yypMinor);
     return;
   }
 #else
   if( yypParser->yyidx>=yypParser->yystksz ){
     yyGrowStack(yypParser);
     if( yypParser->yyidx>=yypParser->yystksz ){
-      yyStackOverflow(yypParser);
+      yyStackOverflow(yypParser, yypMinor);
       return;
     }
   }
 #endif
   yytos = &yypParser->yystack[yypParser->yyidx];
-  yytos->stateno = (YYACTIONTYPE)yyNewState;
-  yytos->major = (YYCODETYPE)yyMajor;
-  yytos->minor.yy0 = yyMinor;
-  yyTraceShift(yypParser, yyNewState);
+  yytos->stateno = yyNewState;
+  yytos->major = yyMajor;
+  yytos->minor = *yypMinor;
+#ifndef NDEBUG
+  if( yyTraceFILE && yypParser->yyidx>0 ){
+    int i;
+    fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
+    fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
+    for(i=1; i<=yypParser->yyidx; i++)
+      fprintf(yyTraceFILE," (%d)%s",yypParser->yystack[i].stateno,yyTokenName[yypParser->yystack[i].major]);
+    fprintf(yyTraceFILE,"\n");
+  }
+#endif
 }
 
 /* The following table contains information about every rule that
@@ -615,46 +500,39 @@ static void yy_accept(yyParser*);  /* Fo
 */
 static void yy_reduce(
   yyParser *yypParser,         /* The parser */
-  unsigned int yyruleno        /* Number of the rule by which to reduce */
+  int yyruleno                 /* Number of the rule by which to reduce */
 ){
   int yygoto;                     /* The next state */
   int yyact;                      /* The next action */
+  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
   yyStackEntry *yymsp;            /* The top of the parser's stack */
   int yysize;                     /* Amount to pop the stack */
   ParseARG_FETCH;
   yymsp = &yypParser->yystack[yypParser->yyidx];
 #ifndef NDEBUG
-  if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
-    yysize = yyRuleInfo[yyruleno].nrhs;
-    fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt,
-      yyRuleName[yyruleno], yymsp[-yysize].stateno);
+  if( yyTraceFILE && yyruleno>=0 
+        && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
+      yyRuleName[yyruleno]);
   }
 #endif /* NDEBUG */
 
-  /* Check that the stack is large enough to grow by a single entry
-  ** if the RHS of the rule is empty.  This ensures that there is room
-  ** enough on the stack to push the LHS value */
-  if( yyRuleInfo[yyruleno].nrhs==0 ){
-#ifdef YYTRACKMAXSTACKDEPTH
-    if( yypParser->yyidx>yypParser->yyidxMax ){
-      yypParser->yyidxMax = yypParser->yyidx;
-    }
-#endif
-#if YYSTACKDEPTH>0
-    if( yypParser->yyidx>=YYSTACKDEPTH-1 ){
-      yyStackOverflow(yypParser);
-      return;
-    }
-#else
-    if( yypParser->yyidx>=yypParser->yystksz-1 ){
-      yyGrowStack(yypParser);
-      if( yypParser->yyidx>=yypParser->yystksz-1 ){
-        yyStackOverflow(yypParser);
-        return;
-      }
-    }
-#endif
-  }
+  /* Silence complaints from purify about yygotominor being uninitialized
+  ** in some cases when it is copied into the stack after the following
+  ** switch.  yygotominor is uninitialized when a rule reduces that does
+  ** not set the value of its left-hand side nonterminal.  Leaving the
+  ** value of the nonterminal uninitialized is utterly harmless as long
+  ** as the value is never used.  So really the only thing this code
+  ** accomplishes is to quieten purify.  
+  **
+  ** 2007-01-16:  The wireshark project (www.wireshark.org) reports that
+  ** without this code, their parser segfaults.  I'm not sure what there
+  ** parser is doing to make this happen.  This is the second bug report
+  ** from wireshark this week.  Clearly they are stressing Lemon in ways
+  ** that it has not been previously stressed...  (SQLite ticket #2172)
+  */
+  memset(&yygotominor, 0, sizeof(yygotominor));
+
 
   switch( yyruleno ){
   /* Beginning here are the reduction cases.  A typical example
@@ -665,24 +543,31 @@ static void yy_reduce(
   **  #line <lineno> <thisfile>
   **     break;
   */
-/********** Begin reduce actions **********************************************/
 %%
-/********** End reduce actions ************************************************/
   };
-  assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
   yygoto = yyRuleInfo[yyruleno].lhs;
   yysize = yyRuleInfo[yyruleno].nrhs;
-  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
-  if( yyact <= YY_MAX_SHIFTREDUCE ){
-    if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
-    yypParser->yyidx -= yysize - 1;
-    yymsp -= yysize-1;
-    yymsp->stateno = (YYACTIONTYPE)yyact;
-    yymsp->major = (YYCODETYPE)yygoto;
-    yyTraceShift(yypParser, yyact);
+  yypParser->yyidx -= yysize;
+  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,yygoto);
+  if( yyact < YYNSTATE ){
+#ifdef NDEBUG
+    /* If we are not debugging and the reduce action popped at least
+    ** one element off the stack, then we can push the new element back
+    ** onto the stack here, and skip the stack overflow test in yy_shift().
+    ** That gives a significant speed improvement. */
+    if( yysize ){
+      yypParser->yyidx++;
+      yymsp -= yysize-1;
+      yymsp->stateno = yyact;
+      yymsp->major = yygoto;
+      yymsp->minor = yygotominor;
+    }else
+#endif
+    {
+      yy_shift(yypParser,yyact,yygoto,&yygotominor);
+    }
   }else{
-    assert( yyact == YY_ACCEPT_ACTION );
-    yypParser->yyidx -= yysize;
+    assert( yyact == YYNSTATE + YYNRULE + 1 );
     yy_accept(yypParser);
   }
 }
@@ -690,7 +575,6 @@ static void yy_reduce(
 /*
 ** The following code executes when the parse fails
 */
-#ifndef YYNOERRORRECOVERY
 static void yy_parse_failed(
   yyParser *yypParser           /* The parser */
 ){
@@ -703,12 +587,9 @@ static void yy_parse_failed(
   while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
   /* Here code is inserted which will be executed whenever the
   ** parser fails */
-/************ Begin %parse_failure code ***************************************/
 %%
-/************ End %parse_failure code *****************************************/
   ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
 }
-#endif /* YYNOERRORRECOVERY */
 
 /*
 ** The following code executes when a syntax error first occurs.
@@ -716,13 +597,11 @@ static void yy_parse_failed(
 static void yy_syntax_error(
   yyParser *yypParser,           /* The parser */
   int yymajor,                   /* The major type of the error token */
-  ParseTOKENTYPE yyminor         /* The minor type of the error token */
+  YYMINORTYPE yyminor            /* The minor type of the error token */
 ){
   ParseARG_FETCH;
-#define TOKEN yyminor
-/************ Begin %syntax_error code ****************************************/
+#define TOKEN (yyminor.yy0)
 %%
-/************ End %syntax_error code ******************************************/
   ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
 }
 
@@ -741,9 +620,7 @@ static void yy_accept(
   while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
   /* Here code is inserted which will be executed whenever the
   ** parser accepts */
-/*********** Begin %parse_accept code *****************************************/
 %%
-/*********** End %parse_accept code *******************************************/
   ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
 }
 
@@ -773,10 +650,8 @@ void Parse(
   ParseARG_PDECL               /* Optional %extra_argument parameter */
 ){
   YYMINORTYPE yyminorunion;
-  unsigned int yyact;   /* The parser action. */
-#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+  int yyact;            /* The parser action. */
   int yyendofinput;     /* True if we are at the end of input */
-#endif
 #ifdef YYERRORSYMBOL
   int yyerrorhit = 0;   /* True if yymajor has invoked an error */
 #endif
@@ -787,51 +662,40 @@ void Parse(
   if( yypParser->yyidx<0 ){
 #if YYSTACKDEPTH<=0
     if( yypParser->yystksz <=0 ){
-      yyStackOverflow(yypParser);
+      memset(&yyminorunion, 0, sizeof(yyminorunion));
+      yyStackOverflow(yypParser, &yyminorunion);
       return;
     }
 #endif
     yypParser->yyidx = 0;
-#ifndef YYNOERRORRECOVERY
     yypParser->yyerrcnt = -1;
-#endif
     yypParser->yystack[0].stateno = 0;
     yypParser->yystack[0].major = 0;
-#ifndef NDEBUG
-    if( yyTraceFILE ){
-      fprintf(yyTraceFILE,"%sInitialize. Empty stack. State 0\n",
-              yyTracePrompt);
-    }
-#endif
   }
-#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+  yyminorunion.yy0 = yyminor;
   yyendofinput = (yymajor==0);
-#endif
   ParseARG_STORE;
 
 #ifndef NDEBUG
   if( yyTraceFILE ){
-    fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]);
+    fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
   }
 #endif
 
   do{
-    yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
-    if( yyact <= YY_MAX_SHIFTREDUCE ){
-      if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
-      yy_shift(yypParser,yyact,yymajor,yyminor);
-#ifndef YYNOERRORRECOVERY
+    yyact = yy_find_shift_action(yypParser,yymajor);
+    if( yyact<YYNSTATE ){
+      assert( !yyendofinput );  /* Impossible to shift the $ token */
+      yy_shift(yypParser,yyact,yymajor,&yyminorunion);
       yypParser->yyerrcnt--;
-#endif
       yymajor = YYNOCODE;
-    }else if( yyact <= YY_MAX_REDUCE ){
-      yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
+    }else if( yyact < YYNSTATE + YYNRULE ){
+      yy_reduce(yypParser,yyact-YYNSTATE);
     }else{
 #ifdef YYERRORSYMBOL
       int yymx;
 #endif
       assert( yyact == YY_ERROR_ACTION );
-      yyminorunion.yy0 = yyminor;
 #ifndef NDEBUG
       if( yyTraceFILE ){
         fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
@@ -840,7 +704,7 @@ void Parse(
 #ifdef YYERRORSYMBOL
       /* A syntax error has occurred.
       ** The response to an error depends upon whether or not the
-      ** grammar defines an error token "ERROR".
+      ** grammar defines an error token "ERROR".  
       **
       ** This is what we do if the grammar does define ERROR:
       **
@@ -858,7 +722,7 @@ void Parse(
       **
       */
       if( yypParser->yyerrcnt<0 ){
-        yy_syntax_error(yypParser,yymajor,yyminor);
+        yy_syntax_error(yypParser,yymajor,yyminorunion);
       }
       yymx = yypParser->yystack[yypParser->yyidx].major;
       if( yymx==YYERRORSYMBOL || yyerrorhit ){
@@ -868,40 +732,30 @@ void Parse(
              yyTracePrompt,yyTokenName[yymajor]);
         }
 #endif
-        yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
+        yy_destructor(yymajor,&yyminorunion);
         yymajor = YYNOCODE;
       }else{
-        while(
+         while(
           yypParser->yyidx >= 0 &&
           yymx != YYERRORSYMBOL &&
           (yyact = yy_find_reduce_action(
                         yypParser->yystack[yypParser->yyidx].stateno,
-                        YYERRORSYMBOL)) >= YY_MIN_REDUCE
+                        YYERRORSYMBOL)) >= YYNSTATE
         ){
           yy_pop_parser_stack(yypParser);
         }
         if( yypParser->yyidx < 0 || yymajor==0 ){
-          yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+          yy_destructor(yymajor,&yyminorunion);
           yy_parse_failed(yypParser);
           yymajor = YYNOCODE;
         }else if( yymx!=YYERRORSYMBOL ){
-          yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
+          YYMINORTYPE u2;
+          u2.YYERRSYMDT = 0;
+          yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
         }
       }
       yypParser->yyerrcnt = 3;
       yyerrorhit = 1;
-#elif defined(YYNOERRORRECOVERY)
-      /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
-      ** do any kind of error recovery.  Instead, simply invoke the syntax
-      ** error routine and continue going as if nothing had happened.
-      **
-      ** Applications can set this macro (for example inside %include) if
-      ** they intend to abandon the parse upon the first syntax error seen.
-      */
-      yy_syntax_error(yypParser,yymajor, yyminor);
-      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
-      yymajor = YYNOCODE;
-
 #else  /* YYERRORSYMBOL is not defined */
       /* This is what we do if the grammar does not define ERROR:
       **
@@ -913,10 +767,10 @@ void Parse(
       ** three input tokens have been successfully shifted.
       */
       if( yypParser->yyerrcnt<=0 ){
-        yy_syntax_error(yypParser,yymajor, yyminor);
+        yy_syntax_error(yypParser,yymajor,yyminorunion);
       }
       yypParser->yyerrcnt = 3;
-      yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+      yy_destructor(yymajor,&yyminorunion);
       if( yyendofinput ){
         yy_parse_failed(yypParser);
       }
@@ -924,15 +778,5 @@ void Parse(
 #endif
     }
   }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
-#ifndef NDEBUG
-  if( yyTraceFILE ){
-    int i;
-    fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
-    for(i=1; i<=yypParser->yyidx; i++)
-      fprintf(yyTraceFILE,"%c%s", i==1 ? '[' : ' ', 
-              yyTokenName[yypParser->yystack[i].major]);
-    fprintf(yyTraceFILE,"]\n");
-  }
-#endif
   return;
 }
