--- .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(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 *¶m) 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 at position

- -// 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 it(IntConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value] = pair->Key; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: FillFloatConstants -// -//========================================================================== - -void VMFunctionBuilder::FillFloatConstants(double *konst) -{ - TMapIterator it(FloatConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value] = pair->Key; - } -} - -//========================================================================== -// -// VMFunctionBuilder :: FillAddressConstants -// -//========================================================================== - -void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags) -{ - TMapIterator it(AddressConstants); - TMap::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 it(StringConstants); - TMap::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 that points at . -// -//========================================================================== - -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 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 IntConstants; - TMap FloatConstants; - TMap AddressConstants; - TMap StringConstants; - - int NumIntConstants; - int NumFloatConstants; - int NumAddressConstants; - int NumStringConstants; - - int MaxParam; - int ActiveParam; - - TArray 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 -#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 -struct VMExec_Checked -{ -#include "vmexec.h" -}; -#if WAS_NDEBUG -#define NDEBUG -#endif - -#if !WAS_NDEBUG -#define NDEBUG -#endif -#undef assert -#include -struct VMExec_Unchecked -{ -#include "vmexec.h" -}; -#if !WAS_NDEBUG -#undef NDEBUG -#endif -#undef assert -#include - -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(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(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 = ®.param[f->NumParam++]; - ::new(param) VMValue(ABCs); - } - NEXTOP; - OP(PARAM): - assert(f->NumParam < sfunc->MaxParam); - { - VMValue *param = ®.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(®.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(®.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(®.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(®.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(call)->NativeCall(stack, reg.param + f->NumParam - B, B, returns, C); - } - else - { - VMScriptFunction *script = static_cast(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(call)->NativeCall(stack, reg.param + f->NumParam - B, B, ret, numret); - } - else - { // FIXME: Not a true tail call - VMScriptFunction *script = static_cast(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 = ®.s[B]; - FString *rC = ®.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 = ®.s[B]; - } - if (a & CMP_CK) - { - ASSERTKS(C); - c = &konsts[C]; - } - else - { - ASSERTS(C); - c = ®.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 = ®.f[C]; - Do_ADDV: - fbp = ®.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 = ®.f[B]; - fcp = ®.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 = ®.f[B]; - fcp = &konstf[C]; - goto Do_SUBV; - OP(SUBV_KR): - ASSERTF(A+2); ASSERTKF(B+2); ASSERTF(C+2); - fbp = &konstf[B]; - fcp = ®.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 = ®.f[B]; - fcp = ®.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 = ®.f[B]; - fcp = &konstf[C]; - goto Do_CROSSV; - OP(CROSSV_KR): - ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C+2); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_CROSSV; - - OP(MULVF_RR): - ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); - fc = reg.f[C]; - fbp = ®.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 = ®.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 = ®.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 ®, 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 ®, 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 = ®.d[regnum]; - } - else // type == REGT_FLOAT - { - assert(regnum < frame->NumRegF); - ret->Location = ®.f[regnum]; - } - } - else if (type == REGT_STRING) - { - assert(regnum < frame->NumRegS); - ret->Location = ®.s[regnum]; - } - else - { - assert(type == REGT_POINTER); - assert(regnum < frame->NumRegA); - ret->Location = ®.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 ®, VMFrame *frame, VMReturn *ret, VM_UBYTE regtype, int regnum) -{ - const void *src; - VMScriptFunction *func = static_cast(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 = ®.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 = ®.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 = ®.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 -#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(®s[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(func)->NativeCall(this, params, numparams, results, numresults); - } - else - { - AllocFrame(static_cast(func)); - allocated = true; - VMFillParams(params, TopFrame(), numparams); - int numret = VMExec(this, static_cast(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 == ) then pc++ ; next instruction must JMP to another CATCH - // A == 3: (pkB == ) 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(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(node->SiblingNext); - node != C; - prev = node, node = static_cast(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(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 */ -{ - NEW_AST_NODE(DynArrayType,arr,T); - arr->ElementType = A; - X = arr; -} - -aggregate_type(X) ::= CLASS(T) class_restrictor(A). /* class */ -{ - 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(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(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(node))) - { - switch (node->NodeType) - { - case AST_Class: Classes.Push(static_cast(node)); break; - case AST_Struct: Structs.Push(static_cast(node)); break; - case AST_ConstantDef: Constants.Push(static_cast(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(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 &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(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(root)); - } - else if (root->NodeType == AST_ExprBinary) - { - return SimplifyBinary(static_cast(root)); - } - else if (root->Operation == PEX_ID) - { - return IdentifyIdentifier(static_cast(root)); - } - else if (root->Operation == PEX_MemberAccess) - { - return SimplifyMemberAccess(static_cast(root)); - } - else if (root->Operation == PEX_FuncCall) - { - return SimplifyFunctionCall(static_cast(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(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(binary->Left), - static_cast(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(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(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(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(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(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(sym)->Node); - Symbols = prevtable; - if (sym == NULL) - { - return NULL; - } - } - if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst))) - { - return NodeFromSymbolConst(static_cast(sym), source); - } - else if (sym->IsKindOf(RUNTIME_CLASS(PSymbolType))) - { - return NodeFromSymbolType(static_cast(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(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(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(sym)->Value; - } - else - { - assert(sym->ValueType->IsKindOf(RUNTIME_CLASS(PFloat))); - val->DoubleVal = static_cast(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(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 &defs); - PSymbolConst *CompileConstant(ZCC_ConstantDef *def); - - TArray Constants; - TArray Structs; - TArray 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 -#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 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 ≻ -}; - -#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 #include @@ -17,14 +17,6 @@ #include #include -#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 #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; inext; - 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; inAction+p->mnLookahead; i++){ + if( p->aAction[i].lookahead<0 ){ + for(j=0; jnLookahead; j++){ + k = p->aLookahead[j].lookahead - p->mnLookahead + i; + if( k<0 ) break; + if( p->aAction[k].lookahead>=0 ) break; + } + if( jnLookahead ) continue; + for(j=0; jnAction; 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; jnLookahead; 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( jnLookahead ) continue; - - /* No possible lookahead value that is not in the aLookahead[] - ** transaction is allowed to match aAction[i] */ n = 0; for(j=0; jnAction; 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; inActionAlloc - p->mxLookahead; i++){ - if( p->aAction[i].lookahead<0 ){ - for(j=0; jnLookahead; j++){ - k = p->aLookahead[j].lookahead - p->mnLookahead + i; - if( k<0 ) break; - if( p->aAction[k].lookahead>=0 ) break; - } - if( jnLookahead ) continue; - for(j=0; jnAction; 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; inrhs; 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->precprec ){ 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; inext; - 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=='-' && i0 ){ - 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->iRuleiRule ){ - *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; iuseCnt = 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; iindex = i; - qsort(lem.symbols,lem.nsymbol,sizeof(struct symbol*), Symbolcmpp); - for(i=0; iindex = 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=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%*s %s\n",op[i].label, - (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); + fprintf(errstream," %s=%*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%*s %s\n",op[i].label, - (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); + fprintf(errstream," %s=%*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%*s %s\n",op[i].label, - (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); + fprintf(errstream," %s=%*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; inrhs; 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; k100000000 || 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; inext; - 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; insymbol; 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; inrhs; i++){ sp = rp->rhs[i]; + printf(" %s", sp->name); if( sp->type==MULTITERMINAL ){ - printf(" %s", sp->subsym[0]->name); for(j=1; jnsubsym; 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; jnsubsym; 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; inxstate; i++){ + for(i=0; instate; 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; inrhs; 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; inrhs; 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; inrhs; 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; jrhsalias[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; insymbol; 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=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; jnrhs; 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; knsubsym; 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; inxstate; i++){ + for(i=0; instate; 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; inxstate*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; inxstate*2 && ax[i].nAction>0; i++){ + for(i=0; instate*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->iNtOfstiNtOfst; 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; jjnAction; 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; instate + 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; inxstate; + 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; isorted[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; isorted[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; isorted[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; interminal; 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; insymbol; 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; insymbol && lemp->symbols[i]->type!=TERMINAL; i++); if( insymbol ){ @@ -4334,27 +3863,24 @@ void ReportTable( } if( lemp->vardest ){ struct symbol *dflt_sp = 0; - int once = 1; for(i=0; insymbol; 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; insymbol; 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; jnsymbol; 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; interminal && 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; interminal; 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; instate; 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; instate; 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->indexnterminal ){ stp->nTknAct++; }else if( ap->sp->indexnsymbol ){ 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; instate; 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 && esize = 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; iname = 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; i0 && 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; icount; - array = (struct state **)calloc(size, sizeof(struct state *)); + array = (struct state **)malloc( sizeof(struct state *)*size ); if( array ){ for(i=0; itbl[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; isize-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 #include #include @@ -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: +**

*/ 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 %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 %s\n", - yyTracePrompt, yyTokenName[iLookAhead], - yyTokenName[YYWILDCARD]); - } -#endif /* NDEBUG */ - return yy_action[j]; + { + int j = i - iLookAhead + YYWILDCARD; + if( j>=0 && j %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 && iyyidx--; #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( yyNewStateyystack[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 ** break; */ -/********** Begin reduce actions **********************************************/ %% -/********** End reduce actions ************************************************/ }; - assert( yyrulenoYY_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( yyactyyerrcnt--; -#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; }