]> git.saurik.com Git - bison.git/commitdiff
parse.lac: implement as %define variable.
authorJoel E. Denny <joeldenny@joeldenny.org>
Sat, 11 Dec 2010 16:13:33 +0000 (11:13 -0500)
committerJoel E. Denny <joeldenny@joeldenny.org>
Fri, 24 Dec 2010 02:13:58 +0000 (21:13 -0500)
LAC = lookahead correction.  See discussion at
<http://lists.gnu.org/archive/html/bison-patches/2009-09/msg00034.html>.
However, one point there must be corrected: because of %nonassoc,
LAC is *not* always redundant for lr.type=canonical-lr.
* data/yacc.c: Accept values of "none" (default) or "full" for
parse.lac.  Accept %define parse.lac.es-capacity to specify
capacity of LAC's temporary exploratory stack.  It defaults to 20
and, for now, will not grow dynamically.
(b4_lac_flag, b4_lac_if): New m4 macros.  Evaluate as true for
parse.lac!=none.
(YYBACKUP): Invoke YY_LAC_DISCARD.
(YY_LAC_ESTABLISH, YY_LAC_DISCARD): New cpp macros that invoke
yy_lac and track when it needs to be invoked
(yy_lac): New function that, given the current stack, determines
whether a token can eventually be shifted.  Return status mimics
yyparse return status.
(yysyntax_error): Change yystate argument to yyssp so stack top
can be passed to yy_lac.  If LAC is requested, build expected
token list by invoking yy_lac for every token instead of just
checking the current state for lookaheads.  Return 2 if yy_lac
exhausts memory.
(yyparse, yypush_parse): Use local variable yy_lac_established and
cpp macros YY_LAC_ESTABLISH and YY_LAC_DISCARD to implement LAC.
Update yysyntax_error invocation.  Add yyexhaustedlab code if LAC
is requested.
* tests/conflicts.at (%nonassoc and eof): Extend to check the
effect of each of -Dlr.type=canonical-lr and -Dparse.lac=full.
(%error-verbose and consistent errors): Likewise.
(LAC: %nonassoc requires splitting canonical LR states): New test
group demonstrating how LAC can fix canonical LR.
* tests/input.at (LAC: Errors for %define): New test group.
* tests/regression.at (LAC: Exploratory stack): New test group.
(LAC: Memory exhaustion): New test group.
(cherry picked from commit bf35c71c5827d735c125ee25b048eabf40960a55)

Conflicts:

src/parse-gram.c
src/parse-gram.h

ChangeLog
data/yacc.c
src/parse-gram.c
src/parse-gram.h
tests/conflicts.at
tests/input.at
tests/regression.at

index 3c6df27f08716c995a547644793f4040f9f33ad3..017deb6d6c30c8ea381955c23b13f87d7fef38f0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2010-12-11  Joel E. Denny  <jdenny@clemson.edu>
+
+       parse.lac: implement as %define variable.
+       LAC = lookahead correction.  See discussion at
+       <http://lists.gnu.org/archive/html/bison-patches/2009-09/msg00034.html>.
+       However, one point there must be corrected: because of %nonassoc,
+       LAC is *not* always redundant for lr.type=canonical-lr.
+       * data/yacc.c: Accept values of "none" (default) or "full" for
+       parse.lac.  Accept %define parse.lac.es-capacity to specify
+       capacity of LAC's temporary exploratory stack.  It defaults to 20
+       and, for now, will not grow dynamically.
+       (b4_lac_flag, b4_lac_if): New m4 macros.  Evaluate as true for
+       parse.lac!=none.
+       (YYBACKUP): Invoke YY_LAC_DISCARD.
+       (YY_LAC_ESTABLISH, YY_LAC_DISCARD): New cpp macros that invoke
+       yy_lac and track when it needs to be invoked
+       (yy_lac): New function that, given the current stack, determines
+       whether a token can eventually be shifted.  Return status mimics
+       yyparse return status.
+       (yysyntax_error): Change yystate argument to yyssp so stack top
+       can be passed to yy_lac.  If LAC is requested, build expected
+       token list by invoking yy_lac for every token instead of just
+       checking the current state for lookaheads.  Return 2 if yy_lac
+       exhausts memory.
+       (yyparse, yypush_parse): Use local variable yy_lac_established and
+       cpp macros YY_LAC_ESTABLISH and YY_LAC_DISCARD to implement LAC.
+       Update yysyntax_error invocation.  Add yyexhaustedlab code if LAC
+       is requested.
+       * tests/conflicts.at (%nonassoc and eof): Extend to check the
+       effect of each of -Dlr.type=canonical-lr and -Dparse.lac=full.
+       (%error-verbose and consistent errors): Likewise.
+       (LAC: %nonassoc requires splitting canonical LR states): New test
+       group demonstrating how LAC can fix canonical LR.
+       * tests/input.at (LAC: Errors for %define): New test group.
+       * tests/regression.at (LAC: Exploratory stack): New test group.
+       (LAC: Memory exhaustion): New test group.
+
 2010-11-21  Joel E. Denny  <jdenny@clemson.edu>
 
        build: use gnulib's new bootstrap_sync option.
 2010-11-21  Joel E. Denny  <jdenny@clemson.edu>
 
        build: use gnulib's new bootstrap_sync option.
index bf804a40472b2b736f1133e64467f4d04a8a2e2a..b6758c695fd519b388615ecb2beab6b1b93bf25a 100644 (file)
@@ -36,6 +36,16 @@ b4_use_push_for_pull_if([
   b4_push_if([m4_define([b4_use_push_for_pull_flag], [[0]])],
              [m4_define([b4_push_flag], [[1]])])])
 
   b4_push_if([m4_define([b4_use_push_for_pull_flag], [[0]])],
              [m4_define([b4_push_flag], [[1]])])])
 
+# Check the value of %define parse.lac, where LAC stands for lookahead
+# correction.
+b4_percent_define_default([[parse.lac]], [[none]])
+b4_percent_define_default([[parse.lac.es-capacity]], [[20]])
+b4_percent_define_check_values([[[[parse.lac]], [[full]], [[none]]]])
+b4_define_flag_if([lac])
+m4_define([b4_lac_flag],
+          [m4_if(b4_percent_define_get([[parse.lac]]),
+                 [none], [[0]], [[1]])])
+
 m4_include(b4_pkgdatadir/[c.m4])
 
 ## ---------------- ##
 m4_include(b4_pkgdatadir/[c.m4])
 
 ## ---------------- ##
@@ -697,7 +707,8 @@ do                                                          \
     {                                                          \
       yychar = (Token);                                                \
       yylval = (Value);                                                \
     {                                                          \
       yychar = (Token);                                                \
       yylval = (Value);                                                \
-      YYPOPSTACK (1);                                          \
+      YYPOPSTACK (1);                                          \]b4_lac_if([[
+      YY_LAC_DISCARD ("YYBACKUP");                             \]])[
       goto yybackup;                                           \
     }                                                          \
   else                                                         \
       goto yybackup;                                           \
     }                                                          \
   else                                                         \
@@ -879,9 +890,173 @@ int yydebug;
 
 #ifndef YYMAXDEPTH
 # define YYMAXDEPTH ]b4_stack_depth_max[
 
 #ifndef YYMAXDEPTH
 # define YYMAXDEPTH ]b4_stack_depth_max[
+#endif]b4_lac_if([[
+
+/* Establish the initial context for the current lookahead if no initial
+   context is currently established.
+
+   We define a context as a snapshot of the parser stacks.  We define
+   the initial context for a lookahead as the context in which the
+   parser initially examines that lookahead in order to select a
+   syntactic action.  Thus, if the lookahead eventually proves
+   syntactically unacceptable (possibly in a later context reached via a
+   series of reductions), the initial context can be used to determine
+   the exact set of tokens that would be syntactically acceptable in the
+   lookahead's place.  Moreover, it is the context after which any
+   further semantic actions would be erroneous because they would be
+   determined by a syntactically unacceptable token.
+
+   YY_LAC_ESTABLISH should be invoked when a reduction is about to be
+   performed in an inconsistent state (which, for the purposes of LAC,
+   includes consistent states that don't know they're consistent because
+   their default reductions have been disabled).  Iff there is a
+   lookahead token, it should also be invoked before reporting a syntax
+   error.  This latter case is for the sake of the debugging output.
+
+   For parse.lac=full, the implementation of YY_LAC_ESTABLISH is as
+   follows.  If no initial context is currently established for the
+   current lookahead, then check if that lookahead can eventually be
+   shifted if syntactic actions continue from the current context.
+   Report a syntax error if it cannot.  */
+#define YY_LAC_ESTABLISH                                       \
+do {                                                           \
+  if (!yy_lac_established)                                     \
+    {                                                          \
+      YYDPRINTF ((stderr,                                      \
+                  "LAC: initial context established for %s\n", \
+                  yytname[yytoken]));                          \
+      yy_lac_established = 1;                                  \
+      {                                                        \
+        int yy_lac_status =                                    \
+          yy_lac (yyssp, yytoken);                             \
+        if (yy_lac_status == 2)                                \
+          goto yyexhaustedlab;                                 \
+        if (yy_lac_status == 1)                                \
+          goto yyerrlab;                                       \
+      }                                                        \
+    }                                                          \
+} while (YYID (0))
+
+/* Discard any previous initial lookahead context because of Event,
+   which may be a lookahead change or an invalidation of the currently
+   established initial context for the current lookahead.
+
+   The most common example of a lookahead change is a shift.  An example
+   of both cases is syntax error recovery.  That is, a syntax error
+   occurs when the lookahead is syntactically erroneous for the
+   currently established initial context, so error recovery manipulates
+   the parser stacks to try to find a new initial context in which the
+   current lookahead is syntactically acceptable.  If it fails to find
+   such a context, it discards the lookahead.  */
+#if YYDEBUG
+# define YY_LAC_DISCARD(Event)                                           \
+do {                                                                     \
+  if (yy_lac_established)                                                \
+    {                                                                    \
+      if (yydebug)                                                       \
+        YYFPRINTF (stderr, "LAC: initial context discarded due to "      \
+                   Event "\n");                                          \
+      yy_lac_established = 0;                                            \
+    }                                                                    \
+} while (YYID (0))
+#else
+# define YY_LAC_DISCARD(Event) yy_lac_established = 0
 #endif
 
 #endif
 
-\f
+/* Given the stack whose top is *YYSSP, return 0 iff YYTOKEN can
+   eventually (after perhaps some reductions) be shifted, and return 1
+   if not.  Return 2 if memory is exhausted.  */
+static int
+yy_lac (yytype_int16 *yyssp, int yytoken)
+{
+  yytype_int16 *yyes_prev = yyssp;
+  yytype_int16 yyes@{]b4_percent_define_get([[parse.lac.es-capacity]])[@};
+  yytype_int16 *yyesp = yyes_prev;
+  YYDPRINTF ((stderr, "LAC: checking lookahead %s:", yytname[yytoken]));
+  if (yytoken == YYUNDEFTOK)
+    {
+      YYDPRINTF ((stderr, " Always Err\n"));
+      return 1;
+    }
+  while (1)
+    {
+      int yyrule = yypact[*yyesp];
+      if (yypact_value_is_default (yyrule)
+          || (yyrule += yytoken) < 0 || YYLAST < yyrule
+          || yycheck[yyrule] != yytoken)
+        {
+          yyrule = yydefact[*yyesp];
+          if (yyrule == 0)
+            {
+              YYDPRINTF ((stderr, " Err\n"));
+              return 1;
+            }
+        }
+      else
+        {
+          yyrule = yytable[yyrule];
+          if (yytable_value_is_error (yyrule))
+            {
+              YYDPRINTF ((stderr, " Err\n"));
+              return 1;
+            }
+          if (0 < yyrule)
+            {
+              YYDPRINTF ((stderr, " S%d\n", yyrule));
+              return 0;
+            }
+          yyrule = -yyrule;
+        }
+      {
+        YYSIZE_T yylen = yyr2[yyrule];
+        YYDPRINTF ((stderr, " R%d", yyrule - 1));
+        if (yyesp != yyes_prev)
+          {
+            YYSIZE_T yysize = yyesp - yyes + 1;
+            if (yylen < yysize)
+              {
+                yyesp -= yylen;
+                yylen = 0;
+              }
+            else
+              {
+                yylen -= yysize;
+                yyesp = yyes_prev;
+              }
+          }
+        if (yylen)
+          yyesp = yyes_prev -= yylen;
+      }
+      {
+        int yystate;
+        {
+          int yylhs = yyr1[yyrule] - YYNTOKENS;
+          yystate = yypgoto[yylhs] + *yyesp;
+          if (yystate < 0 || YYLAST < yystate
+              || yycheck[yystate] != *yyesp)
+            yystate = yydefgoto[yylhs];
+          else
+            yystate = yytable[yystate];
+        }
+        if (yyesp == yyes_prev)
+          {
+            yyesp = yyes;
+            *yyesp = yystate;
+          }
+        else
+          {
+            if (yyesp == yyes + (sizeof yyes / sizeof *yyes) - 1)
+              {
+                YYDPRINTF ((stderr, " (max stack size exceeded)\n"));
+                return 2;
+              }
+            *++yyesp = yystate;
+          }
+        YYDPRINTF ((stderr, " G%d", *yyesp));
+      }
+    }
+}]])[
+
 
 #if YYERROR_VERBOSE
 
 
 #if YYERROR_VERBOSE
 
@@ -970,15 +1145,18 @@ yytnamerr (char *yyres, const char *yystr)
 # endif
 
 /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
 # endif
 
 /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
-   about the unexpected token YYTOKEN while in state YYSTATE.
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.]b4_lac_if([[  In order to see if a particular token T is a
+   valid looakhead, invoke yy_lac (YYSSP, T).]])[
 
    Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
    not large enough to hold the message.  In that case, also set
    *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
 
    Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
    not large enough to hold the message.  In that case, also set
    *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
-   required number of bytes is too large to store.  */
+   required number of bytes is too large to store]b4_lac_if([[ or if
+   yy_lac returned 2]])[.  */
 static int
 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
 static int
 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
-                int yystate, int yytoken)
+                yytype_int16 *yyssp, int yytoken)
 {
   YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
 {
   YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
@@ -1009,7 +1187,12 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
      - Don't assume there isn't a lookahead just because this state is a
        consistent state with a default action.  There might have been a
        previous inconsistent state, consistent state with a non-default
      - Don't assume there isn't a lookahead just because this state is a
        consistent state with a default action.  There might have been a
        previous inconsistent state, consistent state with a non-default
-       action, or user semantic action that manipulated yychar.
+       action, or user semantic action that manipulated yychar.]b4_lac_if([[
+       In the first two cases, it might appear that the current syntax
+       error should have been detected in the previous state when yy_lac
+       was invoked.  However, at that time, there might have been a
+       different syntax error that discarded a different initial context
+       during error recovery, leaving behind the current lookahead.]], [[
      - Of course, the expected token list depends on states to have
        correct lookahead information, and it depends on the parser not
        to perform extra reductions after fetching a lookahead from the
      - Of course, the expected token list depends on states to have
        correct lookahead information, and it depends on the parser not
        to perform extra reductions after fetching a lookahead from the
@@ -1017,26 +1200,39 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
        (from LALR or IELR) and default reductions corrupt the expected
        token list.  However, the list is correct for canonical LR with
        one exception: it will still contain any token that will not be
        (from LALR or IELR) and default reductions corrupt the expected
        token list.  However, the list is correct for canonical LR with
        one exception: it will still contain any token that will not be
-       accepted due to an error action in a later state.
+       accepted due to an error action in a later state.]])[
   */
   if (yytoken != YYEMPTY)
     {
   */
   if (yytoken != YYEMPTY)
     {
-      int yyn = yypact[yystate];
+      int yyn = yypact[*yyssp];]b4_lac_if([[
+      YYDPRINTF ((stderr, "Constructing syntax error message\n"));]])[
       yyarg[yycount++] = yytname[yytoken];
       if (!yypact_value_is_default (yyn))
       yyarg[yycount++] = yytname[yytoken];
       if (!yypact_value_is_default (yyn))
-        {
+        {]b4_lac_if([], [[
           /* Start YYX at -YYN if negative to avoid negative indexes in
              YYCHECK.  In other words, skip the first -YYN actions for
              this state because they are default actions.  */
           int yyxbegin = yyn < 0 ? -yyn : 0;
           /* Stay within bounds of both yycheck and yytname.  */
           int yychecklim = YYLAST - yyn + 1;
           /* Start YYX at -YYN if negative to avoid negative indexes in
              YYCHECK.  In other words, skip the first -YYN actions for
              this state because they are default actions.  */
           int yyxbegin = yyn < 0 ? -yyn : 0;
           /* Stay within bounds of both yycheck and yytname.  */
           int yychecklim = YYLAST - yyn + 1;
-          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-          int yyx;
+          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;]])[
+          int yyx;]b4_lac_if([[
+
+          for (yyx = 0; yyx < YYNTOKENS; ++yyx)
+            if (yyx != YYTERROR && yyx != YYUNDEFTOK)
+              {
+                {
+                  int yy_lac_status = yy_lac (yyssp, yyx);
+                  if (yy_lac_status == 2)
+                    return 2;
+                  if (yy_lac_status == 1)
+                    continue;
+                }]], [[
+
           for (yyx = yyxbegin; yyx < yyxend; ++yyx)
             if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
                 && !yytable_value_is_error (yytable[yyx + yyn]))
           for (yyx = yyxbegin; yyx < yyxend; ++yyx)
             if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
                 && !yytable_value_is_error (yytable[yyx + yyn]))
-              {
+              {]])[
                 if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
                   {
                     yycount = 1;
                 if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
                   {
                     yycount = 1;
@@ -1050,12 +1246,16 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                   return 2;
                 yysize = yysize1;
               }
                   return 2;
                 yysize = yysize1;
               }
-        }
+        }]b4_lac_if([[
+# if YYDEBUG
+      else if (yydebug)
+        YYFPRINTF (stderr, "No expected tokens.\n");
+# endif]])[
     }
 
   switch (yycount)
     {
     }
 
   switch (yycount)
     {
-#define YYCASE_(N, S)                       \
+# define YYCASE_(N, S)                      \
       case N:                               \
         yyformat = S;                       \
       break
       case N:                               \
         yyformat = S;                       \
       break
@@ -1065,7 +1265,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
       YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
       YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
       YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
       YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
       YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-#undef YYCASE_
+# undef YYCASE_
     }
 
   yysize1 = yysize + yystrlen (yyformat);
     }
 
   yysize1 = yysize + yystrlen (yyformat);
@@ -1103,7 +1303,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
   return 0;
 }
 #endif /* YYERROR_VERBOSE */
   return 0;
 }
 #endif /* YYERROR_VERBOSE */
-\f
 
 ]b4_yydestruct_generate([b4_c_function_def])b4_push_if([], [[
 
 
 ]b4_yydestruct_generate([b4_c_function_def])b4_push_if([], [[
 
@@ -1238,7 +1437,8 @@ b4_c_function_def([[yyparse]], [[int]], b4_parse_param)[
   YYLTYPE yypushed_loc = yylloc;]])
 ])],
   [b4_declare_parser_state_variables
   YYLTYPE yypushed_loc = yylloc;]])
 ])],
   [b4_declare_parser_state_variables
-])[
+])b4_lac_if([[
+  int yy_lac_established = 0;]])[
   int yyn;
   int yyresult;
   /* Lookahead token as an internal (translated) token number.  */
   int yyn;
   int yyresult;
   /* Lookahead token as an internal (translated) token number.  */
@@ -1445,13 +1645,18 @@ yyread_pushed_token:]])[
   /* If the proper action on seeing token YYTOKEN is to reduce or to
      detect an error, take that action.  */
   yyn += yytoken;
   /* If the proper action on seeing token YYTOKEN is to reduce or to
      detect an error, take that action.  */
   yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)]b4_lac_if([[
+    {
+      YY_LAC_ESTABLISH;
+      goto yydefault;
+    }]], [[
+    goto yydefault;]])[
   yyn = yytable[yyn];
   if (yyn <= 0)
     {
       if (yytable_value_is_error (yyn))
   yyn = yytable[yyn];
   if (yyn <= 0)
     {
       if (yytable_value_is_error (yyn))
-       goto yyerrlab;
+        goto yyerrlab;]b4_lac_if([[
+      YY_LAC_ESTABLISH;]])[
       yyn = -yyn;
       goto yyreduce;
     }
       yyn = -yyn;
       goto yyreduce;
     }
@@ -1465,7 +1670,8 @@ yyread_pushed_token:]])[
   YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
 
   /* Discard the shifted token.  */
   YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
 
   /* Discard the shifted token.  */
-  yychar = YYEMPTY;
+  yychar = YYEMPTY;]b4_lac_if([[
+  YY_LAC_DISCARD ("shift");]])[
 
   yystate = yyn;
   *++yyvsp = yylval;
 
   yystate = yyn;
   *++yyvsp = yylval;
@@ -1503,12 +1709,22 @@ yyreduce:
 ]b4_locations_if(
 [[  /* Default location.  */
   YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);]])[
 ]b4_locations_if(
 [[  /* Default location.  */
   YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);]])[
-  YY_REDUCE_PRINT (yyn);
+  YY_REDUCE_PRINT (yyn);]b4_lac_if([[
+  {
+    int yychar_backup = yychar;
+    switch (yyn)
+      {
+        ]b4_user_actions[
+        default: break;
+      }
+    if (yychar_backup != yychar)
+      YY_LAC_DISCARD ("yychar change");
+  }]], [[
   switch (yyn)
     {
       ]b4_user_actions[
       default: break;
   switch (yyn)
     {
       ]b4_user_actions[
       default: break;
-    }
+    }]])[
   /* User semantic actions sometimes alter yychar, and that requires
      that yytoken be updated with the new translation.  We take the
      approach of translating immediately before every use of yytoken.
   /* User semantic actions sometimes alter yychar, and that requires
      that yytoken be updated with the new translation.  We take the
      approach of translating immediately before every use of yytoken.
@@ -1559,11 +1775,14 @@ yyerrlab:
 #if ! YYERROR_VERBOSE
       yyerror (]b4_yyerror_args[YY_("syntax error"));
 #else
 #if ! YYERROR_VERBOSE
       yyerror (]b4_yyerror_args[YY_("syntax error"));
 #else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, yystate, \
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, yyssp, \
                                         yytoken)
       {
         char const *yymsgp = YY_("syntax error");
                                         yytoken)
       {
         char const *yymsgp = YY_("syntax error");
-        int yysyntax_error_status = YYSYNTAX_ERROR;
+        int yysyntax_error_status;]b4_lac_if([[
+        if (yychar != YYEMPTY)
+          YY_LAC_ESTABLISH;]])[
+        yysyntax_error_status = YYSYNTAX_ERROR;
         if (yysyntax_error_status == 0)
           yymsgp = yymsg;
         else if (yysyntax_error_status == 1)
         if (yysyntax_error_status == 0)
           yymsgp = yymsg;
         else if (yysyntax_error_status == 1)
@@ -1668,7 +1887,11 @@ yyerrlab1:
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
       YYPOPSTACK (1);
       yystate = *yyssp;
       YY_STACK_PRINT (yyss, yyssp);
-    }
+    }]b4_lac_if([[
+
+  /* If the stack popping above didn't lose the initial context for the
+     current lookahead token, the shift below will for sure.  */
+  YY_LAC_DISCARD ("error recovery");]])[
 
   *++yyvsp = yylval;
 ]b4_locations_if([[
 
   *++yyvsp = yylval;
 ]b4_locations_if([[
@@ -1699,7 +1922,7 @@ yyabortlab:
   yyresult = 1;
   goto yyreturn;
 
   yyresult = 1;
   goto yyreturn;
 
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#if ]b4_lac_if([[1]], [[!defined(yyoverflow) || YYERROR_VERBOSE]])[
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
index a06602de8ba7008f62db21394582e5655fa97c52..50fc1c6060a2a6e6c05523e400220af03e0f9883 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.4.1.247-0e0f-dirty.  */
+/* A Bison parser, made by GNU Bison 2.4.1.252-dcd39.  */
 
 /* Skeleton implementation for Bison's Yacc-like parsers in C
    
 
 /* Skeleton implementation for Bison's Yacc-like parsers in C
    
@@ -45,7 +45,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.4.1.247-0e0f-dirty"
+#define YYBISON_VERSION "2.4.1.252-dcd39"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -74,7 +74,7 @@
 
 /* Copy the first part of user declarations.  */
 
 
 /* Copy the first part of user declarations.  */
 
-/* Line 251 of yacc.c  */
+/* Line 261 of yacc.c  */
 #line 1 "parse-gram.y"
 /* Bison Grammar Parser                             -*- C -*-
 
 #line 1 "parse-gram.y"
 /* Bison Grammar Parser                             -*- C -*-
 
@@ -151,7 +151,7 @@ static int current_prec = 0;
 #define YYTYPE_UINT8 uint_fast8_t
 
 
 #define YYTYPE_UINT8 uint_fast8_t
 
 
-/* Line 251 of yacc.c  */
+/* Line 261 of yacc.c  */
 #line 156 "parse-gram.c"
 
 /* Enabling traces.  */
 #line 156 "parse-gram.c"
 
 /* Enabling traces.  */
@@ -302,7 +302,7 @@ static int current_prec = 0;
 typedef union YYSTYPE
 {
 
 typedef union YYSTYPE
 {
 
-/* Line 276 of yacc.c  */
+/* Line 286 of yacc.c  */
 #line 94 "parse-gram.y"
 
   symbol *symbol;
 #line 94 "parse-gram.y"
 
   symbol *symbol;
@@ -317,7 +317,7 @@ typedef union YYSTYPE
 
 
 
 
 
 
-/* Line 276 of yacc.c  */
+/* Line 286 of yacc.c  */
 #line 322 "parse-gram.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 #line 322 "parse-gram.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
@@ -342,7 +342,7 @@ typedef struct YYLTYPE
 /* Copy the second part of user declarations.  */
 
 
 /* Copy the second part of user declarations.  */
 
 
-/* Line 326 of yacc.c  */
+/* Line 336 of yacc.c  */
 #line 347 "parse-gram.c"
 
 #ifdef short
 #line 347 "parse-gram.c"
 
 #ifdef short
@@ -1049,164 +1049,164 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp)
     {
       case 3: /* "\"string\"" */
 
     {
       case 3: /* "\"string\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 184 "parse-gram.y"
        { fputs (quotearg_style (c_quoting_style, (yyvaluep->chars)), stderr); };
 
 #line 184 "parse-gram.y"
        { fputs (quotearg_style (c_quoting_style, (yyvaluep->chars)), stderr); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1058 "parse-gram.c"
        break;
       case 4: /* "\"integer\"" */
 
 #line 1058 "parse-gram.c"
        break;
       case 4: /* "\"integer\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 196 "parse-gram.y"
        { fprintf (stderr, "%d", (yyvaluep->integer)); };
 
 #line 196 "parse-gram.y"
        { fprintf (stderr, "%d", (yyvaluep->integer)); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1067 "parse-gram.c"
        break;
       case 43: /* "\"{...}\"" */
 
 #line 1067 "parse-gram.c"
        break;
       case 43: /* "\"{...}\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->code)); };
 
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->code)); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1076 "parse-gram.c"
        break;
       case 44: /* "\"[identifier]\"" */
 
 #line 1076 "parse-gram.c"
        break;
       case 44: /* "\"[identifier]\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 191 "parse-gram.y"
        { fprintf (stderr, "[%s]", (yyvaluep->uniqstr)); };
 
 #line 191 "parse-gram.y"
        { fprintf (stderr, "[%s]", (yyvaluep->uniqstr)); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1085 "parse-gram.c"
        break;
       case 45: /* "\"char\"" */
 
 #line 1085 "parse-gram.c"
        break;
       case 45: /* "\"char\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 178 "parse-gram.y"
        { fputs (char_name ((yyvaluep->character)), stderr); };
 
 #line 178 "parse-gram.y"
        { fputs (char_name ((yyvaluep->character)), stderr); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1094 "parse-gram.c"
        break;
       case 46: /* "\"epilogue\"" */
 
 #line 1094 "parse-gram.c"
        break;
       case 46: /* "\"epilogue\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->chars)); };
 
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->chars)); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1103 "parse-gram.c"
        break;
       case 48: /* "\"identifier\"" */
 
 #line 1103 "parse-gram.c"
        break;
       case 48: /* "\"identifier\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 190 "parse-gram.y"
        { fputs ((yyvaluep->uniqstr), stderr); };
 
 #line 190 "parse-gram.y"
        { fputs ((yyvaluep->uniqstr), stderr); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1112 "parse-gram.c"
        break;
       case 49: /* "\"identifier:\"" */
 
 #line 1112 "parse-gram.c"
        break;
       case 49: /* "\"identifier:\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 192 "parse-gram.y"
        { fprintf (stderr, "%s:", (yyvaluep->uniqstr)); };
 
 #line 192 "parse-gram.y"
        { fprintf (stderr, "%s:", (yyvaluep->uniqstr)); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1121 "parse-gram.c"
        break;
       case 52: /* "\"%{...%}\"" */
 
 #line 1121 "parse-gram.c"
        break;
       case 52: /* "\"%{...%}\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->chars)); };
 
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->chars)); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1130 "parse-gram.c"
        break;
       case 54: /* "\"type\"" */
 
 #line 1130 "parse-gram.c"
        break;
       case 54: /* "\"type\"" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 193 "parse-gram.y"
        { fprintf (stderr, "<%s>", (yyvaluep->uniqstr)); };
 
 #line 193 "parse-gram.y"
        { fprintf (stderr, "<%s>", (yyvaluep->uniqstr)); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1139 "parse-gram.c"
        break;
       case 71: /* "symbol.prec" */
 
 #line 1139 "parse-gram.c"
        break;
       case 71: /* "symbol.prec" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 199 "parse-gram.y"
        { fprintf (stderr, "%s", (yyvaluep->symbol)->tag); };
 
 #line 199 "parse-gram.y"
        { fprintf (stderr, "%s", (yyvaluep->symbol)->tag); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1148 "parse-gram.c"
        break;
       case 84: /* "variable" */
 
 #line 1148 "parse-gram.c"
        break;
       case 84: /* "variable" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 190 "parse-gram.y"
        { fputs ((yyvaluep->uniqstr), stderr); };
 
 #line 190 "parse-gram.y"
        { fputs ((yyvaluep->uniqstr), stderr); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1157 "parse-gram.c"
        break;
       case 85: /* "content.opt" */
 
 #line 1157 "parse-gram.c"
        break;
       case 85: /* "content.opt" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->chars)); };
 
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->chars)); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1166 "parse-gram.c"
        break;
       case 86: /* "braceless" */
 
 #line 1166 "parse-gram.c"
        break;
       case 86: /* "braceless" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->chars)); };
 
 #line 186 "parse-gram.y"
        { fprintf (stderr, "{\n%s\n}", (yyvaluep->chars)); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1175 "parse-gram.c"
        break;
       case 87: /* "id" */
 
 #line 1175 "parse-gram.c"
        break;
       case 87: /* "id" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 199 "parse-gram.y"
        { fprintf (stderr, "%s", (yyvaluep->symbol)->tag); };
 
 #line 199 "parse-gram.y"
        { fprintf (stderr, "%s", (yyvaluep->symbol)->tag); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1184 "parse-gram.c"
        break;
       case 88: /* "id_colon" */
 
 #line 1184 "parse-gram.c"
        break;
       case 88: /* "id_colon" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 200 "parse-gram.y"
        { fprintf (stderr, "%s:", (yyvaluep->symbol)->tag); };
 
 #line 200 "parse-gram.y"
        { fprintf (stderr, "%s:", (yyvaluep->symbol)->tag); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1193 "parse-gram.c"
        break;
       case 89: /* "symbol" */
 
 #line 1193 "parse-gram.c"
        break;
       case 89: /* "symbol" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 199 "parse-gram.y"
        { fprintf (stderr, "%s", (yyvaluep->symbol)->tag); };
 
 #line 199 "parse-gram.y"
        { fprintf (stderr, "%s", (yyvaluep->symbol)->tag); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1202 "parse-gram.c"
        break;
       case 90: /* "string_as_id" */
 
 #line 1202 "parse-gram.c"
        break;
       case 90: /* "string_as_id" */
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 199 "parse-gram.y"
        { fprintf (stderr, "%s", (yyvaluep->symbol)->tag); };
 
 #line 199 "parse-gram.y"
        { fprintf (stderr, "%s", (yyvaluep->symbol)->tag); };
 
-/* Line 797 of yacc.c  */
+/* Line 808 of yacc.c  */
 #line 1211 "parse-gram.c"
        break;
       default:
 #line 1211 "parse-gram.c"
        break;
       default:
@@ -1340,7 +1340,6 @@ int yydebug;
 # define YYMAXDEPTH 10000
 #endif
 
 # define YYMAXDEPTH 10000
 #endif
 
-\f
 
 #if YYERROR_VERBOSE
 
 
 #if YYERROR_VERBOSE
 
@@ -1444,7 +1443,8 @@ yytnamerr (char *yyres, const char *yystr)
 # endif
 
 /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
 # endif
 
 /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
-   about the unexpected token YYTOKEN while in state YYSTATE.
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
 
    Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
    not large enough to hold the message.  In that case, also set
 
    Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
    not large enough to hold the message.  In that case, also set
@@ -1452,7 +1452,7 @@ yytnamerr (char *yyres, const char *yystr)
    required number of bytes is too large to store.  */
 static int
 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
    required number of bytes is too large to store.  */
 static int
 yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
-                int yystate, int yytoken)
+                yytype_int16 *yyssp, int yytoken)
 {
   YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
 {
   YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
@@ -1495,7 +1495,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
   */
   if (yytoken != YYEMPTY)
     {
   */
   if (yytoken != YYEMPTY)
     {
-      int yyn = yypact[yystate];
+      int yyn = yypact[*yyssp];
       yyarg[yycount++] = yytname[yytoken];
       if (!yypact_value_is_default (yyn))
         {
       yyarg[yycount++] = yytname[yytoken];
       if (!yypact_value_is_default (yyn))
         {
@@ -1507,6 +1507,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
           int yychecklim = YYLAST - yyn + 1;
           int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
           int yyx;
           int yychecklim = YYLAST - yyn + 1;
           int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
           int yyx;
+
           for (yyx = yyxbegin; yyx < yyxend; ++yyx)
             if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
                 && !yytable_value_is_error (yytable[yyx + yyn]))
           for (yyx = yyxbegin; yyx < yyxend; ++yyx)
             if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
                 && !yytable_value_is_error (yytable[yyx + yyn]))
@@ -1529,7 +1530,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
 
   switch (yycount)
     {
 
   switch (yycount)
     {
-#define YYCASE_(N, S)                       \
+# define YYCASE_(N, S)                      \
       case N:                               \
         yyformat = S;                       \
       break
       case N:                               \
         yyformat = S;                       \
       break
@@ -1539,7 +1540,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
       YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
       YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
       YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
       YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
       YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
       YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-#undef YYCASE_
+# undef YYCASE_
     }
 
   yysize1 = yysize + yystrlen (yyformat);
     }
 
   yysize1 = yysize + yystrlen (yyformat);
@@ -1577,7 +1578,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
   return 0;
 }
 #endif /* YYERROR_VERBOSE */
   return 0;
 }
 #endif /* YYERROR_VERBOSE */
-\f
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
@@ -1750,7 +1750,7 @@ YYLTYPE yylloc;
 
 /* User initialization code.  */
 
 
 /* User initialization code.  */
 
-/* Line 1296 of yacc.c  */
+/* Line 1496 of yacc.c  */
 #line 86 "parse-gram.y"
 {
   /* Bison's grammar can initial empty locations, hence a default
 #line 86 "parse-gram.y"
 {
   /* Bison's grammar can initial empty locations, hence a default
@@ -1759,7 +1759,7 @@ YYLTYPE yylloc;
   boundary_set (&yylloc.end, current_file, 1, 1);
 }
 
   boundary_set (&yylloc.end, current_file, 1, 1);
 }
 
-/* Line 1296 of yacc.c  */
+/* Line 1496 of yacc.c  */
 #line 1764 "parse-gram.c"
   yylsp[0] = yylloc;
 
 #line 1764 "parse-gram.c"
   yylsp[0] = yylloc;
 
@@ -1891,7 +1891,7 @@ yybackup:
   if (yyn <= 0)
     {
       if (yytable_value_is_error (yyn))
   if (yyn <= 0)
     {
       if (yytable_value_is_error (yyn))
-       goto yyerrlab;
+        goto yyerrlab;
       yyn = -yyn;
       goto yyreduce;
     }
       yyn = -yyn;
       goto yyreduce;
     }
@@ -1947,7 +1947,7 @@ yyreduce:
     {
         case 6:
 
     {
         case 6:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 225 "parse-gram.y"
     {
       code_props plain_code;
 #line 225 "parse-gram.y"
     {
       code_props plain_code;
@@ -1962,14 +1962,14 @@ yyreduce:
 
   case 7:
 
 
   case 7:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 234 "parse-gram.y"
     { debug_flag = true; }
     break;
 
   case 8:
 
 #line 234 "parse-gram.y"
     { debug_flag = true; }
     break;
 
   case 8:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 236 "parse-gram.y"
     {
       muscle_percent_define_insert ((yyvsp[(2) - (3)].uniqstr), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].chars),
 #line 236 "parse-gram.y"
     {
       muscle_percent_define_insert ((yyvsp[(2) - (3)].uniqstr), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].chars),
@@ -1979,14 +1979,14 @@ yyreduce:
 
   case 9:
 
 
   case 9:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 240 "parse-gram.y"
     { defines_flag = true; }
     break;
 
   case 10:
 
 #line 240 "parse-gram.y"
     { defines_flag = true; }
     break;
 
   case 10:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 242 "parse-gram.y"
     {
       defines_flag = true;
 #line 242 "parse-gram.y"
     {
       defines_flag = true;
@@ -1996,42 +1996,42 @@ yyreduce:
 
   case 11:
 
 
   case 11:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 246 "parse-gram.y"
     { error_verbose = true; }
     break;
 
   case 12:
 
 #line 246 "parse-gram.y"
     { error_verbose = true; }
     break;
 
   case 12:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 247 "parse-gram.y"
     { expected_sr_conflicts = (yyvsp[(2) - (2)].integer); }
     break;
 
   case 13:
 
 #line 247 "parse-gram.y"
     { expected_sr_conflicts = (yyvsp[(2) - (2)].integer); }
     break;
 
   case 13:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 248 "parse-gram.y"
     { expected_rr_conflicts = (yyvsp[(2) - (2)].integer); }
     break;
 
   case 14:
 
 #line 248 "parse-gram.y"
     { expected_rr_conflicts = (yyvsp[(2) - (2)].integer); }
     break;
 
   case 14:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 249 "parse-gram.y"
     { spec_file_prefix = (yyvsp[(2) - (2)].chars); }
     break;
 
   case 15:
 
 #line 249 "parse-gram.y"
     { spec_file_prefix = (yyvsp[(2) - (2)].chars); }
     break;
 
   case 15:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 250 "parse-gram.y"
     { spec_file_prefix = (yyvsp[(3) - (3)].chars); }
     break;
 
   case 16:
 
 #line 250 "parse-gram.y"
     { spec_file_prefix = (yyvsp[(3) - (3)].chars); }
     break;
 
   case 16:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 252 "parse-gram.y"
     {
       nondeterministic_parser = true;
 #line 252 "parse-gram.y"
     {
       nondeterministic_parser = true;
@@ -2041,7 +2041,7 @@ yyreduce:
 
   case 17:
 
 
   case 17:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 257 "parse-gram.y"
     {
       code_props action;
 #line 257 "parse-gram.y"
     {
       code_props action;
@@ -2055,77 +2055,77 @@ yyreduce:
 
   case 18:
 
 
   case 18:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 265 "parse-gram.y"
     { language_argmatch ((yyvsp[(2) - (2)].chars), grammar_prio, (yylsp[(1) - (2)])); }
     break;
 
   case 19:
 
 #line 265 "parse-gram.y"
     { language_argmatch ((yyvsp[(2) - (2)].chars), grammar_prio, (yylsp[(1) - (2)])); }
     break;
 
   case 19:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 266 "parse-gram.y"
     { add_param ("lex_param", (yyvsp[(2) - (2)].code), (yylsp[(2) - (2)])); }
     break;
 
   case 20:
 
 #line 266 "parse-gram.y"
     { add_param ("lex_param", (yyvsp[(2) - (2)].code), (yylsp[(2) - (2)])); }
     break;
 
   case 20:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 267 "parse-gram.y"
     { locations_flag = true; }
     break;
 
   case 21:
 
 #line 267 "parse-gram.y"
     { locations_flag = true; }
     break;
 
   case 21:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 268 "parse-gram.y"
     { spec_name_prefix = (yyvsp[(2) - (2)].chars); }
     break;
 
   case 22:
 
 #line 268 "parse-gram.y"
     { spec_name_prefix = (yyvsp[(2) - (2)].chars); }
     break;
 
   case 22:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 269 "parse-gram.y"
     { spec_name_prefix = (yyvsp[(3) - (3)].chars); }
     break;
 
   case 23:
 
 #line 269 "parse-gram.y"
     { spec_name_prefix = (yyvsp[(3) - (3)].chars); }
     break;
 
   case 23:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 270 "parse-gram.y"
     { no_lines_flag = true; }
     break;
 
   case 24:
 
 #line 270 "parse-gram.y"
     { no_lines_flag = true; }
     break;
 
   case 24:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 271 "parse-gram.y"
     { nondeterministic_parser = true; }
     break;
 
   case 25:
 
 #line 271 "parse-gram.y"
     { nondeterministic_parser = true; }
     break;
 
   case 25:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 272 "parse-gram.y"
     { spec_outfile = (yyvsp[(2) - (2)].chars); }
     break;
 
   case 26:
 
 #line 272 "parse-gram.y"
     { spec_outfile = (yyvsp[(2) - (2)].chars); }
     break;
 
   case 26:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 273 "parse-gram.y"
     { spec_outfile = (yyvsp[(3) - (3)].chars); }
     break;
 
   case 27:
 
 #line 273 "parse-gram.y"
     { spec_outfile = (yyvsp[(3) - (3)].chars); }
     break;
 
   case 27:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 274 "parse-gram.y"
     { add_param ("parse_param", (yyvsp[(2) - (2)].code), (yylsp[(2) - (2)])); }
     break;
 
   case 28:
 
 #line 274 "parse-gram.y"
     { add_param ("parse_param", (yyvsp[(2) - (2)].code), (yylsp[(2) - (2)])); }
     break;
 
   case 28:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 276 "parse-gram.y"
     {
       /* %pure-parser is deprecated in favor of `%define api.pure', so use
 #line 276 "parse-gram.y"
     {
       /* %pure-parser is deprecated in favor of `%define api.pure', so use
@@ -2145,14 +2145,14 @@ yyreduce:
 
   case 29:
 
 
   case 29:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 290 "parse-gram.y"
     { version_check (&(yylsp[(2) - (2)]), (yyvsp[(2) - (2)].chars)); }
     break;
 
   case 30:
 
 #line 290 "parse-gram.y"
     { version_check (&(yylsp[(2) - (2)]), (yyvsp[(2) - (2)].chars)); }
     break;
 
   case 30:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 292 "parse-gram.y"
     {
       char const *skeleton_user = (yyvsp[(2) - (2)].chars);
 #line 292 "parse-gram.y"
     {
       char const *skeleton_user = (yyvsp[(2) - (2)].chars);
@@ -2181,28 +2181,28 @@ yyreduce:
 
   case 31:
 
 
   case 31:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 315 "parse-gram.y"
     { token_table_flag = true; }
     break;
 
   case 32:
 
 #line 315 "parse-gram.y"
     { token_table_flag = true; }
     break;
 
   case 32:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 316 "parse-gram.y"
     { report_flag |= report_states; }
     break;
 
   case 33:
 
 #line 316 "parse-gram.y"
     { report_flag |= report_states; }
     break;
 
   case 33:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 317 "parse-gram.y"
     { yacc_flag = true; }
     break;
 
   case 37:
 
 #line 317 "parse-gram.y"
     { yacc_flag = true; }
     break;
 
   case 37:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 325 "parse-gram.y"
     {
       grammar_start_symbol_set ((yyvsp[(2) - (2)].symbol), (yylsp[(2) - (2)]));
 #line 325 "parse-gram.y"
     {
       grammar_start_symbol_set ((yyvsp[(2) - (2)].symbol), (yylsp[(2) - (2)]));
@@ -2211,7 +2211,7 @@ yyreduce:
 
   case 38:
 
 
   case 38:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 329 "parse-gram.y"
     {
       symbol_list *list;
 #line 329 "parse-gram.y"
     {
       symbol_list *list;
@@ -2223,7 +2223,7 @@ yyreduce:
 
   case 39:
 
 
   case 39:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 336 "parse-gram.y"
     {
       symbol_list *list;
 #line 336 "parse-gram.y"
     {
       symbol_list *list;
@@ -2235,7 +2235,7 @@ yyreduce:
 
   case 40:
 
 
   case 40:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 343 "parse-gram.y"
     {
       default_prec = true;
 #line 343 "parse-gram.y"
     {
       default_prec = true;
@@ -2244,7 +2244,7 @@ yyreduce:
 
   case 41:
 
 
   case 41:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 347 "parse-gram.y"
     {
       default_prec = false;
 #line 347 "parse-gram.y"
     {
       default_prec = false;
@@ -2253,7 +2253,7 @@ yyreduce:
 
   case 42:
 
 
   case 42:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 351 "parse-gram.y"
     {
       /* Do not invoke muscle_percent_code_grow here since it invokes
 #line 351 "parse-gram.y"
     {
       /* Do not invoke muscle_percent_code_grow here since it invokes
@@ -2265,7 +2265,7 @@ yyreduce:
 
   case 43:
 
 
   case 43:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 358 "parse-gram.y"
     {
       muscle_percent_code_grow ((yyvsp[(2) - (3)].uniqstr), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].chars), (yylsp[(3) - (3)]));
 #line 358 "parse-gram.y"
     {
       muscle_percent_code_grow ((yyvsp[(2) - (3)].uniqstr), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].chars), (yylsp[(3) - (3)]));
@@ -2275,21 +2275,21 @@ yyreduce:
 
   case 44:
 
 
   case 44:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 372 "parse-gram.y"
     {}
     break;
 
   case 45:
 
 #line 372 "parse-gram.y"
     {}
     break;
 
   case 45:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 373 "parse-gram.y"
     { muscle_code_grow ("union_name", (yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 46:
 
 #line 373 "parse-gram.y"
     { muscle_code_grow ("union_name", (yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 46:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 378 "parse-gram.y"
     {
       union_seen = true;
 #line 378 "parse-gram.y"
     {
       union_seen = true;
@@ -2300,14 +2300,14 @@ yyreduce:
 
   case 47:
 
 
   case 47:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 389 "parse-gram.y"
     { current_class = nterm_sym; }
     break;
 
   case 48:
 
 #line 389 "parse-gram.y"
     { current_class = nterm_sym; }
     break;
 
   case 48:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 390 "parse-gram.y"
     {
       current_class = unknown_sym;
 #line 390 "parse-gram.y"
     {
       current_class = unknown_sym;
@@ -2317,14 +2317,14 @@ yyreduce:
 
   case 49:
 
 
   case 49:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 394 "parse-gram.y"
     { current_class = token_sym; }
     break;
 
   case 50:
 
 #line 394 "parse-gram.y"
     { current_class = token_sym; }
     break;
 
   case 50:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 395 "parse-gram.y"
     {
       current_class = unknown_sym;
 #line 395 "parse-gram.y"
     {
       current_class = unknown_sym;
@@ -2334,7 +2334,7 @@ yyreduce:
 
   case 51:
 
 
   case 51:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 400 "parse-gram.y"
     {
       symbol_list *list;
 #line 400 "parse-gram.y"
     {
       symbol_list *list;
@@ -2347,7 +2347,7 @@ yyreduce:
 
   case 52:
 
 
   case 52:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 411 "parse-gram.y"
     {
       symbol_list *list;
 #line 411 "parse-gram.y"
     {
       symbol_list *list;
@@ -2364,126 +2364,126 @@ yyreduce:
 
   case 53:
 
 
   case 53:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 425 "parse-gram.y"
     { (yyval.assoc) = left_assoc; }
     break;
 
   case 54:
 
 #line 425 "parse-gram.y"
     { (yyval.assoc) = left_assoc; }
     break;
 
   case 54:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 426 "parse-gram.y"
     { (yyval.assoc) = right_assoc; }
     break;
 
   case 55:
 
 #line 426 "parse-gram.y"
     { (yyval.assoc) = right_assoc; }
     break;
 
   case 55:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 427 "parse-gram.y"
     { (yyval.assoc) = non_assoc; }
     break;
 
   case 56:
 
 #line 427 "parse-gram.y"
     { (yyval.assoc) = non_assoc; }
     break;
 
   case 56:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 431 "parse-gram.y"
     { current_type = NULL; }
     break;
 
   case 57:
 
 #line 431 "parse-gram.y"
     { current_type = NULL; }
     break;
 
   case 57:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 432 "parse-gram.y"
     { current_type = (yyvsp[(1) - (1)].uniqstr); tag_seen = true; }
     break;
 
   case 58:
 
 #line 432 "parse-gram.y"
     { current_type = (yyvsp[(1) - (1)].uniqstr); tag_seen = true; }
     break;
 
   case 58:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 438 "parse-gram.y"
     { (yyval.list) = symbol_list_sym_new ((yyvsp[(1) - (1)].symbol), (yylsp[(1) - (1)])); }
     break;
 
   case 59:
 
 #line 438 "parse-gram.y"
     { (yyval.list) = symbol_list_sym_new ((yyvsp[(1) - (1)].symbol), (yylsp[(1) - (1)])); }
     break;
 
   case 59:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 440 "parse-gram.y"
     { (yyval.list) = symbol_list_prepend ((yyvsp[(1) - (2)].list), symbol_list_sym_new ((yyvsp[(2) - (2)].symbol), (yylsp[(2) - (2)]))); }
     break;
 
   case 60:
 
 #line 440 "parse-gram.y"
     { (yyval.list) = symbol_list_prepend ((yyvsp[(1) - (2)].list), symbol_list_sym_new ((yyvsp[(2) - (2)].symbol), (yylsp[(2) - (2)]))); }
     break;
 
   case 60:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 444 "parse-gram.y"
     { (yyval.symbol) = (yyvsp[(1) - (1)].symbol); }
     break;
 
   case 61:
 
 #line 444 "parse-gram.y"
     { (yyval.symbol) = (yyvsp[(1) - (1)].symbol); }
     break;
 
   case 61:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 445 "parse-gram.y"
     { (yyval.symbol) = (yyvsp[(1) - (2)].symbol); symbol_user_token_number_set ((yyvsp[(1) - (2)].symbol), (yyvsp[(2) - (2)].integer), (yylsp[(2) - (2)])); }
     break;
 
   case 62:
 
 #line 445 "parse-gram.y"
     { (yyval.symbol) = (yyvsp[(1) - (2)].symbol); symbol_user_token_number_set ((yyvsp[(1) - (2)].symbol), (yyvsp[(2) - (2)].integer), (yylsp[(2) - (2)])); }
     break;
 
   case 62:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 451 "parse-gram.y"
     { (yyval.list) = symbol_list_sym_new ((yyvsp[(1) - (1)].symbol), (yylsp[(1) - (1)])); }
     break;
 
   case 63:
 
 #line 451 "parse-gram.y"
     { (yyval.list) = symbol_list_sym_new ((yyvsp[(1) - (1)].symbol), (yylsp[(1) - (1)])); }
     break;
 
   case 63:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 453 "parse-gram.y"
     { (yyval.list) = symbol_list_prepend ((yyvsp[(1) - (2)].list), symbol_list_sym_new ((yyvsp[(2) - (2)].symbol), (yylsp[(2) - (2)]))); }
     break;
 
   case 64:
 
 #line 453 "parse-gram.y"
     { (yyval.list) = symbol_list_prepend ((yyvsp[(1) - (2)].list), symbol_list_sym_new ((yyvsp[(2) - (2)].symbol), (yylsp[(2) - (2)]))); }
     break;
 
   case 64:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 457 "parse-gram.y"
     { (yyval.list) = (yyvsp[(1) - (1)].list); }
     break;
 
   case 65:
 
 #line 457 "parse-gram.y"
     { (yyval.list) = (yyvsp[(1) - (1)].list); }
     break;
 
   case 65:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 458 "parse-gram.y"
     { (yyval.list) = symbol_list_prepend ((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list)); }
     break;
 
   case 66:
 
 #line 458 "parse-gram.y"
     { (yyval.list) = symbol_list_prepend ((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list)); }
     break;
 
   case 66:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 462 "parse-gram.y"
     { (yyval.list) = symbol_list_sym_new ((yyvsp[(1) - (1)].symbol), (yylsp[(1) - (1)])); }
     break;
 
   case 67:
 
 #line 462 "parse-gram.y"
     { (yyval.list) = symbol_list_sym_new ((yyvsp[(1) - (1)].symbol), (yylsp[(1) - (1)])); }
     break;
 
   case 67:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 463 "parse-gram.y"
     { (yyval.list) = symbol_list_type_new ((yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 68:
 
 #line 463 "parse-gram.y"
     { (yyval.list) = symbol_list_type_new ((yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 68:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 464 "parse-gram.y"
     { (yyval.list) = symbol_list_default_tagged_new ((yylsp[(1) - (1)])); }
     break;
 
   case 69:
 
 #line 464 "parse-gram.y"
     { (yyval.list) = symbol_list_default_tagged_new ((yylsp[(1) - (1)])); }
     break;
 
   case 69:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 465 "parse-gram.y"
     { (yyval.list) = symbol_list_default_tagless_new ((yylsp[(1) - (1)])); }
     break;
 
   case 70:
 
 #line 465 "parse-gram.y"
     { (yyval.list) = symbol_list_default_tagless_new ((yylsp[(1) - (1)])); }
     break;
 
   case 70:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 471 "parse-gram.y"
     {
        current_type = (yyvsp[(1) - (1)].uniqstr);
 #line 471 "parse-gram.y"
     {
        current_type = (yyvsp[(1) - (1)].uniqstr);
@@ -2493,7 +2493,7 @@ yyreduce:
 
   case 71:
 
 
   case 71:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 476 "parse-gram.y"
     {
        symbol_class_set ((yyvsp[(1) - (1)].symbol), current_class, (yylsp[(1) - (1)]), true);
 #line 476 "parse-gram.y"
     {
        symbol_class_set ((yyvsp[(1) - (1)].symbol), current_class, (yylsp[(1) - (1)]), true);
@@ -2503,7 +2503,7 @@ yyreduce:
 
   case 72:
 
 
   case 72:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 481 "parse-gram.y"
     {
       symbol_class_set ((yyvsp[(1) - (2)].symbol), current_class, (yylsp[(1) - (2)]), true);
 #line 481 "parse-gram.y"
     {
       symbol_class_set ((yyvsp[(1) - (2)].symbol), current_class, (yylsp[(1) - (2)]), true);
@@ -2514,7 +2514,7 @@ yyreduce:
 
   case 73:
 
 
   case 73:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 487 "parse-gram.y"
     {
       symbol_class_set ((yyvsp[(1) - (2)].symbol), current_class, (yylsp[(1) - (2)]), true);
 #line 487 "parse-gram.y"
     {
       symbol_class_set ((yyvsp[(1) - (2)].symbol), current_class, (yylsp[(1) - (2)]), true);
@@ -2525,7 +2525,7 @@ yyreduce:
 
   case 74:
 
 
   case 74:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 493 "parse-gram.y"
     {
       symbol_class_set ((yyvsp[(1) - (3)].symbol), current_class, (yylsp[(1) - (3)]), true);
 #line 493 "parse-gram.y"
     {
       symbol_class_set ((yyvsp[(1) - (3)].symbol), current_class, (yylsp[(1) - (3)]), true);
@@ -2537,7 +2537,7 @@ yyreduce:
 
   case 81:
 
 
   case 81:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 523 "parse-gram.y"
     {
       yyerrok;
 #line 523 "parse-gram.y"
     {
       yyerrok;
@@ -2546,7 +2546,7 @@ yyreduce:
 
   case 82:
 
 
   case 82:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 529 "parse-gram.y"
     { current_lhs = (yyvsp[(1) - (2)].symbol); current_lhs_location = (yylsp[(1) - (2)]);
     current_lhs_named_ref = (yyvsp[(2) - (2)].named_ref); }
 #line 529 "parse-gram.y"
     { current_lhs = (yyvsp[(1) - (2)].symbol); current_lhs_location = (yylsp[(1) - (2)]);
     current_lhs_named_ref = (yyvsp[(2) - (2)].named_ref); }
@@ -2554,21 +2554,21 @@ yyreduce:
 
   case 84:
 
 
   case 84:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 534 "parse-gram.y"
     { grammar_current_rule_end ((yylsp[(1) - (1)])); }
     break;
 
   case 85:
 
 #line 534 "parse-gram.y"
     { grammar_current_rule_end ((yylsp[(1) - (1)])); }
     break;
 
   case 85:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 535 "parse-gram.y"
     { grammar_current_rule_end ((yylsp[(3) - (3)])); }
     break;
 
   case 87:
 
 #line 535 "parse-gram.y"
     { grammar_current_rule_end ((yylsp[(3) - (3)])); }
     break;
 
   case 87:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 541 "parse-gram.y"
     { grammar_current_rule_begin (current_lhs, current_lhs_location,
                                  current_lhs_named_ref); }
 #line 541 "parse-gram.y"
     { grammar_current_rule_begin (current_lhs, current_lhs_location,
                                  current_lhs_named_ref); }
@@ -2576,77 +2576,77 @@ yyreduce:
 
   case 88:
 
 
   case 88:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 544 "parse-gram.y"
     { grammar_current_rule_symbol_append ((yyvsp[(2) - (3)].symbol), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].named_ref)); }
     break;
 
   case 89:
 
 #line 544 "parse-gram.y"
     { grammar_current_rule_symbol_append ((yyvsp[(2) - (3)].symbol), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].named_ref)); }
     break;
 
   case 89:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 546 "parse-gram.y"
     { grammar_current_rule_action_append ((yyvsp[(2) - (3)].code), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].named_ref)); }
     break;
 
   case 90:
 
 #line 546 "parse-gram.y"
     { grammar_current_rule_action_append ((yyvsp[(2) - (3)].code), (yylsp[(2) - (3)]), (yyvsp[(3) - (3)].named_ref)); }
     break;
 
   case 90:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 548 "parse-gram.y"
     { grammar_current_rule_prec_set ((yyvsp[(3) - (3)].symbol), (yylsp[(3) - (3)])); }
     break;
 
   case 91:
 
 #line 548 "parse-gram.y"
     { grammar_current_rule_prec_set ((yyvsp[(3) - (3)].symbol), (yylsp[(3) - (3)])); }
     break;
 
   case 91:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 550 "parse-gram.y"
     { grammar_current_rule_dprec_set ((yyvsp[(3) - (3)].integer), (yylsp[(3) - (3)])); }
     break;
 
   case 92:
 
 #line 550 "parse-gram.y"
     { grammar_current_rule_dprec_set ((yyvsp[(3) - (3)].integer), (yylsp[(3) - (3)])); }
     break;
 
   case 92:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 552 "parse-gram.y"
     { grammar_current_rule_merge_set ((yyvsp[(3) - (3)].uniqstr), (yylsp[(3) - (3)])); }
     break;
 
   case 93:
 
 #line 552 "parse-gram.y"
     { grammar_current_rule_merge_set ((yyvsp[(3) - (3)].uniqstr), (yylsp[(3) - (3)])); }
     break;
 
   case 93:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 556 "parse-gram.y"
     { (yyval.named_ref) = 0; }
     break;
 
   case 94:
 
 #line 556 "parse-gram.y"
     { (yyval.named_ref) = 0; }
     break;
 
   case 94:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 558 "parse-gram.y"
     { (yyval.named_ref) = named_ref_new((yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 96:
 
 #line 558 "parse-gram.y"
     { (yyval.named_ref) = named_ref_new((yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 96:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 570 "parse-gram.y"
     { (yyval.uniqstr) = uniqstr_new ((yyvsp[(1) - (1)].chars)); }
     break;
 
   case 97:
 
 #line 570 "parse-gram.y"
     { (yyval.uniqstr) = uniqstr_new ((yyvsp[(1) - (1)].chars)); }
     break;
 
   case 97:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 575 "parse-gram.y"
     { (yyval.chars) = ""; }
     break;
 
   case 98:
 
 #line 575 "parse-gram.y"
     { (yyval.chars) = ""; }
     break;
 
   case 98:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 576 "parse-gram.y"
     { (yyval.chars) = (yyvsp[(1) - (1)].uniqstr); }
     break;
 
   case 100:
 
 #line 576 "parse-gram.y"
     { (yyval.chars) = (yyvsp[(1) - (1)].uniqstr); }
     break;
 
   case 100:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 587 "parse-gram.y"
     {
       code_props plain_code;
 #line 587 "parse-gram.y"
     {
       code_props plain_code;
@@ -2660,14 +2660,14 @@ yyreduce:
 
   case 101:
 
 
   case 101:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 607 "parse-gram.y"
     { (yyval.symbol) = symbol_from_uniqstr ((yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 102:
 
 #line 607 "parse-gram.y"
     { (yyval.symbol) = symbol_from_uniqstr ((yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 102:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 609 "parse-gram.y"
     {
       (yyval.symbol) = symbol_get (char_name ((yyvsp[(1) - (1)].character)), (yylsp[(1) - (1)]));
 #line 609 "parse-gram.y"
     {
       (yyval.symbol) = symbol_get (char_name ((yyvsp[(1) - (1)].character)), (yylsp[(1) - (1)]));
@@ -2678,14 +2678,14 @@ yyreduce:
 
   case 103:
 
 
   case 103:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 617 "parse-gram.y"
     { (yyval.symbol) = symbol_from_uniqstr ((yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 106:
 
 #line 617 "parse-gram.y"
     { (yyval.symbol) = symbol_from_uniqstr ((yyvsp[(1) - (1)].uniqstr), (yylsp[(1) - (1)])); }
     break;
 
   case 106:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 629 "parse-gram.y"
     {
       (yyval.symbol) = symbol_get (quotearg_style (c_quoting_style, (yyvsp[(1) - (1)].chars)), (yylsp[(1) - (1)]));
 #line 629 "parse-gram.y"
     {
       (yyval.symbol) = symbol_get (quotearg_style (c_quoting_style, (yyvsp[(1) - (1)].chars)), (yylsp[(1) - (1)]));
@@ -2695,7 +2695,7 @@ yyreduce:
 
   case 108:
 
 
   case 108:
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 638 "parse-gram.y"
     {
       code_props plain_code;
 #line 638 "parse-gram.y"
     {
       code_props plain_code;
@@ -2709,7 +2709,7 @@ yyreduce:
 
 
 
 
 
 
-/* Line 1509 of yacc.c  */
+/* Line 1712 of yacc.c  */
 #line 2714 "parse-gram.c"
       default: break;
     }
 #line 2714 "parse-gram.c"
       default: break;
     }
@@ -2763,11 +2763,12 @@ yyerrlab:
 #if ! YYERROR_VERBOSE
       yyerror (YY_("syntax error"));
 #else
 #if ! YYERROR_VERBOSE
       yyerror (YY_("syntax error"));
 #else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, yystate, \
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, yyssp, \
                                         yytoken)
       {
         char const *yymsgp = YY_("syntax error");
                                         yytoken)
       {
         char const *yymsgp = YY_("syntax error");
-        int yysyntax_error_status = YYSYNTAX_ERROR;
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
         if (yysyntax_error_status == 0)
           yymsgp = yymsg;
         else if (yysyntax_error_status == 1)
         if (yysyntax_error_status == 0)
           yymsgp = yymsg;
         else if (yysyntax_error_status == 1)
@@ -2946,7 +2947,7 @@ yyreturn:
 
 
 
 
 
 
-/* Line 1747 of yacc.c  */
+/* Line 1970 of yacc.c  */
 #line 648 "parse-gram.y"
 
 
 #line 648 "parse-gram.y"
 
 
index eba94171d255e14e03196449b09ce58bded6c1e9..325cf2455fe4c7c59409b0dbc5177080a47a24f9 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.4.1.247-0e0f-dirty.  */
+/* A Bison parser, made by GNU Bison 2.4.1.252-dcd39.  */
 
 /* Skeleton interface for Bison's Yacc-like parsers in C
    
 
 /* Skeleton interface for Bison's Yacc-like parsers in C
    
 typedef union YYSTYPE
 {
 
 typedef union YYSTYPE
 {
 
-/* Line 1748 of yacc.c  */
+/* Line 1971 of yacc.c  */
 #line 94 "parse-gram.y"
 
   symbol *symbol;
 #line 94 "parse-gram.y"
 
   symbol *symbol;
@@ -176,7 +176,7 @@ typedef union YYSTYPE
 
 
 
 
 
 
-/* Line 1748 of yacc.c  */
+/* Line 1971 of yacc.c  */
 #line 181 "parse-gram.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 #line 181 "parse-gram.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
index f455d1f5627cdd13446a8cdb7ec30e0013231c1d..374116992d5d4e9008f50efbcaa20b9a9155db47 100644 (file)
@@ -94,46 +94,52 @@ main (int argc, const char *argv[])
 }
 ]])
 
 }
 ]])
 
-# Specify the output files to avoid problems on different file systems.
-AT_BISON_CHECK([-o input.c input.y])
+m4_pushdef([AT_NONASSOC_AND_EOF_CHECK],
+[AT_BISON_CHECK([$1[ -o input.c input.y]])
 AT_COMPILE([input])
 
 AT_COMPILE([input])
 
+m4_pushdef([AT_EXPECTING], [m4_if($2, [correct], [[, expecting $end]])])
+
 AT_PARSER_CHECK([./input '0<0'])
 AT_PARSER_CHECK([./input '0<0<0'], [1], [],
 AT_PARSER_CHECK([./input '0<0'])
 AT_PARSER_CHECK([./input '0<0<0'], [1], [],
-         [syntax error, unexpected '<'
+         [syntax error, unexpected '<'AT_EXPECTING
 ])
 
 AT_PARSER_CHECK([./input '0>0'])
 AT_PARSER_CHECK([./input '0>0>0'], [1], [],
 ])
 
 AT_PARSER_CHECK([./input '0>0'])
 AT_PARSER_CHECK([./input '0>0>0'], [1], [],
-         [syntax error, unexpected '>'
+         [syntax error, unexpected '>'AT_EXPECTING
 ])
 
 AT_PARSER_CHECK([./input '0<0>0'], [1], [],
 ])
 
 AT_PARSER_CHECK([./input '0<0>0'], [1], [],
-         [syntax error, unexpected '>'
+         [syntax error, unexpected '>'AT_EXPECTING
 ])
 
 ])
 
-# We must disable default reductions in inconsistent states in order to
-# have an explicit list of all expected tokens.  (However, unless we use
-# canonical LR, lookahead sets are merged for different left contexts,
-# so it is still possible to have extra incorrect tokens in the expected
-# list.  That just doesn't happen to be a problem for this test case.)
-
-AT_BISON_CHECK([-Dlr.default-reductions=consistent -o input.c input.y])
-AT_COMPILE([input])
-
-AT_PARSER_CHECK([./input '0<0'])
-AT_PARSER_CHECK([./input '0<0<0'], [1], [],
-         [syntax error, unexpected '<', expecting $end
-])
+m4_popdef([AT_EXPECTING])])
 
 
-AT_PARSER_CHECK([./input '0>0'])
-AT_PARSER_CHECK([./input '0>0>0'], [1], [],
-         [syntax error, unexpected '>', expecting $end
-])
+# Expected token list is missing.
+AT_NONASSOC_AND_EOF_CHECK([], [[incorrect]])
 
 
-AT_PARSER_CHECK([./input '0<0>0'], [1], [],
-         [syntax error, unexpected '>', expecting $end
-])
+# We must disable default reductions in inconsistent states in order to
+# have an explicit list of all expected tokens.
+AT_NONASSOC_AND_EOF_CHECK([[-Dlr.default-reductions=consistent]],
+                          [[correct]])
+
+# lr.default-reductions=consistent happens to work for this test case.
+# However, for other grammars, lookahead sets can be merged for
+# different left contexts, so it is still possible to have an incorrect
+# expected list.  Canonical LR is almost a general solution (that is, it
+# can fail only when %nonassoc is used), so make sure it gives the same
+# result as above.
+AT_NONASSOC_AND_EOF_CHECK([[-Dlr.type=canonical-lr]], [[correct]])
+
+# parse.lac=full is a completely general solution that does not require
+# any of the above sacrifices.  Of course, it does not extend the
+# language-recognition power of LALR to (IE)LR, but it does ensure that
+# the reported list of expected tokens matches what the given parser
+# would have accepted in place of the unexpected token.
+AT_NONASSOC_AND_EOF_CHECK([[-Dparse.lac=full]], [[correct]])
+
+m4_popdef([AT_NONASSOC_AND_EOF_CHECK])
 
 AT_CLEANUP
 
 
 AT_CLEANUP
 
@@ -343,6 +349,18 @@ AT_CONSISTENT_ERRORS_CHECK([[%define lr.type canonical-lr]],
                            [AT_PREVIOUS_STATE_INPUT],
                            [[$end]], [[ab]])
 
                            [AT_PREVIOUS_STATE_INPUT],
                            [[$end]], [[ab]])
 
+# Only LAC gets it right.
+AT_CONSISTENT_ERRORS_CHECK([[%define lr.type canonical-lr
+                             %define parse.lac full]],
+                           [AT_PREVIOUS_STATE_GRAMMAR],
+                           [AT_PREVIOUS_STATE_INPUT],
+                           [[$end]], [[b]])
+AT_CONSISTENT_ERRORS_CHECK([[%define lr.type ielr
+                             %define parse.lac full]],
+                           [AT_PREVIOUS_STATE_GRAMMAR],
+                           [AT_PREVIOUS_STATE_INPUT],
+                           [[$end]], [[b]])
+
 m4_popdef([AT_PREVIOUS_STATE_GRAMMAR])
 m4_popdef([AT_PREVIOUS_STATE_INPUT])
 
 m4_popdef([AT_PREVIOUS_STATE_GRAMMAR])
 m4_popdef([AT_PREVIOUS_STATE_INPUT])
 
@@ -422,6 +440,16 @@ AT_CONSISTENT_ERRORS_CHECK([[%define lr.type canonical-lr]],
                            [AT_USER_ACTION_INPUT],
                            [[$end]], [[a]])
 
                            [AT_USER_ACTION_INPUT],
                            [[$end]], [[a]])
 
+AT_CONSISTENT_ERRORS_CHECK([[%define parse.lac full]],
+                           [AT_USER_ACTION_GRAMMAR],
+                           [AT_USER_ACTION_INPUT],
+                           [['b']], [[none]])
+AT_CONSISTENT_ERRORS_CHECK([[%define parse.lac full
+                             %define lr.default-reductions accepting]],
+                           [AT_USER_ACTION_GRAMMAR],
+                           [AT_USER_ACTION_INPUT],
+                           [[$end]], [[none]])
+
 m4_popdef([AT_USER_ACTION_GRAMMAR])
 m4_popdef([AT_USER_ACTION_INPUT])
 
 m4_popdef([AT_USER_ACTION_GRAMMAR])
 m4_popdef([AT_USER_ACTION_INPUT])
 
@@ -431,6 +459,113 @@ AT_CLEANUP
 
 
 
 
 
 
+## ------------------------------------------------------- ##
+## LAC: %nonassoc requires splitting canonical LR states.  ##
+## ------------------------------------------------------- ##
+
+# This test case demonstrates that, when %nonassoc is used, canonical
+# LR(1) parser table construction followed by conflict resolution
+# without further state splitting is not always sufficient to produce a
+# parser that can detect all syntax errors as soon as possible on one
+# token of lookahead.  However, LAC solves the problem completely even
+# with minimal LR parser tables.
+
+AT_SETUP([[LAC: %nonassoc requires splitting canonical LR states]])
+
+AT_DATA_GRAMMAR([[input.y]],
+[[%code {
+  #include <stdio.h>
+  void yyerror (char const *);
+  int yylex (void);
+}
+
+%error-verbose
+%nonassoc 'a'
+
+%%
+
+start:
+  'a' problem 'a' // First context.
+| 'b' problem 'b' // Second context.
+| 'c' reduce-nonassoc // Just makes reduce-nonassoc useful.
+;
+
+problem:
+  look reduce-nonassoc
+| look 'a'
+| look 'b'
+;
+
+// For the state reached after shifting the 'a' in these productions,
+// lookahead sets are the same in both the first and second contexts.
+// Thus, canonical LR reuses the same state for both contexts.  However,
+// the lookahead 'a' for the reduction "look: 'a'" later becomes an
+// error action only in the first context.  In order to immediately
+// detect the syntax error on 'a' here for only the first context, this
+// canonical LR state would have to be split into two states, and the
+// 'a' lookahead would have to be removed from only one of the states.
+look:
+  'a' // Reduction lookahead set is always ['a', 'b'].
+| 'a' 'b'
+| 'a' 'c' // 'c' is forgotten as an expected token.
+;
+
+reduce-nonassoc: %prec 'a';
+
+%%
+
+void
+yyerror (char const *msg)
+{
+  fprintf (stderr, "%s\n", msg);
+}
+
+int
+yylex (void)
+{
+  char const *input = "aaa";
+  return *input++;
+}
+
+int
+main (void)
+{
+  return yyparse ();
+}
+]])
+
+# Show canonical LR's failure.
+AT_BISON_CHECK([[-Dlr.type=canonical-lr -o input.c input.y]],
+               [[0]], [[]],
+[[input.y: conflicts: 2 shift/reduce
+]])
+AT_COMPILE([[input]])
+AT_PARSER_CHECK([[./input]], [[1]], [[]],
+[[syntax error, unexpected 'a', expecting 'b'
+]])
+
+# It's corrected by LAC.
+AT_BISON_CHECK([[-Dlr.type=canonical-lr -Dparse.lac=full \
+                 -o input.c input.y]], [[0]], [[]],
+[[input.y: conflicts: 2 shift/reduce
+]])
+AT_COMPILE([[input]])
+AT_PARSER_CHECK([[./input]], [[1]], [[]],
+[[syntax error, unexpected 'a', expecting 'b' or 'c'
+]])
+
+# IELR is sufficient when LAC is used.
+AT_BISON_CHECK([[-Dlr.type=ielr -Dparse.lac=full -o input.c input.y]],
+               [[0]], [[]],
+[[input.y: conflicts: 2 shift/reduce
+]])
+AT_COMPILE([[input]])
+AT_PARSER_CHECK([[./input]], [[1]], [[]],
+[[syntax error, unexpected 'a', expecting 'b' or 'c'
+]])
+
+AT_CLEANUP
+
 ## ------------------------- ##
 ## Unresolved SR Conflicts.  ##
 ## ------------------------- ##
 ## ------------------------- ##
 ## Unresolved SR Conflicts.  ##
 ## ------------------------- ##
index 1d50fe0288cb2ae340a880d5ba7f5b35477167d4..d59f6f15376433e5b2a5b7c099048a3f384c9dd8 100644 (file)
@@ -1283,3 +1283,22 @@ input.y:5.19: invalid character after \-escape: \001
 ]])
 
 AT_CLEANUP
 ]])
 
 AT_CLEANUP
+
+## ------------------------- ##
+## LAC: Errors for %define.  ##
+## ------------------------- ##
+
+AT_SETUP([[LAC: Errors for %define]])
+
+AT_DATA([[input.y]],
+[[%%
+start: ;
+]])
+
+# parse.lac.* options are useless if LAC isn't actually activated.
+AT_BISON_CHECK([[-Dparse.lac.es-capacity-initial=1 input.y]],
+               [[1]], [],
+[[<command line>:2: %define variable `parse.lac.es-capacity-initial' is not used
+]])
+
+AT_CLEANUP
index 544565ade9d1ff902d91ec75d1e82eff4cb2e6eb..1157bea9aa434235b19016e639d9ab86f77b0041 100644 (file)
@@ -1477,3 +1477,186 @@ memory exhausted
 ]])
 
 AT_CLEANUP
 ]])
 
 AT_CLEANUP
+
+
+
+## ------------------------ ##
+## LAC: Exploratory stack.  ##
+## ------------------------ ##
+
+AT_SETUP([[LAC: Exploratory stack]])
+
+m4_pushdef([AT_LAC_CHECK], [
+
+AT_BISON_OPTION_PUSHDEFS([$1])
+
+AT_DATA_GRAMMAR([input.y],
+[[%code {
+  #include <stdio.h>
+  void yyerror (char const *);
+  int yylex (]AT_PURE_IF([[YYSTYPE *]], [[void]])[);
+}
+
+]$1[
+%error-verbose
+%token 'c'
+
+%%
+
+// default reductions in inconsistent states
+// v   v v   v v v v   v v v v v v v
+S: A B A A B A A A A B A A A A A A A B C C A A A A A A A A A A A A B ;
+
+A: 'a' | /*empty*/ { printf ("inconsistent default reduction\n"); } ;
+B: 'b' ;
+C: /*empty*/ { printf ("consistent default reduction\n"); } ;
+
+%%
+
+void
+yyerror (char const *msg)
+{
+  fprintf (stderr, "%s\n", msg);
+}
+
+int
+yylex (]AT_PURE_IF([[YYSTYPE *v]], [[void]])[)
+{
+  static char const *input = "bbbbc";]AT_PURE_IF([[
+  *v = 0;]])[
+  return *input++;
+}
+
+int
+main (void)
+{
+  yydebug = 1;
+  return yyparse ();
+}
+]])
+
+# Give exactly the right amount of memory to be sure there's no
+# off-by-one error, for example.
+AT_BISON_CHECK([[-Dparse.lac=full -Dparse.lac.es-capacity=12 \
+                 -t -o input.c input.y]], [[0]], [],
+[[input.y: conflicts: 21 shift/reduce
+]])
+AT_COMPILE([[input]])
+AT_PARSER_CHECK([[./input > stdout.txt 2> stderr.txt]], [[1]])
+
+# Make sure syntax error doesn't forget that 'a' is expected.  It would
+# be forgotten without lookahead correction.
+AT_CHECK([[grep 'syntax error,' stderr.txt]], [[0]],
+[[syntax error, unexpected 'c', expecting 'a' or 'b'
+]])
+
+# Check number of default reductions in inconsistent states to be sure
+# syntax error is detected before unnecessary reductions are performed.
+AT_CHECK([[perl -0777 -ne 'print s/inconsistent default reduction//g;' \
+           < stdout.txt || exit 77]], [[0]], [[14]])
+
+# Check number of default reductions in consistent states to be sure
+# it is performed before the syntax error is detected.
+AT_CHECK([[perl -0777 -ne 'print s/\bconsistent default reduction//g;' \
+           < stdout.txt || exit 77]], [[0]], [[2]])
+
+AT_BISON_OPTION_POPDEFS
+])
+
+AT_LAC_CHECK([[%define api.push-pull pull]])
+AT_LAC_CHECK([[%define api.push-pull pull %define api.pure]])
+AT_LAC_CHECK([[%define api.push-pull both]])
+AT_LAC_CHECK([[%define api.push-pull both %define api.pure]])
+
+m4_popdef([AT_LAC_CHECK])
+
+AT_CLEANUP
+
+
+
+## ------------------------ ##
+## LAC: Memory exhaustion.  ##
+## ------------------------ ##
+
+AT_SETUP([[LAC: Memory exhaustion]])
+
+m4_pushdef([AT_LAC_CHECK], [
+
+AT_DATA_GRAMMAR([input.y],
+[[%code {
+  #include <stdio.h>
+  void yyerror (char const *);
+  int yylex (void);
+}
+
+%error-verbose
+
+%%
+
+S: A A A A A A A A A ;
+A: /*empty*/ | 'a' ;
+
+%%
+
+void
+yyerror (char const *msg)
+{
+  fprintf (stderr, "%s\n", msg);
+}
+
+int
+yylex (void)
+{
+  static char const *input = "]$1[";
+  return *input++;
+}
+
+int
+main (void)
+{
+  yydebug = 1;
+  return yyparse ();
+}
+]])
+
+AT_BISON_CHECK([[-Dparse.lac=full -Dparse.lac.es-capacity=8 \
+                 -t -o input.c input.y]], [[0]], [],
+[[input.y: conflicts: 8 shift/reduce
+]])
+AT_COMPILE([[input]])
+
+])
+
+# Check for memory exhaustion during parsing.
+AT_LAC_CHECK([[]])
+AT_PARSER_CHECK([[./input]], [[2]], [[]],
+[[Starting parse
+Entering state 0
+Reading a token: Now at end of input.
+LAC: initial context established for $end
+LAC: checking lookahead $end: R2 G3 R2 G5 R2 G6 R2 G7 R2 G8 R2 G9 R2 G10 R2 G11 R2 (max stack size exceeded)
+memory exhausted
+Cleanup: discarding lookahead token $end ()
+Stack now 0
+]])
+
+# Induce an immediate syntax error with an undefined token, and check
+# for memory exhaustion while building syntax error message.
+AT_LAC_CHECK([[z]], [[0]])
+AT_PARSER_CHECK([[./input]], [[2]], [[]],
+[[Starting parse
+Entering state 0
+Reading a token: Next token is token $undefined ()
+LAC: initial context established for $undefined
+LAC: checking lookahead $undefined: Always Err
+Constructing syntax error message
+LAC: checking lookahead $end: R2 G3 R2 G5 R2 G6 R2 G7 R2 G8 R2 G9 R2 G10 R2 G11 R2 (max stack size exceeded)
+syntax error
+memory exhausted
+Cleanup: discarding lookahead token $undefined ()
+Stack now 0
+]])
+
+m4_popdef([AT_LAC_CHECK])
+
+AT_CLEANUP