Skip to content

Commit 9ba3c5c

Browse files
adelavaisakimd
authored andcommitted
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.
1 parent 4bd4cdf commit 9ba3c5c

File tree

3 files changed

+198
-48
lines changed

3 files changed

+198
-48
lines changed

data/skeletons/d.m4

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,10 @@ m4_define([b4_public_types_declare],
573573
alias Symbol = ]b4_parser_class[.Symbol;
574574
alias Value = ]b4_yystype[;]b4_locations_if([[
575575
alias Location = ]b4_location_type[;
576-
alias Position = ]b4_position_type[;]])[
576+
alias Position = ]b4_position_type[;]b4_push_if([[
577+
alias PUSH_MORE = ]b4_parser_class[.YYPUSH_MORE;
578+
alias ABORT = ]b4_parser_class[.YYABORT;
579+
alias ACCEPT = ]b4_parser_class[.YYACCEPT;]])[]])[
577580
]])
578581

579582

data/skeletons/lalr1.d

Lines changed: 191 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,38 @@ m4_define([b4_lac_flag],
2525
[m4_if(b4_percent_define_get([[parse.lac]]),
2626
[none], [[0]], [[1]])])
2727

28+
29+
## --------------- ##
30+
## api.push-pull. ##
31+
## --------------- ##
32+
33+
b4_percent_define_default([[api.push-pull]], [[pull]])
34+
b4_percent_define_check_values([[[[api.push-pull]],
35+
[[pull]], [[push]], [[both]]]])
36+
37+
# Define m4 conditional macros that encode the value
38+
# of the api.push-pull flag.
39+
b4_define_flag_if([pull]) m4_define([b4_pull_flag], [[1]])
40+
b4_define_flag_if([push]) m4_define([b4_push_flag], [[1]])
41+
m4_case(b4_percent_define_get([[api.push-pull]]),
42+
[pull], [m4_define([b4_push_flag], [[0]])],
43+
[push], [m4_define([b4_pull_flag], [[0]])])
44+
45+
# Define a macro to be true when api.push-pull has the value "both".
46+
m4_define([b4_both_if],[b4_push_if([b4_pull_if([$1],[$2])],[$2])])
47+
48+
# Handle BISON_USE_PUSH_FOR_PULL for the test suite. So that push parsing
49+
# tests function as written, do not let BISON_USE_PUSH_FOR_PULL modify the
50+
# behavior of Bison at all when push parsing is already requested.
51+
b4_define_flag_if([use_push_for_pull])
52+
b4_use_push_for_pull_if([
53+
b4_push_if([m4_define([b4_use_push_for_pull_flag], [[0]])],
54+
[m4_define([b4_push_flag], [[1]])])])
55+
56+
57+
# Define a macro to encapsulate the parse state variables. This
58+
# allows them to be defined either in parse() when doing pull parsing,
59+
# or as class instance variable when doing push parsing.
2860
b4_output_begin([b4_parser_file_name])
2961
b4_copyright([Skeleton implementation for Bison LALR(1) parsers in D],
3062
[2007-2012, 2019-2021])[
@@ -328,6 +360,11 @@ b4_user_union_members
328360
* Returned by a Bison action in order to stop the parsing process and
329361
* return failure (<tt>false</tt>). */
330362
public static immutable int YYABORT = 1;
363+
]b4_push_if([
364+
/**
365+
* Returned by a Bison action in order to request a new token.
366+
*/
367+
public static immutable int YYPUSH_MORE = 4;])[
331368
332369
/**
333370
* Returned by a Bison action in order to start error recovery without
@@ -342,6 +379,8 @@ b4_user_union_members
342379
private static immutable int YYREDUCE = 6;
343380
private static immutable int YYERRLAB1 = 7;
344381
private static immutable int YYRETURN = 8;
382+
]b4_push_if([[ private static immutable int YYGETTOKEN = 9; /* Signify that a new token is expected when doing push-parsing. */]])[
383+
345384
]b4_locations_if([
346385
private static immutable YYSemanticType yy_semantic_null;])[
347386
private int yyerrstatus_ = 0;
@@ -351,6 +390,32 @@ b4_user_union_members
351390
yyerrstatus_ = 0;
352391
}
353392
393+
// Lookahead symbol kind.
394+
SymbolKind yytoken = ]b4_symbol(empty, kind)[;
395+
396+
/* State. */
397+
int yyn = 0;
398+
int yylen = 0;
399+
int yystate = 0;
400+
401+
YYStack yystack;
402+
403+
int label = YYNEWSTATE;
404+
405+
/* Error handling. */
406+
]b4_locations_if([[
407+
/// The location where the error started.
408+
Location yyerrloc;
409+
410+
/// Location of the lookahead.
411+
Location yylloc;
412+
413+
/// @@$.
414+
Location yyloc;]])[
415+
416+
/// Semantic value of the lookahead.
417+
Value yylval;
418+
354419
/**
355420
* Whether error recovery is being done. In this state, the parser
356421
* reads token until it reaches a known state, and then restarts normal
@@ -430,40 +495,34 @@ b4_user_union_members
430495
}
431496
]])[
432497
]b4_symbol_type_define[
498+
]b4_push_if([[
499+
/**
500+
* Push Parse input from external lexer
501+
*
502+
* @@param yyla current Symbol
503+
*
504+
* @@return <tt>YYACCEPT, YYABORT, YYPUSH_MORE</tt>
505+
*/
506+
public int pushParse(Symbol yyla)]], [[
433507
/**
434508
* Parse input from the scanner that was specified at object construction
435509
* time. Return whether the end of the input was reached successfully.
436510
*
437511
* @@return <tt>true</tt> if the parsing succeeds. Note that this does not
438512
* imply that there were no syntax errors.
439513
*/
440-
public bool parse ()
441-
{
442-
// Lookahead symbol kind.
443-
SymbolKind yytoken = ]b4_symbol(empty, kind)[;
444-
445-
/* State. */
446-
int yyn = 0;
447-
int yylen = 0;
448-
int yystate = 0;
449-
450-
YYStack yystack;
451-
452-
/* Error handling. */
453-
]b4_locations_if([[
454-
/// The location where the error started.
455-
Location yyerrloc;
456-
457-
/// Location of the lookahead.
458-
Location yylloc;
459-
460-
/// @@$.
461-
Location yyloc;]])[
462-
463-
/// Semantic value of the lookahead.
464-
Value yylval;
514+
public bool parse()]])[
515+
{]b4_push_if([[
516+
if (!this.pushParseInitialized)
517+
{
518+
pushParseInitialize();
519+
yyerrstatus_ = 0;
520+
}
521+
else
522+
label = YYGETTOKEN;
465523
466-
bool yyresult;]b4_lac_if([[
524+
bool push_token_consumed = true;
525+
]], [[ bool yyresult;]b4_lac_if([[
467526
// Discard the LAC context in case there still is one left from a
468527
// previous invocation.
469528
yylacDiscard("init");]])[]b4_parse_trace_if([[
@@ -482,7 +541,7 @@ m4_popdef([b4_at_dollar])])dnl
482541
[ /* Initialize the stack. */
483542
yystack.push (yystate, yylval]b4_locations_if([, yylloc])[);
484543
485-
int label = YYNEWSTATE;
544+
label = YYNEWSTATE;]])[
486545
for (;;)
487546
final switch (label)
488547
{
@@ -494,25 +553,38 @@ m4_popdef([b4_at_dollar])])dnl
494553
yystack.print (yyDebugStream);]])[
495554
496555
/* Accept? */
497-
if (yystate == yyfinal_)
498-
return true;
556+
if (yystate == yyfinal_)]b4_push_if([[
557+
{
558+
label = YYACCEPT;
559+
break;
560+
}]], [[
561+
return true;]])[
499562
500563
/* Take a decision. First try without lookahead. */
501564
yyn = yypact_[yystate];
502565
if (yyPactValueIsDefault(yyn))
503566
{
504567
label = YYDEFAULT;
505568
break;
506-
}
569+
}]b4_push_if([[
570+
goto case;
571+
572+
case YYGETTOKEN:]])[
507573
508574
/* Read a lookahead token. */
509575
if (yytoken == ]b4_symbol(empty, kind)[)
510-
{]b4_parse_trace_if([[
511-
yycdebugln ("Reading a token");]])[
576+
{]b4_push_if([[
577+
if (!push_token_consumed)
578+
return YYPUSH_MORE;]])[]b4_parse_trace_if([[
579+
yycdebugln ("Reading a token");]])[]b4_push_if([[
580+
yytoken = yyla.token;
581+
yylval = yyla.value;]b4_locations_if([[
582+
yylloc = yyla.location;]])[
583+
push_token_consumed = false;]], [[
512584
Symbol yysymbol = yylex();
513585
yytoken = yysymbol.token();
514586
yylval = yysymbol.value();]b4_locations_if([[
515-
yylloc = yysymbol.location();]])[
587+
yylloc = yysymbol.location();]])[]])[
516588
}
517589
518590
/* Token already converted to internal form. */]b4_parse_trace_if([[
@@ -611,8 +683,12 @@ m4_popdef([b4_at_dollar])])dnl
611683
* error, discard it. */
612684
613685
/* Return failure if at end of input. */
614-
if (yytoken == ]b4_symbol(eof, [kind])[)
615-
return false;
686+
if (yytoken == ]b4_symbol(eof, [kind])[)]b4_push_if([[
687+
{
688+
label = YYABORT;
689+
break;
690+
}]], [[
691+
return false;]])[
616692
else
617693
yytoken = ]b4_symbol(empty, kind)[;
618694
}
@@ -657,16 +733,23 @@ m4_popdef([b4_at_dollar])])dnl
657733
}
658734
659735
/* Pop the current state because it cannot handle the error token. */
660-
if (yystack.height == 1)
661-
return false;
736+
if (yystack.height == 1)]b4_push_if([[
737+
{
738+
label = YYABORT;
739+
break;
740+
}]],[[
741+
return false;]])[
662742
663743
]b4_locations_if([ yyerrloc = yystack.locationAt (0);])[
664744
yystack.pop ();
665745
yystate = yystack.stateAt (0);]b4_parse_trace_if([[
666746
if (0 < yydebug)
667747
yystack.print (yyDebugStream);]])[
668-
}
669-
748+
}]b4_push_if([[
749+
if (label == YYABORT)
750+
/* Leave the switch. */
751+
break;
752+
]])[
670753
]b4_locations_if([
671754
/* Muck with the stack to setup for yylloc. */
672755
yystack.push (0, yy_semantic_null, yylloc);
@@ -683,24 +766,86 @@ m4_popdef([b4_at_dollar])])dnl
683766
break;
684767
685768
/* Accept. */
686-
case YYACCEPT:
769+
case YYACCEPT:]b4_push_if([[
770+
this.pushParseInitialized = false;]b4_parse_trace_if([[
771+
if (0 < yydebug)
772+
yystack.print (yyDebugStream);]])[
773+
return YYACCEPT;]], [[
687774
yyresult = true;
688775
label = YYRETURN;
689-
break;
776+
break;]])[
690777
691778
/* Abort. */
692-
case YYABORT:
779+
case YYABORT:]b4_push_if([[
780+
this.pushParseInitialized = false;]b4_parse_trace_if([[
781+
if (0 < yydebug)
782+
yystack.print (yyDebugStream);]])[
783+
return YYABORT;]], [[
693784
yyresult = false;
694785
label = YYRETURN;
695-
break;
696-
697-
case YYRETURN:]b4_parse_trace_if([[
786+
break;]])[
787+
]b4_push_if([[]], [[ ][case YYRETURN:]b4_parse_trace_if([[
698788
if (0 < yydebug)
699789
yystack.print (yyDebugStream);]])[
700-
return yyresult;
790+
return yyresult;]])[
701791
}
792+
assert(0);
702793
}
703794
795+
]b4_push_if([[
796+
bool pushParseInitialized = false;
797+
798+
/**
799+
* (Re-)Initialize the state of the push parser.
800+
*/
801+
public void pushParseInitialize()
802+
{
803+
804+
/* Lookahead and lookahead in internal form. */
805+
this.yytoken = ]b4_symbol(empty, kind)[;
806+
807+
/* State. */
808+
this.yyn = 0;
809+
this.yylen = 0;
810+
this.yystate = 0;
811+
destroy(this.yystack);
812+
this.label = YYNEWSTATE;
813+
]b4_lac_if([[
814+
destroy(this.yylacStack);
815+
this.yylacEstablished = false;]])[
816+
817+
/* Error handling. */
818+
this.yynerrs_ = 0;
819+
]b4_locations_if([
820+
/* The location where the error started. */
821+
this.yyerrloc = Location(Position(), Position());
822+
this.yylloc = Location(Position(), Position());])[
823+
824+
/* Semantic value of the lookahead. */
825+
//destroy(this.yylval);
826+
827+
/* Initialize the stack. */
828+
yystack.push(this.yystate, this.yylval]b4_locations_if([, this.yylloc])[);
829+
830+
this.pushParseInitialized = true;
831+
}]])[]b4_both_if([[
832+
/**
833+
* Parse input from the scanner that was specified at object construction
834+
* time. Return whether the end of the input was reached successfully.
835+
* This version of parse() is defined only when api.push-push=both.
836+
*
837+
* @@return <tt>true</tt> if the parsing succeeds. Note that this does not
838+
* imply that there were no syntax errors.
839+
*/
840+
bool parse()
841+
{
842+
int status = 0;
843+
do {
844+
status = this.pushParse(yylex());
845+
} while (status == YYPUSH_MORE);
846+
return status == YYACCEPT;
847+
}]])[
848+
704849
// Generate an error message.
705850
private final void yyreportSyntaxError(Context yyctx)
706851
{]b4_parse_error_bmatch(

tests/calc.at

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ m4_define([AT_CALC_MAIN(d)],
540540
auto l = calcLexer (input);
541541
auto p = new YYParser (l);]AT_DEBUG_IF([[
542542
p.setDebugLevel (1);]])[
543-
return !p.parse ();
543+
return !p.parse();
544544
}
545545
]])
546546

@@ -1510,6 +1510,8 @@ AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error det
15101510

15111511
AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error custom %define api.value.type union])
15121512
AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error detailed])
1513+
AT_CHECK_CALC_LALR1_D([%define api.push-pull both])
1514+
AT_CHECK_CALC_LALR1_D([%define parse.trace %define parse.error custom %locations %define api.push-pull both %define parse.lac full])
15131515

15141516
# ----------------------- #
15151517
# LALR1 Java Calculator. #

0 commit comments

Comments
 (0)