d: add push parser support

Support the push-pull directive with the options pull, push and both.
Pull remains the default option.

* data/skeletons/d.m4: Add user aliases for the push parser's return
values: PUSH_MORE, ABORT, ACCEPT.
* data/skeletons/lalr1.d: Add push parser support.
* tests/calc.at: Test it.
This commit is contained in:
Adela Vais
2021-01-29 16:56:13 +02:00
committed by Akim Demaille
parent 4bd4cdf377
commit 9ba3c5ceb9
3 changed files with 204 additions and 54 deletions

View File

@@ -573,7 +573,10 @@ m4_define([b4_public_types_declare],
alias Symbol = ]b4_parser_class[.Symbol;
alias Value = ]b4_yystype[;]b4_locations_if([[
alias Location = ]b4_location_type[;
alias Position = ]b4_position_type[;]])[
alias Position = ]b4_position_type[;]b4_push_if([[
alias PUSH_MORE = ]b4_parser_class[.YYPUSH_MORE;
alias ABORT = ]b4_parser_class[.YYABORT;
alias ACCEPT = ]b4_parser_class[.YYACCEPT;]])[]])[
]])

View File

@@ -25,6 +25,38 @@ m4_define([b4_lac_flag],
[m4_if(b4_percent_define_get([[parse.lac]]),
[none], [[0]], [[1]])])
## --------------- ##
## api.push-pull. ##
## --------------- ##
b4_percent_define_default([[api.push-pull]], [[pull]])
b4_percent_define_check_values([[[[api.push-pull]],
[[pull]], [[push]], [[both]]]])
# Define m4 conditional macros that encode the value
# of the api.push-pull flag.
b4_define_flag_if([pull]) m4_define([b4_pull_flag], [[1]])
b4_define_flag_if([push]) m4_define([b4_push_flag], [[1]])
m4_case(b4_percent_define_get([[api.push-pull]]),
[pull], [m4_define([b4_push_flag], [[0]])],
[push], [m4_define([b4_pull_flag], [[0]])])
# Define a macro to be true when api.push-pull has the value "both".
m4_define([b4_both_if],[b4_push_if([b4_pull_if([$1],[$2])],[$2])])
# Handle BISON_USE_PUSH_FOR_PULL for the test suite. So that push parsing
# tests function as written, do not let BISON_USE_PUSH_FOR_PULL modify the
# behavior of Bison at all when push parsing is already requested.
b4_define_flag_if([use_push_for_pull])
b4_use_push_for_pull_if([
b4_push_if([m4_define([b4_use_push_for_pull_flag], [[0]])],
[m4_define([b4_push_flag], [[1]])])])
# Define a macro to encapsulate the parse state variables. This
# allows them to be defined either in parse() when doing pull parsing,
# or as class instance variable when doing push parsing.
b4_output_begin([b4_parser_file_name])
b4_copyright([Skeleton implementation for Bison LALR(1) parsers in D],
[2007-2012, 2019-2021])[
@@ -328,6 +360,11 @@ b4_user_union_members
* Returned by a Bison action in order to stop the parsing process and
* return failure (<tt>false</tt>). */
public static immutable int YYABORT = 1;
]b4_push_if([
/**
* Returned by a Bison action in order to request a new token.
*/
public static immutable int YYPUSH_MORE = 4;])[
/**
* Returned by a Bison action in order to start error recovery without
@@ -342,6 +379,8 @@ b4_user_union_members
private static immutable int YYREDUCE = 6;
private static immutable int YYERRLAB1 = 7;
private static immutable int YYRETURN = 8;
]b4_push_if([[ private static immutable int YYGETTOKEN = 9; /* Signify that a new token is expected when doing push-parsing. */]])[
]b4_locations_if([
private static immutable YYSemanticType yy_semantic_null;])[
private int yyerrstatus_ = 0;
@@ -351,6 +390,32 @@ b4_user_union_members
yyerrstatus_ = 0;
}
// Lookahead symbol kind.
SymbolKind yytoken = ]b4_symbol(empty, kind)[;
/* State. */
int yyn = 0;
int yylen = 0;
int yystate = 0;
YYStack yystack;
int label = YYNEWSTATE;
/* Error handling. */
]b4_locations_if([[
/// The location where the error started.
Location yyerrloc;
/// Location of the lookahead.
Location yylloc;
/// @@$.
Location yyloc;]])[
/// Semantic value of the lookahead.
Value yylval;
/**
* Whether error recovery is being done. In this state, the parser
* reads token until it reaches a known state, and then restarts normal
@@ -430,6 +495,15 @@ b4_user_union_members
}
]])[
]b4_symbol_type_define[
]b4_push_if([[
/**
* Push Parse input from external lexer
*
* @@param yyla current Symbol
*
* @@return <tt>YYACCEPT, YYABORT, YYPUSH_MORE</tt>
*/
public int pushParse(Symbol yyla)]], [[
/**
* Parse input from the scanner that was specified at object construction
* time. Return whether the end of the input was reached successfully.
@@ -437,33 +511,18 @@ b4_user_union_members
* @@return <tt>true</tt> if the parsing succeeds. Note that this does not
* imply that there were no syntax errors.
*/
public bool parse ()
{
// Lookahead symbol kind.
SymbolKind yytoken = ]b4_symbol(empty, kind)[;
public bool parse()]])[
{]b4_push_if([[
if (!this.pushParseInitialized)
{
pushParseInitialize();
yyerrstatus_ = 0;
}
else
label = YYGETTOKEN;
/* State. */
int yyn = 0;
int yylen = 0;
int yystate = 0;
YYStack yystack;
/* Error handling. */
]b4_locations_if([[
/// The location where the error started.
Location yyerrloc;
/// Location of the lookahead.
Location yylloc;
/// @@$.
Location yyloc;]])[
/// Semantic value of the lookahead.
Value yylval;
bool yyresult;]b4_lac_if([[
bool push_token_consumed = true;
]], [[ bool yyresult;]b4_lac_if([[
// Discard the LAC context in case there still is one left from a
// previous invocation.
yylacDiscard("init");]])[]b4_parse_trace_if([[
@@ -482,7 +541,7 @@ m4_popdef([b4_at_dollar])])dnl
[ /* Initialize the stack. */
yystack.push (yystate, yylval]b4_locations_if([, yylloc])[);
int label = YYNEWSTATE;
label = YYNEWSTATE;]])[
for (;;)
final switch (label)
{
@@ -494,8 +553,12 @@ m4_popdef([b4_at_dollar])])dnl
yystack.print (yyDebugStream);]])[
/* Accept? */
if (yystate == yyfinal_)
return true;
if (yystate == yyfinal_)]b4_push_if([[
{
label = YYACCEPT;
break;
}]], [[
return true;]])[
/* Take a decision. First try without lookahead. */
yyn = yypact_[yystate];
@@ -503,16 +566,25 @@ m4_popdef([b4_at_dollar])])dnl
{
label = YYDEFAULT;
break;
}
}]b4_push_if([[
goto case;
case YYGETTOKEN:]])[
/* Read a lookahead token. */
if (yytoken == ]b4_symbol(empty, kind)[)
{]b4_parse_trace_if([[
yycdebugln ("Reading a token");]])[
{]b4_push_if([[
if (!push_token_consumed)
return YYPUSH_MORE;]])[]b4_parse_trace_if([[
yycdebugln ("Reading a token");]])[]b4_push_if([[
yytoken = yyla.token;
yylval = yyla.value;]b4_locations_if([[
yylloc = yyla.location;]])[
push_token_consumed = false;]], [[
Symbol yysymbol = yylex();
yytoken = yysymbol.token();
yylval = yysymbol.value();]b4_locations_if([[
yylloc = yysymbol.location();]])[
yylloc = yysymbol.location();]])[]])[
}
/* Token already converted to internal form. */]b4_parse_trace_if([[
@@ -611,8 +683,12 @@ m4_popdef([b4_at_dollar])])dnl
* error, discard it. */
/* Return failure if at end of input. */
if (yytoken == ]b4_symbol(eof, [kind])[)
return false;
if (yytoken == ]b4_symbol(eof, [kind])[)]b4_push_if([[
{
label = YYABORT;
break;
}]], [[
return false;]])[
else
yytoken = ]b4_symbol(empty, kind)[;
}
@@ -657,16 +733,23 @@ m4_popdef([b4_at_dollar])])dnl
}
/* Pop the current state because it cannot handle the error token. */
if (yystack.height == 1)
return false;
if (yystack.height == 1)]b4_push_if([[
{
label = YYABORT;
break;
}]],[[
return false;]])[
]b4_locations_if([ yyerrloc = yystack.locationAt (0);])[
yystack.pop ();
yystate = yystack.stateAt (0);]b4_parse_trace_if([[
if (0 < yydebug)
yystack.print (yyDebugStream);]])[
}
}]b4_push_if([[
if (label == YYABORT)
/* Leave the switch. */
break;
]])[
]b4_locations_if([
/* Muck with the stack to setup for yylloc. */
yystack.push (0, yy_semantic_null, yylloc);
@@ -683,24 +766,86 @@ m4_popdef([b4_at_dollar])])dnl
break;
/* Accept. */
case YYACCEPT:
yyresult = true;
label = YYRETURN;
break;
/* Abort. */
case YYABORT:
yyresult = false;
label = YYRETURN;
break;
case YYRETURN:]b4_parse_trace_if([[
case YYACCEPT:]b4_push_if([[
this.pushParseInitialized = false;]b4_parse_trace_if([[
if (0 < yydebug)
yystack.print (yyDebugStream);]])[
return yyresult;
return YYACCEPT;]], [[
yyresult = true;
label = YYRETURN;
break;]])[
/* Abort. */
case YYABORT:]b4_push_if([[
this.pushParseInitialized = false;]b4_parse_trace_if([[
if (0 < yydebug)
yystack.print (yyDebugStream);]])[
return YYABORT;]], [[
yyresult = false;
label = YYRETURN;
break;]])[
]b4_push_if([[]], [[ ][case YYRETURN:]b4_parse_trace_if([[
if (0 < yydebug)
yystack.print (yyDebugStream);]])[
return yyresult;]])[
}
assert(0);
}
]b4_push_if([[
bool pushParseInitialized = false;
/**
* (Re-)Initialize the state of the push parser.
*/
public void pushParseInitialize()
{
/* Lookahead and lookahead in internal form. */
this.yytoken = ]b4_symbol(empty, kind)[;
/* State. */
this.yyn = 0;
this.yylen = 0;
this.yystate = 0;
destroy(this.yystack);
this.label = YYNEWSTATE;
]b4_lac_if([[
destroy(this.yylacStack);
this.yylacEstablished = false;]])[
/* Error handling. */
this.yynerrs_ = 0;
]b4_locations_if([
/* The location where the error started. */
this.yyerrloc = Location(Position(), Position());
this.yylloc = Location(Position(), Position());])[
/* Semantic value of the lookahead. */
//destroy(this.yylval);
/* Initialize the stack. */
yystack.push(this.yystate, this.yylval]b4_locations_if([, this.yylloc])[);
this.pushParseInitialized = true;
}]])[]b4_both_if([[
/**
* Parse input from the scanner that was specified at object construction
* time. Return whether the end of the input was reached successfully.
* This version of parse() is defined only when api.push-push=both.
*
* @@return <tt>true</tt> if the parsing succeeds. Note that this does not
* imply that there were no syntax errors.
*/
bool parse()
{
int status = 0;
do {
status = this.pushParse(yylex());
} while (status == YYPUSH_MORE);
return status == YYACCEPT;
}]])[
// Generate an error message.
private final void yyreportSyntaxError(Context yyctx)
{]b4_parse_error_bmatch(

View File

@@ -540,7 +540,7 @@ m4_define([AT_CALC_MAIN(d)],
auto l = calcLexer (input);
auto p = new YYParser (l);]AT_DEBUG_IF([[
p.setDebugLevel (1);]])[
return !p.parse ();
return !p.parse();
}
]])
@@ -1510,6 +1510,8 @@ AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error det
AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error custom %define api.value.type union])
AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error detailed])
AT_CHECK_CALC_LALR1_D([%define api.push-pull both])
AT_CHECK_CALC_LALR1_D([%define parse.trace %define parse.error custom %locations %define api.push-pull both %define parse.lac full])
# ----------------------- #
# LALR1 Java Calculator. #