diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3c80613ecd..dc42f81e14 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -758,15 +758,11 @@ else() endif() add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h - 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} + COMMAND lemon -C${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y 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 ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/zscript/zcc-parse.lemon . - COMMAND lemon zcc-parse.lemon - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + 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 @@ -1515,5 +1511,5 @@ source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_sh 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/.+") +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) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index b8a5cbcf9c..609ec17211 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -2711,6 +2711,7 @@ END_POINTERS IMPLEMENT_POINTY_CLASS(PSymbolVMFunction) DECLARE_POINTER(Function) END_POINTERS +IMPLEMENT_CLASS(PSymbolTreeNode) //========================================================================== // @@ -2773,6 +2774,22 @@ PSymbol *PSymbolTable::FindSymbol (FName symname, bool searchparents) const return value != NULL ? *value : NULL; } +PSymbol *PSymbolTable::FindSymbolInTable(FName symname, PSymbolTable *&symtable) +{ + PSymbol * const *value = Symbols.CheckKey(symname); + if (value == NULL) + { + if (ParentSymbolTable != NULL) + { + return ParentSymbolTable->FindSymbolInTable(symname, symtable); + } + symtable = NULL; + return NULL; + } + symtable = this; + return *value; +} + PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) { // Symbols that already exist are not inserted. @@ -2783,3 +2800,19 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym) Symbols.Insert(sym->SymbolName, sym); return sym; } + +PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym) +{ + // If a symbol with a matching name exists, take its place and return it. + PSymbol **symslot = Symbols.CheckKey(newsym->SymbolName); + if (symslot != NULL) + { + PSymbol *oldsym = *symslot; + *symslot = newsym; + return oldsym; + } + // Else, just insert normally and return NULL since there was no + // symbol to replace. + Symbols.Insert(newsym->SymbolName, newsym); + return NULL; +} diff --git a/src/dobjtype.h b/src/dobjtype.h index 70c5d850d9..b482efe457 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -67,6 +67,18 @@ public: PSymbolType() : PSymbol(NAME_None) {} }; +// A symbol for a compiler tree node ---------------------------------------- + +class PSymbolTreeNode : public PSymbol +{ + DECLARE_CLASS(PSymbolTreeNode, PSymbol); +public: + struct ZCC_NamedNode *Node; + + PSymbolTreeNode(FName name, struct ZCC_NamedNode *node) : PSymbol(name), Node(node) {} + PSymbolTreeNode() : PSymbol(NAME_None) {} +}; + // A symbol table ----------------------------------------------------------- struct PSymbolTable @@ -85,11 +97,19 @@ struct PSymbolTable // as well. PSymbol *FindSymbol (FName symname, bool searchparents) const; + // Like FindSymbol with searchparents set true, but also returns the + // specific symbol table the symbol was found in. + PSymbol *FindSymbolInTable(FName symname, PSymbolTable *&symtable); + // Places the symbol in the table and returns a pointer to it or NULL if // a symbol with the same name is already in the table. This symbol is // not copied and will be freed when the symbol table is destroyed. PSymbol *AddSymbol (PSymbol *sym); + // Similar to AddSymbol but always succeeds. Returns the symbol that used + // to be in the table with this name, if any. + PSymbol *ReplaceSymbol(PSymbol *sym); + // Frees all symbols from this table. void ReleaseSymbols(); diff --git a/src/g_doom/a_revenant.cpp b/src/g_doom/a_revenant.cpp index 252a1c1cd7..1b36d6cb2c 100644 --- a/src/g_doom/a_revenant.cpp +++ b/src/g_doom/a_revenant.cpp @@ -28,8 +28,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkelMissile) return 0; A_FaceTarget (self); - missile = P_SpawnMissileZ (self, self->Z() + 48*FRACUNIT, - self->target, PClass::FindActor("RevenantTracer")); + self->AddZ(16*FRACUNIT); + missile = P_SpawnMissile (self, self->target, PClass::FindActor("RevenantTracer")); + self->AddZ(-16*FRACUNIT); if (missile != NULL) { diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 24d54dd4de..8abf3fa18f 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -30,7 +30,7 @@ void AdjustPlayerAngle (AActor *pmo, FTranslatedLineTarget *t) angle_t angle; int difference; - angle = t->angleFromSource; + angle = pmo->AngleTo(t->linetarget); difference = (int)angle - (int)pmo->angle; if (abs(difference) > MAX_ANGLE_ADJUST) { diff --git a/src/g_hexen/a_heresiarch.cpp b/src/g_hexen/a_heresiarch.cpp index 0cdc7922b6..6aee19a71c 100644 --- a/src/g_hexen/a_heresiarch.cpp +++ b/src/g_hexen/a_heresiarch.cpp @@ -710,7 +710,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnFizzle) { PARAM_ACTION_PROLOGUE; fixed_t dist = 5*FRACUNIT; - fixed_t speed = self->Speed; + fixed_t speed = self->Speed >> FRACBITS; angle_t rangle; AActor *mo; int ix; diff --git a/src/g_shared/a_quake.cpp b/src/g_shared/a_quake.cpp index e75a084c58..2e1c5fa163 100644 --- a/src/g_shared/a_quake.cpp +++ b/src/g_shared/a_quake.cpp @@ -143,15 +143,15 @@ void DEarthquake::Tick () angle_t an = victim->angle + ANGLE_1*pr_quake(); if (m_IntensityX == m_IntensityY) { // Thrust in a circle - P_ThrustMobj (victim, an, m_IntensityX << (FRACBITS-1)); + P_ThrustMobj (victim, an, m_IntensityX/2); } else { // Thrust in an ellipse an >>= ANGLETOFINESHIFT; // So this is actually completely wrong, but it ought to be good // enough. Otherwise, I'd have to use tangents and square roots. - victim->vel.x += FixedMul(m_IntensityX << (FRACBITS-1), finecosine[an]); - victim->vel.y += FixedMul(m_IntensityY << (FRACBITS-1), finesine[an]); + victim->vel.x += FixedMul(m_IntensityX/2, finecosine[an]); + victim->vel.y += FixedMul(m_IntensityY/2, finesine[an]); } } } diff --git a/src/p_map.cpp b/src/p_map.cpp index 8c9b210555..aafe2d125c 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4940,7 +4940,7 @@ bool P_TalkFacing(AActor *player) if (t.linetarget != NULL) { if (t.linetarget->health > 0 && // Dead things can't talk. - t.linetarget->flags4 & MF4_INCOMBAT && // Fighting things don't talk either. + !(t.linetarget->flags4 & MF4_INCOMBAT) && // Fighting things don't talk either. t.linetarget->Conversation != NULL) { // Give the NPC a chance to play a brief animation diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 106abd776a..d1a4efd17f 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -109,6 +109,18 @@ CUSTOM_CVAR (Float, snd_waterlp, 250, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) } } +CUSTOM_CVAR (Int, snd_streambuffersize, 64, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 16) + { + self = 16; + } + else if (self > 1024) + { + self = 1024; + } +} + #ifndef NO_FMOD #if FMOD_VERSION < 0x43400 #define FMOD_OPENSTATE_PLAYING FMOD_OPENSTATE_STREAMING @@ -1168,9 +1180,7 @@ bool FMODSoundRenderer::Init() } Sys->set3DSettings(0.5f, 96.f, 1.f); Sys->set3DRolloffCallback(RolloffCallback); - // The default is 16k, which periodically starves later FMOD versions - // when streaming FLAC files. - Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES); + Sys->setStreamBufferSize(snd_streambuffersize * 1024, FMOD_TIMEUNIT_RAWBYTES); snd_sfxvolume.Callback (); return true; } diff --git a/src/textures/multipatchtexture.cpp b/src/textures/multipatchtexture.cpp index 358fde9ea4..f33bfa7028 100644 --- a/src/textures/multipatchtexture.cpp +++ b/src/textures/multipatchtexture.cpp @@ -1148,7 +1148,7 @@ void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, bool silent, i sc.MustGetStringName(","); sc.MustGetNumber(); b = sc.Number; - sc.MustGetStringName(","); + //sc.MustGetStringName(","); This was never supposed to be here. part.Blend = MAKERGB(r, g, b); } // Blend.a may never be 0 here. diff --git a/src/xlat/xlat_parser.y b/src/xlat/xlat_parser.y index f0850c625c..9bafb9fb8d 100644 --- a/src/xlat/xlat_parser.y +++ b/src/xlat/xlat_parser.y @@ -202,10 +202,7 @@ special_args(Z) ::= . /* empty */ Z.args[3] = 0; Z.args[4] = 0; } -special_args(Z) ::= multi_special_arg(A). -{ - Z = A; -} +special_args(Z) ::= multi_special_arg(Z). //========================================================================== // diff --git a/src/zscript/ast.cpp b/src/zscript/ast.cpp index a59a656af0..a68b1c69f3 100644 --- a/src/zscript/ast.cpp +++ b/src/zscript/ast.cpp @@ -281,7 +281,7 @@ static void PrintClass(FLispString &out, ZCC_TreeNode *node) ZCC_Class *cnode = (ZCC_Class *)node; out.Break(); out.Open("class"); - out.AddName(cnode->ClassName); + out.AddName(cnode->NodeName); PrintNodes(out, cnode->ParentName); PrintNodes(out, cnode->Replaces); out.AddHex(cnode->Flags); @@ -294,7 +294,7 @@ static void PrintStruct(FLispString &out, ZCC_TreeNode *node) ZCC_Struct *snode = (ZCC_Struct *)node; out.Break(); out.Open("struct"); - out.AddName(snode->StructName); + out.AddName(snode->NodeName); PrintNodes(out, snode->Body, false, true); out.Close(); } @@ -304,7 +304,7 @@ static void PrintEnum(FLispString &out, ZCC_TreeNode *node) ZCC_Enum *enode = (ZCC_Enum *)node; out.Break(); out.Open("enum"); - out.AddName(enode->EnumName); + out.AddName(enode->NodeName); PrintBuiltInType(out, enode->EnumType); out.Add(enode->Elements == NULL ? "nil" : "...", 3); out.Close(); @@ -733,7 +733,7 @@ static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node) ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node; out.Break(); out.Open("constant-def"); - out.AddName(dnode->Name); + out.AddName(dnode->NodeName); PrintNodes(out, dnode->Value, false); out.Close(); } diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index c42e0818b9..ee8296ff66 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -90,7 +90,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) for (int j = 1; j < YYERRORSYMBOL; ++j) { int k = i + j; - if (k >= 0 && k < YY_SZ_ACTTAB && yy_lookahead[k] == j) + if (k >= 0 && k < YY_ACTTAB_COUNT && yy_lookahead[k] == j) { expecting << (expecting.IsEmpty() ? "Expecting " : " or ") << ZCCTokenName(j); } @@ -128,15 +128,15 @@ main ::= translation_unit(A). { stat->TopNode = A; stat->sc.ScriptMessage("Parse %type translation_unit {ZCC_TreeNode *} translation_unit(X) ::= . { X = NULL; } -translation_unit(X) ::= translation_unit(A) external_declaration(B). { SAFE_APPEND(A,B); X = A; } -translation_unit(X) ::= translation_unit(A) EOF. { X = A; } +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; } -external_declaration(X) ::= struct_def(A). { X = A; } -external_declaration(X) ::= enum_def(A). { X = A; } -external_declaration(X) ::= const_def(A). { X = A; } +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 ::= . @@ -150,10 +150,7 @@ opt_expr(X) ::= . { X = NULL; } -opt_expr(X) ::= expr(A). -{ - X = A; -} +opt_expr(X) ::= expr(X). /************ Class Definition ************/ @@ -168,13 +165,13 @@ opt_expr(X) ::= expr(A). class_definition(X) ::= class_head(A) class_body(B). { A->Body = B; - X = A; + 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->ClassName = A.Name(); + head->NodeName = A.Name(); head->ParentName = B; head->Flags = C.Flags; head->Replaces = C.Replaces; @@ -183,7 +180,7 @@ class_head(X) ::= CLASS(T) IDENTIFIER(A) class_ancestry(B) class_flags(C). %type class_ancestry{ZCC_Identifier *} class_ancestry(X) ::= . { X = NULL; } -class_ancestry(X) ::= COLON dottable_id(A). { X = A; } +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; } @@ -207,7 +204,7 @@ 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 = A; /*X-overwrites-A*/ } /*------ Class Body ------*/ @@ -220,23 +217,23 @@ dottable_id(X) ::= dottable_id(A) DOT IDENTIFIER(B). // * constants // * defaults -class_body(X) ::= SEMICOLON class_innards(A) EOF. { X = A; } -class_body(X) ::= LBRACE class_innards(A) RBRACE. { X = A; } +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(A) class_member(B). { SAFE_APPEND(A,B); X = A; } +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; } -class_member(X) ::= enum_def(A). { X = A; } -class_member(X) ::= struct_def(A). { X = A; } -class_member(X) ::= states_def(A). { X = A; } -class_member(X) ::= default_def(A). { X = A; } -class_member(X) ::= const_def(A). { X = A; } +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. */ @@ -248,28 +245,28 @@ class_member(X) ::= const_def(A). { X = A; } struct_def(X) ::= STRUCT(T) IDENTIFIER(A) LBRACE opt_struct_body(B) RBRACE opt_semicolon. { NEW_AST_NODE(Struct,def,T); - def->StructName = A.Name(); + def->NodeName = A.Name(); def->Body = B; X = def; } opt_struct_body(X) ::= . { X = NULL; } -opt_struct_body(X) ::= struct_body(A). { X = A; } +opt_struct_body(X) ::= struct_body(X). struct_body(X) ::= error. { X = NULL; } -struct_body(X) ::= struct_member(A). { X = A; } -struct_body(X) ::= struct_member(A) struct_body(B). { X = A; A->AppendSibling(B); } +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; } -struct_member(X) ::= enum_def(A). { X = A; } -struct_member(X) ::= const_def(A). { X = A; } +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->Name = A.Name(); + def->NodeName = A.Name(); def->Value = B; def->Symbol = NULL; X = def; @@ -286,7 +283,7 @@ const_def(X) ::= CONST(T) IDENTIFIER(A) EQ expr(B) SEMICOLON. 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->EnumName = A.Name(); + def->NodeName = A.Name(); def->EnumType = (EZCCBuiltinType)B.Int; def->Elements = C; @@ -324,7 +321,7 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC NEW_INTCONST_NODE(one, TypeSInt32, 1, T); NEW_AST_NODE(ExprID, label, node); label->Operation = PEX_ID; - label->Identifier = prev->Name; + label->Identifier = prev->NodeName; label->Type = NULL; BINARY_EXPR(label, one, PEX_Add); @@ -343,19 +340,19 @@ enum_def(X) ::= ENUM(T) IDENTIFIER(A) enum_type(B) LBRACE opt_enum_list(C) RBRAC } enum_type(X) ::= . { X.Int = ZCC_IntAuto; X.SourceLoc = stat->sc.GetMessageLine(); } -enum_type(X) ::= COLON int_type(A). { X = A; } +enum_type(X) ::= COLON int_type(A). { X = A; /*X-overwrites-A*/ } enum_list(X) ::= error. { X = NULL; } -enum_list(X) ::= enumerator(A). { X = A; } -enum_list(X) ::= enum_list(A) COMMA enumerator(B). { X = A; A->AppendSibling(B); } +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(A) opt_comma. { X = A; } +opt_enum_list(X) ::= enum_list(X) opt_comma. enumerator(X) ::= IDENTIFIER(A). { NEW_AST_NODE(ConstantDef,node,A); - node->Name = A.Name(); + node->NodeName = A.Name(); node->Value = NULL; node->Symbol = NULL; X = node; @@ -363,7 +360,7 @@ enumerator(X) ::= IDENTIFIER(A). enumerator(X) ::= IDENTIFIER(A) EQ expr(B). /* Expression must be constant. */ { NEW_AST_NODE(ConstantDef,node,A); - node->Name = A.Name(); + node->NodeName = A.Name(); node->Value = B; node->Symbol = NULL; X = node; @@ -405,9 +402,9 @@ scanner_mode ::= . { stat->sc.SetStateMode(true); } states_body(X) ::= . { X = NULL; } states_body(X) ::= error. { X = NULL; } -states_body(X) ::= states_body(A) state_line(B). { SAFE_APPEND(A,B); X = A; } -states_body(X) ::= states_body(A) state_label(B). { SAFE_APPEND(A,B); X = A; } -states_body(X) ::= states_body(A) state_flow(B). { SAFE_APPEND(A,B); X = A; } +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. { @@ -416,7 +413,7 @@ state_label(X) ::= NWS(A) COLON. X = label; } -state_flow(X) ::= state_flow_type(A) scanner_mode SEMICOLON. { X = A; } +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; } @@ -431,7 +428,7 @@ state_flow_type(X) ::= GOTO(T) dottable_id(A) state_goto_offset(B). } state_goto_offset(X) ::= . { X = NULL; } -state_goto_offset(X) ::= PLUS expr(A). { X = A; } /* Must evaluate to a non-negative integer constant. */ +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). { @@ -457,21 +454,21 @@ state_line(X) ::= NWS(A) NWS(B) expr state_opts(C) state_action(D). } state_opts(X) ::= . { StateOpts opts; opts.Zero(); X = opts; } -state_opts(X) ::= state_opts(A) BRIGHT. { A.Bright = true; X = A; } -state_opts(X) ::= state_opts(A) FAST. { A.Fast = true; X = A; } -state_opts(X) ::= state_opts(A) SLOW. { A.Slow = true; X = A; } -state_opts(X) ::= state_opts(A) NODELAY. { A.NoDelay = true; X = A; } -state_opts(X) ::= state_opts(A) CANRAISE. { A.CanRaise = true; X = A; } -state_opts(X) ::= state_opts(A) OFFSET LPAREN expr(B) COMMA expr(C) RPAREN. { A.Offset = B; B->AppendSibling(C); X = A; } -state_opts(X) ::= state_opts(A) LIGHT LPAREN light_list RPAREN. { X = A; } ///FIXME: GZDoom would want to know this +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; } +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; } +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). @@ -488,11 +485,11 @@ state_call(X) ::= IDENTIFIER(A) state_call_params(B). } state_call_params(X) ::= . { X = NULL; } -state_call_params(X) ::= LPAREN func_expr_list(A) RPAREN. { X = A; } +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; } +default_def(X) ::= DEFAULT compound_statement(A). { X = A; /*X-overwrites-A*/ } /* Type names */ %type type_name {ZCC_BasicType *} @@ -505,7 +502,7 @@ 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(A). { X = A; } +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; } @@ -540,6 +537,7 @@ type_name(X) ::= DOT dottable_id(A). * (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. { @@ -554,8 +552,6 @@ vector_size(X) ::= LT intconst(A) GT. } X.SourceLoc = A.SourceLoc; } -intconst(X) ::= INTCONST(A). { X = A; } -intconst(X) ::= UINTCONST(A). { X = A; } /* Type names can also be used as identifiers in contexts where type names * are not normally allowed. */ @@ -594,19 +590,19 @@ aggregate_type(X) ::= CLASS(T) class_restrictor(A). /* class */ X = cls; } class_restrictor(X) ::= . { X = NULL; } -class_restrictor(X) ::= LT dottable_id(A) GT. { X = A; } +class_restrictor(X) ::= LT dottable_id(A) GT. { X = A; /*X-overwrites-A*/ } -type(X) ::= type_name(A). { X = A; A->ArraySize = NULL; } -type(X) ::= aggregate_type(A). { X = A; A->ArraySize = NULL; } +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(A). { X = A; } -type_or_array(X) ::= type(A) array_size(B). { X = A; A->ArraySize = B; } +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(A). { X = A; }/* A comma-separated list of types */ -type_list(X) ::= type_list(A) COMMA type_or_array(B). { X = A; A->AppendSibling(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(A). { X = A; } +type_list_or_void(X) ::= type_list(X). array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET. { @@ -622,14 +618,11 @@ array_size_expr(X) ::= LBRACKET opt_expr(A) RBRACKET. X = A; } } -array_size(X) ::= array_size_expr(A). -{ - 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 = A; /*X-overwrites-A*/ } %type variables_or_function {VarOrFun} @@ -738,14 +731,11 @@ variable_name(X) ::= IDENTIFIER(A) array_size(B). X = var; } -variable_list(X) ::= variable_name(A). -{ - X = A; -} +variable_list(X) ::= variable_name(X). variable_list(X) ::= variable_list(A) COMMA variable_name(B). { A->AppendSibling(B); - X = A; + X = A; /*X-overwrites-A*/ } decl_flags(X) ::= . { X.Int = 0; X.SourceLoc = 0; } @@ -764,7 +754,7 @@ 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(A). { X = A; } +opt_func_body(X) ::= function_body(X). %type func_params {ZCC_FuncParamDecl *} %type func_param_list {ZCC_FuncParamDecl *} @@ -772,10 +762,10 @@ opt_func_body(X) ::= function_body(A). { X = A; } func_params(X) ::= . /* empty */ { X = NULL; } func_params(X) ::= VOID. { X = NULL; } -func_params(X) ::= func_param_list(A). { X = A; } +func_params(X) ::= func_param_list(X). -func_param_list(X) ::= func_param(A). { X = A; } -func_param_list(X) ::= func_param_list(A) COMMA func_param(B). { X = A; A->AppendSibling(B); } +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). { @@ -819,10 +809,7 @@ primary(X) ::= SUPER(T). expr->Type = NULL; X = expr; } -primary(X) ::= constant(A). -{ - X = A; -} +primary(X) ::= constant(A). { X = A; /*X-overwrites-A*/ } primary(X) ::= SELF(T). { NEW_AST_NODE(Expression, expr, T); @@ -832,7 +819,7 @@ primary(X) ::= SELF(T). } primary(X) ::= LPAREN expr(A) RPAREN. { - X = A; + X = A; /*X-overwrites-A*/ } primary ::= LPAREN error RPAREN. primary(X) ::= primary(A) LPAREN func_expr_list(B) RPAREN. [DOT] // Function call @@ -881,10 +868,7 @@ primary(X) ::= SCOPE primary(B). */ /*----- Unary Expressions -----*/ -unary_expr(X) ::= primary(A). -{ - X = A; -} +unary_expr(X) ::= primary(X). unary_expr(X) ::= SUB unary_expr(A). [UNARY] { ZCC_ExprConstant *con = static_cast(A); @@ -959,10 +943,7 @@ unary_expr(X) ::= ALIGNOF unary_expr(A). [UNARY] /*----- Binary Expressions -----*/ -expr(X) ::= unary_expr(A). -{ - X = A; -} +expr(X) ::= unary_expr(X). expr(X) ::= expr(A) ADD expr(B). /* a + b */ { BINARY_EXPR(A,B,PEX_Add); @@ -1118,14 +1099,11 @@ expr(X) ::= expr(A) QUESTION expr(B) COLON expr(C). %type expr_list{ZCC_Expression *} -expr_list(X) ::= expr(A). -{ - X = A; -} +expr_list(X) ::= expr(X). expr_list(X) ::= expr_list(A) COMMA expr(B). { - X = A; - A->AppendSibling(B); + X = A; /*X-overwrites-A*/ + X->AppendSibling(B); } /*----- Function argument lists -----*/ @@ -1137,10 +1115,7 @@ expr_list(X) ::= expr_list(A) COMMA expr(B). %type func_expr_item{ZCC_FuncParm *} %type named_expr{ZCC_FuncParm *} -func_expr_list(X) ::= func_expr_item(A). -{ - X = A; -} +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. @@ -1158,18 +1133,15 @@ func_expr_list(X) ::= func_expr_list(A) COMMA(T) func_expr_item(B). nil_b->Label = NAME_None; B = nil_b; } - X = A; - A->AppendSibling(B); + X = A; /*X-overwrites-A*/ + X->AppendSibling(B); } func_expr_item(X) ::= . { X = NULL; } -func_expr_item(X) ::= named_expr(A). -{ - X = A; -} +func_expr_item(X) ::= named_expr(X). named_expr(X) ::= IDENTIFIER(A) COLON expr(B). { @@ -1208,10 +1180,7 @@ string_constant(X) ::= string_constant(A) STRCONST(B). X = strconst; } -constant(X) ::= string_constant(A). -{ - X = A; -} +constant(X) ::= string_constant(X). constant(X) ::= INTCONST(A). { NEW_INTCONST_NODE(intconst, TypeSInt32, A.Int, A); @@ -1251,18 +1220,18 @@ constant(X) ::= TRUE(A). /************ Statements ************/ -function_body(X) ::= compound_statement(A). { X = A; } +function_body(X) ::= compound_statement(X). %type statement{ZCC_Statement *} statement(X) ::= SEMICOLON. { X = NULL; } -statement(X) ::= labeled_statement(A). { X = A; } -statement(X) ::= compound_statement(A). { X = A; } -statement(X) ::= expression_statement(A) SEMICOLON. { X = A; } -statement(X) ::= selection_statement(A). { X = A; } -statement(X) ::= iteration_statement(A). { X = A; } -statement(X) ::= jump_statement(A). { X = A; } -statement(X) ::= assign_statement(A) SEMICOLON. { X = A; } -statement(X) ::= local_var(A) SEMICOLON. { X = A; } +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 -----*/ @@ -1318,12 +1287,11 @@ compound_statement(X) ::= LBRACE(T) error RBRACE. statement_list(X) ::= statement(A). { - X = A; + X = A; /*X-overwrites-A*/ } -statement_list(X) ::= statement_list(A) statement(B). +statement_list(X) ::= statement_list(X) statement(B). { - SAFE_APPEND(A,B); - X = A; + SAFE_APPEND(X,B); } /*----- Expression Statements -----*/ @@ -1407,13 +1375,13 @@ while_or_until(X) ::= UNTIL(T). } %type for_init{ZCC_Statement *} -for_init(X) ::= local_var(A). { X = A; } -for_init(X) ::= for_bump(A). { X = A; } +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; } -for_bump(X) ::= assign_statement(A). { X = A; } +for_bump(X) ::= expression_statement(A). { X = A; /*X-overwrites-A*/ } +for_bump(X) ::= assign_statement(A). { X = A; /*X-overwrites-A*/ } /*----- If Statements -----*/ @@ -1428,12 +1396,12 @@ for_bump(X) ::= assign_statement(A). { X = A; } selection_statement(X) ::= if_front(A). [IF] { - X = A; + X = A; /*X-overwrites-A*/ } selection_statement(X) ::= if_front(A) ELSE statement(B). [ELSE] { A->FalsePath = B; - X = A; + X = A; /*X-overwrites-A*/ } if_front(X) ::= IF(T) LPAREN expr(A) RPAREN statement(B). @@ -1512,4 +1480,4 @@ local_var(X) ::= type(A) variable_list(B) var_init(C). %type var_init{ZCC_Expression *} var_init(X) ::= . { X = NULL; } -var_init(X) ::= EQ expr_list(A). { X = A; } +var_init(X) ::= EQ expr_list(A). { X = A; /*X-overwrites-A*/ } diff --git a/src/zscript/zcc_compile.cpp b/src/zscript/zcc_compile.cpp index 5a3276a071..b7bfe81ba1 100644 --- a/src/zscript/zcc_compile.cpp +++ b/src/zscript/zcc_compile.cpp @@ -19,7 +19,7 @@ //========================================================================== ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) -: Outer(_outer), Symbols(_symbols), AST(ast), ErrorCount(0), WarnCount(0) +: Outer(_outer), Symbols(&_symbols), AST(ast), ErrorCount(0), WarnCount(0) { // Group top-level nodes by type if (ast.TopNode != NULL) @@ -30,29 +30,23 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) switch (node->NodeType) { case AST_Class: - if (AddNamedNode(static_cast(node)->ClassName, node)) - { - Classes.Push(static_cast(node)); - } - break; - case AST_Struct: - if (AddNamedNode(static_cast(node)->StructName, node)) + case AST_ConstantDef: + if (AddNamedNode(static_cast(node))) { - Structs.Push(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; - case AST_ConstantDef: - if (AddNamedNode(static_cast(node)->Name, node)) - { - Constants.Push(static_cast(node)); - } - break; - default: assert(0 && "Unhandled AST node type"); break; @@ -72,55 +66,76 @@ ZCCCompiler::ZCCCompiler(ZCC_AST &ast, DObject *_outer, PSymbolTable &_symbols) // //========================================================================== -bool ZCCCompiler::AddNamedNode(FName name, ZCC_TreeNode *node) +bool ZCCCompiler::AddNamedNode(ZCC_NamedNode *node) { - ZCC_TreeNode **check = NamedNodes.CheckKey(name); - if (check != NULL && *check != NULL) + FName name = node->NodeName; + PSymbol *check = Symbols->FindSymbol(name, false); + if (check != NULL) { - Message(node, ERR_symbol_redefinition, "Attempt to redefine '%s'", name.GetChars()); - Message(*check, ERR_original_definition, " Original definition is here"); + 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 { - NamedNodes.Insert(name, node); + Symbols->AddSymbol(new PSymbolTreeNode(name, node)); return true; } } //========================================================================== // -// ZCCCompiler :: Message +// ZCCCompiler :: Warn // -// Prints a warning or error message, and increments the appropriate -// counter. +// Prints a warning message, and increments WarnCount. // //========================================================================== -void ZCCCompiler::Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...) +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: ", - errnum & ZCCERR_ERROR ? TEXTCOLOR_RED : TEXTCOLOR_ORANGE, - node->SourceName->GetChars(), node->SourceLoc); - - va_list argptr; - va_start(argptr, msg); + composed.Format("%s%s, line %d: ", txtcolor, node->SourceName->GetChars(), node->SourceLoc); composed.VAppendFormat(msg, argptr); - va_end(argptr); - composed += '\n'; PrintString(PRINT_HIGH, composed); - - if (errnum & ZCCERR_ERROR) - { - ErrorCount++; - } - else - { - WarnCount++; - } } //========================================================================== @@ -133,7 +148,7 @@ void ZCCCompiler::Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, int ZCCCompiler::Compile() { - CompileConstants(); + CompileConstants(Constants); return ErrorCount; } @@ -145,14 +160,14 @@ int ZCCCompiler::Compile() // //========================================================================== -void ZCCCompiler::CompileConstants() +void ZCCCompiler::CompileConstants(const TArray &defs) { - for (unsigned i = 0; i < Constants.Size(); ++i) + for (unsigned i = 0; i < defs.Size(); ++i) { - ZCC_ConstantDef *def = Constants[i]; + ZCC_ConstantDef *def = defs[i]; if (def->Symbol == NULL) { - CompileConstant(def); + PSymbolConst *sym = CompileConstant(def); } } } @@ -180,33 +195,32 @@ PSymbolConst *ZCCCompiler::CompileConstant(ZCC_ConstantDef *def) ZCC_ExprConstant *cval = static_cast(val); if (cval->Type == TypeString) { - sym = new PSymbolConstString(def->Name, *(cval->StringVal)); + sym = new PSymbolConstString(def->NodeName, *(cval->StringVal)); } else if (cval->Type->IsA(RUNTIME_CLASS(PInt))) { - sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->IntVal); + sym = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->IntVal); } else if (cval->Type->IsA(RUNTIME_CLASS(PFloat))) { - sym = new PSymbolConstNumeric(def->Name, cval->Type, cval->DoubleVal); + sym = new PSymbolConstNumeric(def->NodeName, cval->Type, cval->DoubleVal); } else { - Message(def->Value, ERR_bad_const_def_type, "Bad type for constant definiton"); + Error(def->Value, "Bad type for constant definiton"); } } else { - Message(def->Value, ERR_const_def_not_constant, "Constant definition requires a constant value"); + 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->Name, TypeError, 0); + sym = new PSymbolConstNumeric(def->NodeName, TypeError, 0); } def->Symbol = sym; - PSymbol *addsym = Symbols.AddSymbol(sym); - assert(NULL != addsym && "Symbol was redefined (but we shouldn't have even had the chance to do so)"); + Symbols->ReplaceSymbol(sym); return sym; } @@ -307,17 +321,18 @@ ZCC_Expression *ZCCCompiler::SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop) if (dotop->Left->Operation == PEX_TypeRef) { // Type refs can be evaluated now. PType *ref = static_cast(dotop->Left)->RefType; - PSymbol *sym = ref->Symbols.FindSymbol(dotop->Right, true); + PSymbolTable *symtable; + PSymbol *sym = ref->Symbols.FindSymbolInTable(dotop->Right, symtable); if (sym == NULL) { - Message(dotop, ERR_not_a_member, "'%s' is not a valid member", FName(dotop->Right).GetChars()); + Error(dotop, "'%s' is not a valid member", FName(dotop->Right).GetChars()); } else { - ZCC_Expression *expr = NodeFromSymbol(sym, dotop); + ZCC_Expression *expr = NodeFromSymbol(sym, dotop, symtable); if (expr == NULL) { - Message(dotop, ERR_bad_symbol, "Unhandled symbol type encountered"); + Error(dotop, "Unhandled symbol type encountered"); } else { @@ -361,7 +376,7 @@ ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop) { if (parmcount != 1) { - Message(callop, ERR_cast_needs_1_parm, "Type cast requires one parameter"); + Error(callop, "Type cast requires one parameter"); callop->ToErrorNode(); } else @@ -371,8 +386,8 @@ ZCC_Expression *ZCCCompiler::SimplifyFunctionCall(ZCC_ExprFuncCall *callop) int routelen = parm->Value->Type->FindConversion(dest, route, countof(route)); if (routelen < 0) { - // FIXME: Need real type names - Message(callop, ERR_cast_not_possible, "Cannot convert type 1 to type 2"); + ///FIXME: Need real type names + Error(callop, "Cannot convert type 1 to type 2"); callop->ToErrorNode(); } else @@ -483,53 +498,79 @@ ZCC_Expression *ZCCCompiler::AddCastNode(PType *type, ZCC_Expression *expr) ZCC_Expression *ZCCCompiler::IdentifyIdentifier(ZCC_ExprID *idnode) { - // First things first: Check the symbol table. - PSymbol *sym; - if (NULL != (sym = Symbols.FindSymbol(idnode->Identifier, true))) + // 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); + ZCC_Expression *node = NodeFromSymbol(sym, idnode, table); if (node != NULL) { return node; } } else - { // Check nodes that haven't had symbols created for them yet. - ZCC_TreeNode **node = NamedNodes.CheckKey(idnode->Identifier); - if (node != NULL && *node != NULL) - { - if ((*node)->NodeType == AST_ConstantDef) - { - ZCC_ConstantDef *def = static_cast(*node); - PSymbolConst *sym = def->Symbol; - - if (sym == DEFINING_CONST) - { - Message(idnode, ERR_recursive_definition, "Definition of '%s' is infinitely recursive", FName(idnode->Identifier).GetChars()); - sym = NULL; - } - else - { - assert(sym == NULL); - sym = CompileConstant(def); - } - return NodeFromSymbolConst(sym, idnode); - } - } + { + 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) +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); diff --git a/src/zscript/zcc_compile.h b/src/zscript/zcc_compile.h index c8933ff5fe..d034464b77 100644 --- a/src/zscript/zcc_compile.h +++ b/src/zscript/zcc_compile.h @@ -1,8 +1,6 @@ #ifndef ZCC_COMPILE_H #define ZCC_COMPILE_H -#include "zcc_errors.h" - class ZCCCompiler { public: @@ -10,15 +8,14 @@ public: int Compile(); private: - void CompileConstants(); + void CompileConstants(const TArray &defs); PSymbolConst *CompileConstant(ZCC_ConstantDef *def); TArray Constants; TArray Structs; TArray Classes; - TMap NamedNodes; - bool AddNamedNode(FName name, ZCC_TreeNode *node); + bool AddNamedNode(ZCC_NamedNode *node); ZCC_Expression *Simplify(ZCC_Expression *root); ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary); @@ -37,14 +34,18 @@ private: ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr); ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode); - ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source); + 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 Message(ZCC_TreeNode *node, EZCCError errnum, const char *msg, ...); + + 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; + PSymbolTable *Symbols; ZCC_AST &AST; int ErrorCount; int WarnCount; diff --git a/src/zscript/zcc_errors.h b/src/zscript/zcc_errors.h deleted file mode 100644 index cb38a00d58..0000000000 --- a/src/zscript/zcc_errors.h +++ /dev/null @@ -1,14 +0,0 @@ -#define ZCCERR_ERROR 0x40000000 - -enum EZCCError -{ - ERR_const_def_not_constant = 20000 | ZCCERR_ERROR, - ERR_bad_const_def_type = 20001 | ZCCERR_ERROR, - ERR_symbol_redefinition = 20002 | ZCCERR_ERROR, - ERR_original_definition = 20003 | ZCCERR_ERROR, - ERR_recursive_definition = 20004 | ZCCERR_ERROR, - ERR_not_a_member = 20005 | ZCCERR_ERROR, - ERR_bad_symbol = 20006 | ZCCERR_ERROR, - ERR_cast_needs_1_parm = 20007 | ZCCERR_ERROR, - ERR_cast_not_possible = 20008 | ZCCERR_ERROR, -}; diff --git a/src/zscript/zcc_parser.h b/src/zscript/zcc_parser.h index cf51ff7651..e74b5263ec 100644 --- a/src/zscript/zcc_parser.h +++ b/src/zscript/zcc_parser.h @@ -174,24 +174,26 @@ struct ZCC_Identifier : ZCC_TreeNode ENamedName Id; }; -struct ZCC_Class : ZCC_TreeNode +struct ZCC_NamedNode : ZCC_TreeNode +{ + ENamedName NodeName; +}; + +struct ZCC_Class : ZCC_NamedNode { - ENamedName ClassName; ZCC_Identifier *ParentName; ZCC_Identifier *Replaces; VM_UWORD Flags; ZCC_TreeNode *Body; }; -struct ZCC_Struct : ZCC_TreeNode +struct ZCC_Struct : ZCC_NamedNode { - ENamedName StructName; ZCC_TreeNode *Body; }; -struct ZCC_Enum : ZCC_TreeNode +struct ZCC_Enum : ZCC_NamedNode { - ENamedName EnumName; EZCCBuiltinType EnumType; struct ZCC_ConstantDef *Elements; }; @@ -432,9 +434,8 @@ struct ZCC_FuncParamDecl : ZCC_TreeNode int Flags; }; -struct ZCC_ConstantDef : ZCC_TreeNode +struct ZCC_ConstantDef : ZCC_NamedNode { - ENamedName Name; ZCC_Expression *Value; PSymbolConst *Symbol; }; diff --git a/tools/lemon/lemon.c b/tools/lemon/lemon.c index 026e3f1d96..546cf515ea 100644 --- a/tools/lemon/lemon.c +++ b/tools/lemon/lemon.c @@ -17,6 +17,14 @@ #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__ @@ -24,7 +32,13 @@ #endif #ifdef __WIN32__ -extern int access(); +#ifdef __cplusplus +extern "C" { +#endif +extern int access(char *path, int mode); +#ifdef __cplusplus +} +#endif #else #include #endif @@ -38,6 +52,7 @@ extern int access(); #define MAXRHS 1000 #endif +static int showPrecedenceConflict = 0; static void *msort(void *list, void *next, int (*cmp)()); /* @@ -47,6 +62,11 @@ static void *msort(void *list, void *next, int (*cmp)()); */ #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 *); @@ -60,59 +80,58 @@ 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(/* 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 */); +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); /********* 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 { OPT_FLAG=1, OPT_INT, OPT_DBL, OPT_STR, - OPT_FFLAG, OPT_FINT, OPT_FDBL, OPT_FSTR} type; - char *label; + enum option_type type; + const char *label; char *arg; - char *message; + const 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 * */); -void ReportHeader(/* struct lemon * */); -void CompressTables(/* struct lemon * */); -void ResortStates(/* struct lemon * */); +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 *); /********** From the file "set.h" ****************************************/ -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 */ - +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 */ #define SetFind(X,Y) (X[Y]) /* True if Y is in set X */ /********** From the file "struct.h" *************************************/ @@ -124,23 +143,25 @@ typedef enum {LEMON_FALSE=0, LEMON_TRUE} Boolean; /* Symbols (terminals and nonterminals) of the grammar are stored ** in the following: */ -struct symbol { - char *name; /* Name of the symbol */ - int index; /* Index number for this symbol */ - 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 { +enum symbol_type { + TERMINAL, + NONTERMINAL, + MULTITERMINAL +}; +enum e_assoc { LEFT, RIGHT, NONE, UNK - } assoc; /* Associativity if precedence is defined */ +}; +struct symbol { + const char *name; /* Name of the symbol */ + int index; /* Index number for this symbol */ + enum symbol_type 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 */ 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 */ @@ -161,16 +182,19 @@ struct symbol { ** structure. */ struct rule { struct symbol *lhs; /* Left-hand side of the rule */ - char *lhsalias; /* Alias for the LHS (NULL if none) */ + const 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 */ - char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ + const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ int line; /* Line number at which code begins */ - char *code; /* The code executed when this rule is reduced */ + 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 */ 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 */ @@ -181,6 +205,10 @@ 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 */ @@ -188,29 +216,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 { - COMPLETE, /* The status is used during followset and */ - INCOMPLETE /* shift computations */ - } status; + enum cfgstatus status; /* used during followset and shift computations */ 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 { - 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; + enum e_action type; union { struct state *stp; /* The new state, if a shift */ struct rule *rp; /* The rule, if a reduce */ @@ -228,7 +256,9 @@ struct 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 iDflt; /* Default action */ + 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 */ }; #define NO_OFFSET (-2147483647) @@ -243,11 +273,13 @@ 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 begin global variables in the program.) */ +** of as being 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 */ @@ -270,10 +302,12 @@ struct lemon { char *tokendest; /* Code to execute to destroy token data */ char *vardest; /* Code for the default non-terminal destructor */ 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 tablesize; /* Size of the parse tables */ + int nactiontab; /* Number of entries in the yy_action[] table */ + int tablesize; /* Total table size of all tables in bytes */ 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 */ @@ -297,41 +331,41 @@ struct lemon { /* ** Code for processing tables in the LEMON parser generator. */ - /* Routines for handling a strings */ -char *Strsafe(); +const char *Strsafe(const char *); -void Strsafe_init(/* void */); -int Strsafe_insert(/* char * */); -char *Strsafe_find(/* char * */); +void Strsafe_init(void); +int Strsafe_insert(const char *); +const char *Strsafe_find(const char *); /* Routines for handling symbols of the grammar */ -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(/* */); +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); /* Routines to manage the state table */ -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 * */); +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 *); 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. @@ -340,7 +374,7 @@ void Configtable_clear(/* int(*)(struct config *) */); /* Allocate a new parser action */ static struct action *Action_new(void){ static struct action *freelist = 0; - struct action *new; + struct action *newaction; if( freelist==0 ){ int i; @@ -353,9 +387,9 @@ static struct action *Action_new(void){ for(i=0; inext; - return new; + return newaction; } /* Compare two actions for sorting purposes. Return negative, zero, or @@ -371,9 +405,12 @@ struct action *ap2; if( rc==0 ){ rc = (int)ap1->type - (int)ap2->type; } - if( rc==0 && ap1->type==REDUCE ){ + if( rc==0 && (ap1->type==REDUCE || ap1->type==SHIFTREDUCE) ){ rc = ap1->x.rp->index - ap2->x.rp->index; } + if( rc==0 ){ + rc = ap2 - ap1; + } return rc; } @@ -384,22 +421,22 @@ static struct action *Action_sort(struct action *ap) return ap; } -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; +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; if( type==SHIFT ){ - new->x.stp = (struct state *)arg; + newaction->x.stp = (struct state *)arg; }else{ - new->x.rp = (struct rule *)arg; + newaction->x.rp = (struct rule *)arg; } } /********************** New code to implement the "acttab" module ***********/ @@ -409,16 +446,34 @@ char *arg; /* ** The state of the yy_action table under construction is an instance of -** the following structure +** 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 */ +}; typedef struct acttab acttab; struct acttab { int nAction; /* Number of used slots in aAction[] */ int nActionAlloc; /* Slots allocated for aAction[] */ - struct { - int lookahead; /* Value of the lookahead token */ - int action; /* Action to take on the given lookahead */ - } *aAction, /* The yy_action[] table under construction */ + struct lookahead_action + *aAction, /* The yy_action[] table under construction */ *aLookahead; /* A single new transaction set */ int mnLookahead; /* Minimum aLookahead[].lookahead */ int mnAction; /* Action associated with mnLookahead */ @@ -446,7 +501,7 @@ void acttab_free(acttab **pp){ /* Allocate a new acttab structure */ acttab *acttab_alloc(void){ - acttab *p = calloc( 1, sizeof(*p) ); + acttab *p = (acttab *) calloc( 1, sizeof(*p) ); if( p==0 ){ fprintf(stderr,"Unable to allocate memory for a new acttab."); exit(1); @@ -455,12 +510,15 @@ acttab *acttab_alloc(void){ return p; } -/* Add a new action to the current transaction set +/* Add a new action to the current transaction set. +** +** This routine is called once for each lookahead for a particular +** state. */ void acttab_action(acttab *p, int lookahead, int action){ if( p->nLookahead>=p->nLookaheadAlloc ){ p->nLookaheadAlloc += 25; - p->aLookahead = realloc( p->aLookahead, + p->aLookahead = (struct lookahead_action *) realloc( p->aLookahead, sizeof(p->aLookahead[0])*p->nLookaheadAlloc ); if( p->aLookahead==0 ){ fprintf(stderr,"malloc failed\n"); @@ -502,7 +560,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 = realloc( p->aAction, + p->aAction = (struct lookahead_action *) realloc( p->aAction, sizeof(p->aAction[0])*p->nActionAlloc); if( p->aAction==0 ){ fprintf(stderr,"malloc failed\n"); @@ -514,28 +572,16 @@ int acttab_insert(acttab *p){ } } - /* 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. + /* 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. ** ** i is the index in p->aAction[] where p->mnLookahead is inserted. */ - 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 ){ + 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. */ if( p->aAction[i].action!=p->mnAction ) continue; for(j=0; jnLookahead; j++){ k = p->aLookahead[j].lookahead - p->mnLookahead + i; @@ -544,13 +590,43 @@ 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; /* Same as a prior transaction set */ + 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 */ + } } } } @@ -582,8 +658,7 @@ int acttab_insert(acttab *p){ ** are not RHS symbols with a defined precedence, the precedence ** symbol field is left blank. */ -void FindRulePrecedences(xp) -struct lemon *xp; +void FindRulePrecedences(struct lemon *xp) { struct rule *rp; for(rp=xp->rule; rp; rp=rp->next){ @@ -612,8 +687,7 @@ struct lemon *xp; ** The first set is the set of all terminal symbols which can begin ** a string generated by that nonterminal. */ -void FindFirstSets(lemp) -struct lemon *lemp; +void FindFirstSets(struct lemon *lemp) { int i, j; struct rule *rp; @@ -675,9 +749,8 @@ 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(lemp) -struct lemon *lemp; +PRIVATE struct state *getstate(struct lemon *); /* forward reference */ +void FindStates(struct lemon *lemp) { struct symbol *sp; struct rule *rp; @@ -691,12 +764,12 @@ 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->rule->lhs->name); +symbol instead.",lemp->start,lemp->startRule->lhs->name); lemp->errorcnt++; - sp = lemp->rule->lhs; + sp = lemp->startRule->lhs; } }else{ - sp = lemp->rule->lhs; + sp = lemp->startRule->lhs; } /* Make sure the start symbol doesn't occur on the right-hand side of @@ -735,9 +808,8 @@ 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(lemp) -struct lemon *lemp; +PRIVATE void buildshifts(struct lemon *, struct state *); /* Forwd ref */ +PRIVATE struct state *getstate(struct lemon *lemp) { struct config *cfp, *bp; struct state *stp; @@ -781,9 +853,7 @@ struct lemon *lemp; /* ** Return true if two symbols are the same. */ -int same_symbol(a,b) -struct symbol *a; -struct symbol *b; +int same_symbol(struct symbol *a, struct symbol *b) { int i; if( a==b ) return 1; @@ -799,13 +869,11 @@ struct symbol *b; /* 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(lemp,stp) -struct lemon *lemp; -struct state *stp; /* The state from which successors are computed */ +PRIVATE void buildshifts(struct lemon *lemp, struct state *stp) { 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 *new; /* */ + struct config *newcfg; /* */ 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 */ @@ -830,8 +898,8 @@ struct state *stp; /* The state from which successors are computed */ 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 */ - new = Configlist_addbasis(bcfp->rp,bcfp->dot+1); - Plink_add(&new->bplp,bcfp); + newcfg = Configlist_addbasis(bcfp->rp,bcfp->dot+1); + Plink_add(&newcfg->bplp,bcfp); } /* Get a pointer to the state described by the basis configuration set @@ -854,8 +922,7 @@ struct state *stp; /* The state from which successors are computed */ /* ** Construct the propagation links */ -void FindLinks(lemp) -struct lemon *lemp; +void FindLinks(struct lemon *lemp) { int i; struct config *cfp, *other; @@ -890,8 +957,7 @@ struct lemon *lemp; ** A followset is the set of all symbols which can come immediately ** after a configuration. */ -void FindFollowSets(lemp) -struct lemon *lemp; +void FindFollowSets(struct lemon *lemp) { int i; struct config *cfp; @@ -923,12 +989,11 @@ struct lemon *lemp; }while( progress ); } -static int resolve_conflict(); +static int resolve_conflict(struct action *,struct action *); /* Compute the reduce actions, and resolve conflicts. */ -void FindActions(lemp) -struct lemon *lemp; +void FindActions(struct lemon *lemp) { int i,j; struct config *cfp; @@ -958,9 +1023,9 @@ struct lemon *lemp; /* Add the accepting token */ if( lemp->start ){ sp = Symbol_find(lemp->start); - if( sp==0 ) sp = lemp->rule->lhs; + if( sp==0 ) sp = lemp->startRule->lhs; }else{ - sp = lemp->rule->lhs; + sp = lemp->startRule->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 @@ -978,7 +1043,7 @@ 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->errsym); + lemp->nconflict += resolve_conflict(ap,nap); } } } @@ -1011,11 +1076,10 @@ 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(apx,apy,errsym) -struct action *apx; -struct action *apy; -struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */ -{ +static int resolve_conflict( + struct action *apx, + struct action *apy +){ struct symbol *spx, *spy; int errcnt = 0; assert( apx->sp==apy->sp ); /* Otherwise there would be no conflict */ @@ -1030,7 +1094,7 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */ /* Not enough precedence information. */ apy->type = SRCONFLICT; errcnt++; - }else if( spx->prec>spy->prec ){ /* Lower precedence wins */ + }else if( spx->prec>spy->prec ){ /* higher precedence wins */ apy->type = RD_RESOLVED; }else if( spx->precprec ){ apx->type = SH_RESOLVED; @@ -1040,8 +1104,7 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */ apx->type = SH_RESOLVED; }else{ assert( spx->prec==spy->prec && spx->assoc==NONE ); - apy->type = SRCONFLICT; - errcnt++; + apy->type = ERROR; } }else if( apx->type==REDUCE && apy->type==REDUCE ){ spx = apx->x.rp->precsym; @@ -1088,7 +1151,7 @@ static struct config **basisend = 0; /* End of list of basis configs */ /* Return a pointer to a new configuration */ PRIVATE struct config *newconfig(){ - struct config *new; + struct config *newcfg; if( freelist==0 ){ int i; int amt = 3; @@ -1100,14 +1163,13 @@ PRIVATE struct config *newconfig(){ for(i=0; inext; - return new; + return newcfg; } /* The configuration "old" is no longer used */ -PRIVATE void deleteconfig(old) -struct config *old; +PRIVATE void deleteconfig(struct config *old) { old->next = freelist; freelist = old; @@ -1134,10 +1196,10 @@ void Configlist_reset(){ } /* Add another configuration to the configuration list */ -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 *Configlist_add( + 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 ); @@ -1161,9 +1223,7 @@ int dot; /* Index into the RHS of the rule where the dot goes */ } /* Add a basis configuration to the configuration list */ -struct config *Configlist_addbasis(rp,dot) -struct rule *rp; -int dot; +struct config *Configlist_addbasis(struct rule *rp, int dot) { struct config *cfp, model; @@ -1191,8 +1251,7 @@ int dot; } /* Compute the closure of the configuration list */ -void Configlist_closure(lemp) -struct lemon *lemp; +void Configlist_closure(struct lemon *lemp) { struct config *cfp, *newcfp; struct rule *rp, *newrp; @@ -1238,14 +1297,16 @@ struct lemon *lemp; /* Sort the configuration list */ void Configlist_sort(){ - current = (struct config *)msort(current,&(current->next),Configcmp); + current = (struct config*)msort((char*)current,(char**)&(current->next), + Configcmp); currentend = 0; return; } /* Sort the basis configuration list */ void Configlist_sortbasis(){ - basis = (struct config *)msort(current,&(current->bp),Configcmp); + basis = (struct config *)msort((char*)current,(char**)&(current->bp), + Configcmp); basisend = 0; return; } @@ -1271,8 +1332,7 @@ struct config *Configlist_basis(){ } /* Free all elements of the given configuration list */ -void Configlist_eat(cfp) -struct config *cfp; +void Configlist_eat(struct config *cfp) { struct config *nextcfp; for(; cfp; cfp=nextcfp){ @@ -1289,84 +1349,26 @@ 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 ){ - sprintf(prefix,"%.*s(%d) : error : ",PREFIXLIMIT-10,filename,lineno); + fprintf(stderr,"%s(%d) : error : ",filename,lineno); }else{ - sprintf(prefix,"%.*s : error : ",PREFIXLIMIT-10,filename); + fprintf(stderr,"%s : error : ",filename); } #else if( lineno>0 ){ - sprintf(prefix,"%.*s:%d: ",PREFIXLIMIT-10,filename,lineno); + fprintf(stderr,"%s:%d: ",filename,lineno); }else{ - sprintf(prefix,"%.*s: ",PREFIXLIMIT-10,filename); + fprintf(stderr,"%s: ",filename); } #endif - prefixsize = lemonStrlen(prefix); - availablewidth = LINEWIDTH - prefixsize; - - /* Generate the error message */ - vsprintf(errmsg,format,ap); + va_start(ap, format); + vfprintf(stderr,format,ap); va_end(ap); - errmsgsize = lemonStrlen(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; - } + fprintf(stderr, "\n"); } /**************** From the file "main.c" ************************************/ /* @@ -1390,13 +1392,13 @@ static char **azDefine = 0; /* Name of the -D macros */ static void handle_D_option(char *z){ char **paz; nDefine++; - azDefine = realloc(azDefine, sizeof(azDefine[0])*nDefine); + azDefine = (char **) realloc(azDefine, sizeof(azDefine[0])*nDefine); if( azDefine==0 ){ fprintf(stderr,"out of memory\n"); exit(1); } paz = &azDefine[nDefine-1]; - *paz = malloc( lemonStrlen(z)+1 ); + *paz = (char *) malloc( lemonStrlen(z)+1 ); if( *paz==0 ){ fprintf(stderr,"out of memory\n"); exit(1); @@ -1406,11 +1408,143 @@ 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; iindex = 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++); + 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++); 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); @@ -1512,8 +1670,9 @@ char **argv; if( compress==0 ) CompressTables(&lem); /* Reorder and renumber the states so that states with fewer choices - ** occur at the end. */ - ResortStates(&lem); + ** occur at the end. This is an optimization that helps make the + ** generated parser tables smaller. */ + if( noResort==0 ) ResortStates(&lem); /* Generate a report of the parser generated. (the "y.output" file) */ if( !quiet ) ReportOutput(&lem); @@ -1527,10 +1686,15 @@ char **argv; if( !mhflag ) ReportHeader(&lem); } if( statistics ){ - 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); + 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); } if( lem.nconflict ){ fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); @@ -1591,7 +1755,7 @@ static void *merge(void *a,void *b,int (*cmp)(),size_t offset) }else if( b==0 ){ head = a; }else{ - if( (*cmp)(a,b)<0 ){ + if( (*cmp)(a,b)<=0 ){ ptr = a; a = NEXT(a); }else{ @@ -1600,7 +1764,7 @@ static void *merge(void *a,void *b,int (*cmp)(),size_t offset) } head = ptr; while( a && b ){ - if( (*cmp)(a,b)<0 ){ + if( (*cmp)(a,b)<=0 ){ NEXT(ptr) = a; ptr = a; a = NEXT(a); @@ -1649,7 +1813,7 @@ static void *msort(void *list,void *next,int (*cmp)()) set[i] = ep; } ep = 0; - for(i=0; i=0 ? argv[i] : 0; } -void OptErr(n) -int n; +void OptErr(int n) { int i; i = argindex(n); @@ -1924,17 +2078,17 @@ void OptPrint(){ break; case OPT_INT: case OPT_FINT: - fprintf(errstream," %s=%*s %s\n",op[i].label, + fprintf(errstream," -%s%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-9),"",op[i].message); break; case OPT_DBL: case OPT_FDBL: - fprintf(errstream," %s=%*s %s\n",op[i].label, + fprintf(errstream," -%s%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-6),"",op[i].message); break; case OPT_STR: case OPT_FSTR: - fprintf(errstream," %s=%*s %s\n",op[i].label, + fprintf(errstream," -%s%*s %s\n",op[i].label, (int)(max-lemonStrlen(op[i].label)-8),"",op[i].message); break; } @@ -1946,42 +2100,46 @@ 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 { - 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 */ + enum e_state 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 */ - char *lhsalias; /* Alias for the LHS */ + const char *lhsalias; /* Alias for the LHS */ int nrhs; /* Number of right-hand side symbols seen */ struct symbol *rhs[MAXRHS]; /* RHS symbols */ - char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */ + const char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */ struct rule *prevrule; /* Previous rule parsed */ - char *declkeyword; /* Keyword of a declaration */ + const 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 */ @@ -1992,10 +2150,9 @@ struct pstate { }; /* Parse a single token */ -static void parseonetoken(psp) -struct pstate *psp; +static void parseonetoken(struct pstate *psp) { - char *x; + const char *x; x = Strsafe(psp->tokenstart); /* Save the token permanently */ #if 0 printf("%s:%d: Token=[%s] state=%d\n",psp->filename,psp->tokenlineno, @@ -2011,7 +2168,7 @@ struct pstate *psp; 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; @@ -2041,7 +2198,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++; @@ -2081,7 +2238,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{ @@ -2127,7 +2284,7 @@ to follow the previous rule."); int i; rp->ruleline = psp->tokenlineno; rp->rhs = (struct symbol**)&rp[1]; - rp->rhsalias = (char**)&(rp->rhs[psp->nrhs]); + rp->rhsalias = (const char**)&(rp->rhs[psp->nrhs]); for(i=0; inrhs; i++){ rp->rhs[i] = psp->rhs[i]; rp->rhsalias[i] = psp->alias[i]; @@ -2146,11 +2303,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\".", @@ -2166,18 +2323,19 @@ to follow the previous rule."); struct symbol *msp = psp->rhs[psp->nrhs-1]; if( msp->type!=MULTITERMINAL ){ struct symbol *origsp = msp; - msp = calloc(1,sizeof(*msp)); + msp = (struct symbol *) calloc(1,sizeof(*msp)); msp->type = MULTITERMINAL; msp->nsubsym = 1; - msp->subsym = calloc(1,sizeof(struct symbol*)); + msp->subsym = (struct symbol **) calloc(1,sizeof(struct symbol*)); msp->subsym[0] = origsp; msp->name = origsp->name; psp->rhs[psp->nrhs-1] = msp; } msp->nsubsym++; - msp->subsym = realloc(msp->subsym, sizeof(struct symbol*)*msp->nsubsym); + msp->subsym = (struct symbol **) 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++; @@ -2192,7 +2350,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{ @@ -2214,7 +2372,7 @@ 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; @@ -2278,6 +2436,8 @@ 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); @@ -2292,7 +2452,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++; @@ -2306,22 +2466,32 @@ to follow the previous rule."); } break; case WAITING_FOR_DATATYPE_SYMBOL: - if( !isalpha(x[0]) ){ + if( !ISALPHA(x[0]) ){ ErrorMsg(psp->filename,psp->tokenlineno, - "Symbol name missing after %%destructor keyword"); + "Symbol name missing after %%type keyword"); psp->errorcnt++; psp->state = RESYNC_AFTER_DECL_ERROR; }else{ - struct symbol *sp = Symbol_new(x); - psp->declargslot = &sp->datatype; - psp->insertLineMacro = 0; - psp->state = WAITING_FOR_DECL_ARG; + 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; + } } 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 ){ @@ -2339,8 +2509,9 @@ to follow the previous rule."); } break; case WAITING_FOR_DECL_ARG: - if( x[0]=='{' || x[0]=='\"' || isalnum(x[0]) ){ - char *zOld, *zNew, *zBuf, *z; + 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]; @@ -2364,8 +2535,8 @@ to follow the previous rule."); nLine = lemonStrlen(zLine); n += nLine + lemonStrlen(psp->filename) + nBack; } - *psp->declargslot = zBuf = realloc(*psp->declargslot, n); - zBuf += nOld; + *psp->declargslot = (char *) realloc(*psp->declargslot, n); + zBuf = *psp->declargslot + nOld; if( addLineMacro ){ if( nOld && zBuf[-1]!='\n' ){ *(zBuf++) = '\n'; @@ -2399,7 +2570,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++; @@ -2420,7 +2591,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++; @@ -2435,6 +2606,40 @@ 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; */ @@ -2459,7 +2664,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 ){ @@ -2467,13 +2672,13 @@ 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."); gp->errorcnt++; - fclose(fp); + fclose(fp); return; } if( fread(filebuf,1,filesize,fp)!=filesize ){ @@ -2559,7 +2762,7 @@ struct lemon *gp; filesize); free(filebuf); gp->errorcnt++; - fclose(fp); + fclose(fp); return; } fclose(fp); @@ -2573,7 +2776,7 @@ 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++; @@ -2643,15 +2846,15 @@ 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++; @@ -2676,7 +2879,7 @@ static struct plink *plink_freelist = 0; /* Allocate a new plink */ struct plink *Plink_new(){ - struct plink *new; + struct plink *newlink; if( plink_freelist==0 ){ int i; @@ -2690,27 +2893,23 @@ struct plink *Plink_new(){ for(i=0; inext; - return new; + return newlink; } /* Add a plink to a plink list */ -void Plink_add(plpp,cfp) -struct plink **plpp; -struct config *cfp; +void Plink_add(struct plink **plpp, struct config *cfp) { - struct plink *new; - new = Plink_new(); - new->next = *plpp; - *plpp = new; - new->cfp = cfp; + struct plink *newlink; + newlink = Plink_new(); + newlink->next = *plpp; + *plpp = newlink; + newlink->cfp = cfp; } /* Transfer every plink on the list "from" to the list "to" */ -void Plink_copy(to,from) -struct plink **to; -struct plink *from; +void Plink_copy(struct plink **to, struct plink *from) { struct plink *nextpl; while( from ){ @@ -2722,8 +2921,7 @@ struct plink *from; } /* Delete every plink on the list */ -void Plink_delete(plp) -struct plink *plp; +void Plink_delete(struct plink *plp) { struct plink *nextpl; @@ -2743,19 +2941,17 @@ struct plink *plp; ** name comes from malloc() and must be freed by the calling ** function. */ -PRIVATE char *file_makename(lemp,suffix) -struct lemon *lemp; -char *suffix; +PRIVATE char *file_makename(struct lemon *lemp, const char *suffix) { char *name; char *cp; - name = malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 ); + name = (char*)malloc( lemonStrlen(lemp->outbasefilename) + lemonStrlen(suffix) + 5 ); if( name==0 ){ fprintf(stderr,"Can't allocate space for a filename.\n"); exit(1); } - strcpy(name,lemp->filename); + strcpy(name,lemp->outbasefilename); cp = strrchr(name,'.'); if( cp ) *cp = 0; strcat(name,suffix); @@ -2765,11 +2961,11 @@ char *suffix; /* 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(lemp,suffix,mode) -struct lemon *lemp; -char *suffix; -char *mode; -{ +PRIVATE FILE *file_open( + struct lemon *lemp, + const char *suffix, + const char *mode +){ FILE *fp; if( lemp->outname ) free(lemp->outname); @@ -2785,8 +2981,7 @@ char *mode; /* Duplicate the input file without comments and without actions ** on rules */ -void Reprint(lemp) -struct lemon *lemp; +void Reprint(struct lemon *lemp) { struct rule *rp; struct symbol *sp; @@ -2816,11 +3011,13 @@ 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]); */ } @@ -2831,28 +3028,33 @@ struct lemon *lemp; } } -void ConfigPrint(fp,cfp) -FILE *fp; -struct config *cfp; -{ - struct rule *rp; +/* Print a single rule. +*/ +void RulePrint(FILE *fp, struct rule *rp, int iCursor){ struct symbol *sp; int i, j; - rp = cfp->rp; fprintf(fp,"%s ::=",rp->lhs->name); for(i=0; i<=rp->nrhs; i++){ - if( i==cfp->dot ) fprintf(fp," *"); + if( i==iCursor ) 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 */ @@ -2892,15 +3094,30 @@ char *tag; /* Print an action to the given file descriptor. Return FALSE if ** nothing was actually printed. */ -int PrintAction(struct action *ap, FILE *fp, int indent){ +int PrintAction( + struct action *ap, /* The action to print */ + FILE *fp, /* Print the action here */ + int indent /* Indent by this amount */ +){ int result = 1; switch( ap->type ){ - case SHIFT: - fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum); + case SHIFT: { + struct state *stp = ap->x.stp; + fprintf(fp,"%*s shift %-7d",indent,ap->sp->name,stp->statenum); break; - case REDUCE: - fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index); + } + case REDUCE: { + struct rule *rp = ap->x.rp; + fprintf(fp,"%*s reduce %-7d",indent,ap->sp->name,rp->iRule); + RulePrint(fp, rp, -1); 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; @@ -2909,15 +3126,29 @@ int PrintAction(struct action *ap, FILE *fp, int indent){ break; case SRCONFLICT: case RRCONFLICT: - fprintf(fp,"%*s reduce %-3d ** Parsing conflict **", - indent,ap->sp->name,ap->x.rp->index); + fprintf(fp,"%*s reduce %-7d ** Parsing conflict **", + indent,ap->sp->name,ap->x.rp->iRule); break; case SSCONFLICT: - fprintf(fp,"%*s shift %d ** Parsing conflict **", + fprintf(fp,"%*s shift %-7d ** 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; @@ -2925,9 +3156,8 @@ int PrintAction(struct action *ap, FILE *fp, int indent){ return result; } -/* Generate the "y.output" log file */ -void ReportOutput(lemp) -struct lemon *lemp; +/* Generate the "*.out" log file */ +void ReportOutput(struct lemon *lemp) { int i; struct state *stp; @@ -2937,7 +3167,7 @@ struct lemon *lemp; fp = file_open(lemp,".out","wb"); if( fp==0 ) return; - for(i=0; instate; i++){ + for(i=0; inxstate; i++){ stp = lemp->sorted[i]; fprintf(fp,"State %d:\n",stp->statenum); if( lemp->basisflag ) cfp=stp->bp; @@ -2945,7 +3175,7 @@ struct lemon *lemp; while( cfp ){ char buf[20]; if( cfp->dot==cfp->rp->nrhs ){ - sprintf(buf,"(%d)",cfp->rp->index); + sprintf(buf,"(%d)",cfp->rp->iRule); fprintf(fp," %5s ",buf); }else{ fprintf(fp," "); @@ -2993,12 +3223,11 @@ struct lemon *lemp; /* Search for the file "name" which is in the same directory as ** the exacutable */ -PRIVATE char *pathsearch(argv0,name,modemask) -char *argv0; -char *name; -int modemask; +PRIVATE char *pathsearch(char *argv0, char *name, int modemask) { - char *pathlist; + const char *pathlist; + char *pathbufptr; + char *pathbuf; char *path,*cp; char c; @@ -3018,22 +3247,25 @@ int modemask; 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( path!=0 ){ - while( *pathlist ){ - cp = strchr(pathlist,':'); - if( cp==0 ) cp = &pathlist[lemonStrlen(pathlist)]; + if( (pathbuf != 0) && (path!=0) ){ + pathbufptr = pathbuf; + strcpy(pathbuf, pathlist); + while( *pathbuf ){ + cp = strchr(pathbuf,':'); + if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)]; c = *cp; *cp = 0; - sprintf(path,"%s/%s",pathlist,name); + sprintf(path,"%s/%s",pathbuf,name); *cp = c; - if( c==0 ) pathlist = ""; - else pathlist = &cp[1]; + if( c==0 ) pathbuf[0] = 0; + else pathbuf = &cp[1]; if( access(path,modemask)==0 ) break; } + free(pathbufptr); } } return path; @@ -3043,16 +3275,15 @@ int modemask; ** 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(lemp,ap) -struct lemon *lemp; -struct action *ap; +PRIVATE int compute_action(struct lemon *lemp, struct action *ap) { int act; switch( ap->type ){ - 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; + 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; default: act = -1; break; } return act; @@ -3068,11 +3299,7 @@ struct action *ap; ** if name!=0, then any word that begin with "Parse" is changed to ** begin with *name instead. */ -PRIVATE void tplt_xfer(name,in,out,lineno) -char *name; -FILE *in; -FILE *out; -int *lineno; +PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno) { int i, iStart; char line[LINESIZE]; @@ -3082,7 +3309,7 @@ int *lineno; 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); @@ -3097,8 +3324,7 @@ int *lineno; /* The next function finds the template file and opens it, returning ** a pointer to the opened file. */ -PRIVATE FILE *tplt_open(lemp) -struct lemon *lemp; +PRIVATE FILE *tplt_open(struct lemon *lemp) { static char templatename[] = "lempar.c"; char buf[1000]; @@ -3107,6 +3333,24 @@ struct lemon *lemp; 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); @@ -3141,10 +3385,7 @@ struct lemon *lemp; } /* Print a #line directive line to the output file. */ -PRIVATE void tplt_linedir(out,lineno,filename) -FILE *out; -int lineno; -char *filename; +PRIVATE void tplt_linedir(FILE *out, int lineno, char *filename) { fprintf(out,"#line %d \"",lineno); while( *filename ){ @@ -3156,11 +3397,7 @@ char *filename; } /* Print a string to the file and keep the linenumber up to date */ -PRIVATE void tplt_print(out,lemp,str,lineno) -FILE *out; -struct lemon *lemp; -char *str; -int *lineno; +PRIVATE void tplt_print(FILE *out, struct lemon *lemp, char *str, int *lineno) { if( str==0 ) return; while( *str ){ @@ -3183,12 +3420,12 @@ int *lineno; ** The following routine emits code for the destructor for the ** symbol sp */ -void emit_destructor_code(out,sp,lemp,lineno) -FILE *out; -struct symbol *sp; -struct lemon *lemp; -int *lineno; -{ +void emit_destructor_code( + FILE *out, + struct symbol *sp, + struct lemon *lemp, + int *lineno +){ char *cp = 0; if( sp->type==TERMINAL ){ @@ -3198,7 +3435,10 @@ int *lineno; }else if( sp->destructor ){ cp = sp->destructor; fprintf(out,"{\n"); (*lineno)++; - if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,sp->destLineno,lemp->filename); } + if( !lemp->nolinenosflag ){ + (*lineno)++; + tplt_linedir(out,sp->destLineno,lemp->filename); + } }else if( lemp->vardest ){ cp = lemp->vardest; if( cp==0 ) return; @@ -3226,9 +3466,7 @@ int *lineno; /* ** Return TRUE (non-zero) if the given symbol has a destructor. */ -int has_destructor(sp, lemp) -struct symbol *sp; -struct lemon *lemp; +int has_destructor(struct symbol *sp, struct lemon *lemp) { int ret; if( sp->type==TERMINAL ){ @@ -3251,14 +3489,15 @@ struct lemon *lemp; ** ** If n==-1, then the previous character is overwritten. */ -PRIVATE char *append_str(char *zText, int n, int p1, int p2, int bNoSubst){ +PRIVATE char *append_str(const char *zText, int n, int p1, int p2, int bNoSubst){ + static char empty[1] = { 0 }; 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; } @@ -3271,9 +3510,9 @@ PRIVATE char *append_str(char *zText, int n, int p1, int p2, int bNoSubst){ } if( n+sizeof(zInt)*2+used >= (size_t)alloced ){ alloced = n + sizeof(zInt)*2 + used + 200; - z = realloc(z, alloced); + z = (char *) realloc(z, alloced); } - if( z==0 ) return ""; + if( z==0 ) return empty; while( n-- > 0 ){ c = *(zText++); if( !bNoSubst && c=='%' && n>0 && zText[0]=='d' ){ @@ -3295,36 +3534,106 @@ PRIVATE char *append_str(char *zText, int n, int p1, int p2, int bNoSubst){ ** 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 void translate_code(struct lemon *lemp, struct rule *rp){ +PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){ char *cp, *xp; int i; - char lhsused = 0; /* True if the LHS element has been used */ - char used[MAXRHS]; /* True for each RHS element which is used */ + 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 */ for(i=0; inrhs; i++) used[i] = 0; lhsused = 0; if( rp->code==0 ){ - rp->code = "\n"; - rp->line = rp->ruleline; + 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); } append_str(0,0,0,0,0); - for(cp=rp->code; *cp; cp++){ - if( isalpha(*cp) && (cp==rp->code || (!isalnum(cp[-1]) && cp[-1]!='_')) ){ + + /* 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]!='_')) ){ 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("yygotominor.yy%d",0,rp->lhs->dtnum,0,0); + append_str(zLhs,0,0,0,0); cp = xp; lhsused = 1; }else{ for(i=0; inrhs; i++){ if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){ - if( cp!=rp->code && cp[-1]=='@' ){ + 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 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); @@ -3349,6 +3658,11 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ 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, @@ -3357,51 +3671,99 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ lemp->errorcnt++; } - /* Generate destructor code for RHS symbols which are not used in the - ** reduce code */ + /* Generate destructor code for RHS minor values which are not referenced. + ** Generate error messages for unused labels and duplicate labels. + */ for(i=0; inrhs; i++){ - 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(yypParser,%d,&yymsp[%d].minor);\n", 0, - rp->rhs[i]->index,i-rp->nrhs+1,0); - }else{ - /* No destructor defined for this term */ + 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++; + } + }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( rp->code ){ - cp = append_str(0,0,0,0,0); - rp->code = Strsafe(cp?cp:""); + + /* 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); } + + /* 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(out,rp,lemp,lineno) -FILE *out; -struct rule *rp; -struct lemon *lemp; -int *lineno; -{ - char *cp; +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)++; } + } /* Generate code to do the reduce action */ if( rp->code ){ - if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,rp->line,lemp->filename); } + if( !lemp->nolinenosflag ){ + (*lineno)++; + tplt_linedir(out,rp->line,lemp->filename); + } fprintf(out,"{%s",rp->code); - for(cp=rp->code; *cp; cp++){ - if( *cp=='\n' ) (*lineno)++; - } /* End loop */ + for(cp=rp->code; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; } fprintf(out,"}\n"); (*lineno)++; - if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); } - } /* End if( rp->code ) */ + 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)++; + } return; } @@ -3413,20 +3775,20 @@ int *lineno; ** union, also set the ".dtnum" field of every terminal and nonterminal ** symbol. */ -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 */ -{ +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 */ +){ 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 */ - int hash; /* For hashing the name of a type */ - char *name; /* Name of the parser */ + unsigned hash; /* For hashing the name of a type */ + const char *name; /* Name of the parser */ /* Allocate and initialize types[] and allocate stddt[] */ arraysize = lemp->nsymbol * 2; @@ -3472,9 +3834,9 @@ int mhflag; /* True if generating makeheaders output */ 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; @@ -3491,7 +3853,7 @@ int mhflag; /* True if generating makeheaders output */ break; } hash++; - if( hash>=arraysize ) hash = 0; + if( hash>=(unsigned)arraysize ) hash = 0; } if( types[hash]==0 ){ sp->dtnum = hash + 1; @@ -3530,24 +3892,32 @@ int mhflag; /* True if generating makeheaders output */ /* ** Return the name of a C datatype able to represent values between -** lwr and upr, inclusive. +** lwr and upr, inclusive. If pnByte!=NULL then also write the sizeof +** for that type (1, 2, or 4) into *pnByte. */ -static const char *minimum_size_type(int lwr, int upr){ +static const char *minimum_size_type(int lwr, int upr, int *pnByte){ + const char *zType = "int"; + int nByte = 4; if( lwr>=0 ){ if( upr<=255 ){ - return "unsigned char"; + zType = "unsigned char"; + nByte = 1; }else if( upr<65535 ){ - return "unsigned short int"; + zType = "unsigned short int"; + nByte = 2; }else{ - return "unsigned int"; + zType = "unsigned int"; + nByte = 4; } }else if( lwr>=-127 && upr<=127 ){ - return "signed char"; + zType = "signed char"; + nByte = 1; }else if( lwr>=-32767 && upr<32767 ){ - return "short"; - }else{ - return "int"; + zType = "short"; + nByte = 2; } + if( pnByte ) *pnByte = nByte; + return zType; } /* @@ -3560,6 +3930,7 @@ 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 */ }; /* @@ -3568,7 +3939,13 @@ struct axset { static int axset_compare(const void *a, const void *b){ struct axset *p1 = (struct axset*)a; struct axset *p2 = (struct axset*)b; - return p2->nAction - p1->nAction; + int c; + c = p2->nAction - p1->nAction; + if( c==0 ){ + c = p1->iOrder - p2->iOrder; + } + assert( c!=0 || p1==p2 ); + return c; } /* @@ -3579,9 +3956,11 @@ static void writeRuleText(FILE *out, struct rule *rp){ fprintf(out,"%s ::=", rp->lhs->name); for(j=0; jnrhs; j++){ struct symbol *sp = rp->rhs[j]; - fprintf(out," %s", sp->name); - if( sp->type==MULTITERMINAL ){ + if( sp->type!=MULTITERMINAL ){ + fprintf(out," %s", sp->name); + }else{ int k; + fprintf(out," %s", sp->subsym[0]->name); for(k=1; knsubsym; k++){ fprintf(out,"|%s",sp->subsym[k]->name); } @@ -3591,10 +3970,10 @@ static void writeRuleText(FILE *out, struct rule *rp){ /* Generate C source code for the parser */ -void ReportTable(lemp, mhflag) -struct lemon *lemp; -int mhflag; /* Output in makeheaders format if true */ -{ +void ReportTable( + struct lemon *lemp, + int mhflag /* Output in makeheaders format if true */ +){ FILE *out, *in; char line[LINESIZE]; int lineno; @@ -3602,8 +3981,10 @@ int mhflag; /* Output in makeheaders format if true */ struct action *ap; struct rule *rp; struct acttab *pActtab; - int i, j, n; - char *name; + int i, j, n, sz; + int szActionType; /* sizeof(YYACTIONTYPE) */ + int szCodeType; /* sizeof(YYCODETYPE) */ + const char *name; int mnTknOfst, mxTknOfst; int mnNtOfst, mxNtOfst; struct axset *ax; @@ -3629,7 +4010,7 @@ int mhflag; /* Output in makeheaders format if true */ /* Generate #defines for all tokens */ if( mhflag ){ - char *prefix; + const char *prefix; fprintf(out,"#if INTERFACE\n"); lineno++; if( lemp->tokenprefix ) prefix = lemp->tokenprefix; else prefix = ""; @@ -3643,10 +4024,10 @@ int mhflag; /* Output in makeheaders format if true */ /* Generate the defines */ fprintf(out,"#define YYCODETYPE %s\n", - minimum_size_type(0, lemp->nsymbol+1)); lineno++; + minimum_size_type(0, lemp->nsymbol+1, &szCodeType)); 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+5)); lineno++; + minimum_size_type(0,lemp->nstate+lemp->nrule*2+5,&szActionType)); lineno++; if( lemp->wildcard ){ fprintf(out,"#define YYWILDCARD %d\n", lemp->wildcard->index); lineno++; @@ -3666,8 +4047,8 @@ int mhflag; /* Output in makeheaders format if true */ 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--; + 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", @@ -3683,36 +4064,24 @@ int mhflag; /* Output in makeheaders format if true */ 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); - /* 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. + /* 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. */ - - /* Compute the actions on all states and count them up */ - ax = calloc(lemp->nstate*2 , sizeof(ax[0])); + ax = (struct axset *) calloc(lemp->nxstate*2 , sizeof(ax[0])); if( ax==0 ){ fprintf(stderr,"malloc failed\n"); exit(1); } - for(i=0; instate; i++){ + for(i=0; inxstate; i++){ stp = lemp->sorted[i]; ax[i*2].stp = stp; ax[i*2].isTkn = 1; @@ -3723,14 +4092,12 @@ int mhflag; /* Output in makeheaders format if true */ } mxTknOfst = mnTknOfst = 0; mxNtOfst = mnNtOfst = 0; - - /* 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); + /* 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); pActtab = acttab_alloc(); - for(i=0; instate*2 && ax[i].nAction>0; i++){ + for(i=0; inxstate*2 && ax[i].nAction>0; i++){ stp = ax[i].stp; if( ax[i].isTkn ){ for(ap=stp->ap; ap; ap=ap->next){ @@ -3756,12 +4123,52 @@ int mhflag; /* Output in makeheaders format if true */ 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; @@ -3777,6 +4184,7 @@ int mhflag; /* Output in makeheaders format if true */ 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; instate; + n = lemp->nxstate; while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; - fprintf(out, "#define YY_SHIFT_MAX %d\n", n-1); lineno++; + 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, "static const %s yy_shift_ofst[] = {\n", - minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++; + minimum_size_type(mnTknOfst-1, mxTknOfst, &sz)); lineno++; + lemp->tablesize += n*sz; for(i=j=0; isorted[i]; @@ -3817,11 +4228,14 @@ int mhflag; /* Output in makeheaders format if true */ /* Output the yy_reduce_ofst[] table */ fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; - n = lemp->nstate; + n = lemp->nxstate; while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; - fprintf(out, "#define YY_REDUCE_MAX %d\n", n-1); lineno++; + 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, "static const %s yy_reduce_ofst[] = {\n", - minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; + minimum_size_type(mnNtOfst-1, mxNtOfst, &sz)); lineno++; + lemp->tablesize += n*sz; for(i=j=0; isorted[i]; @@ -3840,11 +4254,12 @@ int mhflag; /* Output in makeheaders format if true */ /* Output the default action table */ fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; - n = lemp->nstate; + n = lemp->nxstate; + lemp->tablesize += n*szActionType; for(i=j=0; isorted[i]; if( j==0 ) fprintf(out," /* %5d */ ", i); - fprintf(out, " %4d,", stp->iDflt); + fprintf(out, " %4d,", stp->iDfltReduce+lemp->nstate+lemp->nrule); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; @@ -3859,7 +4274,8 @@ int mhflag; /* Output in makeheaders format if true */ */ if( lemp->has_fallback ){ int mx = lemp->nterminal - 1; - while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } + while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } + lemp->tablesize += (mx+1)*szCodeType; for(i=0; i<=mx; i++){ struct symbol *p = lemp->symbols[i]; if( p->fallback==0 ){ @@ -3888,7 +4304,7 @@ int mhflag; /* Output in makeheaders format if true */ ** when tracing REDUCE actions. */ for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ - assert( rp->index==i ); + assert( rp->iRule==i ); fprintf(out," /* %3d */ \"", i); writeRuleText(out, rp); fprintf(out,"\",\n"); lineno++; @@ -3972,22 +4388,26 @@ int mhflag; /* Output in makeheaders format if true */ 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){ - translate_code(lemp, rp); + i += 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 */ if( rp->code==0 ) continue; - if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ - fprintf(out," case %d: /* ",rp->index); + if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ + fprintf(out," case %d: /* ",rp->iRule); writeRuleText(out, rp); fprintf(out," */\n"); lineno++; for(rp2=rp->next; rp2; rp2=rp2->next){ if( rp2->code==rp->code ){ - fprintf(out," case %d: /*",rp2->index); + fprintf(out," case %d: /*",rp2->iRule); writeRuleText(out, rp2); - fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp2->index); lineno++; + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp2->iRule); lineno++; rp2->code = 0; } } @@ -3999,11 +4419,11 @@ int mhflag; /* Output in makeheaders format if true */ ** 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->index); - writeRuleText(out, rp); - fprintf(out," */ yytestcase(yyruleno==%d);\n", rp->index); lineno++; + 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); @@ -4030,11 +4450,10 @@ int mhflag; /* Output in makeheaders format if true */ } /* Generate a header file for the parser */ -void ReportHeader(lemp) -struct lemon *lemp; +void ReportHeader(struct lemon *lemp) { FILE *out, *in; - char *prefix; + const char *prefix; char line[LINESIZE]; char pattern[LINESIZE]; int i; @@ -4045,7 +4464,8 @@ struct lemon *lemp; 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); @@ -4059,7 +4479,7 @@ struct lemon *lemp; out = file_open(lemp,".h","wb"); if( out ){ for(i=1; interminal; i++){ - fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); + fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i); } fclose(out); } @@ -4073,8 +4493,7 @@ struct lemon *lemp; ** it the default. Except, there is no default if the wildcard token ** is a possible look-ahead. */ -void CompressTables(lemp) -struct lemon *lemp; +void CompressTables(struct lemon *lemp) { struct state *stp; struct action *ap, *ap2; @@ -4127,6 +4546,32 @@ 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; + } + } } } @@ -4145,7 +4590,11 @@ static int stateResortCompare(const void *a, const void *b){ 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; } @@ -4154,8 +4603,7 @@ static int stateResortCompare(const void *a, const void *b){ ** Renumber and resort states so that states with fewer choices ** occur at the end. Except, keep state 0 as the first state. */ -void ResortStates(lemp) -struct lemon *lemp; +void ResortStates(struct lemon *lemp) { int i; struct state *stp; @@ -4164,17 +4612,19 @@ struct lemon *lemp; for(i=0; instate; i++){ stp = lemp->sorted[i]; stp->nTknAct = stp->nNtAct = 0; - stp->iDflt = lemp->nstate + lemp->nrule; + stp->iDfltReduce = lemp->nrule; /* Init dflt action to "syntax error" */ stp->iTknOfst = NO_OFFSET; stp->iNtOfst = NO_OFFSET; for(ap=stp->ap; ap; ap=ap->next){ - if( compute_action(lemp,ap)>=0 ){ + int iAction = compute_action(lemp,ap); + if( iAction>=0 ){ if( ap->sp->indexnterminal ){ stp->nTknAct++; }else if( ap->sp->indexnsymbol ){ stp->nNtAct++; }else{ - stp->iDflt = compute_action(lemp, ap); + assert( stp->autoReduce==0 || stp->pDfltReduce==ap->x.rp ); + stp->iDfltReduce = iAction - lemp->nstate - lemp->nrule; } } } @@ -4184,6 +4634,10 @@ 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--; + } } @@ -4195,8 +4649,7 @@ struct lemon *lemp; static int size = 0; /* Set the set size */ -void SetSize(n) -int n; +void SetSize(int n) { size = n+1; } @@ -4213,17 +4666,14 @@ char *SetNew(){ } /* Deallocate a set */ -void SetFree(s) -char *s; +void SetFree(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(s,e) -char *s; -int e; +int SetAdd(char *s, int e) { int rv; assert( e>=0 && esize = 1024; x1a->count = 0; - x1a->tbl = (x1node*)malloc( - (sizeof(x1node) + sizeof(x1node*))*1024 ); + x1a->tbl = (x1node*)calloc(1024, sizeof(x1node) + sizeof(x1node*)); if( x1a->tbl==0 ){ free(x1a); x1a = 0; @@ -4333,12 +4780,11 @@ 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(data) -char *data; +int Strsafe_insert(const char *data) { x1node *np; - int h; - int ph; + unsigned h; + unsigned ph; if( x1a==0 ) return 0; ph = strhash(data); @@ -4358,8 +4804,7 @@ char *data; struct s_x1 array; array.size = size = x1a->size*2; array.count = x1a->count; - array.tbl = (x1node*)malloc( - (sizeof(x1node) + sizeof(x1node*))*size ); + array.tbl = (x1node*)calloc(size, sizeof(x1node) + sizeof(x1node*)); 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; @@ -4436,20 +4879,27 @@ char *x; return sp; } -/* Compare two symbols for working purposes +/* Compare two symbols for sorting purposes. Return negative, +** zero, or positive if a is less then, equal to, or greater +** than b. ** ** Symbols that begin with upper case letters (terminals or tokens) ** must sort before symbols that begin with lower case letters -** (non-terminals). Other than that, the order does not matter. +** (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. ** ** 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(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; +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; } /* There is one instance of the following structure for each @@ -4468,8 +4918,8 @@ struct s_x2 { ** in an associative array of type "x2". */ typedef struct s_x2node { - struct symbol *data; /* The data */ - char *key; /* The key */ + struct symbol *data; /* The data */ + const char *key; /* The key */ struct s_x2node *next; /* Next entry with the same hash */ struct s_x2node **from; /* Previous link */ } x2node; @@ -4484,8 +4934,7 @@ void Symbol_init(){ if( x2a ){ x2a->size = 128; x2a->count = 0; - x2a->tbl = (x2node*)malloc( - (sizeof(x2node) + sizeof(x2node*))*128 ); + x2a->tbl = (x2node*)calloc(128, sizeof(x2node) + sizeof(x2node*)); if( x2a->tbl==0 ){ free(x2a); x2a = 0; @@ -4498,13 +4947,11 @@ 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(data,key) -struct symbol *data; -char *key; +int Symbol_insert(struct symbol *data, const char *key) { x2node *np; - int h; - int ph; + unsigned h; + unsigned ph; if( x2a==0 ) return 0; ph = strhash(key); @@ -4524,8 +4971,7 @@ char *key; struct s_x2 array; array.size = size = x2a->size*2; array.count = x2a->count; - array.tbl = (x2node*)malloc( - (sizeof(x2node) + sizeof(x2node*))*size ); + array.tbl = (x2node*)calloc(size, sizeof(x2node) + sizeof(x2node*)); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ array.ht = (x2node**)&(array.tbl[size]); for(i=0; i0 && n<=x2a->count ){ @@ -4610,10 +5054,10 @@ struct symbol **Symbol_arrayof() } /* Compare two configurations */ -int Configcmp(a,b) -struct config *a; -struct config *b; +int Configcmp(const char *_a,const char *_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; @@ -4621,9 +5065,7 @@ struct config *b; } /* Compare two states */ -PRIVATE int statecmp(a,b) -struct config *a; -struct config *b; +PRIVATE int statecmp(struct config *a, struct config *b) { int rc; for(rc=0; rc==0 && a && b; a=a->bp, b=b->bp){ @@ -4638,10 +5080,9 @@ struct config *b; } /* Hash a state */ -PRIVATE int statehash(a) -struct config *a; +PRIVATE unsigned statehash(struct config *a) { - int h=0; + unsigned h=0; while( a ){ h = h*571 + a->rp->index*37 + a->dot; a = a->bp; @@ -4652,10 +5093,10 @@ struct config *a; /* Allocate a new state structure */ struct state *State_new() { - struct state *new; - new = (struct state *)calloc(1, sizeof(struct state) ); - MemoryCheck(new); - return new; + struct state *newstate; + newstate = (struct state *)calloc(1, sizeof(struct state) ); + MemoryCheck(newstate); + return newstate; } /* There is one instance of the following structure for each @@ -4690,8 +5131,7 @@ void State_init(){ if( x3a ){ x3a->size = 128; x3a->count = 0; - x3a->tbl = (x3node*)malloc( - (sizeof(x3node) + sizeof(x3node*))*128 ); + x3a->tbl = (x3node*)calloc(128, sizeof(x3node) + sizeof(x3node*)); if( x3a->tbl==0 ){ free(x3a); x3a = 0; @@ -4704,13 +5144,11 @@ 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(data,key) -struct state *data; -struct config *key; +int State_insert(struct state *data, struct config *key) { x3node *np; - int h; - int ph; + unsigned h; + unsigned ph; if( x3a==0 ) return 0; ph = statehash(key); @@ -4730,8 +5168,7 @@ struct config *key; struct s_x3 array; array.size = size = x3a->size*2; array.count = x3a->count; - array.tbl = (x3node*)malloc( - (sizeof(x3node) + sizeof(x3node*))*size ); + array.tbl = (x3node*)calloc(size, sizeof(x3node) + sizeof(x3node*)); if( array.tbl==0 ) return 0; /* Fail due to malloc failure */ array.ht = (x3node**)&(array.tbl[size]); for(i=0; icount; - array = (struct state **)malloc( sizeof(struct state *)*size ); + array = (struct state **)calloc(size, sizeof(struct state *)); if( array ){ for(i=0; itbl[i].data; } @@ -4797,10 +5233,9 @@ struct state **State_arrayof() } /* Hash a configuration */ -PRIVATE int confighash(a) -struct config *a; +PRIVATE unsigned confighash(struct config *a) { - int h=0; + unsigned h=0; h = h*571 + a->rp->index*37 + a->dot; return h; } @@ -4836,8 +5271,7 @@ void Configtable_init(){ if( x4a ){ x4a->size = 64; x4a->count = 0; - x4a->tbl = (x4node*)malloc( - (sizeof(x4node) + sizeof(x4node*))*64 ); + x4a->tbl = (x4node*)calloc(64, sizeof(x4node) + sizeof(x4node*)); if( x4a->tbl==0 ){ free(x4a); x4a = 0; @@ -4850,19 +5284,18 @@ 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(data) -struct config *data; +int Configtable_insert(struct config *data) { x4node *np; - int h; - int ph; + unsigned h; + unsigned ph; if( x4a==0 ) return 0; ph = confighash(data); h = ph & (x4a->size-1); np = x4a->ht[h]; while( np ){ - if( Configcmp(np->data,data)==0 ){ + if( Configcmp((const char *) np->data,(const char *) data)==0 ){ /* An existing entry with the same key is found. */ /* Fail because overwrite is not allows. */ return 0; @@ -4875,8 +5308,7 @@ struct config *data; struct s_x4 array; array.size = size = x4a->size*2; array.count = x4a->count; - array.tbl = (x4node*)malloc( - (sizeof(x4node) + sizeof(x4node*))*size ); + array.tbl = (x4node*)calloc(size, sizeof(x4node) + sizeof(x4node*)); 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(np->data,key)==0 ) break; + if( Configcmp((const char *) np->data,(const char *) key)==0 ) break; np = np->next; } return np ? np->data : 0; @@ -4925,8 +5356,7 @@ struct config *key; /* 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(f) -int(*f)(/* struct config * */); +void Configtable_clear(int(*f)(struct config *)) { int i; if( x4a==0 || x4a->count==0 ) return; diff --git a/tools/lemon/lempar.c b/tools/lemon/lempar.c index 6e9bf92c27..0549a9dadc 100644 --- a/tools/lemon/lempar.c +++ b/tools/lemon/lempar.c @@ -1,8 +1,27 @@ -/* Driver template for the LEMON parser generator. -** The author disclaims copyright to this source code. +/* +** 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: */ -/* First off, code is included that follows the "include" declaration -** in the input grammar file. */ #include #include #include @@ -13,65 +32,70 @@ #define CDECL #endif +/************ Begin %include sections from the grammar ************************/ %% -/* 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 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 *************************/ %% -/* Make sure the INTERFACE macro is defined. -*/ -#ifndef INTERFACE -# define INTERFACE 1 -#endif -/* The next thing included is series of defines which control +/**************** End makeheaders token definitions ***************************/ +/* The next section is a series of control #defines. ** various aspects of the generated parser. -** 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. +** 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. ** 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. -** 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. +** (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. ** This is typically a union of many types, one of ** which is ParseTOKENTYPE. The entry in the union -** for base tokens is called "yy0". +** for terminal symbols 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 -** YYNSTATE the combined number of states. -** YYNRULE the number of rules in the grammar ** 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 */ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/************* Begin control #defines *****************************************/ %% -#define YY_NO_ACTION (YYNSTATE+YYNRULE+2) -#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) -#define YY_ERROR_ACTION (YYNSTATE+YYNRULE) - -/* The yyzerominor constant is used to initialize instances of -** YYMINORTYPE objects to zero. */ -static const YYMINORTYPE yyzerominor = { 0 }; +/************* End control #defines *******************************************/ /* Define the yytestcase() macro to be a no-op if is not already defined ** otherwise. @@ -94,16 +118,20 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** Suppose the action integer is N. Then the action is determined as ** follows ** -** 0 <= N < YYNSTATE Shift N. That is, push the lookahead +** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead ** token onto the stack and goto state N. ** -** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. +** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then +** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. ** -** N == YYNSTATE+YYNRULE A syntax error has occurred. +** 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+1 The parser accepts its input. +** N == YY_ACCEPT_ACTION The parser accepts its input. ** -** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused +** N == YY_NO_ACTION No such action. Denotes unused ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. @@ -132,12 +160,13 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** 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 **********************************************/ %% -#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0])) +/********** End of lemon-generated parsing tables *****************************/ -/* The next table maps tokens into fallback tokens. If a construct -** like the following: +/* The next table maps tokens (terminal symbols) into fallback tokens. +** If a construct like the following: ** ** %fallback ID X Y Z. ** @@ -145,6 +174,10 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** 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[] = { @@ -163,9 +196,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 */ + 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 @@ -180,7 +217,9 @@ struct yyParser { #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 */ @@ -262,6 +301,15 @@ 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 @@ -274,9 +322,9 @@ 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)(size_t)){ +void *ParseAlloc(void *(CDECL *mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); + pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( pParser ){ pParser->yyidx = -1; #ifdef YYTRACKMAXSTACKDEPTH @@ -291,10 +339,12 @@ void *ParseAlloc(void *(CDECL *mallocProc)(size_t)){ return pParser; } -/* 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. +/* 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 */ @@ -310,10 +360,12 @@ 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 */ } } @@ -323,45 +375,37 @@ 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 int yy_pop_parser_stack(yyParser *pParser){ - YYCODETYPE yymajor; - yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; - - if( pParser->yyidx<0 ) return 0; +static void yy_pop_parser_stack(yyParser *pParser){ + yyStackEntry *yytos; + assert( pParser->yyidx>=0 ); + yytos = &pParser->yystack[pParser->yyidx--]; #ifndef NDEBUG - if( yyTraceFILE && pParser->yyidx>=0 ){ + if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); } #endif - yymajor = yytos->major; - yy_destructor(pParser, yymajor, &yytos->minor); - pParser->yyidx--; - return yymajor; + yy_destructor(pParser, yytos->major, &yytos->minor); } -/* -** Deallocate and destroy a parser. Destructors are all called for +/* +** Deallocate and destroy a parser. Destructors are called for ** all stack elements before shutting the parser down. -** -** Inputs: -**
    -**
  • A pointer to the parser. This should be a pointer -** obtained from ParseAlloc. -**
  • A pointer to a function used to reclaim memory obtained -** from malloc. -**
+* +** 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. */ 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); @@ -382,66 +426,72 @@ int ParseStackPeak(void *p){ /* ** 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 int yy_find_shift_action( +static unsigned 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_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 ){ + 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 ){ #ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } -#endif - return yy_find_shift_action(pParser, iFallback); - } -#endif -#ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( j>=0 && j %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } +#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]; } -#endif /* NDEBUG */ - return yy_action[j]; } - } #endif /* YYWILDCARD */ + } + return yy_default[stateno]; + }else{ + return yy_action[i]; } - return yy_default[stateno]; - }else{ - return yy_action[i]; - } + }while(1); } /* ** 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 */ @@ -449,22 +499,22 @@ static int yy_find_reduce_action( ){ int i; #ifdef YYERRORSYMBOL - if( stateno>YY_REDUCE_MAX ){ + if( stateno>YY_REDUCE_COUNT ){ return yy_default[stateno]; } #else - assert( stateno<=YY_REDUCE_MAX ); + 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_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){ + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ return yy_default[stateno]; } #else - assert( i>=0 && i=0 && iyyidx--; #ifndef NDEBUG @@ -484,10 +534,32 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ 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 ******************************************/ %% +/******** 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. */ @@ -495,7 +567,7 @@ 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 */ - YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ + ParseTOKENTYPE yyMinor /* The minor token to shift in */ ){ yyStackEntry *yytos; yypParser->yyidx++; @@ -506,14 +578,14 @@ static void yy_shift( #endif #if YYSTACKDEPTH>0 if( yypParser->yyidx>=YYSTACKDEPTH ){ - yyStackOverflow(yypParser, yypMinor); + yyStackOverflow(yypParser); return; } #else if( yypParser->yyidx>=yypParser->yystksz ){ yyGrowStack(yypParser); if( yypParser->yyidx>=yypParser->yystksz ){ - yyStackOverflow(yypParser, yypMinor); + yyStackOverflow(yypParser); return; } } @@ -521,17 +593,8 @@ static void yy_shift( yytos = &yypParser->yystack[yypParser->yyidx]; yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)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 + yytos->minor.yy0 = yyMinor; + yyTraceShift(yypParser, yyNewState); } /* The following table contains information about every rule that @@ -552,39 +615,46 @@ static void yy_accept(yyParser*); /* Forward Declaration */ */ static void yy_reduce( yyParser *yypParser, /* The parser */ - int yyruleno /* Number of the rule by which to reduce */ + unsigned 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>=0 - && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ - fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, - yyRuleName[yyruleno]); + 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); } #endif /* NDEBUG */ - /* 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));*/ - yygotominor = yyzerominor; + /* 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 + } switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example @@ -595,31 +665,24 @@ static void yy_reduce( ** #line ** break; */ +/********** Begin reduce actions **********************************************/ %% +/********** End reduce actions ************************************************/ }; + assert( yyrulenoyyidx -= yysize; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)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 = (YYACTIONTYPE)yyact; - yymsp->major = (YYCODETYPE)yygoto; - yymsp->minor = yygotominor; - }else -#endif - { - yy_shift(yypParser,yyact,yygoto,&yygotominor); - } + if( yyact <= YY_MAX_SHIFTREDUCE ){ + if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + yypParser->yyidx -= yysize - 1; + yymsp -= yysize-1; + yymsp->stateno = (YYACTIONTYPE)yyact; + yymsp->major = (YYCODETYPE)yygoto; + yyTraceShift(yypParser, yyact); }else{ - assert( yyact == YYNSTATE + YYNRULE + 1 ); + assert( yyact == YY_ACCEPT_ACTION ); + yypParser->yyidx -= yysize; yy_accept(yypParser); } } @@ -640,7 +703,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 */ @@ -651,11 +716,13 @@ static void yy_parse_failed( static void yy_syntax_error( yyParser *yypParser, /* The parser */ int yymajor, /* The major type of the error token */ - YYMINORTYPE yyminor /* The minor type of the error token */ + ParseTOKENTYPE yyminor /* The minor type of the error token */ ){ ParseARG_FETCH; -#define TOKEN (yyminor.yy0) +#define TOKEN yyminor +/************ Begin %syntax_error code ****************************************/ %% +/************ End %syntax_error code ******************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } @@ -674,7 +741,9 @@ 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 */ } @@ -704,8 +773,10 @@ void Parse( ParseARG_PDECL /* Optional %extra_argument parameter */ ){ YYMINORTYPE yyminorunion; - int yyact; /* The parser action. */ + unsigned int yyact; /* The parser action. */ +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 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 @@ -716,41 +787,51 @@ void Parse( if( yypParser->yyidx<0 ){ #if YYSTACKDEPTH<=0 if( yypParser->yystksz <=0 ){ - /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ - yyminorunion = yyzerominor; - yyStackOverflow(yypParser, &yyminorunion); + yyStackOverflow(yypParser); 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 } - yyminorunion.yy0 = yyminor; +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) 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_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + yy_shift(yypParser,yyact,yymajor,yyminor); +#ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; +#endif yymajor = YYNOCODE; - }else if( yyact < YYNSTATE + YYNRULE ){ - yy_reduce(yypParser,yyact-YYNSTATE); + }else if( yyact <= YY_MAX_REDUCE ){ + yy_reduce(yypParser,yyact-YY_MIN_REDUCE); }else{ #ifdef YYERRORSYMBOL int yymx; #endif assert( yyact == YY_ERROR_ACTION ); + yyminorunion.yy0 = yyminor; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); @@ -759,7 +840,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: ** @@ -777,7 +858,7 @@ void Parse( ** */ if( yypParser->yyerrcnt<0 ){ - yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_syntax_error(yypParser,yymajor,yyminor); } yymx = yypParser->yystack[yypParser->yyidx].major; if( yymx==YYERRORSYMBOL || yyerrorhit ){ @@ -787,15 +868,15 @@ void Parse( yyTracePrompt,yyTokenName[yymajor]); } #endif - yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); + yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ - while( + while( yypParser->yyidx >= 0 && yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yystack[yypParser->yyidx].stateno, - YYERRORSYMBOL)) >= YYNSTATE + YYERRORSYMBOL)) >= YY_MIN_REDUCE ){ yy_pop_parser_stack(yypParser); } @@ -804,9 +885,7 @@ void Parse( yy_parse_failed(yypParser); yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ - YYMINORTYPE u2; - u2.YYERRSYMDT = 0; - yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); + yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); } } yypParser->yyerrcnt = 3; @@ -819,7 +898,7 @@ void Parse( ** 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,yyminorunion); + yy_syntax_error(yypParser,yymajor, yyminor); yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yymajor = YYNOCODE; @@ -834,7 +913,7 @@ void Parse( ** three input tokens have been successfully shifted. */ if( yypParser->yyerrcnt<=0 ){ - yy_syntax_error(yypParser,yymajor,yyminorunion); + yy_syntax_error(yypParser,yymajor, yyminor); } yypParser->yyerrcnt = 3; yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); @@ -845,5 +924,15 @@ 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; }