[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 1/8] glr2.cc: move parser::parse into glr_stack
From: |
Akim Demaille |
Subject: |
[PATCH 1/8] glr2.cc: move parser::parse into glr_stack |
Date: |
Sat, 16 Jan 2021 07:20:08 +0100 |
Currently we have two classes that actually should be fused together:
parser and glr_stack. Both carry part of the parsing: (i) parser
contains `parse`, which is the top-level of the parsing process, it
uses yygetToken, etc., and (ii) glr_stack takes care of all the
details (dealing with the stack), and also calls yygetToken.
However if we fuse them together, we would get a large parser class,
in the header file. So it is probably better to split this large
class using the pimpl idiom. But then it appears that glr_stack is
very close from being the impl of parser.
Let's improve this.
For a start...
* data/skeletons/glr2.cc (parser::parse): Move to...
(glr_stack::parse): here.
(parser::parse): Use it.
---
data/skeletons/glr2.cc | 404 +++++++++++++++++++++--------------------
1 file changed, 205 insertions(+), 199 deletions(-)
diff --git a/data/skeletons/glr2.cc b/data/skeletons/glr2.cc
index 5f2f836e..2ff2dcc1 100644
--- a/data/skeletons/glr2.cc
+++ b/data/skeletons/glr2.cc
@@ -2038,9 +2038,210 @@ public:
YYJMP_BUF yyexception_buffer;
]b4_namespace_ref[::]b4_parser_class[& yyparser;
- void yyreserveGlrStack() {
+#define YYCHK1(YYE) \
+ do { \
+ switch (YYE) { \
+ case yyok: \
+ break; \
+ case yyabort: \
+ goto yyabortlab; \
+ case yyaccept: \
+ goto yyacceptlab; \
+ case yyerr: \
+ goto yyuser_error; \
+ default: \
+ goto yybuglab; \
+ } \
+ } while (false)
+
+ int
+ parse ()
+ {
+ int yyresult;
+ size_t yyposn;
+
+ YYCDEBUG << "Starting parse\n";
+
+ this->yytoken = ]b4_symbol(empty, kind)[;]b4_variant_if([], [[
+ this->yylval = yyval_default;]])[]b4_locations_if([
+ this->yylloc = yyloc_default;])[
+]m4_ifdef([b4_initial_action], [
+b4_dollar_pushdef([this->yylval], [], [], [this->yylloc])dnl
+ b4_user_initial_action
+b4_dollar_popdef])[]dnl
+[
+ switch (YYSETJMP (this->yyexception_buffer))
+ {
+ case 0: break;
+ case 1: goto yyabortlab;
+ case 2: goto yyexhaustedlab;
+ default: goto yybuglab;
+ }
+ this->yyglrShift (create_state_set_index(0), 0, 0,
this->yylval]b4_locations_if([, this->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 = this->firstTopState()->yylrState;
+ YYCDEBUG << "Entering state " << yystate << '\n';
+ if (yystate == YYFINAL)
+ goto yyacceptlab;
+ if (yyisDefaultedState (yystate))
+ {
+ const rule_num yyrule = yydefaultAction (yystate);
+ if (yyrule == 0)
+ {]b4_locations_if([[
+ this->yyerror_range[1].getState().yyloc = this->yylloc;]])[
+ this->yyreportSyntaxError ();
+ goto yyuser_error;
+ }
+ YYCHK1 (this->yyglrReduce (create_state_set_index(0), yyrule,
true));
+ }
+ else
+ {
+ yygetToken (yyparser, *this]b4_user_args[);
+ const short* yyconflicts;
+ const int yyaction = yygetLRActions (yystate, this->yytoken,
yyconflicts);
+ if (*yyconflicts != 0)
+ break;
+ if (yyisShiftAction (yyaction))
+ {
+ YY_SYMBOL_PRINT ("Shifting", this->yytoken, this->yylval,
this->yylloc);
+ yyposn += 1;
+ // FIXME: we should move yylval.
+ this->yyglrShift (create_state_set_index(0), yyaction,
yyposn, this->yylval]b4_locations_if([, this->yylloc])[);]b4_variant_if([[
+ // FIXME: User destructors.
+ // Value type destructor.
+ ]b4_symbol_variant([[this->yytoken]], [[this->yylval]],
[[template destroy]])])[
+ this->yytoken = ]b4_symbol(empty, kind)[;
+ if (0 < this->yyerrState)
+ this->yyerrState -= 1;
+ }
+ else if (yyisErrorAction (yyaction))
+ {]b4_locations_if([[
+ this->yyerror_range[1].getState().yyloc = this->yylloc;]])[
+ /* Don't issue an error message again for exceptions
+ thrown from the scanner. */
+ if (this->yytoken != ]b4_symbol(error, kind)[)
+ this->yyreportSyntaxError ();
+ goto yyuser_error;
+ }
+ else
+ YYCHK1 (this->yyglrReduce (create_state_set_index(0),
-yyaction, true));
+ }
+ }
+
+ while (true)
+ {
+ for (state_set_index yys = create_state_set_index(0); yys.uget() <
this->yystateStack.numTops(); ++yys)
+ this->yystateStack.yytops.setLookaheadNeeds(yys, this->yytoken
!= ]b4_symbol(empty, kind)[);
+
+ /* 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() <
this->yystateStack.numTops(); ++yys)
+ YYCHK1 (this->yyprocessOneStack (yys, yyposn]b4_locations_if([,
&this->yylloc])[));
+ this->yystateStack.yytops.yyremoveDeletes ();
+ if (this->yystateStack.yytops.size() == 0)
+ {
+ this->yystateStack.yytops.yyundeleteLastStack ();
+ if (this->yystateStack.yytops.size() == 0)
+ this->yyFail (]b4_locations_if([&this->yylloc,
])[YY_("syntax error"));
+ YYCHK1 (this->yyresolveStack ());
+ YYCDEBUG << "Returning to deterministic
operation.\n";]b4_locations_if([[
+ this->yyerror_range[1].getState().yyloc = this->yylloc;]])[
+ this->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, yytoken is set to
]b4_symbol(empty, kind)[
+ before the loop to make sure the user destructor for yylval
isn't
+ called twice. */
+ yysymbol_kind_t yytoken_to_shift = this->yytoken;
+ this->yytoken = ]b4_symbol(empty, kind)[;
+ yyposn += 1;
+ for (state_set_index yys = create_state_set_index(0); yys.uget() <
this->yystateStack.numTops(); ++yys)
+ {
+ const state_num yystate = this->topState(yys)->yylrState;
+ const short* yyconflicts;
+ const int yyaction
+ = yygetLRActions (yystate, yytoken_to_shift, yyconflicts);
+ /* Note that yyconflicts were handled by yyprocessOneStack. */
+ YYCDEBUG << "On stack " << yys.get() << ", ";
+ YY_SYMBOL_PRINT ("shifting", yytoken_to_shift, this->yylval,
this->yylloc);
+ this->yyglrShift (yys, yyaction, yyposn,
this->yylval]b4_locations_if([, this->yylloc])[);
+ YYCDEBUG << "Stack " << yys.get() << " now in state "
+ << this->topState(yys)->yylrState << '\n';
+ }
+]b4_variant_if([[
+ // FIXME: User destructors.
+ // Value type destructor.
+ ]b4_symbol_variant([[yytoken_to_shift]], [[this->yylval]],
[[template destroy]])])[
+
+ if (this->yystateStack.yytops.size() == 1)
+ {
+ YYCHK1 (this->yyresolveStack ());
+ YYCDEBUG << "Returning to deterministic operation.\n";
+ this->yystateStack.yycompressStack ();
+ break;
+ }
+ }
+ continue;
+ yyuser_error:
+ this->yyrecoverSyntaxError (]b4_locations_if([&this->yylloc])[);
+ yyposn = this->firstTopState()->yyposn;
+ }
+
+ yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+ yybuglab:
+ YYASSERT (false);
+ goto yyabortlab;
+
+ yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+ yyexhaustedlab:
+ yyparser.error (]b4_locations_if([this->yylloc, ])[YY_("memory
exhausted"));
+ yyresult = 2;
+ goto yyreturn;
+
+ yyreturn:
+ return yyresult;
+ }
+#undef YYCHK1
+
+ void yyreserveGlrStack ()
+ {
if (!yystateStack.yyexpandGLRStackIfNeeded ())
- yyMemoryExhausted();
+ yyMemoryExhausted ();
}
_Noreturn void
@@ -3025,23 +3226,6 @@ yypreference (const semantic_option& y0, const
semantic_option& y1)
return 0;
}
-#define YYCHK1(YYE) \
- do { \
- switch (YYE) { \
- case yyok: \
- break; \
- case yyabort: \
- goto yyabortlab; \
- case yyaccept: \
- goto yyacceptlab; \
- case yyerr: \
- goto yyuser_error; \
- default: \
- goto yybuglab; \
- } \
- } while (false)
-
-
/* DEBUGGING ONLY */
#if ]b4_api_PREFIX[DEBUG
static void
@@ -3080,187 +3264,9 @@ static void yypdumpstack (const glr_stack& yystack)
int
]b4_parser_class[::parse ()
{
- ]b4_parser_class[ &yyparser = *this;
- int yyresult;
glr_stack yystack(YYINITDEPTH, *this]b4_user_args[);
- size_t yyposn;
-
- YYCDEBUG << "Starting parse\n";
-
- yystack.yytoken = ]b4_symbol(empty, kind)[;]b4_variant_if([], [[
- yystack.yylval = yyval_default;]])[]b4_locations_if([
- yystack.yylloc = yyloc_default;])[
-]m4_ifdef([b4_initial_action], [
-b4_dollar_pushdef([yystack.yylval], [], [], [yystack.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,
yystack.yylval]b4_locations_if([, yystack.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;
- YYCDEBUG << "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 =
yystack.yylloc;]])[
- yystack.yyreportSyntaxError ();
- goto yyuser_error;
- }
- YYCHK1 (yystack.yyglrReduce (create_state_set_index(0),
yyrule, true));
- }
- else
- {
- yygetToken (yyparser, yystack]b4_user_args[);
- const short* yyconflicts;
- const int yyaction = yygetLRActions (yystate, yystack.yytoken,
yyconflicts);
- if (*yyconflicts != 0)
- break;
- if (yyisShiftAction (yyaction))
- {
- YY_SYMBOL_PRINT ("Shifting", yystack.yytoken,
yystack.yylval, yystack.yylloc);
- yyposn += 1;
- // FIXME: we should move yylval.
- yystack.yyglrShift (create_state_set_index(0), yyaction,
yyposn, yystack.yylval]b4_locations_if([, yystack.yylloc])[);]b4_variant_if([[
- // FIXME: User destructors.
- // Value type destructor.
- ]b4_symbol_variant([[yystack.yytoken]],
[[yystack.yylval]], [[template destroy]])])[
- yystack.yytoken = ]b4_symbol(empty, kind)[;
- if (0 < yystack.yyerrState)
- yystack.yyerrState -= 1;
- }
- else if (yyisErrorAction (yyaction))
- {]b4_locations_if([[
- yystack.yyerror_range[1].getState().yyloc =
yystack.yylloc;]])[
- /* Don't issue an error message again for exceptions
- thrown from the scanner. */
- if (yystack.yytoken != ]b4_symbol(error, kind)[)
- 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)
- yystack.yystateStack.yytops.setLookaheadNeeds(yys,
yystack.yytoken != ]b4_symbol(empty, kind)[);
-
- /* 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([, &yystack.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([&yystack.yylloc,
])[YY_("syntax error"));
- YYCHK1 (yystack.yyresolveStack ());
- YYCDEBUG << "Returning to deterministic
operation.\n";]b4_locations_if([[
- yystack.yyerror_range[1].getState().yyloc = yystack.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, yytoken is set to
]b4_symbol(empty, kind)[
- before the loop to make sure the user destructor for yylval
isn't
- called twice. */
- yysymbol_kind_t yytoken_to_shift = yystack.yytoken;
- yystack.yytoken = ]b4_symbol(empty, kind)[;
- 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. */
- YYCDEBUG << "On stack " << yys.get() << ", ";
- YY_SYMBOL_PRINT ("shifting", yytoken_to_shift, yystack.yylval,
yystack.yylloc);
- yystack.yyglrShift (yys, yyaction, yyposn,
yystack.yylval]b4_locations_if([, yystack.yylloc])[);
- YYCDEBUG << "Stack " << yys.get() << " now in state "
- << yystack.topState(yys)->yylrState << '\n';
- }
-]b4_variant_if([[
- // FIXME: User destructors.
- // Value type destructor.
- ]b4_symbol_variant([[yytoken_to_shift]], [[yystack.yylval]],
[[template destroy]])])[
-
- if (yystack.yystateStack.yytops.size() == 1)
- {
- YYCHK1 (yystack.yyresolveStack ());
- YYCDEBUG << "Returning to deterministic operation.\n";
- yystack.yystateStack.yycompressStack ();
- break;
- }
- }
- continue;
- yyuser_error:
- yystack.yyrecoverSyntaxError (]b4_locations_if([&yystack.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([yystack.yylloc, ])[YY_("memory exhausted"));
- yyresult = 2;
- goto yyreturn;
-
- yyreturn:
- return yyresult;
-}
+ return yystack.parse ();
+ }
]b4_parse_error_bmatch([custom\|detailed],
[[ const char *
--
2.30.0
- [PATCH 0/8] glr2.cc: clean up, Akim Demaille, 2021/01/16
- [PATCH 1/8] glr2.cc: move parser::parse into glr_stack,
Akim Demaille <=
- [PATCH 2/8] glr2.cc: make yygetToken a member of glr_stack, Akim Demaille, 2021/01/16
- [PATCH 3/8] glr2.cc: move free-functions into glr_stack, Akim Demaille, 2021/01/16
- [PATCH 4/8] glr2.cc: more free functions about the automaton into glr_stack, Akim Demaille, 2021/01/16
- [PATCH 5/8] glr2.cc: remove some useless qualifications, Akim Demaille, 2021/01/16
- [PATCH 6/8] glr2.cc: move strong_index_alias into implementation file, Akim Demaille, 2021/01/16
- [PATCH 7/8] glr2.cc: formatting changes, Akim Demaille, 2021/01/16
- [PATCH 8/8] glr2.cc: don't prepare for subclassing, Akim Demaille, 2021/01/16