d: add support for lookahead correction
[bison.git] / data / skeletons / lalr1.d
blobbf95e9297fa3202608e179c9933d1fd4b624fcf5
1 # D skeleton for Bison -*- autoconf -*-
3 # Copyright (C) 2007-2012, 2019-2020 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-2020])[
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;
44 /**
45 * A Bison parser, automatically generated from <tt>]m4_bpatsubst(b4_file_name, [^"\(.*\)"$], [\1])[</tt>.
47 * @@author LALR (1) parser skeleton written by Paolo Bonzini.
48 * Port to D language was done by Oliver Mangold.
51 /**
52 * Communication interface between the scanner and the Bison-generated
53 * parser <tt>]b4_parser_class[</tt>.
55 public interface Lexer
56 {]b4_locations_if([[
57 /**
58 * Method to retrieve the beginning position of the last scanned token.
59 * @@return the position at which the last scanned token starts. */
60 ]b4_position_type[ startPos ();
62 /**
63 * Method to retrieve the ending position of the last scanned token.
64 * @@return the first position beyond the last scanned token. */
65 ]b4_position_type[ endPos ();
67 ]])[
68 /**
69 * Method to retrieve the semantic value of the last scanned token.
70 * @@return the semantic value of the last scanned token. */
71 ]b4_yystype[ semanticVal ();
73 /**
74 * Entry point for the scanner. Returns the token identifier corresponding
75 * to the next token and prepares to return the semantic value
76 * ]b4_locations_if([and beginning/ending positions ])[of the token.
77 * @@return the token identifier corresponding to the next token. */
78 TokenKind yylex ();
80 /**
81 * Entry point for error reporting. Emits an error
82 * ]b4_locations_if([referring to the given location ])[in a user-defined way.
83 *]b4_locations_if([[
84 * @@param loc The location of the element to which the
85 * error message is related]])[
86 * @@param s The string for the error message. */
87 void yyerror (]b4_locations_if([[const ]b4_location_type[ loc, ]])[string s);
88 ]b4_parse_error_bmatch([custom], [[
89 /**
90 * Build and emit a "syntax error" message in a user-defined way.
92 * @@param ctx The context of the error.
94 void reportSyntaxError(]b4_parser_class[.Context ctx);
95 ]])[
98 ]b4_locations_if([b4_position_type_if([[
99 static assert(__traits(compiles,
100 (new ]b4_position_type[[1])[0]=(new ]b4_position_type[[1])[0]),
101 "struct/class ]b4_position_type[ must be default-constructible "
102 "and assignable");
103 static assert(__traits(compiles, (new string[1])[0]=(new ]b4_position_type[).toString()),
104 "error: struct/class ]b4_position_type[ must have toString method");
105 ]], [[
107 * A struct denoting a point in the input.*/
108 public struct ]b4_position_type[ {
110 /** The column index within the line of input. */
111 public int column = 1;
112 /** The line number within an input file. */
113 public int line = 1;
114 /** The name of the input file. */
115 public string filename = null;
118 * A string representation of the position. */
119 public string toString() const {
120 if (filename)
121 return format("%s:%d.%d", filename, line, column);
122 else
123 return format("%d.%d", line, column);
126 ]])b4_location_type_if([[
127 static assert(__traits(compiles, (new ]b4_location_type[((new ]b4_position_type[[1])[0]))) &&
128 __traits(compiles, (new ]b4_location_type[((new ]b4_position_type[[1])[0], (new ]b4_position_type[[1])[0]))),
129 "error: struct/class ]b4_location_type[ must have "
130 "default constructor and constructors this(]b4_position_type[) and this(]b4_position_type[, ]b4_position_type[).");
131 static assert(__traits(compiles, (new ]b4_location_type[[1])[0].begin=(new ]b4_location_type[[1])[0].begin) &&
132 __traits(compiles, (new ]b4_location_type[[1])[0].begin=(new ]b4_location_type[[1])[0].end) &&
133 __traits(compiles, (new ]b4_location_type[[1])[0].end=(new ]b4_location_type[[1])[0].begin) &&
134 __traits(compiles, (new ]b4_location_type[[1])[0].end=(new ]b4_location_type[[1])[0].end),
135 "error: struct/class ]b4_location_type[ must have assignment-compatible "
136 "members/properties 'begin' and 'end'.");
137 static assert(__traits(compiles, (new string[1])[0]=(new ]b4_location_type[[1])[0].toString()),
138 "error: struct/class ]b4_location_type[ must have toString method.");
140 private immutable bool yy_location_is_class = !__traits(compiles, *(new ]b4_location_type[((new ]b4_position_type[[1])[0])));]], [[
142 * A class defining a pair of positions. Positions, defined by the
143 * <code>]b4_position_type[</code> class, denote a point in the input.
144 * Locations represent a part of the input through the beginning
145 * and ending positions. */
146 public class ]b4_location_type[
148 /** The first, inclusive, position in the range. */
149 public ]b4_position_type[ begin;
151 /** The first position beyond the range. */
152 public ]b4_position_type[ end;
155 * Create a <code>]b4_location_type[</code> denoting an empty range located at
156 * a given point.
157 * @@param loc The position at which the range is anchored. */
158 public this (]b4_position_type[ loc) {
159 this.begin = this.end = loc;
162 public this () {
166 * Create a <code>]b4_location_type[</code> from the endpoints of the range.
167 * @@param begin The first position included in the range.
168 * @@param end The first position beyond the range. */
169 public this (]b4_position_type[ begin, ]b4_position_type[ end)
171 this.begin = begin;
172 this.end = end;
176 * A representation of the location. For this to be correct,
177 * <code>]b4_position_type[</code> should override the <code>toString</code>
178 * method. */
179 public override string toString () const {
180 auto end_col = 0 < end.column ? end.column - 1 : 0;
181 auto res = begin.toString ();
182 if (end.filename && begin.filename != end.filename)
183 res ~= "-" ~ format("%s:%d.%d", end.filename, end.line, end_col);
184 else if (begin.line < end.line)
185 res ~= "-" ~ format("%d.%d", end.line, end_col);
186 else if (begin.column < end_col)
187 res ~= "-" ~ format("%d", end_col);
188 return res;
192 private immutable bool yy_location_is_class = true;
194 ]])])m4_ifdef([b4_user_union_members], [private union YYSemanticType
196 b4_user_union_members
197 };],
198 [m4_if(b4_tag_seen_flag, 0,
199 [[private alias int YYSemanticType;]])])[
200 ]b4_token_enums[
201 ]b4_parser_class_declaration[
203 ]b4_identification[
205 ]b4_declare_symbol_enum[
207 ]b4_locations_if([[
208 private final ]b4_location_type[ yylloc_from_stack (ref YYStack rhs, int n)
210 static if (yy_location_is_class) {
211 if (n > 0)
212 return new ]b4_location_type[ (rhs.locationAt (n-1).begin, rhs.locationAt (0).end);
213 else
214 return new ]b4_location_type[ (rhs.locationAt (0).end);
215 } else {
216 if (n > 0)
217 return ]b4_location_type[ (rhs.locationAt (n-1).begin, rhs.locationAt (0).end);
218 else
219 return ]b4_location_type[ (rhs.locationAt (0).end);
221 }]])[
223 ]b4_lexer_if([[ private class YYLexer implements Lexer {
224 ]b4_percent_code_get([[lexer]])[
226 ]])[
227 /** The object doing lexical analysis for us. */
228 private Lexer yylexer;
230 ]b4_parse_param_vars[
232 ]b4_lexer_if([[
234 * Instantiate the Bison-generated parser.
236 public this] (b4_parse_param_decl([b4_lex_param_decl])[) {
237 ]b4_percent_code_get([[init]])[]b4_lac_if([[
238 this.yylacStack = new int[];
239 this.yylacEstablished = false;]])[
240 this (new YYLexer(]b4_lex_param_call[));
242 ]])[
245 * Instantiate the Bison-generated parser.
246 * @@param yylexer The scanner that will supply tokens to the parser.
248 ]b4_lexer_if([[protected]], [[public]]) [this (]b4_parse_param_decl([[Lexer yylexer]])[) {
249 this.yylexer = yylexer;]b4_parse_trace_if([[
250 this.yyDebugStream = stderr;]])[
251 ]b4_parse_param_cons[
253 ]b4_parse_trace_if([[
254 private File yyDebugStream;
257 * The <tt>File</tt> on which the debugging output is
258 * printed.
260 public File getDebugStream () { return yyDebugStream; }
263 * Set the <tt>std.File</tt> on which the debug output is printed.
264 * @@param s The stream that is used for debugging output.
266 public final void setDebugStream(File s) { yyDebugStream = s; }
268 private int yydebug = 0;
271 * Answer the verbosity of the debugging output; 0 means that all kinds of
272 * output from the parser are suppressed.
274 public final int getDebugLevel() { return yydebug; }
277 * Set the verbosity of the debugging output; 0 means that all kinds of
278 * output from the parser are suppressed.
279 * @@param level The verbosity level for debugging output.
281 public final void setDebugLevel(int level) { yydebug = level; }
283 protected final void yycdebug (string s) {
284 if (0 < yydebug)
285 yyDebugStream.write (s);
288 protected final void yycdebugln (string s) {
289 if (0 < yydebug)
290 yyDebugStream.writeln (s);
292 ]])[
293 private final TokenKind yylex () {
294 return yylexer.yylex ();
297 protected final void yyerror (]b4_locations_if([[const ]b4_location_type[ loc, ]])[string s) {
298 yylexer.yyerror (]b4_locations_if([loc, ])[s);
302 * Returned by a Bison action in order to stop the parsing process and
303 * return success (<tt>true</tt>). */
304 public static immutable int YYACCEPT = 0;
307 * Returned by a Bison action in order to stop the parsing process and
308 * return failure (<tt>false</tt>). */
309 public static immutable int YYABORT = 1;
312 * Returned by a Bison action in order to start error recovery without
313 * printing an error message. */
314 public static immutable int YYERROR = 2;
316 // Internal return codes that are not supported for user semantic
317 // actions.
318 private static immutable int YYERRLAB = 3;
319 private static immutable int YYNEWSTATE = 4;
320 private static immutable int YYDEFAULT = 5;
321 private static immutable int YYREDUCE = 6;
322 private static immutable int YYERRLAB1 = 7;
323 private static immutable int YYRETURN = 8;
324 ]b4_locations_if([
325 private static immutable YYSemanticType yy_semantic_null;])[
326 private int yyerrstatus_ = 0;
328 private void yyerrok()
330 yyerrstatus_ = 0;
334 * Whether error recovery is being done. In this state, the parser
335 * reads token until it reaches a known state, and then restarts normal
336 * operation. */
337 public final bool recovering ()
339 return yyerrstatus_ == 0;
342 /** Compute post-reduction state.
343 * @@param yystate the current state
344 * @@param yysym the nonterminal to push on the stack
346 private int yyLRGotoState(int yystate, int yysym) {
347 int yyr = yypgoto_[yysym - yyntokens_] + yystate;
348 if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate)
349 return yytable_[yyr];
350 else
351 return yydefgoto_[yysym - yyntokens_];
354 private int yyaction (int yyn, ref YYStack yystack, int yylen)
356 ]b4_yystype[ yyval;]b4_locations_if([[
357 ]b4_location_type[ yyloc = yylloc_from_stack (yystack, yylen);]])[
359 /* If YYLEN is nonzero, implement the default value of the action:
360 `$$ = $1'. Otherwise, use the top of the stack.
362 Otherwise, the following line sets YYVAL to garbage.
363 This behavior is undocumented and Bison
364 users should not rely upon it. */
365 if (yylen > 0)
366 yyval = yystack.valueAt (yylen - 1);
367 else
368 yyval = yystack.valueAt (0);
370 ]b4_parse_trace_if([[
371 yy_reduce_print (yyn, yystack);]])[
373 switch (yyn)
375 ]b4_user_actions[
376 default: break;
379 ]b4_parse_trace_if([[
380 import std.conv : to;
381 yy_symbol_print ("-> $$ =", to!SymbolKind (yyr1_[yyn]), yyval]b4_locations_if([, yyloc])[);]])[
383 yystack.pop (yylen);
384 yylen = 0;
386 /* Shift the result of the reduction. */
387 int yystate = yyLRGotoState(yystack.stateAt(0), yyr1_[yyn]);
388 yystack.push (yystate, yyval]b4_locations_if([, yyloc])[);
389 return YYNEWSTATE;
392 ]b4_parse_trace_if([[
393 /*--------------------------------.
394 | Print this symbol on YYOUTPUT. |
395 `--------------------------------*/
397 private final void yy_symbol_print (string s, SymbolKind yykind,
398 ref ]b4_yystype[ yyvaluep]dnl
399 b4_locations_if([, ref ]b4_location_type[ yylocationp])[)
401 if (0 < yydebug)
403 string message = s ~ (yykind < yyntokens_ ? " token " : " nterm ")
404 ~ format("%s", yykind) ~ " ("]b4_locations_if([
405 ~ yylocationp.toString() ~ ": "])[;
406 static if (__traits(compiles, message ~= yyvaluep.toString()))
407 message ~= yyvaluep.toString();
408 else
409 message ~= format("%s", &yyvaluep);
410 message ~= ")";
411 yycdebugln (message);
414 ]])[
416 * Parse input from the scanner that was specified at object construction
417 * time. Return whether the end of the input was reached successfully.
419 * @@return <tt>true</tt> if the parsing succeeds. Note that this does not
420 * imply that there were no syntax errors.
422 public bool parse ()
424 // Lookahead token kind.
425 int yychar = TokenKind.]b4_symbol(empty, id)[;
426 // Lookahead symbol kind.
427 SymbolKind yytoken = ]b4_symbol(empty, kind)[;
429 /* State. */
430 int yyn = 0;
431 int yylen = 0;
432 int yystate = 0;
434 YYStack yystack;
436 /* Error handling. */
437 int yynerrs_ = 0;]b4_locations_if([[
438 /// The location where the error started.
439 ]b4_location_type[ yyerrloc = null;
441 /// ]b4_location_type[ of the lookahead.
442 ]b4_location_type[ yylloc;
444 /// @@$.
445 ]b4_location_type[ yyloc;]])[
447 /// Semantic value of the lookahead.
448 ]b4_yystype[ yylval;
450 bool yyresult;]b4_lac_if([[
451 // Discard the LAC context in case there still is one left from a
452 // previous invocation.
453 yylacDiscard("init");]])[]b4_parse_trace_if([[
455 yycdebugln ("Starting parse");]])[
456 yyerrstatus_ = 0;
458 ]m4_ifdef([b4_initial_action], [
459 m4_pushdef([b4_at_dollar], [yylloc])dnl
460 m4_pushdef([b4_dollar_dollar], [yylval])dnl
461 /* User initialization code. */
462 b4_user_initial_action
463 m4_popdef([b4_dollar_dollar])dnl
464 m4_popdef([b4_at_dollar])])dnl
466 [ /* Initialize the stack. */
467 yystack.push (yystate, yylval]b4_locations_if([, yylloc])[);
469 int label = YYNEWSTATE;
470 for (;;)
471 final switch (label)
473 /* New state. Unlike in the C/C++ skeletons, the state is already
474 pushed when we come here. */
475 case YYNEWSTATE:]b4_parse_trace_if([[
476 yycdebugln (format("Entering state %d", yystate));
477 if (0 < yydebug)
478 yystack.print (yyDebugStream);]])[
480 /* Accept? */
481 if (yystate == yyfinal_)
482 return true;
484 /* Take a decision. First try without lookahead. */
485 yyn = yypact_[yystate];
486 if (yyPactValueIsDefault(yyn))
488 label = YYDEFAULT;
489 break;
492 /* Read a lookahead token. */
493 if (yychar == TokenKind.]b4_symbol(empty, id)[)
494 {]b4_parse_trace_if([[
495 yycdebugln ("Reading a token");]])[
496 yychar = yylex ();]b4_locations_if([[
497 static if (yy_location_is_class) {
498 yylloc = new ]b4_location_type[(yylexer.startPos, yylexer.endPos);
499 } else {
500 yylloc = ]b4_location_type[(yylexer.startPos, yylexer.endPos);
501 }]])
502 yylval = yylexer.semanticVal;[
505 /* Convert token to internal form. */
506 yytoken = yytranslate_ (yychar);]b4_parse_trace_if([[
507 yy_symbol_print ("Next token is", yytoken, yylval]b4_locations_if([, yylloc])[);]])[
509 if (yytoken == ]b4_symbol(error, kind)[)
511 // The scanner already issued an error message, process directly
512 // to error recovery. But do not keep the error token as
513 // lookahead, it is too special and may lead us to an endless
514 // loop in error recovery. */
515 yychar = TokenKind.]b4_symbol(undef, id)[;
516 yytoken = ]b4_symbol(undef, kind)[;]b4_locations_if([[
517 yyerrloc = yylloc;]])[
518 label = YYERRLAB1;
520 else
522 /* If the proper action on seeing token YYTOKEN is to reduce or to
523 detect an error, take that action. */
524 yyn += yytoken;
525 if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yytoken) {]b4_lac_if([[
526 if (!yylacEstablish(yystack, yytoken))
527 label = YYERRLAB;
528 else]])[
529 label = YYDEFAULT;
531 /* <= 0 means reduce or error. */
532 else if ((yyn = yytable_[yyn]) <= 0)
534 if (yyTableValueIsError(yyn))
535 label = YYERRLAB;]b4_lac_if([[
536 else if (!yylacEstablish(yystack, yytoken))
537 label = YYERRLAB;]])[
538 else
540 yyn = -yyn;
541 label = YYREDUCE;
544 else
546 /* Shift the lookahead token. */]b4_parse_trace_if([[
547 yy_symbol_print ("Shifting", yytoken, yylval]b4_locations_if([, yylloc])[);]])[
549 /* Discard the token being shifted. */
550 yychar = TokenKind.]b4_symbol(empty, id)[;
552 /* Count tokens shifted since error; after three, turn off error
553 * status. */
554 if (yyerrstatus_ > 0)
555 --yyerrstatus_;
557 yystate = yyn;
558 yystack.push (yystate, yylval]b4_locations_if([, yylloc])[);]b4_lac_if([[
559 yylacDiscard("shift");]])[
560 label = YYNEWSTATE;
563 break;
565 /*-----------------------------------------------------------.
566 | yydefault -- do the default action for the current state. |
567 `-----------------------------------------------------------*/
568 case YYDEFAULT:
569 yyn = yydefact_[yystate];
570 if (yyn == 0)
571 label = YYERRLAB;
572 else
573 label = YYREDUCE;
574 break;
576 /*-----------------------------.
577 | yyreduce -- Do a reduction. |
578 `-----------------------------*/
579 case YYREDUCE:
580 yylen = yyr2_[yyn];
581 label = yyaction (yyn, yystack, yylen);
582 yystate = yystack.stateAt (0);
583 break;
585 /*--------------------------------------.
586 | yyerrlab -- here on detecting error. |
587 `--------------------------------------*/
588 case YYERRLAB:
589 /* If not already recovering from an error, report this error. */
590 if (yyerrstatus_ == 0)
592 ++yynerrs_;
593 if (yychar == TokenKind.]b4_symbol(empty, id)[)
594 yytoken = ]b4_symbol(empty, kind)[;
595 yyreportSyntaxError(new Context(]b4_lac_if([[this, ]])[yystack, yytoken]b4_locations_if([[, yylloc]])[));
597 ]b4_locations_if([
598 yyerrloc = yylloc;])[
599 if (yyerrstatus_ == 3)
601 /* If just tried and failed to reuse lookahead token after an
602 * error, discard it. */
604 if (yychar <= TokenKind.]b4_symbol(eof, [id])[)
606 /* Return failure if at end of input. */
607 if (yychar == TokenKind.]b4_symbol(eof, [id])[)
608 return false;
610 else
611 yychar = TokenKind.]b4_symbol(empty, id)[;
614 /* Else will try to reuse lookahead token after shifting the error
615 * token. */
616 label = YYERRLAB1;
617 break;
619 /*-------------------------------------------------.
620 | errorlab -- error raised explicitly by YYERROR. |
621 `-------------------------------------------------*/
622 case YYERROR:]b4_locations_if([
623 yyerrloc = yystack.locationAt (yylen - 1);])[
624 /* Do not reclaim the symbols of the rule which action triggered
625 this YYERROR. */
626 yystack.pop (yylen);
627 yylen = 0;
628 yystate = yystack.stateAt (0);
629 label = YYERRLAB1;
630 break;
632 /*-------------------------------------------------------------.
633 | yyerrlab1 -- common code for both syntax error and YYERROR. |
634 `-------------------------------------------------------------*/
635 case YYERRLAB1:
636 yyerrstatus_ = 3; /* Each real token shifted decrements this. */
638 // Pop stack until we find a state that shifts the error token.
639 for (;;)
641 yyn = yypact_[yystate];
642 if (!yyPactValueIsDefault(yyn))
644 yyn += ]b4_symbol(error, kind)[;
645 if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == ]b4_symbol(error, kind)[)
647 yyn = yytable_[yyn];
648 if (0 < yyn)
649 break;
653 /* Pop the current state because it cannot handle the error token. */
654 if (yystack.height == 1)
655 return false;
657 ]b4_locations_if([ yyerrloc = yystack.locationAt (0);])[
658 yystack.pop ();
659 yystate = yystack.stateAt (0);]b4_parse_trace_if([[
660 if (0 < yydebug)
661 yystack.print (yyDebugStream);]])[
664 ]b4_locations_if([
665 /* Muck with the stack to setup for yylloc. */
666 yystack.push (0, yy_semantic_null, yylloc);
667 yystack.push (0, yy_semantic_null, yyerrloc);
668 yyloc = yylloc_from_stack (yystack, 2);
669 yystack.pop (2);])[
671 /* Shift the error token. */]b4_lac_if([[
672 yylacDiscard("error recovery");]])[]b4_parse_trace_if([[
673 import std.conv : to;
674 yy_symbol_print ("Shifting", to!SymbolKind (yystos_[yyn]), yylval]b4_locations_if([, yyloc])[);]])[
675 yystate = yyn;
676 yystack.push (yyn, yylval]b4_locations_if([, yyloc])[);
677 label = YYNEWSTATE;
678 break;
680 /* Accept. */
681 case YYACCEPT:
682 yyresult = true;
683 label = YYRETURN;
684 break;
686 /* Abort. */
687 case YYABORT:
688 yyresult = false;
689 label = YYRETURN;
690 break;
692 case YYRETURN:]b4_parse_trace_if([[
693 if (0 < yydebug)
694 yystack.print (yyDebugStream);]])[
695 return yyresult;
699 // Generate an error message.
700 private final void yyreportSyntaxError(Context yyctx)
701 {]b4_parse_error_bmatch(
702 [custom], [[
703 yylexer.reportSyntaxError(yyctx);]],
704 [detailed\|verbose], [[
705 if (yyctx.getToken() != ]b4_symbol(empty, kind)[)
707 // FIXME: This method of building the message is not compatible
708 // with internationalization.
709 immutable int argmax = 5;
710 SymbolKind[] yyarg = new SymbolKind[argmax];
711 int yycount = yysyntaxErrorArguments(yyctx, yyarg, argmax);
712 string res = "syntax error, unexpected ";
713 res ~= format!"%s"(yyarg[0]);
714 if (yycount < argmax + 1)
716 for (int yyi = 1; yyi < yycount; yyi++)
718 res ~= yyi == 1 ? ", expecting " : " or ";
719 res ~= format!"%s"(SymbolKind(yyarg[yyi]));
722 yyerror(]b4_locations_if([yyctx.getLocation(), ])[res);
723 }]],
724 [[simple]], [[
725 yyerror(]b4_locations_if([yyctx.getLocation(), ])["syntax error");]])[
728 ]b4_parse_error_bmatch(
729 [detailed\|verbose], [[
730 private int yysyntaxErrorArguments(Context yyctx, SymbolKind[] yyarg, int yyargn) {
731 /* There are many possibilities here to consider:
732 - If this state is a consistent state with a default action,
733 then the only way this function was invoked is if the
734 default action is an error action. In that case, don't
735 check for expected tokens because there are none.
736 - The only way there can be no lookahead present (in tok) is
737 if this state is a consistent state with a default action.
738 Thus, detecting the absence of a lookahead is sufficient to
739 determine that there is no unexpected or expected token to
740 report. In that case, just report a simple "syntax error".
741 - Don't assume there isn't a lookahead just because this
742 state is a consistent state with a default action. There
743 might have been a previous inconsistent state, consistent
744 state with a non-default action, or user semantic action
745 that manipulated yychar. (However, yychar is currently out
746 of scope during semantic actions.)
747 - Of course, the expected token list depends on states to
748 have correct lookahead information, and it depends on the
749 parser not to perform extra reductions after fetching a
750 lookahead from the scanner and before detecting a syntax
751 error. Thus, state merging (from LALR or IELR) and default
752 reductions corrupt the expected token list. However, the
753 list is correct for canonical LR with one exception: it
754 will still contain any token that will not be accepted due
755 to an error action in a later state.
757 int yycount = 0;
758 if (yyctx.getToken() != ]b4_symbol(empty, kind)[)
760 if (yyarg !is null)
761 yyarg[yycount] = yyctx.getToken();
762 yycount += 1;
763 yycount += yyctx.getExpectedTokens(yyarg, 1, yyargn);
765 return yycount;
767 ]])[
771 * Information needed to get the list of expected tokens and to forge
772 * a syntax error diagnostic.
774 public static final class Context
775 {]b4_lac_if([[
776 private ]b4_parser_class[ yyparser;]])[
777 private const(YYStack) yystack;
778 private SymbolKind yytoken;]b4_locations_if([[
779 private const(]b4_location_type[) yylocation;]])[
781 this(]b4_lac_if([[]b4_parser_class[ parser, ]])[YYStack stack, SymbolKind kind]b4_locations_if([[, ]b4_location_type[ loc]])[)
782 {]b4_lac_if([[
783 yyparser = parser;]])[
784 yystack = stack;
785 yytoken = kind;]b4_locations_if([[
786 yylocation = loc;]])[
789 final SymbolKind getToken() const
791 return yytoken;
792 }]b4_locations_if([[
794 final const(]b4_location_type[) getLocation() const
796 return yylocation;
797 }]])[
799 * Put in YYARG at most YYARGN of the expected tokens given the
800 * current YYCTX, and return the number of tokens stored in YYARG. If
801 * YYARG is null, return the number of expected tokens (guaranteed to
802 * be less than YYNTOKENS).
804 int getExpectedTokens(SymbolKind[] yyarg, int yyargn)]b4_lac_if([[]], [[ const]])[
806 return getExpectedTokens(yyarg, 0, yyargn);
809 int getExpectedTokens(SymbolKind[] yyarg, int yyoffset, int yyargn)]b4_lac_if([[]], [[ const]])[
811 int yycount = yyoffset;]b4_lac_if([b4_parse_trace_if([[
812 // Execute LAC once. We don't care if it is successful, we
813 // only do it for the sake of debugging output.
815 if (!yyparser.yylacEstablished)
816 yyparser.yylacCheck(yystack, yytoken);
817 ]])[
818 for (int yyx = 0; yyx < yyntokens_; ++yyx)
820 SymbolKind yysym = SymbolKind(yyx);
821 if (yysym != ]b4_symbol(error, kind)[
822 && yysym != ]b4_symbol(undef, kind)[
823 && yyparser.yylacCheck(yystack, yysym))
825 if (yyarg == null)
826 yycount += 1;
827 else if (yycount == yyargn)
828 return 0;
829 else
830 yyarg[yycount++] = yysym;
832 }]], [[
833 int yyn = yypact_[this.yystack.stateAt(0)];
834 if (!yyPactValueIsDefault(yyn))
836 /* Start YYX at -YYN if negative to avoid negative
837 indexes in YYCHECK. In other words, skip the first
838 -YYN actions for this state because they are default
839 actions. */
840 int yyxbegin = yyn < 0 ? -yyn : 0;
841 /* Stay within bounds of both yycheck and yytname. */
842 int yychecklim = yylast_ - yyn + 1;
843 int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_;
844 for (int yyx = yyxbegin; yyx < yyxend; ++yyx)
845 if (yycheck_[yyx + yyn] == yyx && yyx != ]b4_symbol(error, kind)[
846 && !yyTableValueIsError(yytable_[yyx + yyn]))
848 if (yyarg is null)
849 ++yycount;
850 else if (yycount == yyargn)
851 return 0;
852 else
853 yyarg[yycount++] = SymbolKind(yyx);
855 }]])[
856 if (yyarg !is null && yycount == yyoffset && yyoffset < yyargn)
857 yyarg[yyoffset] = ]b4_symbol(empty, kind)[;
858 return yycount - yyoffset;
862 ]b4_lac_if([[
863 /** Check the lookahead yytoken.
864 * \returns true iff the token will be eventually shifted.
866 bool yylacCheck(const YYStack yystack, SymbolKind yytoken)
868 // Logically, the yylacStack's lifetime is confined to this function.
869 // Clear it, to get rid of potential left-overs from previous call.
870 destroy(yylacStack);
871 // Reduce until we encounter a shift and thereby accept the token.
872 ]b4_parse_trace_if([[
873 import std.conv;
874 yycdebug("LAC: checking lookahead " ~ format("%s", yytoken) ~ ":");]])[
875 int lacTop = 0;
876 while (true)
878 int topState = (yylacStack.length == 0
879 ? yystack.stateAt(lacTop)
880 : yylacStack[$ - 1]);
881 int yyrule = yypact_[topState];
882 if (yyPactValueIsDefault(yyrule)
883 || (yyrule += yytoken) < 0 || yylast_ < yyrule
884 || yycheck_[yyrule] != yytoken)
886 // Use the default action.
887 yyrule = yydefact_[+topState];
888 if (yyrule == 0)
889 {]b4_parse_trace_if([[
890 yycdebugln(" Err");]])[
891 return false;
894 else
896 // Use the action from yytable.
897 yyrule = yytable_[yyrule];
898 if (yyTableValueIsError(yyrule))
899 {]b4_parse_trace_if([[
900 yycdebugln(" Err");]])[
901 return false;
903 if (0 < yyrule)
904 {]b4_parse_trace_if([[
905 yycdebugln(" S" ~ to!string(yyrule));]])[
906 return true;
908 yyrule = -yyrule;
910 // By now we know we have to simulate a reduce.
911 ]b4_parse_trace_if([[
912 yycdebug(" R" ~ to!string(yyrule - 1));]])[
913 // Pop the corresponding number of values from the stack.
915 int yylen = yyr2_[yyrule];
916 // First pop from the LAC stack as many tokens as possible.
917 int lacSize = cast (int) yylacStack.length;
918 if (yylen < lacSize)
920 yylacStack.length -= yylen;
921 yylen = 0;
923 else if (lacSize != 0)
925 destroy(yylacStack);
926 yylen -= lacSize;
928 // Only afterwards look at the main stack.
929 // We simulate popping elements by incrementing lacTop.
930 lacTop += yylen;
932 // Keep topState in sync with the updated stack.
933 topState = (yylacStack.length == 0
934 ? yystack.stateAt(lacTop)
935 : yylacStack[$ - 1]);
936 // Push the resulting state of the reduction.
937 int state = yyLRGotoState(topState, yyr1_[yyrule]);]b4_parse_trace_if([[
938 yycdebug(" G" ~ to!string(state));]])[
939 yylacStack.length++;
940 yylacStack[$ - 1] = state;
944 /** Establish the initial context if no initial context currently exists.
945 * \returns true iff the token will be eventually shifted.
947 bool yylacEstablish(YYStack yystack, SymbolKind yytoken)
949 /* Establish the initial context for the current lookahead if no initial
950 context is currently established.
952 We define a context as a snapshot of the parser stacks. We define
953 the initial context for a lookahead as the context in which the
954 parser initially examines that lookahead in order to select a
955 syntactic action. Thus, if the lookahead eventually proves
956 syntactically unacceptable (possibly in a later context reached via a
957 series of reductions), the initial context can be used to determine
958 the exact set of tokens that would be syntactically acceptable in the
959 lookahead's place. Moreover, it is the context after which any
960 further semantic actions would be erroneous because they would be
961 determined by a syntactically unacceptable token.
963 yylacEstablish should be invoked when a reduction is about to be
964 performed in an inconsistent state (which, for the purposes of LAC,
965 includes consistent states that don't know they're consistent because
966 their default reductions have been disabled).
968 For parse.lac=full, the implementation of yylacEstablish is as
969 follows. If no initial context is currently established for the
970 current lookahead, then check if that lookahead can eventually be
971 shifted if syntactic actions continue from the current context. */
972 if (yylacEstablished)
973 return true;
974 else
975 {]b4_parse_trace_if([[
976 yycdebugln("LAC: initial context established for " ~ format("%s", yytoken));]])[
977 yylacEstablished = true;
978 return yylacCheck(yystack, yytoken);
982 /** Discard any previous initial lookahead context because of event.
983 * \param event the event which caused the lookahead to be discarded.
984 * Only used for debbuging output. */
985 void yylacDiscard(string event)
987 /* Discard any previous initial lookahead context because of Event,
988 which may be a lookahead change or an invalidation of the currently
989 established initial context for the current lookahead.
991 The most common example of a lookahead change is a shift. An example
992 of both cases is syntax error recovery. That is, a syntax error
993 occurs when the lookahead is syntactically erroneous for the
994 currently established initial context, so error recovery manipulates
995 the parser stacks to try to find a new initial context in which the
996 current lookahead is syntactically acceptable. If it fails to find
997 such a context, it discards the lookahead. */
998 if (yylacEstablished)
999 {]b4_parse_trace_if([[
1000 yycdebugln("LAC: initial context discarded due to " ~ event);]])[
1001 yylacEstablished = false;
1005 /** The stack for LAC.
1006 * Logically, the yylacStack's lifetime is confined to the function
1007 * yylacCheck. We just store it as a member of this class to hold
1008 * on to the memory and to avoid frequent reallocations.
1010 int[] yylacStack;
1011 /** Whether an initial LAC context was established. */
1012 bool yylacEstablished;
1013 ]])[
1016 * Whether the given <code>yypact_</code> value indicates a defaulted state.
1017 * @@param yyvalue the value to check
1019 private static bool yyPactValueIsDefault(int yyvalue)
1021 return yyvalue == yypact_ninf_;
1025 * Whether the given <code>yytable_</code> value indicates a syntax error.
1026 * @@param yyvalue the value to check
1028 private static bool yyTableValueIsError(int yyvalue)
1030 return yyvalue == yytable_ninf_;
1033 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
1034 STATE-NUM. */
1035 private static immutable ]b4_int_type_for([b4_pact])[ yypact_ninf_ = ]b4_pact_ninf[;
1037 /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
1038 positive, shift that token. If negative, reduce the rule which
1039 number is the opposite. If YYTABLE_NINF_, syntax error. */
1040 private static immutable ]b4_int_type_for([b4_table])[ yytable_ninf_ = ]b4_table_ninf[;
1042 ]b4_parser_tables_define[
1044 ]b4_parse_trace_if([[
1045 /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
1046 private static immutable ]b4_int_type_for([b4_rline])[[] yyrline_ =
1048 ]b4_rline[
1051 // Report on the debug stream that the rule yyrule is going to be reduced.
1052 private final void yy_reduce_print (int yyrule, ref YYStack yystack)
1054 if (yydebug == 0)
1055 return;
1057 int yylno = yyrline_[yyrule];
1058 int yynrhs = yyr2_[yyrule];
1059 /* Print the symbols being reduced, and their result. */
1060 yycdebugln (format("Reducing stack by rule %d (line %d):",
1061 yyrule - 1, yylno));
1063 /* The symbols being reduced. */
1064 import std.conv : to;
1065 for (int yyi = 0; yyi < yynrhs; yyi++)
1066 yy_symbol_print (format(" $%d =", yyi + 1),
1067 to!SymbolKind (yystos_[yystack.stateAt(yynrhs - (yyi + 1))]),
1068 ]b4_rhs_value(yynrhs, yyi + 1)b4_locations_if([,
1069 b4_rhs_location(yynrhs, yyi + 1)])[);
1071 ]])[
1073 private static auto yytranslate_ (int t)
1075 ]b4_api_token_raw_if(
1076 [[ return SymbolKind(t);]],
1077 [[ /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
1078 immutable ]b4_int_type_for([b4_translate])[[] translate_table =
1080 ]b4_translate[
1083 // Last valid token kind.
1084 immutable int code_max = ]b4_code_max[;
1086 if (t <= 0)
1087 return ]b4_symbol(eof, kind)[;
1088 else if (t <= code_max)
1089 return SymbolKind(translate_table[t]);
1090 else
1091 return ]b4_symbol(undef, kind)[;]])[
1094 private static immutable int yylast_ = ]b4_last[;
1095 private static immutable int yynnts_ = ]b4_nterms_number[;
1096 private static immutable int yyfinal_ = ]b4_final_state_number[;
1097 private static immutable int yyntokens_ = ]b4_tokens_number[;
1099 private final struct YYStackElement {
1100 int state;
1101 ]b4_yystype[ value;]b4_locations_if(
1102 b4_location_type[[] location;])[
1105 private final struct YYStack {
1106 private YYStackElement[] stack = [];
1108 public final ulong height()
1110 return stack.length;
1113 public final void push (int state, ]b4_yystype[ value]dnl
1114 b4_locations_if([, ref ]b4_location_type[ loc])[)
1116 stack ~= YYStackElement(state, value]b4_locations_if([, loc])[);
1119 public final void pop ()
1121 pop (1);
1124 public final void pop (int num)
1126 stack.length -= num;
1129 public final int stateAt (int i) const
1131 return stack[$-i-1].state;
1134 ]b4_locations_if([[
1135 public final ref ]b4_location_type[ locationAt (int i)
1137 return stack[$-i-1].location;
1138 }]])[
1140 public final ref ]b4_yystype[ valueAt (int i)
1142 return stack[$-i-1].value;
1144 ]b4_parse_trace_if([[
1145 // Print the state stack on the debug stream.
1146 public final void print (File stream)
1148 stream.write ("Stack now");
1149 for (int i = 0; i < stack.length; i++)
1150 stream.write (" ", stack[i].state);
1151 stream.writeln ();
1152 }]])[
1154 ]b4_percent_code_get[
1156 ]b4_percent_code_get([[epilogue]])[]dnl
1157 b4_epilogue[]dnl
1158 b4_output_end