1 # D skeleton
for Bison
-*- autoconf
-*-
3 #
Copyright (C
) 2007-2012, 2019-2022 Free Software Foundation
, Inc
.
5 # This program
is free software
: you can redistribute it
and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation
, either
version 3 of the License
, or
8 #
(at your option
) any later
version.
10 # This program
is distributed
in the hope that it will be useful
,
11 # but WITHOUT ANY WARRANTY
; without even the implied warranty of
12 # MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE
. See the
13 # GNU General Public License
for more details
.
15 # You should have received a copy of the GNU General Public License
16 # along
with this program
. If
not, see
<https
://www.gnu.org/licenses/>.
18 m4_include(b4_skeletonsdir
/[d
.m4
])
20 b4_header_if([b4_complain([%header
/%defines does
not make sense
in D
])])
23 b4_percent_define_default([[parse
.lac
]], [[none
]])
24 b4_percent_define_check_values([[[[parse
.lac
]], [[full
]], [[none
]]]])
25 b4_define_flag_if([lac
])
26 m4_define([b4_lac_flag
],
27 [m4_if(b4_percent_define_get([[parse
.lac
]]),
28 [none
], [[0]], [[1]])])
35 b4_percent_define_default([[api
.push-pull
]], [[pull
]])
36 b4_percent_define_check_values([[[[api
.push-pull
]],
37 [[pull
]], [[push]], [[both
]]]])
39 # Define m4 conditional macros that encode the value
40 # of the api
.push-pull flag
.
41 b4_define_flag_if([pull
]) m4_define([b4_pull_flag
], [[1]])
42 b4_define_flag_if([push]) m4_define([b4_push_flag
], [[1]])
43 m4_case(b4_percent_define_get([[api
.push-pull
]]),
44 [pull
], [m4_define([b4_push_flag
], [[0]])],
45 [push], [m4_define([b4_pull_flag
], [[0]])])
47 # Define a
macro to be
true when api
.push-pull has the value
"both".
48 m4_define([b4_both_if
],[b4_push_if([b4_pull_if([$1],[$2])],[$2])])
50 # Handle BISON_USE_PUSH_FOR_PULL
for the
test suite
. So that
push parsing
51 # tests
function as written
, do not let BISON_USE_PUSH_FOR_PULL modify the
52 # behavior of Bison at all when
push parsing
is already requested
.
53 b4_define_flag_if([use_push_for_pull
])
54 b4_use_push_for_pull_if([
55 b4_push_if([m4_define([b4_use_push_for_pull_flag
], [[0]])],
56 [m4_define([b4_push_flag
], [[1]])])])
59 # Define a
macro to encapsulate the parse state variables
. This
60 # allows them to be defined either
in parse() when doing pull parsing
,
61 #
or as
class instance variable when doing
push parsing
.
62 b4_output_begin([b4_parser_file_name
])
63 b4_copyright([Skeleton implementation
for Bison
LALR(1) parsers
in D
],
64 [2007-2012, 2019-2022])[
66 ]b4_percent_define_ifdef([package], [module b4_percent_define_get([package]);
70 static assert(false, "need compiler for D Version 2");
73 ]b4_user_pre_prologue
[
74 ]b4_user_post_prologue
[
75 ]b4_percent_code_get([[imports
]])[
80 * Handle error message internationalisation.
82 static if (!is(typeof(YY_
))) {
87 extern(C
) char* dgettext(const char*, const char*);
88 string
YY_(const char* s
)
90 return to
!string(dgettext("bison-runtime", s
));
94 static if (!is(typeof(YY_
)))
97 string
YY_(string msg
) { return msg
; }
102 * A Bison parser, automatically generated from <tt>]m4_bpatsubst(b4_file_name, [^"\(.*\)"$], [\1])[</tt>.
104 * @@author LALR (1) parser skeleton written by Paolo Bonzini.
105 * Port to D language was done by Oliver Mangold.
109 * Communication interface between the scanner and the Bison-generated
110 * parser <tt>]b4_parser_class[</tt>.
112 public interface Lexer
115 * Entry point for the scanner. Returns the token identifier corresponding
116 * to the next token and prepares to return the semantic value
117 * ]b4_locations_if([and beginning/ending positions ])[of the token.
118 * @@return the token identifier corresponding to the next token. */
122 * Entry point for error reporting. Emits an error
123 * ]b4_locations_if([referring to the given location ])[in a user-defined way.
125 * @@param loc The location of the element to which the
126 * error message is related]])[
127 * @@param s The string for the error message. */
128 void yyerror (]b4_locations_if([[const Location loc
, ]])[string s
);
129 ]b4_parse_error_bmatch([custom
], [[
131 * Build and emit a "syntax error" message in a user-defined way.
133 * @@param ctx The context of the error.
135 void reportSyntaxError(]b4_parser_class
[.Context ctx
);
139 ]b4_public_types_declare
[
141 ]b4_locations_if([b4_position_type_if([[
142 static assert(__traits(compiles
,
143 (new Position
[1])[0]=(new Position
[1])[0]),
144 "struct/class Position must be default-constructible "
146 static assert(__traits(compiles
, (new string
[1])[0]=(new Position
).toString()),
147 "error: struct/class Position must have toString method");
150 * A struct denoting a point in the input.*/
151 public struct ]b4_position_type
[ {
153 /** The column index within the line of input. */
154 public int column
= 1;
155 /** The line number within an input file. */
157 /** The name of the input file. */
158 public string filename
= null;
161 * A string representation of the position. */
162 public string
toString() const {
164 return format("%s:%d.%d", filename
, line
, column
);
166 return format("%d.%d", line
, column
);
169 ]])b4_location_type_if([[
170 static assert(__traits(compiles
, (new Location((new Position
[1])[0]))) &&
171 __traits(compiles
, (new Location((new Position
[1])[0], (new Position
[1])[0]))),
172 "error: struct/class Location must have "
173 "default constructor and constructors this(Position) and this(Position, Position).");
174 static assert(__traits(compiles
, (new Location
[1])[0].begin
=(new Location
[1])[0].begin
) &&
175 __traits(compiles
, (new Location
[1])[0].begin
=(new Location
[1])[0].end
) &&
176 __traits(compiles
, (new Location
[1])[0].end
=(new Location
[1])[0].begin
) &&
177 __traits(compiles
, (new Location
[1])[0].end
=(new Location
[1])[0].end
),
178 "error: struct/class Location must have assignment-compatible "
179 "members/properties 'begin' and 'end'.");
180 static assert(__traits(compiles
, (new string
[1])[0]=(new Location
[1])[0].toString()),
181 "error: struct/class Location must have toString method.");
183 private immutable bool yy_location_is_class
= !__traits(compiles
, *(new Location((new Position
[1])[0])));]], [[
185 * A struct defining a pair of positions. Positions, defined by the
186 * <code>Position</code> struct, denote a point in the input.
187 * Locations represent a part of the input through the beginning
188 * and ending positions. */
189 public struct ]b4_location_type
[
191 /** The first, inclusive, position in the range. */
192 public Position begin
;
194 /** The first position beyond the range. */
198 * Create a <code>Location</code> denoting an empty range located at
200 * @@param loc The position at which the range is anchored. */
201 public this(Position loc
)
203 this.begin
= this.end
= loc
;
207 * Create a <code>Location</code> from the endpoints of the range.
208 * @@param begin The first position included in the range.
209 * @@param end The first position beyond the range. */
210 public this(Position begin
, Position end
)
217 * Reset initial location to final location.
221 this.begin
= this.end
;
225 * A representation of the location.
227 public string
toString() const
229 auto end_col
= 0 < end
.column ? end
.column
- 1 : 0;
230 auto res
= begin
.toString ();
231 if (end
.filename
&& begin
.filename
!= end
.filename
)
232 res
~= "-" ~ format("%s:%d.%d", end
.filename
, end
.line
, end_col
);
233 else if (begin
.line
< end
.line
)
234 res
~= "-" ~ format("%d.%d", end
.line
, end_col
);
235 else if (begin
.column
< end_col
)
236 res
~= "-" ~ format("%d", end_col
);
241 private immutable bool yy_location_is_class
= false;
243 ]])])[]b4_value_type_setup
[]m4_ifdef([b4_user_union_members
], [private union YYSemanticType
245 b4_user_union_members
247 [m4_if(b4_tag_seen_flag
, 0,
248 [[private alias int YYSemanticType
;]])])[
250 ]b4_parser_class_declaration
[
254 ]b4_declare_symbol_enum
[
257 private final Location
yylloc_from_stack (ref YYStack rhs
, int n
)
259 static if (yy_location_is_class
) {
261 return new Location (rhs
.locationAt (n
-1).begin
, rhs
.locationAt (0).end
);
263 return new Location (rhs
.locationAt (0).end
);
266 return Location (rhs
.locationAt (n
-1).begin
, rhs
.locationAt (0).end
);
268 return Location (rhs
.locationAt (0).end
);
272 ]b4_lexer_if([[private class YYLexer
: Lexer
274 ]b4_percent_code_get([[lexer
]])[
277 /** The object doing lexical analysis for us. */
278 private Lexer yylexer
;
280 ]b4_parse_param_vars
[
284 * Instantiate the Bison-generated parser.
286 public this] (b4_parse_param_decl([b4_lex_param_decl
])[) {
287 ]b4_percent_code_get([[init
]])[]b4_lac_if([[
288 this.yylacStack
= new int[];
289 this.yylacEstablished
= false;]])[
290 this (new YYLexer(]b4_lex_param_call
[));
295 * Instantiate the Bison-generated parser.
296 * @@param yylexer The scanner that will supply tokens to the parser.
298 ]b4_lexer_if([[protected]], [[public]]) [this (]b4_parse_param_decl([[Lexer yylexer
]])[) {
299 this.yylexer
= yylexer
;]b4_parse_trace_if([[
300 this.yyDebugStream
= stderr
;]])[
301 ]b4_parse_param_cons
[
303 ]b4_parse_trace_if([[
305 private File yyDebugStream
;
308 * The <tt>File</tt> on which the debugging output is
311 public File
getDebugStream () { return yyDebugStream
; }
314 * Set the <tt>std.File</tt> on which the debug output is printed.
315 * @@param s The stream that is used for debugging output.
317 public final void setDebugStream(File s
) { yyDebugStream
= s
; }
319 private int yydebug
= 0;
322 * Answer the verbosity of the debugging output; 0 means that all kinds of
323 * output from the parser are suppressed.
325 public final int getDebugLevel() { return yydebug
; }
328 * Set the verbosity of the debugging output; 0 means that all kinds of
329 * output from the parser are suppressed.
330 * @@param level The verbosity level for debugging output.
332 public final void setDebugLevel(int level
) { yydebug
= level
; }
334 protected final void yycdebug (string s
) {
336 yyDebugStream
.write (s
);
339 protected final void yycdebugln (string s
) {
341 yyDebugStream
.writeln (s
);
344 private final ]b4_parser_class
[.Symbol
yylex () {
345 return yylexer
.yylex ();
348 protected final void yyerror (]b4_locations_if([[const Location loc
, ]])[string s
) {
349 yylexer
.yyerror (]b4_locations_if([loc
, ])[s
);
353 * The number of syntax errors so far.
355 public int numberOfErrors() const { return yynerrs_
; }
356 private int yynerrs_
= 0;
359 * Returned by a Bison action in order to stop the parsing process and
360 * return success (<tt>true</tt>). */
361 public static immutable int YYACCEPT
= 0;
364 * Returned by a Bison action in order to stop the parsing process and
365 * return failure (<tt>false</tt>). */
366 public static immutable int YYABORT
= 1;
369 * Returned by a Bison action in order to request a new token.
371 public static immutable int YYPUSH_MORE
= 4;])[
374 * Returned by a Bison action in order to start error recovery without
375 * printing an error message. */
376 public static immutable int YYERROR
= 2;
378 // Internal return codes that are not supported for user semantic
380 private static immutable int YYERRLAB
= 3;
381 private static immutable int YYNEWSTATE
= 4;
382 private static immutable int YYDEFAULT
= 5;
383 private static immutable int YYREDUCE
= 6;
384 private static immutable int YYERRLAB1
= 7;
385 private static immutable int YYRETURN
= 8;
386 ]b4_push_if([[ private static immutable int YYGETTOKEN
= 9; /* Signify that a new token is expected when doing push-parsing. */]])[
389 private static immutable YYSemanticType yy_semantic_null
;])[
390 private int yyerrstatus_
= 0;
392 private void yyerrok()
397 // Lookahead symbol kind.
398 SymbolKind yytoken
= ]b4_symbol(empty
, kind
)[;
407 int label
= YYNEWSTATE
;
409 /* Error handling. */
411 /// The location where the error started.
414 /// Location of the lookahead.
420 /// Semantic value of the lookahead.
424 * Whether error recovery is being done. In this state, the parser
425 * reads token until it reaches a known state, and then restarts normal
427 public final bool recovering ()
429 return yyerrstatus_
== 0;
432 /** Compute post-reduction state.
433 * @@param yystate the current state
434 * @@param yysym the nonterminal to push on the stack
436 private int yyLRGotoState(int yystate
, int yysym
) {
437 int yyr
= yypgoto_
[yysym
- yyntokens_
] + yystate
;
438 if (0 <= yyr
&& yyr
<= yylast_
&& yycheck_
[yyr
] == yystate
)
439 return yytable_
[yyr
];
441 return yydefgoto_
[yysym
- yyntokens_
];
444 private int yyaction (int yyn
, ref YYStack yystack
, int yylen
)
446 Value yyval
;]b4_locations_if([[
447 Location yyloc
= yylloc_from_stack (yystack
, yylen
);]])[
449 /* If YYLEN is nonzero, implement the default value of the action:
450 `$$ = $1'. Otherwise, use the top of the stack.
452 Otherwise, the following line sets YYVAL to garbage.
453 This behavior is undocumented and Bison
454 users should not rely upon it. */
456 yyval
= yystack
.valueAt (yylen
- 1);
458 yyval
= yystack
.valueAt (0);
460 ]b4_parse_trace_if([[
461 yy_reduce_print (yyn
, yystack
);]])[
469 ]b4_parse_trace_if([[
470 yy_symbol_print ("-> $$ =", to
!SymbolKind (yyr1_
[yyn
]), yyval
]b4_locations_if([, yyloc
])[);]])[
475 /* Shift the result of the reduction. */
476 int yystate
= yyLRGotoState(yystack
.stateAt(0), yyr1_
[yyn
]);
477 yystack
.push (yystate
, yyval
]b4_locations_if([, yyloc
])[);
481 ]b4_parse_trace_if([[
482 /*--------------------------------.
483 | Print this symbol on YYOUTPUT. |
484 `--------------------------------*/
486 private final void yy_symbol_print (string s
, SymbolKind yykind
,
487 ref Value yyval
]b4_locations_if([, ref Location yyloc
])[)
491 File yyo
= yyDebugStream
;
493 yyo
.write(yykind
< yyntokens_ ?
" token " : " nterm ");
494 yyo
.write(format("%s", yykind
));
495 yyo
.write(" ("]b4_locations_if([ ~ yyloc
.toString() ~ ": "])[);
496 ]b4_symbol_actions([printer
])[
501 ]b4_symbol_type_define
[
504 * Push Parse input from external lexer
506 * @@param yyla current Symbol
508 * @@return <tt>YYACCEPT, YYABORT, YYPUSH_MORE</tt>
510 public int pushParse(Symbol yyla
)]], [[
512 * Parse input from the scanner that was specified at object construction
513 * time. Return whether the end of the input was reached successfully.
515 * @@return <tt>true</tt> if the parsing succeeds. Note that this does not
516 * imply that there were no syntax errors.
518 public bool parse()]])[
520 if (!this.pushParseInitialized
)
522 pushParseInitialize();
528 bool push_token_consumed
= true;
529 ]], [[ bool yyresult
;]b4_lac_if([[
530 // Discard the LAC context in case there still is one left from a
531 // previous invocation.
532 yylacDiscard("init");]])[]b4_parse_trace_if([[
534 yycdebugln ("Starting parse");]])[
537 ]m4_ifdef([b4_initial_action
], [
538 m4_pushdef([b4_at_dollar
], [yylloc
])dnl
539 m4_pushdef([b4_dollar_dollar
], [yylval
])dnl
540 /* User initialization code. */
541 b4_user_initial_action
542 m4_popdef([b4_dollar_dollar
])dnl
543 m4_popdef([b4_at_dollar
])])dnl
545 [ /* Initialize the stack. */
546 yystack
.push (yystate
, yylval
]b4_locations_if([, yylloc
])[);
548 label
= YYNEWSTATE
;]])[
552 /* New state. Unlike in the C/C++ skeletons, the state is already
553 pushed when we come here. */
554 case YYNEWSTATE
:]b4_parse_trace_if([[
555 yycdebugln (format("Entering state %d", yystate
));
557 yystack
.print (yyDebugStream
);]])[
560 if (yystate
== yyfinal_
)]b4_push_if([[
567 /* Take a decision. First try without lookahead. */
568 yyn
= yypact_
[yystate
];
569 if (yyPactValueIsDefault(yyn
))
578 /* Read a lookahead token. */
579 if (yytoken
== ]b4_symbol(empty
, kind
)[)
581 if (!push_token_consumed
)
582 return YYPUSH_MORE
;]])[]b4_parse_trace_if([[
583 yycdebugln ("Reading a token");]])[]b4_push_if([[
584 yytoken
= yyla
.token
;
585 yylval
= yyla
.value
;]b4_locations_if([[
586 yylloc
= yyla
.location
;]])[
587 push_token_consumed
= false;]], [[
588 Symbol yysymbol
= yylex();
589 yytoken
= yysymbol
.token();
590 yylval
= yysymbol
.value();]b4_locations_if([[
591 yylloc
= yysymbol
.location();]])[]])[
594 /* Token already converted to internal form. */]b4_parse_trace_if([[
595 yy_symbol_print ("Next token is", yytoken
, yylval
]b4_locations_if([, yylloc
])[);]])[
597 if (yytoken
== ]b4_symbol(error
, kind
)[)
599 // The scanner already issued an error message, process directly
600 // to error recovery. But do not keep the error token as
601 // lookahead, it is too special and may lead us to an endless
602 // loop in error recovery. */
603 yytoken
= ]b4_symbol(undef
, kind
)[;]b4_locations_if([[
604 yyerrloc
= yylloc
;]])[
609 /* If the proper action on seeing token YYTOKEN is to reduce or to
610 detect an error, take that action. */
612 if (yyn
< 0 || yylast_
< yyn || yycheck_
[yyn
] != yytoken
) {]b4_lac_if([[
613 if (!yylacEstablish(yystack
, yytoken
))
618 /* <= 0 means reduce or error. */
619 else if ((yyn
= yytable_
[yyn
]) <= 0)
621 if (yyTableValueIsError(yyn
))
622 label
= YYERRLAB
;]b4_lac_if([[
623 else if (!yylacEstablish(yystack
, yytoken
))
624 label
= YYERRLAB
;]])[
633 /* Shift the lookahead token. */]b4_parse_trace_if([[
634 yy_symbol_print ("Shifting", yytoken
, yylval
]b4_locations_if([, yylloc
])[);]])[
636 /* Discard the token being shifted. */
637 yytoken
= ]b4_symbol(empty
, kind
)[;
639 /* Count tokens shifted since error; after three, turn off error
641 if (yyerrstatus_
> 0)
645 yystack
.push (yystate
, yylval
]b4_locations_if([, yylloc
])[);]b4_lac_if([[
646 yylacDiscard("shift");]])[
652 /*-----------------------------------------------------------.
653 | yydefault -- do the default action for the current state. |
654 `-----------------------------------------------------------*/
656 yyn
= yydefact_
[yystate
];
663 /*-----------------------------.
664 | yyreduce -- Do a reduction. |
665 `-----------------------------*/
668 label
= yyaction (yyn
, yystack
, yylen
);
669 yystate
= yystack
.stateAt (0);
672 /*--------------------------------------.
673 | yyerrlab -- here on detecting error. |
674 `--------------------------------------*/
676 /* If not already recovering from an error, report this error. */
677 if (yyerrstatus_
== 0)
680 yyreportSyntaxError(new Context(]b4_lac_if([[this, ]])[yystack
, yytoken
]b4_locations_if([[, yylloc
]])[));
683 yyerrloc
= yylloc
;])[
684 if (yyerrstatus_
== 3)
686 /* If just tried and failed to reuse lookahead token after an
687 * error, discard it. */
689 /* Return failure if at end of input. */
690 if (yytoken
== ]b4_symbol(eof
, [kind
])[)]b4_push_if([[
697 yytoken
= ]b4_symbol(empty
, kind
)[;
700 /* Else will try to reuse lookahead token after shifting the error
705 /*-------------------------------------------------.
706 | errorlab -- error raised explicitly by YYERROR. |
707 `-------------------------------------------------*/
708 case YYERROR
:]b4_locations_if([
709 yyerrloc
= yystack
.locationAt (yylen
- 1);])[
710 /* Do not reclaim the symbols of the rule which action triggered
714 yystate
= yystack
.stateAt (0);
718 /*-------------------------------------------------------------.
719 | yyerrlab1 -- common code for both syntax error and YYERROR. |
720 `-------------------------------------------------------------*/
722 yyerrstatus_
= 3; /* Each real token shifted decrements this. */
724 // Pop stack until we find a state that shifts the error token.
727 yyn
= yypact_
[yystate
];
728 if (!yyPactValueIsDefault(yyn
))
730 yyn
+= ]b4_symbol(error
, kind
)[;
731 if (0 <= yyn
&& yyn
<= yylast_
&& yycheck_
[yyn
] == ]b4_symbol(error
, kind
)[)
739 /* Pop the current state because it cannot handle the error token. */
740 if (yystack
.height
== 1)]b4_push_if([[
747 ]b4_locations_if([ yyerrloc
= yystack
.locationAt (0);])[
749 yystate
= yystack
.stateAt (0);]b4_parse_trace_if([[
751 yystack
.print (yyDebugStream
);]])[
753 if (label
== YYABORT
)
754 /* Leave the switch. */
758 /* Muck with the stack to setup for yylloc. */
759 yystack
.push (0, yy_semantic_null
, yylloc
);
760 yystack
.push (0, yy_semantic_null
, yyerrloc
);
761 yyloc
= yylloc_from_stack (yystack
, 2);
764 /* Shift the error token. */]b4_lac_if([[
765 yylacDiscard("error recovery");]])[]b4_parse_trace_if([[
766 yy_symbol_print ("Shifting", to
!SymbolKind (yystos_
[yyn
]), yylval
]b4_locations_if([, yyloc
])[);]])[
768 yystack
.push (yyn
, yylval
]b4_locations_if([, yyloc
])[);
773 case YYACCEPT
:]b4_push_if([[
774 this.pushParseInitialized
= false;]b4_parse_trace_if([[
776 yystack
.print (yyDebugStream
);]])[
777 return YYACCEPT
;]], [[
783 case YYABORT
:]b4_push_if([[
784 this.pushParseInitialized
= false;]b4_parse_trace_if([[
786 yystack
.print (yyDebugStream
);]])[
787 return YYABORT
;]], [[
791 ]b4_push_if([[]], [[ ][case YYRETURN
:]b4_parse_trace_if([[
793 yystack
.print (yyDebugStream
);]])[
800 bool pushParseInitialized
= false;
803 * (Re-)Initialize the state of the push parser.
805 public void pushParseInitialize()
808 /* Lookahead and lookahead in internal form. */
809 this.yytoken
= ]b4_symbol(empty
, kind
)[;
815 destroy(this.yystack
);
816 this.label
= YYNEWSTATE
;
818 destroy(this.yylacStack
);
819 this.yylacEstablished
= false;]])[
821 /* Error handling. */
824 /* The location where the error started. */
825 this.yyerrloc
= Location(Position(), Position());
826 this.yylloc
= Location(Position(), Position());])[
828 /* Semantic value of the lookahead. */
829 //destroy(this.yylval);
831 /* Initialize the stack. */
832 yystack
.push(this.yystate
, this.yylval
]b4_locations_if([, this.yylloc
])[);
834 this.pushParseInitialized
= true;
837 * Parse input from the scanner that was specified at object construction
838 * time. Return whether the end of the input was reached successfully.
839 * This version of parse() is defined only when api.push-push=both.
841 * @@return <tt>true</tt> if the parsing succeeds. Note that this does not
842 * imply that there were no syntax errors.
848 status
= this.pushParse(yylex());
849 } while (status
== YYPUSH_MORE
);
850 return status
== YYACCEPT
;
853 // Generate an error message.
854 private final void yyreportSyntaxError(Context yyctx
)
855 {]b4_parse_error_bmatch(
857 yylexer
.reportSyntaxError(yyctx
);]],
859 if (yyctx
.getToken() != ]b4_symbol(empty
, kind
)[)
861 // FIXME: This method of building the message is not compatible
862 // with internationalization.
863 immutable int argmax
= 5;
864 SymbolKind
[] yyarg
= new SymbolKind
[argmax
];
865 int yycount
= yysyntaxErrorArguments(yyctx
, yyarg
, argmax
);
866 string res
, yyformat
;
870 yyformat
= YY_("syntax error, unexpected %s");
871 res
= format(yyformat
, yyarg
[0]);
874 yyformat
= YY_("syntax error, unexpected %s, expecting %s");
875 res
= format(yyformat
, yyarg
[0], yyarg
[1]);
878 yyformat
= YY_("syntax error, unexpected %s, expecting %s or %s");
879 res
= format(yyformat
, yyarg
[0], yyarg
[1], yyarg
[2]);
882 yyformat
= YY_("syntax error, unexpected %s, expecting %s or %s or %s");
883 res
= format(yyformat
, yyarg
[0], yyarg
[1], yyarg
[2], yyarg
[3]);
886 yyformat
= YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
887 res
= format(yyformat
, yyarg
[0], yyarg
[1], yyarg
[2], yyarg
[3], yyarg
[4]);
890 res
= YY_("syntax error");
893 yyerror(]b4_locations_if([yyctx
.getLocation(), ])[res
);
896 yyerror(]b4_locations_if([yyctx
.getLocation(), ])[YY_("syntax error"));]])[
899 ]b4_parse_error_bmatch(
901 private int yysyntaxErrorArguments(Context yyctx
, SymbolKind
[] yyarg
, int yyargn
) {
902 /* There are many possibilities here to consider:
903 - If this state is a consistent state with a default action,
904 then the only way this function was invoked is if the
905 default action is an error action. In that case, don't
906 check for expected tokens because there are none.
907 - The only way there can be no lookahead present (in tok) is
908 if this state is a consistent state with a default action.
909 Thus, detecting the absence of a lookahead is sufficient to
910 determine that there is no unexpected or expected token to
911 report. In that case, just report a simple "syntax error".
912 - Don't assume there isn't a lookahead just because this
913 state is a consistent state with a default action. There
914 might have been a previous inconsistent state, consistent
915 state with a non-default action, or user semantic action
916 that manipulated yychar. (However, yychar is currently out
917 of scope during semantic actions.)
918 - Of course, the expected token list depends on states to
919 have correct lookahead information, and it depends on the
920 parser not to perform extra reductions after fetching a
921 lookahead from the scanner and before detecting a syntax
922 error. Thus, state merging (from LALR or IELR) and default
923 reductions corrupt the expected token list. However, the
924 list is correct for canonical LR with one exception: it
925 will still contain any token that will not be accepted due
926 to an error action in a later state.
929 if (yyctx
.getToken() != ]b4_symbol(empty
, kind
)[)
932 yyarg
[yycount
] = yyctx
.getToken();
934 yycount
+= yyctx
.getExpectedTokens(yyarg
, 1, yyargn
);
942 * Information needed to get the list of expected tokens and to forge
943 * a syntax error diagnostic.
945 public static final class Context
947 private ]b4_parser_class
[ yyparser
;]])[
948 private const(YYStack
) yystack
;
949 private SymbolKind yytoken
;]b4_locations_if([[
950 private const(Location
) yylocation
;]])[
952 this(]b4_lac_if([[]b4_parser_class
[ parser
, ]])[YYStack stack
, SymbolKind kind
]b4_locations_if([[, Location loc
]])[)
954 yyparser
= parser
;]])[
956 yytoken
= kind
;]b4_locations_if([[
957 yylocation
= loc
;]])[
960 final SymbolKind
getToken() const
965 final const(Location
) getLocation() const
970 * Put in YYARG at most YYARGN of the expected tokens given the
971 * current YYCTX, and return the number of tokens stored in YYARG. If
972 * YYARG is null, return the number of expected tokens (guaranteed to
973 * be less than YYNTOKENS).
975 int getExpectedTokens(SymbolKind
[] yyarg
, int yyargn
)]b4_lac_if([[]], [[ const]])[
977 return getExpectedTokens(yyarg
, 0, yyargn
);
980 int getExpectedTokens(SymbolKind
[] yyarg
, int yyoffset
, int yyargn
)]b4_lac_if([[]], [[ const]])[
982 int yycount
= yyoffset
;]b4_lac_if([b4_parse_trace_if([[
983 // Execute LAC once. We don't care if it is successful, we
984 // only do it for the sake of debugging output.
986 if (!yyparser
.yylacEstablished
)
987 yyparser
.yylacCheck(yystack
, yytoken
);
989 for (int yyx
= 0; yyx
< yyntokens_
; ++yyx
)
991 SymbolKind yysym
= SymbolKind(yyx
);
992 if (yysym
!= ]b4_symbol(error
, kind
)[
993 && yysym
!= ]b4_symbol(undef
, kind
)[
994 && yyparser
.yylacCheck(yystack
, yysym
))
998 else if (yycount
== yyargn
)
1001 yyarg
[yycount
++] = yysym
;
1004 int yyn
= yypact_
[this.yystack
.stateAt(0)];
1005 if (!yyPactValueIsDefault(yyn
))
1007 /* Start YYX at -YYN if negative to avoid negative
1008 indexes in YYCHECK. In other words, skip the first
1009 -YYN actions for this state because they are default
1011 int yyxbegin
= yyn
< 0 ?
-yyn
: 0;
1012 /* Stay within bounds of both yycheck and yytname. */
1013 int yychecklim
= yylast_
- yyn
+ 1;
1014 int yyxend
= yychecklim
< yyntokens_ ? yychecklim
: yyntokens_
;
1015 for (int yyx
= yyxbegin
; yyx
< yyxend
; ++yyx
)
1016 if (yycheck_
[yyx
+ yyn
] == yyx
&& yyx
!= ]b4_symbol(error
, kind
)[
1017 && !yyTableValueIsError(yytable_
[yyx
+ yyn
]))
1021 else if (yycount
== yyargn
)
1024 yyarg
[yycount
++] = SymbolKind(yyx
);
1027 if (yyarg
!is null && yycount
== yyoffset
&& yyoffset
< yyargn
)
1028 yyarg
[yyoffset
] = ]b4_symbol(empty
, kind
)[;
1029 return yycount
- yyoffset
;
1034 /** Check the lookahead yytoken.
1035 * \returns true iff the token will be eventually shifted.
1037 bool yylacCheck(const YYStack yystack
, SymbolKind yytoken
)
1039 // Logically, the yylacStack's lifetime is confined to this function.
1040 // Clear it, to get rid of potential left-overs from previous call.
1041 destroy(yylacStack
);
1042 // Reduce until we encounter a shift and thereby accept the token.
1043 ]b4_parse_trace_if([[
1044 yycdebug("LAC: checking lookahead " ~ format("%s", yytoken
) ~ ":");]])[
1048 int topState
= (yylacStack
.length
== 0
1049 ? yystack
.stateAt(lacTop
)
1050 : yylacStack
[$ - 1]);
1051 int yyrule
= yypact_
[topState
];
1052 if (yyPactValueIsDefault(yyrule
)
1053 ||
(yyrule
+= yytoken
) < 0 || yylast_
< yyrule
1054 || yycheck_
[yyrule
] != yytoken
)
1056 // Use the default action.
1057 yyrule
= yydefact_
[+topState
];
1059 {]b4_parse_trace_if([[
1060 yycdebugln(" Err");]])[
1066 // Use the action from yytable.
1067 yyrule
= yytable_
[yyrule
];
1068 if (yyTableValueIsError(yyrule
))
1069 {]b4_parse_trace_if([[
1070 yycdebugln(" Err");]])[
1074 {]b4_parse_trace_if([[
1075 yycdebugln(" S" ~ to
!string(yyrule
));]])[
1080 // By now we know we have to simulate a reduce.
1081 ]b4_parse_trace_if([[
1082 yycdebug(" R" ~ to
!string(yyrule
- 1));]])[
1083 // Pop the corresponding number of values from the stack.
1085 int yylen
= yyr2_
[yyrule
];
1086 // First pop from the LAC stack as many tokens as possible.
1087 int lacSize
= cast (int) yylacStack
.length
;
1088 if (yylen
< lacSize
)
1090 yylacStack
.length
-= yylen
;
1093 else if (lacSize
!= 0)
1095 destroy(yylacStack
);
1098 // Only afterwards look at the main stack.
1099 // We simulate popping elements by incrementing lacTop.
1102 // Keep topState in sync with the updated stack.
1103 topState
= (yylacStack
.length
== 0
1104 ? yystack
.stateAt(lacTop
)
1105 : yylacStack
[$ - 1]);
1106 // Push the resulting state of the reduction.
1107 int state
= yyLRGotoState(topState
, yyr1_
[yyrule
]);]b4_parse_trace_if([[
1108 yycdebug(" G" ~ to
!string(state
));]])[
1109 yylacStack
.length
++;
1110 yylacStack
[$ - 1] = state
;
1114 /** Establish the initial context if no initial context currently exists.
1115 * \returns true iff the token will be eventually shifted.
1117 bool yylacEstablish(YYStack yystack
, SymbolKind yytoken
)
1119 /* Establish the initial context for the current lookahead if no initial
1120 context is currently established.
1122 We define a context as a snapshot of the parser stacks. We define
1123 the initial context for a lookahead as the context in which the
1124 parser initially examines that lookahead in order to select a
1125 syntactic action. Thus, if the lookahead eventually proves
1126 syntactically unacceptable (possibly in a later context reached via a
1127 series of reductions), the initial context can be used to determine
1128 the exact set of tokens that would be syntactically acceptable in the
1129 lookahead's place. Moreover, it is the context after which any
1130 further semantic actions would be erroneous because they would be
1131 determined by a syntactically unacceptable token.
1133 yylacEstablish should be invoked when a reduction is about to be
1134 performed in an inconsistent state (which, for the purposes of LAC,
1135 includes consistent states that don't know they're consistent because
1136 their default reductions have been disabled).
1138 For parse.lac=full, the implementation of yylacEstablish is as
1139 follows. If no initial context is currently established for the
1140 current lookahead, then check if that lookahead can eventually be
1141 shifted if syntactic actions continue from the current context. */
1142 if (yylacEstablished
)
1145 {]b4_parse_trace_if([[
1146 yycdebugln("LAC: initial context established for " ~ format("%s", yytoken
));]])[
1147 yylacEstablished
= true;
1148 return yylacCheck(yystack
, yytoken
);
1152 /** Discard any previous initial lookahead context because of event.
1153 * \param event the event which caused the lookahead to be discarded.
1154 * Only used for debbuging output. */
1155 void yylacDiscard(string event
)
1157 /* Discard any previous initial lookahead context because of Event,
1158 which may be a lookahead change or an invalidation of the currently
1159 established initial context for the current lookahead.
1161 The most common example of a lookahead change is a shift. An example
1162 of both cases is syntax error recovery. That is, a syntax error
1163 occurs when the lookahead is syntactically erroneous for the
1164 currently established initial context, so error recovery manipulates
1165 the parser stacks to try to find a new initial context in which the
1166 current lookahead is syntactically acceptable. If it fails to find
1167 such a context, it discards the lookahead. */
1168 if (yylacEstablished
)
1169 {]b4_parse_trace_if([[
1170 yycdebugln("LAC: initial context discarded due to " ~ event
);]])[
1171 yylacEstablished
= false;
1175 /** The stack for LAC.
1176 * Logically, the yylacStack's lifetime is confined to the function
1177 * yylacCheck. We just store it as a member of this class to hold
1178 * on to the memory and to avoid frequent reallocations.
1181 /** Whether an initial LAC context was established. */
1182 bool yylacEstablished
;
1186 * Whether the given <code>yypact_</code> value indicates a defaulted state.
1187 * @@param yyvalue the value to check
1189 private static bool yyPactValueIsDefault(int yyvalue
)
1191 return yyvalue
== yypact_ninf_
;
1195 * Whether the given <code>yytable_</code> value indicates a syntax error.
1196 * @@param yyvalue the value to check
1198 private static bool yyTableValueIsError(int yyvalue
)
1200 return yyvalue
== yytable_ninf_
;
1203 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
1205 private static immutable ]b4_int_type_for([b4_pact
])[ yypact_ninf_
= ]b4_pact_ninf
[;
1207 /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
1208 positive, shift that token. If negative, reduce the rule which
1209 number is the opposite. If YYTABLE_NINF_, syntax error. */
1210 private static immutable ]b4_int_type_for([b4_table
])[ yytable_ninf_
= ]b4_table_ninf
[;
1212 ]b4_parser_tables_define
[
1214 ]b4_parse_trace_if([[
1215 /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
1216 private static immutable ]b4_int_type_for([b4_rline
])[[] yyrline_
=
1221 // Report on the debug stream that the rule yyrule is going to be reduced.
1222 private final void yy_reduce_print (int yyrule
, ref YYStack yystack
)
1227 int yylno
= yyrline_
[yyrule
];
1228 int yynrhs
= yyr2_
[yyrule
];
1229 /* Print the symbols being reduced, and their result. */
1230 yycdebugln (format("Reducing stack by rule %d (line %d):",
1231 yyrule
- 1, yylno
));
1233 /* The symbols being reduced. */
1234 for (int yyi
= 0; yyi
< yynrhs
; yyi
++)
1235 yy_symbol_print (format(" $%d =", yyi
+ 1),
1236 to
!SymbolKind (yystos_
[yystack
.stateAt(yynrhs
- (yyi
+ 1))]),
1237 ]b4_rhs_value(yynrhs
, yyi
+ 1)b4_locations_if([,
1238 b4_rhs_location(yynrhs
, yyi
+ 1)])[);
1242 private static auto yytranslate_ (int t
)
1244 ]b4_api_token_raw_if(
1245 [[ return SymbolKind(t
);]],
1246 [[ /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
1247 immutable ]b4_int_type_for([b4_translate
])[[] translate_table
=
1252 // Last valid token kind.
1253 immutable int code_max
= ]b4_code_max
[;
1256 return ]b4_symbol(eof
, kind
)[;
1257 else if (t
<= code_max
)
1258 return SymbolKind(translate_table
[t
]);
1260 return ]b4_symbol(undef
, kind
)[;]])[
1263 private static immutable int yylast_
= ]b4_last
[;
1264 private static immutable int yynnts_
= ]b4_nterms_number
[;
1265 private static immutable int yyfinal_
= ]b4_final_state_number
[;
1266 private static immutable int yyntokens_
= ]b4_tokens_number
[;
1268 private final struct YYStackElement
{
1270 Value value
;]b4_locations_if(
1271 b4_location_type
[[] location
;])[
1274 private final struct YYStack
{
1275 private YYStackElement
[] stack
= [];
1277 public final ulong height()
1279 return stack
.length
;
1282 public final void push (int state
, Value value
]dnl
1283 b4_locations_if([, ref Location loc
])[)
1285 stack
~= YYStackElement(state
, value
]b4_locations_if([, loc
])[);
1288 public final void pop ()
1293 public final void pop (int num
)
1295 stack
.length
-= num
;
1298 public final int stateAt (int i
) const
1300 return stack
[$-i
-1].state
;
1304 public final ref Location
locationAt (int i
)
1306 return stack
[$-i
-1].location
;
1309 public final ref Value
valueAt (int i
)
1311 return stack
[$-i
-1].value
;
1313 ]b4_parse_trace_if([[
1314 // Print the state stack on the debug stream.
1315 public final void print (File stream
)
1317 stream
.write ("Stack now");
1318 for (int i
= 0; i
< stack
.length
; i
++)
1319 stream
.write (" ", stack
[i
].state
);
1323 ]b4_percent_code_get
[
1325 ]b4_percent_code_get([[epilogue
]])[]dnl