d: examples: reduce scopes
[bison.git] / data / skeletons / lalr1.d
blob62b12d1c2749296a1409ff8a3937b9eaebab6225
1 # D skeleton for Bison -*- autoconf -*-
3 # Copyright (C) 2007-2012, 2019-2021 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 <http://www.gnu.org/licenses/>.
18 m4_include(b4_skeletonsdir/[d.m4])
20 # parse.lac
21 b4_percent_define_default([[parse.lac]], [[none]])
22 b4_percent_define_check_values([[[[parse.lac]], [[full]], [[none]]]])
23 b4_define_flag_if([lac])
24 m4_define([b4_lac_flag],
25 [m4_if(b4_percent_define_get([[parse.lac]]),
26 [none], [[0]], [[1]])])
28 b4_output_begin([b4_parser_file_name])
29 b4_copyright([Skeleton implementation for Bison LALR(1) parsers in D],
30 [2007-2012, 2019-2021])[
31 ]b4_disclaimer[
32 ]b4_percent_define_ifdef([package], [module b4_percent_define_get([package]);
33 ])[
34 version(D_Version2) {
35 } else {
36 static assert(false, "need compiler for D Version 2");
39 ]b4_user_pre_prologue[
40 ]b4_user_post_prologue[
41 ]b4_percent_code_get([[imports]])[
42 import std.format;
43 import std.conv;
45 /**
46 * Handle error message internationalisation.
48 static if (!is(typeof(YY_))) {
49 version(YYENABLE_NLS)
51 version(ENABLE_NLS)
53 extern(C) char* dgettext(const char*, const char*);
54 string YY_(const char* s)
56 return to!string(dgettext("bison-runtime", s));
60 static if (!is(typeof(YY_)))
62 pragma(inline, true)
63 string YY_(string msg) { return msg; }
67 /**
68 * A Bison parser, automatically generated from <tt>]m4_bpatsubst(b4_file_name, [^"\(.*\)"$], [\1])[</tt>.
70 * @@author LALR (1) parser skeleton written by Paolo Bonzini.
71 * Port to D language was done by Oliver Mangold.
74 /**
75 * Communication interface between the scanner and the Bison-generated
76 * parser <tt>]b4_parser_class[</tt>.
78 public interface Lexer
80 /**
81 * Entry point for the scanner. Returns the token identifier corresponding
82 * to the next token and prepares to return the semantic value
83 * ]b4_locations_if([and beginning/ending positions ])[of the token.
84 * @@return the token identifier corresponding to the next token. */
85 Symbol yylex ();
87 /**
88 * Entry point for error reporting. Emits an error
89 * ]b4_locations_if([referring to the given location ])[in a user-defined way.
90 *]b4_locations_if([[
91 * @@param loc The location of the element to which the
92 * error message is related]])[
93 * @@param s The string for the error message. */
94 void yyerror (]b4_locations_if([[const Location loc, ]])[string s);
95 ]b4_parse_error_bmatch([custom], [[
96 /**
97 * Build and emit a "syntax error" message in a user-defined way.
99 * @@param ctx The context of the error.
101 void reportSyntaxError(]b4_parser_class[.Context ctx);
102 ]])[
105 ]b4_public_types_declare[
107 ]b4_locations_if([b4_position_type_if([[
108 static assert(__traits(compiles,
109 (new Position[1])[0]=(new Position[1])[0]),
110 "struct/class Position must be default-constructible "
111 "and assignable");
112 static assert(__traits(compiles, (new string[1])[0]=(new Position).toString()),
113 "error: struct/class Position must have toString method");
114 ]], [[
116 * A struct denoting a point in the input.*/
117 public struct ]b4_position_type[ {
119 /** The column index within the line of input. */
120 public int column = 1;
121 /** The line number within an input file. */
122 public int line = 1;
123 /** The name of the input file. */
124 public string filename = null;
127 * A string representation of the position. */
128 public string toString() const {
129 if (filename)
130 return format("%s:%d.%d", filename, line, column);
131 else
132 return format("%d.%d", line, column);
135 ]])b4_location_type_if([[
136 static assert(__traits(compiles, (new Location((new Position[1])[0]))) &&
137 __traits(compiles, (new Location((new Position[1])[0], (new Position[1])[0]))),
138 "error: struct/class Location must have "
139 "default constructor and constructors this(Position) and this(Position, Position).");
140 static assert(__traits(compiles, (new Location[1])[0].begin=(new Location[1])[0].begin) &&
141 __traits(compiles, (new Location[1])[0].begin=(new Location[1])[0].end) &&
142 __traits(compiles, (new Location[1])[0].end=(new Location[1])[0].begin) &&
143 __traits(compiles, (new Location[1])[0].end=(new Location[1])[0].end),
144 "error: struct/class Location must have assignment-compatible "
145 "members/properties 'begin' and 'end'.");
146 static assert(__traits(compiles, (new string[1])[0]=(new Location[1])[0].toString()),
147 "error: struct/class Location must have toString method.");
149 private immutable bool yy_location_is_class = !__traits(compiles, *(new Location((new Position[1])[0])));]], [[
151 * A struct defining a pair of positions. Positions, defined by the
152 * <code>Position</code> struct, denote a point in the input.
153 * Locations represent a part of the input through the beginning
154 * and ending positions. */
155 public struct ]b4_location_type[
157 /** The first, inclusive, position in the range. */
158 public Position begin;
160 /** The first position beyond the range. */
161 public Position end;
164 * Create a <code>Location</code> denoting an empty range located at
165 * a given point.
166 * @@param loc The position at which the range is anchored. */
167 public this(Position loc)
169 this.begin = this.end = loc;
173 * Create a <code>Location</code> from the endpoints of the range.
174 * @@param begin The first position included in the range.
175 * @@param end The first position beyond the range. */
176 public this(Position begin, Position end)
178 this.begin = begin;
179 this.end = end;
183 * Reset initial location to final location.
185 public void step()
187 this.begin = this.end;
191 * A representation of the location.
193 public string toString() const
195 auto end_col = 0 < end.column ? end.column - 1 : 0;
196 auto res = begin.toString ();
197 if (end.filename && begin.filename != end.filename)
198 res ~= "-" ~ format("%s:%d.%d", end.filename, end.line, end_col);
199 else if (begin.line < end.line)
200 res ~= "-" ~ format("%d.%d", end.line, end_col);
201 else if (begin.column < end_col)
202 res ~= "-" ~ format("%d", end_col);
203 return res;
207 private immutable bool yy_location_is_class = false;
209 ]])])m4_ifdef([b4_user_union_members], [private union YYSemanticType
211 b4_user_union_members
212 };],
213 [m4_if(b4_tag_seen_flag, 0,
214 [[private alias int YYSemanticType;]])])[
215 ]b4_token_enums[
216 ]b4_parser_class_declaration[
218 ]b4_identification[
220 ]b4_declare_symbol_enum[
222 ]b4_locations_if([[
223 private final Location yylloc_from_stack (ref YYStack rhs, int n)
225 static if (yy_location_is_class) {
226 if (n > 0)
227 return new Location (rhs.locationAt (n-1).begin, rhs.locationAt (0).end);
228 else
229 return new Location (rhs.locationAt (0).end);
230 } else {
231 if (n > 0)
232 return Location (rhs.locationAt (n-1).begin, rhs.locationAt (0).end);
233 else
234 return Location (rhs.locationAt (0).end);
236 }]])[
238 ]b4_lexer_if([[ private class YYLexer implements Lexer {
239 ]b4_percent_code_get([[lexer]])[
241 ]])[
242 /** The object doing lexical analysis for us. */
243 private Lexer yylexer;
245 ]b4_parse_param_vars[
247 ]b4_lexer_if([[
249 * Instantiate the Bison-generated parser.
251 public this] (b4_parse_param_decl([b4_lex_param_decl])[) {
252 ]b4_percent_code_get([[init]])[]b4_lac_if([[
253 this.yylacStack = new int[];
254 this.yylacEstablished = false;]])[
255 this (new YYLexer(]b4_lex_param_call[));
257 ]])[
260 * Instantiate the Bison-generated parser.
261 * @@param yylexer The scanner that will supply tokens to the parser.
263 ]b4_lexer_if([[protected]], [[public]]) [this (]b4_parse_param_decl([[Lexer yylexer]])[) {
264 this.yylexer = yylexer;]b4_parse_trace_if([[
265 this.yyDebugStream = stderr;]])[
266 ]b4_parse_param_cons[
268 ]b4_parse_trace_if([[
269 private File yyDebugStream;
272 * The <tt>File</tt> on which the debugging output is
273 * printed.
275 public File getDebugStream () { return yyDebugStream; }
278 * Set the <tt>std.File</tt> on which the debug output is printed.
279 * @@param s The stream that is used for debugging output.
281 public final void setDebugStream(File s) { yyDebugStream = s; }
283 private int yydebug = 0;
286 * Answer the verbosity of the debugging output; 0 means that all kinds of
287 * output from the parser are suppressed.
289 public final int getDebugLevel() { return yydebug; }
292 * Set the verbosity of the debugging output; 0 means that all kinds of
293 * output from the parser are suppressed.
294 * @@param level The verbosity level for debugging output.
296 public final void setDebugLevel(int level) { yydebug = level; }
298 protected final void yycdebug (string s) {
299 if (0 < yydebug)
300 yyDebugStream.write (s);
303 protected final void yycdebugln (string s) {
304 if (0 < yydebug)
305 yyDebugStream.writeln (s);
307 ]])[
308 private final ]b4_parser_class[.Symbol yylex () {
309 return yylexer.yylex ();
312 protected final void yyerror (]b4_locations_if([[const Location loc, ]])[string s) {
313 yylexer.yyerror (]b4_locations_if([loc, ])[s);
317 * The number of syntax errors so far.
319 public int numberOfErrors() const { return yynerrs_; }
320 private int yynerrs_ = 0;
323 * Returned by a Bison action in order to stop the parsing process and
324 * return success (<tt>true</tt>). */
325 public static immutable int YYACCEPT = 0;
328 * Returned by a Bison action in order to stop the parsing process and
329 * return failure (<tt>false</tt>). */
330 public static immutable int YYABORT = 1;
333 * Returned by a Bison action in order to start error recovery without
334 * printing an error message. */
335 public static immutable int YYERROR = 2;
337 // Internal return codes that are not supported for user semantic
338 // actions.
339 private static immutable int YYERRLAB = 3;
340 private static immutable int YYNEWSTATE = 4;
341 private static immutable int YYDEFAULT = 5;
342 private static immutable int YYREDUCE = 6;
343 private static immutable int YYERRLAB1 = 7;
344 private static immutable int YYRETURN = 8;
345 ]b4_locations_if([
346 private static immutable YYSemanticType yy_semantic_null;])[
347 private int yyerrstatus_ = 0;
349 private void yyerrok()
351 yyerrstatus_ = 0;
355 * Whether error recovery is being done. In this state, the parser
356 * reads token until it reaches a known state, and then restarts normal
357 * operation. */
358 public final bool recovering ()
360 return yyerrstatus_ == 0;
363 /** Compute post-reduction state.
364 * @@param yystate the current state
365 * @@param yysym the nonterminal to push on the stack
367 private int yyLRGotoState(int yystate, int yysym) {
368 int yyr = yypgoto_[yysym - yyntokens_] + yystate;
369 if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate)
370 return yytable_[yyr];
371 else
372 return yydefgoto_[yysym - yyntokens_];
375 private int yyaction (int yyn, ref YYStack yystack, int yylen)
377 Value yyval;]b4_locations_if([[
378 Location yyloc = yylloc_from_stack (yystack, yylen);]])[
380 /* If YYLEN is nonzero, implement the default value of the action:
381 `$$ = $1'. Otherwise, use the top of the stack.
383 Otherwise, the following line sets YYVAL to garbage.
384 This behavior is undocumented and Bison
385 users should not rely upon it. */
386 if (yylen > 0)
387 yyval = yystack.valueAt (yylen - 1);
388 else
389 yyval = yystack.valueAt (0);
391 ]b4_parse_trace_if([[
392 yy_reduce_print (yyn, yystack);]])[
394 switch (yyn)
396 ]b4_user_actions[
397 default: break;
400 ]b4_parse_trace_if([[
401 yy_symbol_print ("-> $$ =", to!SymbolKind (yyr1_[yyn]), yyval]b4_locations_if([, yyloc])[);]])[
403 yystack.pop (yylen);
404 yylen = 0;
406 /* Shift the result of the reduction. */
407 int yystate = yyLRGotoState(yystack.stateAt(0), yyr1_[yyn]);
408 yystack.push (yystate, yyval]b4_locations_if([, yyloc])[);
409 return YYNEWSTATE;
412 ]b4_parse_trace_if([[
413 /*--------------------------------.
414 | Print this symbol on YYOUTPUT. |
415 `--------------------------------*/
417 private final void yy_symbol_print (string s, SymbolKind yykind,
418 ref Value yyval]b4_locations_if([, ref Location yyloc])[)
420 if (0 < yydebug)
422 File yyo = yyDebugStream;
423 yyo.write(s);
424 yyo.write(yykind < yyntokens_ ? " token " : " nterm ");
425 yyo.write(format("%s", yykind));
426 yyo.write(" ("]b4_locations_if([ ~ yyloc.toString() ~ ": "])[);
427 ]b4_symbol_actions([printer])[
428 yyo.write(")\n");
431 ]])[
432 ]b4_symbol_type_define[
434 * Parse input from the scanner that was specified at object construction
435 * time. Return whether the end of the input was reached successfully.
437 * @@return <tt>true</tt> if the parsing succeeds. Note that this does not
438 * imply that there were no syntax errors.
440 public bool parse ()
442 // Lookahead symbol kind.
443 SymbolKind yytoken = ]b4_symbol(empty, kind)[;
445 /* State. */
446 int yyn = 0;
447 int yylen = 0;
448 int yystate = 0;
450 YYStack yystack;
452 /* Error handling. */
453 ]b4_locations_if([[
454 /// The location where the error started.
455 Location yyerrloc;
457 /// Location of the lookahead.
458 Location yylloc;
460 /// @@$.
461 Location yyloc;]])[
463 /// Semantic value of the lookahead.
464 Value yylval;
466 bool yyresult;]b4_lac_if([[
467 // Discard the LAC context in case there still is one left from a
468 // previous invocation.
469 yylacDiscard("init");]])[]b4_parse_trace_if([[
471 yycdebugln ("Starting parse");]])[
472 yyerrstatus_ = 0;
474 ]m4_ifdef([b4_initial_action], [
475 m4_pushdef([b4_at_dollar], [yylloc])dnl
476 m4_pushdef([b4_dollar_dollar], [yylval])dnl
477 /* User initialization code. */
478 b4_user_initial_action
479 m4_popdef([b4_dollar_dollar])dnl
480 m4_popdef([b4_at_dollar])])dnl
482 [ /* Initialize the stack. */
483 yystack.push (yystate, yylval]b4_locations_if([, yylloc])[);
485 int label = YYNEWSTATE;
486 for (;;)
487 final switch (label)
489 /* New state. Unlike in the C/C++ skeletons, the state is already
490 pushed when we come here. */
491 case YYNEWSTATE:]b4_parse_trace_if([[
492 yycdebugln (format("Entering state %d", yystate));
493 if (0 < yydebug)
494 yystack.print (yyDebugStream);]])[
496 /* Accept? */
497 if (yystate == yyfinal_)
498 return true;
500 /* Take a decision. First try without lookahead. */
501 yyn = yypact_[yystate];
502 if (yyPactValueIsDefault(yyn))
504 label = YYDEFAULT;
505 break;
508 /* Read a lookahead token. */
509 if (yytoken == ]b4_symbol(empty, kind)[)
510 {]b4_parse_trace_if([[
511 yycdebugln ("Reading a token");]])[
512 Symbol yysymbol = yylex();
513 yytoken = yysymbol.token();
514 yylval = yysymbol.value();]b4_locations_if([[
515 yylloc = yysymbol.location();]])[
518 /* Token already converted to internal form. */]b4_parse_trace_if([[
519 yy_symbol_print ("Next token is", yytoken, yylval]b4_locations_if([, yylloc])[);]])[
521 if (yytoken == ]b4_symbol(error, kind)[)
523 // The scanner already issued an error message, process directly
524 // to error recovery. But do not keep the error token as
525 // lookahead, it is too special and may lead us to an endless
526 // loop in error recovery. */
527 yytoken = ]b4_symbol(undef, kind)[;]b4_locations_if([[
528 yyerrloc = yylloc;]])[
529 label = YYERRLAB1;
531 else
533 /* If the proper action on seeing token YYTOKEN is to reduce or to
534 detect an error, take that action. */
535 yyn += yytoken;
536 if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yytoken) {]b4_lac_if([[
537 if (!yylacEstablish(yystack, yytoken))
538 label = YYERRLAB;
539 else]])[
540 label = YYDEFAULT;
542 /* <= 0 means reduce or error. */
543 else if ((yyn = yytable_[yyn]) <= 0)
545 if (yyTableValueIsError(yyn))
546 label = YYERRLAB;]b4_lac_if([[
547 else if (!yylacEstablish(yystack, yytoken))
548 label = YYERRLAB;]])[
549 else
551 yyn = -yyn;
552 label = YYREDUCE;
555 else
557 /* Shift the lookahead token. */]b4_parse_trace_if([[
558 yy_symbol_print ("Shifting", yytoken, yylval]b4_locations_if([, yylloc])[);]])[
560 /* Discard the token being shifted. */
561 yytoken = ]b4_symbol(empty, kind)[;
563 /* Count tokens shifted since error; after three, turn off error
564 * status. */
565 if (yyerrstatus_ > 0)
566 --yyerrstatus_;
568 yystate = yyn;
569 yystack.push (yystate, yylval]b4_locations_if([, yylloc])[);]b4_lac_if([[
570 yylacDiscard("shift");]])[
571 label = YYNEWSTATE;
574 break;
576 /*-----------------------------------------------------------.
577 | yydefault -- do the default action for the current state. |
578 `-----------------------------------------------------------*/
579 case YYDEFAULT:
580 yyn = yydefact_[yystate];
581 if (yyn == 0)
582 label = YYERRLAB;
583 else
584 label = YYREDUCE;
585 break;
587 /*-----------------------------.
588 | yyreduce -- Do a reduction. |
589 `-----------------------------*/
590 case YYREDUCE:
591 yylen = yyr2_[yyn];
592 label = yyaction (yyn, yystack, yylen);
593 yystate = yystack.stateAt (0);
594 break;
596 /*--------------------------------------.
597 | yyerrlab -- here on detecting error. |
598 `--------------------------------------*/
599 case YYERRLAB:
600 /* If not already recovering from an error, report this error. */
601 if (yyerrstatus_ == 0)
603 ++yynerrs_;
604 yyreportSyntaxError(new Context(]b4_lac_if([[this, ]])[yystack, yytoken]b4_locations_if([[, yylloc]])[));
606 ]b4_locations_if([
607 yyerrloc = yylloc;])[
608 if (yyerrstatus_ == 3)
610 /* If just tried and failed to reuse lookahead token after an
611 * error, discard it. */
613 /* Return failure if at end of input. */
614 if (yytoken == ]b4_symbol(eof, [kind])[)
615 return false;
616 else
617 yytoken = ]b4_symbol(empty, kind)[;
620 /* Else will try to reuse lookahead token after shifting the error
621 * token. */
622 label = YYERRLAB1;
623 break;
625 /*-------------------------------------------------.
626 | errorlab -- error raised explicitly by YYERROR. |
627 `-------------------------------------------------*/
628 case YYERROR:]b4_locations_if([
629 yyerrloc = yystack.locationAt (yylen - 1);])[
630 /* Do not reclaim the symbols of the rule which action triggered
631 this YYERROR. */
632 yystack.pop (yylen);
633 yylen = 0;
634 yystate = yystack.stateAt (0);
635 label = YYERRLAB1;
636 break;
638 /*-------------------------------------------------------------.
639 | yyerrlab1 -- common code for both syntax error and YYERROR. |
640 `-------------------------------------------------------------*/
641 case YYERRLAB1:
642 yyerrstatus_ = 3; /* Each real token shifted decrements this. */
644 // Pop stack until we find a state that shifts the error token.
645 for (;;)
647 yyn = yypact_[yystate];
648 if (!yyPactValueIsDefault(yyn))
650 yyn += ]b4_symbol(error, kind)[;
651 if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == ]b4_symbol(error, kind)[)
653 yyn = yytable_[yyn];
654 if (0 < yyn)
655 break;
659 /* Pop the current state because it cannot handle the error token. */
660 if (yystack.height == 1)
661 return false;
663 ]b4_locations_if([ yyerrloc = yystack.locationAt (0);])[
664 yystack.pop ();
665 yystate = yystack.stateAt (0);]b4_parse_trace_if([[
666 if (0 < yydebug)
667 yystack.print (yyDebugStream);]])[
670 ]b4_locations_if([
671 /* Muck with the stack to setup for yylloc. */
672 yystack.push (0, yy_semantic_null, yylloc);
673 yystack.push (0, yy_semantic_null, yyerrloc);
674 yyloc = yylloc_from_stack (yystack, 2);
675 yystack.pop (2);])[
677 /* Shift the error token. */]b4_lac_if([[
678 yylacDiscard("error recovery");]])[]b4_parse_trace_if([[
679 yy_symbol_print ("Shifting", to!SymbolKind (yystos_[yyn]), yylval]b4_locations_if([, yyloc])[);]])[
680 yystate = yyn;
681 yystack.push (yyn, yylval]b4_locations_if([, yyloc])[);
682 label = YYNEWSTATE;
683 break;
685 /* Accept. */
686 case YYACCEPT:
687 yyresult = true;
688 label = YYRETURN;
689 break;
691 /* Abort. */
692 case YYABORT:
693 yyresult = false;
694 label = YYRETURN;
695 break;
697 case YYRETURN:]b4_parse_trace_if([[
698 if (0 < yydebug)
699 yystack.print (yyDebugStream);]])[
700 return yyresult;
704 // Generate an error message.
705 private final void yyreportSyntaxError(Context yyctx)
706 {]b4_parse_error_bmatch(
707 [custom], [[
708 yylexer.reportSyntaxError(yyctx);]],
709 [detailed], [[
710 if (yyctx.getToken() != ]b4_symbol(empty, kind)[)
712 // FIXME: This method of building the message is not compatible
713 // with internationalization.
714 immutable int argmax = 5;
715 SymbolKind[] yyarg = new SymbolKind[argmax];
716 int yycount = yysyntaxErrorArguments(yyctx, yyarg, argmax);
717 string res, yyformat;
718 switch (yycount)
720 case 1:
721 yyformat = YY_("syntax error, unexpected %s");
722 res = format(yyformat, yyarg[0]);
723 break;
724 case 2:
725 yyformat = YY_("syntax error, unexpected %s, expecting %s");
726 res = format(yyformat, yyarg[0], yyarg[1]);
727 break;
728 case 3:
729 yyformat = YY_("syntax error, unexpected %s, expecting %s or %s");
730 res = format(yyformat, yyarg[0], yyarg[1], yyarg[2]);
731 break;
732 case 4:
733 yyformat = YY_("syntax error, unexpected %s, expecting %s or %s or %s");
734 res = format(yyformat, yyarg[0], yyarg[1], yyarg[2], yyarg[3]);
735 break;
736 case 5:
737 yyformat = YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
738 res = format(yyformat, yyarg[0], yyarg[1], yyarg[2], yyarg[3], yyarg[4]);
739 break;
740 default:
741 res = YY_("syntax error");
742 break;
744 yyerror(]b4_locations_if([yyctx.getLocation(), ])[res);
745 }]],
746 [[simple]], [[
747 yyerror(]b4_locations_if([yyctx.getLocation(), ])[YY_("syntax error"));]])[
750 ]b4_parse_error_bmatch(
751 [detailed], [[
752 private int yysyntaxErrorArguments(Context yyctx, SymbolKind[] yyarg, int yyargn) {
753 /* There are many possibilities here to consider:
754 - If this state is a consistent state with a default action,
755 then the only way this function was invoked is if the
756 default action is an error action. In that case, don't
757 check for expected tokens because there are none.
758 - The only way there can be no lookahead present (in tok) is
759 if this state is a consistent state with a default action.
760 Thus, detecting the absence of a lookahead is sufficient to
761 determine that there is no unexpected or expected token to
762 report. In that case, just report a simple "syntax error".
763 - Don't assume there isn't a lookahead just because this
764 state is a consistent state with a default action. There
765 might have been a previous inconsistent state, consistent
766 state with a non-default action, or user semantic action
767 that manipulated yychar. (However, yychar is currently out
768 of scope during semantic actions.)
769 - Of course, the expected token list depends on states to
770 have correct lookahead information, and it depends on the
771 parser not to perform extra reductions after fetching a
772 lookahead from the scanner and before detecting a syntax
773 error. Thus, state merging (from LALR or IELR) and default
774 reductions corrupt the expected token list. However, the
775 list is correct for canonical LR with one exception: it
776 will still contain any token that will not be accepted due
777 to an error action in a later state.
779 int yycount = 0;
780 if (yyctx.getToken() != ]b4_symbol(empty, kind)[)
782 if (yyarg !is null)
783 yyarg[yycount] = yyctx.getToken();
784 yycount += 1;
785 yycount += yyctx.getExpectedTokens(yyarg, 1, yyargn);
787 return yycount;
789 ]])[
793 * Information needed to get the list of expected tokens and to forge
794 * a syntax error diagnostic.
796 public static final class Context
797 {]b4_lac_if([[
798 private ]b4_parser_class[ yyparser;]])[
799 private const(YYStack) yystack;
800 private SymbolKind yytoken;]b4_locations_if([[
801 private const(Location) yylocation;]])[
803 this(]b4_lac_if([[]b4_parser_class[ parser, ]])[YYStack stack, SymbolKind kind]b4_locations_if([[, Location loc]])[)
804 {]b4_lac_if([[
805 yyparser = parser;]])[
806 yystack = stack;
807 yytoken = kind;]b4_locations_if([[
808 yylocation = loc;]])[
811 final SymbolKind getToken() const
813 return yytoken;
814 }]b4_locations_if([[
816 final const(Location) getLocation() const
818 return yylocation;
819 }]])[
821 * Put in YYARG at most YYARGN of the expected tokens given the
822 * current YYCTX, and return the number of tokens stored in YYARG. If
823 * YYARG is null, return the number of expected tokens (guaranteed to
824 * be less than YYNTOKENS).
826 int getExpectedTokens(SymbolKind[] yyarg, int yyargn)]b4_lac_if([[]], [[ const]])[
828 return getExpectedTokens(yyarg, 0, yyargn);
831 int getExpectedTokens(SymbolKind[] yyarg, int yyoffset, int yyargn)]b4_lac_if([[]], [[ const]])[
833 int yycount = yyoffset;]b4_lac_if([b4_parse_trace_if([[
834 // Execute LAC once. We don't care if it is successful, we
835 // only do it for the sake of debugging output.
837 if (!yyparser.yylacEstablished)
838 yyparser.yylacCheck(yystack, yytoken);
839 ]])[
840 for (int yyx = 0; yyx < yyntokens_; ++yyx)
842 SymbolKind yysym = SymbolKind(yyx);
843 if (yysym != ]b4_symbol(error, kind)[
844 && yysym != ]b4_symbol(undef, kind)[
845 && yyparser.yylacCheck(yystack, yysym))
847 if (yyarg == null)
848 yycount += 1;
849 else if (yycount == yyargn)
850 return 0;
851 else
852 yyarg[yycount++] = yysym;
854 }]], [[
855 int yyn = yypact_[this.yystack.stateAt(0)];
856 if (!yyPactValueIsDefault(yyn))
858 /* Start YYX at -YYN if negative to avoid negative
859 indexes in YYCHECK. In other words, skip the first
860 -YYN actions for this state because they are default
861 actions. */
862 int yyxbegin = yyn < 0 ? -yyn : 0;
863 /* Stay within bounds of both yycheck and yytname. */
864 int yychecklim = yylast_ - yyn + 1;
865 int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_;
866 for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
867 if (yycheck_[yyx + yyn] == yyx && yyx != ]b4_symbol(error, kind)[
868 && !yyTableValueIsError(yytable_[yyx + yyn]))
870 if (yyarg is null)
871 ++yycount;
872 else if (yycount == yyargn)
873 return 0;
874 else
875 yyarg[yycount++] = SymbolKind(yyx);
877 }]])[
878 if (yyarg !is null && yycount == yyoffset && yyoffset < yyargn)
879 yyarg[yyoffset] = ]b4_symbol(empty, kind)[;
880 return yycount - yyoffset;
884 ]b4_lac_if([[
885 /** Check the lookahead yytoken.
886 * \returns true iff the token will be eventually shifted.
888 bool yylacCheck(const YYStack yystack, SymbolKind yytoken)
890 // Logically, the yylacStack's lifetime is confined to this function.
891 // Clear it, to get rid of potential left-overs from previous call.
892 destroy(yylacStack);
893 // Reduce until we encounter a shift and thereby accept the token.
894 ]b4_parse_trace_if([[
895 yycdebug("LAC: checking lookahead " ~ format("%s", yytoken) ~ ":");]])[
896 int lacTop = 0;
897 while (true)
899 int topState = (yylacStack.length == 0
900 ? yystack.stateAt(lacTop)
901 : yylacStack[$ - 1]);
902 int yyrule = yypact_[topState];
903 if (yyPactValueIsDefault(yyrule)
904 || (yyrule += yytoken) < 0 || yylast_ < yyrule
905 || yycheck_[yyrule] != yytoken)
907 // Use the default action.
908 yyrule = yydefact_[+topState];
909 if (yyrule == 0)
910 {]b4_parse_trace_if([[
911 yycdebugln(" Err");]])[
912 return false;
915 else
917 // Use the action from yytable.
918 yyrule = yytable_[yyrule];
919 if (yyTableValueIsError(yyrule))
920 {]b4_parse_trace_if([[
921 yycdebugln(" Err");]])[
922 return false;
924 if (0 < yyrule)
925 {]b4_parse_trace_if([[
926 yycdebugln(" S" ~ to!string(yyrule));]])[
927 return true;
929 yyrule = -yyrule;
931 // By now we know we have to simulate a reduce.
932 ]b4_parse_trace_if([[
933 yycdebug(" R" ~ to!string(yyrule - 1));]])[
934 // Pop the corresponding number of values from the stack.
936 int yylen = yyr2_[yyrule];
937 // First pop from the LAC stack as many tokens as possible.
938 int lacSize = cast (int) yylacStack.length;
939 if (yylen < lacSize)
941 yylacStack.length -= yylen;
942 yylen = 0;
944 else if (lacSize != 0)
946 destroy(yylacStack);
947 yylen -= lacSize;
949 // Only afterwards look at the main stack.
950 // We simulate popping elements by incrementing lacTop.
951 lacTop += yylen;
953 // Keep topState in sync with the updated stack.
954 topState = (yylacStack.length == 0
955 ? yystack.stateAt(lacTop)
956 : yylacStack[$ - 1]);
957 // Push the resulting state of the reduction.
958 int state = yyLRGotoState(topState, yyr1_[yyrule]);]b4_parse_trace_if([[
959 yycdebug(" G" ~ to!string(state));]])[
960 yylacStack.length++;
961 yylacStack[$ - 1] = state;
965 /** Establish the initial context if no initial context currently exists.
966 * \returns true iff the token will be eventually shifted.
968 bool yylacEstablish(YYStack yystack, SymbolKind yytoken)
970 /* Establish the initial context for the current lookahead if no initial
971 context is currently established.
973 We define a context as a snapshot of the parser stacks. We define
974 the initial context for a lookahead as the context in which the
975 parser initially examines that lookahead in order to select a
976 syntactic action. Thus, if the lookahead eventually proves
977 syntactically unacceptable (possibly in a later context reached via a
978 series of reductions), the initial context can be used to determine
979 the exact set of tokens that would be syntactically acceptable in the
980 lookahead's place. Moreover, it is the context after which any
981 further semantic actions would be erroneous because they would be
982 determined by a syntactically unacceptable token.
984 yylacEstablish should be invoked when a reduction is about to be
985 performed in an inconsistent state (which, for the purposes of LAC,
986 includes consistent states that don't know they're consistent because
987 their default reductions have been disabled).
989 For parse.lac=full, the implementation of yylacEstablish is as
990 follows. If no initial context is currently established for the
991 current lookahead, then check if that lookahead can eventually be
992 shifted if syntactic actions continue from the current context. */
993 if (yylacEstablished)
994 return true;
995 else
996 {]b4_parse_trace_if([[
997 yycdebugln("LAC: initial context established for " ~ format("%s", yytoken));]])[
998 yylacEstablished = true;
999 return yylacCheck(yystack, yytoken);
1003 /** Discard any previous initial lookahead context because of event.
1004 * \param event the event which caused the lookahead to be discarded.
1005 * Only used for debbuging output. */
1006 void yylacDiscard(string event)
1008 /* Discard any previous initial lookahead context because of Event,
1009 which may be a lookahead change or an invalidation of the currently
1010 established initial context for the current lookahead.
1012 The most common example of a lookahead change is a shift. An example
1013 of both cases is syntax error recovery. That is, a syntax error
1014 occurs when the lookahead is syntactically erroneous for the
1015 currently established initial context, so error recovery manipulates
1016 the parser stacks to try to find a new initial context in which the
1017 current lookahead is syntactically acceptable. If it fails to find
1018 such a context, it discards the lookahead. */
1019 if (yylacEstablished)
1020 {]b4_parse_trace_if([[
1021 yycdebugln("LAC: initial context discarded due to " ~ event);]])[
1022 yylacEstablished = false;
1026 /** The stack for LAC.
1027 * Logically, the yylacStack's lifetime is confined to the function
1028 * yylacCheck. We just store it as a member of this class to hold
1029 * on to the memory and to avoid frequent reallocations.
1031 int[] yylacStack;
1032 /** Whether an initial LAC context was established. */
1033 bool yylacEstablished;
1034 ]])[
1037 * Whether the given <code>yypact_</code> value indicates a defaulted state.
1038 * @@param yyvalue the value to check
1040 private static bool yyPactValueIsDefault(int yyvalue)
1042 return yyvalue == yypact_ninf_;
1046 * Whether the given <code>yytable_</code> value indicates a syntax error.
1047 * @@param yyvalue the value to check
1049 private static bool yyTableValueIsError(int yyvalue)
1051 return yyvalue == yytable_ninf_;
1054 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
1055 STATE-NUM. */
1056 private static immutable ]b4_int_type_for([b4_pact])[ yypact_ninf_ = ]b4_pact_ninf[;
1058 /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
1059 positive, shift that token. If negative, reduce the rule which
1060 number is the opposite. If YYTABLE_NINF_, syntax error. */
1061 private static immutable ]b4_int_type_for([b4_table])[ yytable_ninf_ = ]b4_table_ninf[;
1063 ]b4_parser_tables_define[
1065 ]b4_parse_trace_if([[
1066 /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
1067 private static immutable ]b4_int_type_for([b4_rline])[[] yyrline_ =
1069 ]b4_rline[
1072 // Report on the debug stream that the rule yyrule is going to be reduced.
1073 private final void yy_reduce_print (int yyrule, ref YYStack yystack)
1075 if (yydebug == 0)
1076 return;
1078 int yylno = yyrline_[yyrule];
1079 int yynrhs = yyr2_[yyrule];
1080 /* Print the symbols being reduced, and their result. */
1081 yycdebugln (format("Reducing stack by rule %d (line %d):",
1082 yyrule - 1, yylno));
1084 /* The symbols being reduced. */
1085 for (int yyi = 0; yyi < yynrhs; yyi++)
1086 yy_symbol_print (format(" $%d =", yyi + 1),
1087 to!SymbolKind (yystos_[yystack.stateAt(yynrhs - (yyi + 1))]),
1088 ]b4_rhs_value(yynrhs, yyi + 1)b4_locations_if([,
1089 b4_rhs_location(yynrhs, yyi + 1)])[);
1091 ]])[
1093 private static auto yytranslate_ (int t)
1095 ]b4_api_token_raw_if(
1096 [[ return SymbolKind(t);]],
1097 [[ /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
1098 immutable ]b4_int_type_for([b4_translate])[[] translate_table =
1100 ]b4_translate[
1103 // Last valid token kind.
1104 immutable int code_max = ]b4_code_max[;
1106 if (t <= 0)
1107 return ]b4_symbol(eof, kind)[;
1108 else if (t <= code_max)
1109 return SymbolKind(translate_table[t]);
1110 else
1111 return ]b4_symbol(undef, kind)[;]])[
1114 private static immutable int yylast_ = ]b4_last[;
1115 private static immutable int yynnts_ = ]b4_nterms_number[;
1116 private static immutable int yyfinal_ = ]b4_final_state_number[;
1117 private static immutable int yyntokens_ = ]b4_tokens_number[;
1119 private final struct YYStackElement {
1120 int state;
1121 Value value;]b4_locations_if(
1122 b4_location_type[[] location;])[
1125 private final struct YYStack {
1126 private YYStackElement[] stack = [];
1128 public final ulong height()
1130 return stack.length;
1133 public final void push (int state, Value value]dnl
1134 b4_locations_if([, ref Location loc])[)
1136 stack ~= YYStackElement(state, value]b4_locations_if([, loc])[);
1139 public final void pop ()
1141 pop (1);
1144 public final void pop (int num)
1146 stack.length -= num;
1149 public final int stateAt (int i) const
1151 return stack[$-i-1].state;
1154 ]b4_locations_if([[
1155 public final ref Location locationAt (int i)
1157 return stack[$-i-1].location;
1158 }]])[
1160 public final ref Value valueAt (int i)
1162 return stack[$-i-1].value;
1164 ]b4_parse_trace_if([[
1165 // Print the state stack on the debug stream.
1166 public final void print (File stream)
1168 stream.write ("Stack now");
1169 for (int i = 0; i < stack.length; i++)
1170 stream.write (" ", stack[i].state);
1171 stream.writeln ();
1172 }]])[
1174 ]b4_percent_code_get[
1176 ]b4_percent_code_get([[epilogue]])[]dnl
1177 b4_epilogue[]dnl
1178 b4_output_end