From 855d46678a4c472540afadea6c8f0138d507c75f Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Sat, 12 Dec 2020 19:41:35 +0100 Subject: [PATCH] glr2.cc: make yyparse a member function Amusingly enough, glr2.cc still had its core function, yyparse, being a free function instead of a member function. * data/skeletons/glr2.cc (yyparse): Remove this free function called from yyparser::parse. Inline its body into... (yyparser::parse): this member function. This requires moving a bit the yychar, etc. macros. Access to token can be simplified (the b4_namespace_ref::b4_parser_class prefix is no longer needed). --- data/skeletons/glr2.cc | 382 +++++++++++++++++++---------------------- 1 file changed, 180 insertions(+), 202 deletions(-) diff --git a/data/skeletons/glr2.cc b/data/skeletons/glr2.cc index 5c8e51bc..613440ac 100644 --- a/data/skeletons/glr2.cc +++ b/data/skeletons/glr2.cc @@ -2849,189 +2849,6 @@ yypreference (const semantic_option& y0, const semantic_option& y1) } while (0) -/*----------. -| yyparse. | -`----------*/ - -int -yyparse (]b4_namespace_ref[::]b4_parser_class[& yyparser]b4_user_formals[) -{ - int yyresult; - glr_stack yystack(YYINITDEPTH, yyparser]b4_user_args[); - glr_stack* const yystackp = &yystack; - size_t yyposn; - - YY_DEBUG_STREAM << "Starting parse\n"; - - yychar = ]b4_namespace_ref::b4_parser_class::token::b4_symbol(empty, id)[; - yylval = yyval_default;]b4_locations_if([ - yylloc = yyloc_default;])[ -]m4_ifdef([b4_initial_action], [ -b4_dollar_pushdef([yylval], [], [], [yylloc])dnl - b4_user_initial_action -b4_dollar_popdef])[]dnl -[ - switch (YYSETJMP (yystack.yyexception_buffer)) - { - case 0: break; - case 1: goto yyabortlab; - case 2: goto yyexhaustedlab; - default: goto yybuglab; - } - yystack.yyglrShift (create_state_set_index(0), 0, 0, yylval]b4_locations_if([, &yylloc])[); - yyposn = 0; - - while (true) - { - /* For efficiency, we have two loops, the first of which is - specialized to deterministic operation (single stack, no - potential ambiguity). */ - /* Standard mode */ - while (true) - { - const state_num yystate = yystack.firstTopState()->yylrState; - YY_DEBUG_STREAM << "Entering state " << yystate << "\n"; - if (yystate == YYFINAL) - goto yyacceptlab; - if (yyisDefaultedState (yystate)) - { - const rule_num yyrule = yydefaultAction (yystate); - if (yyrule == 0) - {]b4_locations_if([[ - yystack.yyerror_range[1].getState().yyloc = yylloc;]])[ - yystack.yyreportSyntaxError (); - goto yyuser_error; - } - YYCHK1 (yystack.yyglrReduce (create_state_set_index(0), yyrule, true)); - } - else - { - const yysymbol_kind_t yytoken = ]b4_yygetToken_call[; - const short* yyconflicts; - const int yyaction = yygetLRActions (yystate, yytoken, yyconflicts); - if (*yyconflicts != 0) - break; - if (yyisShiftAction (yyaction)) - { - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - yychar = ]b4_namespace_ref::b4_parser_class::token::b4_symbol(empty, id)[; - yyposn += 1; - yystack.yyglrShift (create_state_set_index(0), yyaction, yyposn, yylval]b4_locations_if([, &yylloc])[); - if (0 < yystack.yyerrState) - yystack.yyerrState -= 1; - } - else if (yyisErrorAction (yyaction)) - {]b4_locations_if([[ - yystack.yyerror_range[1].getState().yyloc = yylloc;]])[ - /* Don't issue an error message again for exceptions - thrown from the scanner. */ - if (yychar != ]b4_namespace_ref::b4_parser_class::token::b4_symbol(error, id)[) - yystack.yyreportSyntaxError (); - goto yyuser_error; - } - else - YYCHK1 (yystack.yyglrReduce (create_state_set_index(0), -yyaction, true)); - } - } - - while (true) - { - for (state_set_index yys = create_state_set_index(0); yys.uget() < yystack.yystateStack.numTops(); ++yys) - yystackp->yystateStack.yytops.setLookaheadNeeds(yys, yychar != ]b4_namespace_ref::b4_parser_class::token::b4_symbol(empty, id)[); - - /* yyprocessOneStack returns one of three things: - - - An error flag. If the caller is yyprocessOneStack, it - immediately returns as well. When the caller is finally - yyparse, it jumps to an error label via YYCHK1. - - - yyok, but yyprocessOneStack has invoked yymarkStackDeleted - (yys), which sets the top state of yys to NULL. Thus, - yyparse's following invocation of yyremoveDeletes will remove - the stack. - - - yyok, when ready to shift a token. - - Except in the first case, yyparse will invoke yyremoveDeletes and - then shift the next token onto all remaining stacks. This - synchronization of the shift (that is, after all preceding - reductions on all stacks) helps prevent double destructor calls - on yylval in the event of memory exhaustion. */ - - for (state_set_index yys = create_state_set_index(0); yys.uget() < yystack.yystateStack.numTops(); ++yys) - YYCHK1 (yystack.yyprocessOneStack (yys, yyposn]b4_locations_if([, &yylloc])[)); - yystack.yystateStack.yytops.yyremoveDeletes (); - if (yystack.yystateStack.yytops.size() == 0) - { - yystack.yystateStack.yytops.yyundeleteLastStack (); - if (yystack.yystateStack.yytops.size() == 0) - yystack.yyFail (]b4_locations_if([&yylloc, ])[YY_("syntax error")); - YYCHK1 (yystack.yyresolveStack ()); - YY_DEBUG_STREAM << "Returning to deterministic operation.\n";]b4_locations_if([[ - yystack.yyerror_range[1].getState().yyloc = yylloc;]])[ - yystack.yyreportSyntaxError (); - goto yyuser_error; - } - - /* If any yyglrShift call fails, it will fail after shifting. Thus, - a copy of yylval will already be on stack 0 in the event of a - failure in the following loop. Thus, yychar is set to ]b4_symbol(empty, id)[ - before the loop to make sure the user destructor for yylval isn't - called twice. */ - yysymbol_kind_t yytoken_to_shift = YYTRANSLATE (yychar); - yychar = ]b4_namespace_ref::b4_parser_class::token::b4_symbol(empty, id)[; - yyposn += 1; - for (state_set_index yys = create_state_set_index(0); yys.uget() < yystack.yystateStack.numTops(); ++yys) - { - const state_num yystate = yystack.topState(yys)->yylrState; - const short* yyconflicts; - const int yyaction = yygetLRActions (yystate, yytoken_to_shift, - yyconflicts); - /* Note that yyconflicts were handled by yyprocessOneStack. */ - YY_DEBUG_STREAM << "On stack " << yys.get() << ", "; - YY_SYMBOL_PRINT ("shifting", yytoken_to_shift, &yylval, &yylloc); - yystack.yyglrShift (yys, yyaction, yyposn, - yylval]b4_locations_if([, &yylloc])[); - YY_DEBUG_STREAM << "Stack " << yys.get() << " now in state #" - << yystack.topState(yys)->yylrState << '\n'; - } - - if (yystack.yystateStack.yytops.size() == 1) - { - YYCHK1 (yystack.yyresolveStack ()); - YY_DEBUG_STREAM << "Returning to deterministic operation.\n"; - yystack.yystateStack.yycompressStack (); - break; - } - } - continue; - yyuser_error: - yystack.yyrecoverSyntaxError (]b4_locations_if([&yylloc])[); - yyposn = yystack.firstTopState()->yyposn; - } - - yyacceptlab: - yyresult = 0; - goto yyreturn; - - yybuglab: - YYASSERT (false); - goto yyabortlab; - - yyabortlab: - yyresult = 1; - goto yyreturn; - - yyexhaustedlab: - yyparser.error (]b4_locations_if([yylloc, ])[YY_("memory exhausted")); - yyresult = 2; - goto yyreturn; - - yyreturn: - return yyresult; -} - - /* DEBUGGING ONLY */ #if ]b4_api_PREFIX[DEBUG static void @@ -3045,23 +2862,6 @@ static void yypdumpstack (glr_stack* yystackp) { #endif -#undef yylval -#undef yychar -#undef yynerrs]b4_locations_if([ -#undef yylloc]) - -m4_if(b4_prefix, [yy], [], -[[/* Substitute the variable and function names. */ -#define yyparse ]b4_prefix[parse -#define yylex ]b4_prefix[lex -#define yyerror ]b4_prefix[error -#define yylval ]b4_prefix[lval -#define yychar ]b4_prefix[char -#define yydebug ]b4_prefix[debug -#define yynerrs ]b4_prefix[nerrs]b4_locations_if([[ -#define yylloc ]b4_prefix[lloc]])])[ - - ]b4_namespace_open[ ]dnl In this section, the parse params are the original parse_params. m4_pushdef([b4_parse_param], m4_defn([b4_parse_param_orig]))dnl @@ -3088,8 +2888,186 @@ m4_pushdef([b4_parse_param], m4_defn([b4_parse_param_orig]))dnl int ]b4_parser_class[::parse () { - return ::yyparse (*this]b4_user_args[); - } + ]b4_parser_class[ &yyparser = *this; + int yyresult; + glr_stack yystack(YYINITDEPTH, *this]b4_user_args[); + glr_stack* const yystackp = &yystack; + size_t yyposn; + + YY_DEBUG_STREAM << "Starting parse\n"; + + yychar = ]b4_namespace_ref::b4_parser_class::token::b4_symbol(empty, id)[; + yylval = yyval_default;]b4_locations_if([ + yylloc = yyloc_default;])[ +]m4_ifdef([b4_initial_action], [ +b4_dollar_pushdef([yylval], [], [], [yylloc])dnl + b4_user_initial_action +b4_dollar_popdef])[]dnl +[ + switch (YYSETJMP (yystack.yyexception_buffer)) + { + case 0: break; + case 1: goto yyabortlab; + case 2: goto yyexhaustedlab; + default: goto yybuglab; + } + yystack.yyglrShift (create_state_set_index(0), 0, 0, yylval]b4_locations_if([, &yylloc])[); + yyposn = 0; + + while (true) + { + /* For efficiency, we have two loops, the first of which is + specialized to deterministic operation (single stack, no + potential ambiguity). */ + /* Standard mode */ + while (true) + { + const state_num yystate = yystack.firstTopState()->yylrState; + YY_DEBUG_STREAM << "Entering state " << yystate << "\n"; + if (yystate == YYFINAL) + goto yyacceptlab; + if (yyisDefaultedState (yystate)) + { + const rule_num yyrule = yydefaultAction (yystate); + if (yyrule == 0) + {]b4_locations_if([[ + yystack.yyerror_range[1].getState().yyloc = yylloc;]])[ + yystack.yyreportSyntaxError (); + goto yyuser_error; + } + YYCHK1 (yystack.yyglrReduce (create_state_set_index(0), yyrule, true)); + } + else + { + const yysymbol_kind_t yytoken = ]b4_yygetToken_call[; + const short* yyconflicts; + const int yyaction = yygetLRActions (yystate, yytoken, yyconflicts); + if (*yyconflicts != 0) + break; + if (yyisShiftAction (yyaction)) + { + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + yychar = token::]b4_symbol(empty, id)[; + yyposn += 1; + yystack.yyglrShift (create_state_set_index(0), yyaction, yyposn, yylval]b4_locations_if([, &yylloc])[); + if (0 < yystack.yyerrState) + yystack.yyerrState -= 1; + } + else if (yyisErrorAction (yyaction)) + {]b4_locations_if([[ + yystack.yyerror_range[1].getState().yyloc = yylloc;]])[ + /* Don't issue an error message again for exceptions + thrown from the scanner. */ + if (yychar != token::]b4_symbol(error, id)[) + yystack.yyreportSyntaxError (); + goto yyuser_error; + } + else + YYCHK1 (yystack.yyglrReduce (create_state_set_index(0), -yyaction, true)); + } + } + + while (true) + { + for (state_set_index yys = create_state_set_index(0); yys.uget() < yystack.yystateStack.numTops(); ++yys) + yystackp->yystateStack.yytops.setLookaheadNeeds(yys, yychar != token::]b4_symbol(empty, id)[); + + /* yyprocessOneStack returns one of three things: + + - An error flag. If the caller is yyprocessOneStack, it + immediately returns as well. When the caller is finally + yyparse, it jumps to an error label via YYCHK1. + + - yyok, but yyprocessOneStack has invoked yymarkStackDeleted + (yys), which sets the top state of yys to NULL. Thus, + yyparse's following invocation of yyremoveDeletes will remove + the stack. + + - yyok, when ready to shift a token. + + Except in the first case, yyparse will invoke yyremoveDeletes and + then shift the next token onto all remaining stacks. This + synchronization of the shift (that is, after all preceding + reductions on all stacks) helps prevent double destructor calls + on yylval in the event of memory exhaustion. */ + + for (state_set_index yys = create_state_set_index(0); yys.uget() < yystack.yystateStack.numTops(); ++yys) + YYCHK1 (yystack.yyprocessOneStack (yys, yyposn]b4_locations_if([, &yylloc])[)); + yystack.yystateStack.yytops.yyremoveDeletes (); + if (yystack.yystateStack.yytops.size() == 0) + { + yystack.yystateStack.yytops.yyundeleteLastStack (); + if (yystack.yystateStack.yytops.size() == 0) + yystack.yyFail (]b4_locations_if([&yylloc, ])[YY_("syntax error")); + YYCHK1 (yystack.yyresolveStack ()); + YY_DEBUG_STREAM << "Returning to deterministic operation.\n";]b4_locations_if([[ + yystack.yyerror_range[1].getState().yyloc = yylloc;]])[ + yystack.yyreportSyntaxError (); + goto yyuser_error; + } + + /* If any yyglrShift call fails, it will fail after shifting. Thus, + a copy of yylval will already be on stack 0 in the event of a + failure in the following loop. Thus, yychar is set to ]b4_symbol(empty, id)[ + before the loop to make sure the user destructor for yylval isn't + called twice. */ + yysymbol_kind_t yytoken_to_shift = YYTRANSLATE (yychar); + yychar = token::]b4_symbol(empty, id)[; + yyposn += 1; + for (state_set_index yys = create_state_set_index(0); yys.uget() < yystack.yystateStack.numTops(); ++yys) + { + const state_num yystate = yystack.topState(yys)->yylrState; + const short* yyconflicts; + const int yyaction = yygetLRActions (yystate, yytoken_to_shift, + yyconflicts); + /* Note that yyconflicts were handled by yyprocessOneStack. */ + YY_DEBUG_STREAM << "On stack " << yys.get() << ", "; + YY_SYMBOL_PRINT ("shifting", yytoken_to_shift, &yylval, &yylloc); + yystack.yyglrShift (yys, yyaction, yyposn, + yylval]b4_locations_if([, &yylloc])[); + YY_DEBUG_STREAM << "Stack " << yys.get() << " now in state #" + << yystack.topState(yys)->yylrState << '\n'; + } + + if (yystack.yystateStack.yytops.size() == 1) + { + YYCHK1 (yystack.yyresolveStack ()); + YY_DEBUG_STREAM << "Returning to deterministic operation.\n"; + yystack.yystateStack.yycompressStack (); + break; + } + } + continue; + yyuser_error: + yystack.yyrecoverSyntaxError (]b4_locations_if([&yylloc])[); + yyposn = yystack.firstTopState()->yyposn; + } + + yyacceptlab: + yyresult = 0; + goto yyreturn; + + yybuglab: + YYASSERT (false); + goto yyabortlab; + + yyabortlab: + yyresult = 1; + goto yyreturn; + + yyexhaustedlab: + error (]b4_locations_if([yylloc, ])[YY_("memory exhausted")); + yyresult = 2; + goto yyreturn; + + yyreturn: + return yyresult; +} + +#undef yylval +#undef yychar +#undef yynerrs]b4_locations_if([ +#undef yylloc])[ ]b4_parse_error_bmatch([custom\|detailed], [[ const char *