]> 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>
Sat, 11 Dec 2010 19:43:43 +0000 (14:43 -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.
(parse.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.

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

index 154fd3507987ffc2742a5a833c28a5017de408f6..63d41ed6375c549295348762f821bbeb2c4c2ad2 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.
+       (parse.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.
index 5cf15eed5d4ed1e1cfad1f32c617e9edd3bd135f..5ba564e87eb58da3d51592f601c57626bae38fbf 100644 (file)
@@ -38,6 +38,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]])])])
 
+# 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])
 
 ## ---------------- ##
@@ -629,7 +639,8 @@ do                                                          \
     {                                                          \
       yychar = (Token);                                                \
       yylval = (Value);                                                \
-      YYPOPSTACK (1);                                          \
+      YYPOPSTACK (1);                                          \]b4_lac_if([[
+      YY_LAC_DISCARD ("YYBACKUP");                             \]])[
       goto yybackup;                                           \
     }                                                          \
   else                                                         \
@@ -813,9 +824,173 @@ int yydebug;
 
 #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
 
-\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
 
@@ -904,15 +1079,18 @@ yytnamerr (char *yyres, const char *yystr)
 # 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
-   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,
-                int yystate, int yytoken)
+                yytype_int16 *yyssp, int yytoken)
 {
   YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
@@ -943,7 +1121,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
-       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
@@ -951,26 +1134,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
-       accepted due to an error action in a later state.
+       accepted due to an error action in a later state.]])[
   */
   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))
-        {
+        {]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;
-          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]))
-              {
+              {]])[
                 if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
                   {
                     yycount = 1;
@@ -984,12 +1180,16 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
                   return 2;
                 yysize = yysize1;
               }
-        }
+        }]b4_lac_if([[
+# if YYDEBUG
+      else if (yydebug)
+        YYFPRINTF (stderr, "No expected tokens.\n");
+# endif]])[
     }
 
   switch (yycount)
     {
-#define YYCASE_(N, S)                       \
+# define YYCASE_(N, S)                      \
       case N:                               \
         yyformat = S;                       \
       break
@@ -999,7 +1199,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"));
-#undef YYCASE_
+# undef YYCASE_
     }
 
   yysize1 = yysize + yystrlen (yyformat);
@@ -1037,7 +1237,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
   return 0;
 }
 #endif /* YYERROR_VERBOSE */
-\f
 
 ]b4_yydestruct_generate([b4_c_function_def])b4_push_if([], [[
 
@@ -1172,7 +1371,8 @@ b4_c_function_def([[yyparse]], [[int]], b4_parse_param)[
   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.  */
@@ -1379,13 +1579,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 (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))
-       goto yyerrlab;
+        goto yyerrlab;]b4_lac_if([[
+      YY_LAC_ESTABLISH;]])[
       yyn = -yyn;
       goto yyreduce;
     }
@@ -1399,7 +1604,8 @@ yyread_pushed_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;
@@ -1437,12 +1643,22 @@ yyreduce:
 ]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;
-    }
+    }]])[
   /* 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.
@@ -1493,11 +1709,14 @@ yyerrlab:
 #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");
-        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)
@@ -1602,7 +1821,11 @@ yyerrlab1:
       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([[
@@ -1633,7 +1856,7 @@ yyabortlab:
   yyresult = 1;
   goto yyreturn;
 
-#if !defined(yyoverflow) || YYERROR_VERBOSE
+#if ]b4_lac_if([[1]], [[!defined(yyoverflow) || YYERROR_VERBOSE]])[
 /*-------------------------------------------------.
 | yyexhaustedlab -- memory exhaustion comes here.  |
 `-------------------------------------------------*/
index f55a15b67802f149f87922e5b2c5f8f8f665ec4d..9cf16f9ba26370756b22e3749d03a0e9c8172131 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.4.537-34db.  */
+/* A Bison parser, made by GNU Bison 2.4.542-10bae.  */
 
 /* Implementation for Bison's Yacc-like parsers in C
 
@@ -45,7 +45,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.4.537-34db"
+#define YYBISON_VERSION "2.4.542-10bae"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -73,7 +73,7 @@
 #define yylloc          gram_lloc
 
 /* Copy the first part of user declarations.  */
-/* Line 252 of yacc.c  */
+/* Line 262 of yacc.c  */
 #line 1 "src/parse-gram.y"
 /* Bison Grammar Parser                             -*- C -*-
 
@@ -128,7 +128,7 @@ static void gram_error (location const *, char const *);
 
 static char const *char_name (char);
 
-/* Line 252 of yacc.c  */
+/* Line 262 of yacc.c  */
 #line 133 "src/parse-gram.c"
 
 /* Enabling traces.  */
@@ -150,7 +150,7 @@ static char const *char_name (char);
 #endif
 
 /* "%code requires" blocks.  */
-/* Line 272 of yacc.c  */
+/* Line 282 of yacc.c  */
 #line 202 "src/parse-gram.y"
 
 # ifndef PARAM_TYPE
@@ -165,7 +165,7 @@ static char const *char_name (char);
 # endif
 
 
-/* Line 272 of yacc.c  */
+/* Line 282 of yacc.c  */
 #line 170 "src/parse-gram.c"
 
 /* Tokens.  */
@@ -294,7 +294,7 @@ static char const *char_name (char);
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-/* Line 277 of yacc.c  */
+/* Line 287 of yacc.c  */
 #line 88 "src/parse-gram.y"
 
   assoc assoc;
@@ -307,13 +307,13 @@ typedef union YYSTYPE
   uniqstr uniqstr;
   unsigned char character;
 
-/* Line 277 of yacc.c  */
+/* Line 287 of yacc.c  */
 #line 226 "src/parse-gram.y"
 
   param_type param;
 
 
-/* Line 277 of yacc.c  */
+/* Line 287 of yacc.c  */
 #line 318 "src/parse-gram.c"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
@@ -337,10 +337,10 @@ typedef struct YYLTYPE
 
 /* Copy the second part of user declarations.  */
 
-/* Line 327 of yacc.c  */
+/* Line 337 of yacc.c  */
 #line 342 "src/parse-gram.c"
 /* Unqualified %code blocks.  */
-/* Line 328 of yacc.c  */
+/* Line 338 of yacc.c  */
 #line 56 "src/parse-gram.y"
 
   static int current_prec = 0;
@@ -355,7 +355,7 @@ typedef struct YYLTYPE
   #define YYTYPE_UINT16 uint_fast16_t
   #define YYTYPE_UINT8 uint_fast8_t
 
-/* Line 328 of yacc.c  */
+/* Line 338 of yacc.c  */
 #line 215 "src/parse-gram.y"
 
   /** Add a lex-param and/or a parse-param.
@@ -368,7 +368,7 @@ typedef struct YYLTYPE
   static param_type current_param = param_none;
 
 
-/* Line 328 of yacc.c  */
+/* Line 338 of yacc.c  */
 #line 373 "src/parse-gram.c"
 
 #ifdef short
@@ -1033,106 +1033,106 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp)
     {
             case 3: // "string"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 175 "src/parse-gram.y"
         { fputs (quotearg_style (c_quoting_style, ((*yyvaluep).chars)), stderr); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1041 "src/parse-gram.c"
         break;
 
             case 4: // "integer"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 188 "src/parse-gram.y"
         { fprintf (stderr, "%d", ((*yyvaluep).integer)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1050 "src/parse-gram.c"
         break;
 
             case 24: // "%<flag>"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 184 "src/parse-gram.y"
         { fprintf (stderr, "%%%s", ((*yyvaluep).uniqstr)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1059 "src/parse-gram.c"
         break;
 
             case 40: // "{...}"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 177 "src/parse-gram.y"
         { fprintf (stderr, "{\n%s\n}", ((*yyvaluep).code)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1068 "src/parse-gram.c"
         break;
 
             case 42: // "[identifier]"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 182 "src/parse-gram.y"
         { fprintf (stderr, "[%s]", ((*yyvaluep).uniqstr)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1077 "src/parse-gram.c"
         break;
 
             case 43: // "char"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 169 "src/parse-gram.y"
         { fputs (char_name (((*yyvaluep).character)), stderr); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1086 "src/parse-gram.c"
         break;
 
             case 44: // "epilogue"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 177 "src/parse-gram.y"
         { fprintf (stderr, "{\n%s\n}", ((*yyvaluep).chars)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1095 "src/parse-gram.c"
         break;
 
             case 46: // "identifier"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 181 "src/parse-gram.y"
         { fputs (((*yyvaluep).uniqstr), stderr); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1104 "src/parse-gram.c"
         break;
 
             case 47: // "identifier:"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 183 "src/parse-gram.y"
         { fprintf (stderr, "%s:", ((*yyvaluep).uniqstr)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1113 "src/parse-gram.c"
         break;
 
             case 50: // "%{...%}"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 177 "src/parse-gram.y"
         { fprintf (stderr, "{\n%s\n}", ((*yyvaluep).chars)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1122 "src/parse-gram.c"
         break;
 
             case 52: // "<tag>"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 185 "src/parse-gram.y"
         { fprintf (stderr, "<%s>", ((*yyvaluep).uniqstr)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1131 "src/parse-gram.c"
         break;
 
             case 55: // "%param"
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 231 "src/parse-gram.y"
         {
   switch (((*yyvaluep).param))
@@ -1146,79 +1146,79 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp)
       case param_none: aver (false); break;
     }
 }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1151 "src/parse-gram.c"
         break;
 
             case 72: // symbol.prec
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 191 "src/parse-gram.y"
         { fprintf (stderr, "%s", ((*yyvaluep).symbol)->tag); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1160 "src/parse-gram.c"
         break;
 
             case 85: // variable
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 181 "src/parse-gram.y"
         { fputs (((*yyvaluep).uniqstr), stderr); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1169 "src/parse-gram.c"
         break;
 
             case 86: // content.opt
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 177 "src/parse-gram.y"
         { fprintf (stderr, "{\n%s\n}", ((*yyvaluep).chars)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1178 "src/parse-gram.c"
         break;
 
             case 87: // braceless
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 177 "src/parse-gram.y"
         { fprintf (stderr, "{\n%s\n}", ((*yyvaluep).chars)); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1187 "src/parse-gram.c"
         break;
 
             case 88: // id
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 191 "src/parse-gram.y"
         { fprintf (stderr, "%s", ((*yyvaluep).symbol)->tag); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1196 "src/parse-gram.c"
         break;
 
             case 89: // id_colon
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 192 "src/parse-gram.y"
         { fprintf (stderr, "%s:", ((*yyvaluep).symbol)->tag); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1205 "src/parse-gram.c"
         break;
 
             case 90: // symbol
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 191 "src/parse-gram.y"
         { fprintf (stderr, "%s", ((*yyvaluep).symbol)->tag); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1214 "src/parse-gram.c"
         break;
 
             case 91: // string_as_id
 
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 191 "src/parse-gram.y"
         { fprintf (stderr, "%s", ((*yyvaluep).symbol)->tag); }
-/* Line 729 of yacc.c  */
+/* Line 740 of yacc.c  */
 #line 1223 "src/parse-gram.c"
         break;
 
@@ -1355,7 +1355,6 @@ int yydebug;
 # define YYMAXDEPTH 10000
 #endif
 
-\f
 
 #if YYERROR_VERBOSE
 
@@ -1459,7 +1458,8 @@ yytnamerr (char *yyres, const char *yystr)
 # 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
@@ -1467,7 +1467,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,
-                int yystate, int yytoken)
+                yytype_int16 *yyssp, int yytoken)
 {
   YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
   YYSIZE_T yysize = yysize0;
@@ -1510,7 +1510,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
   */
   if (yytoken != YYEMPTY)
     {
-      int yyn = yypact[yystate];
+      int yyn = yypact[*yyssp];
       yyarg[yycount++] = yytname[yytoken];
       if (!yypact_value_is_default (yyn))
         {
@@ -1522,6 +1522,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
           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]))
@@ -1544,7 +1545,7 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
 
   switch (yycount)
     {
-#define YYCASE_(N, S)                       \
+# define YYCASE_(N, S)                      \
       case N:                               \
         yyformat = S;                       \
       break
@@ -1554,7 +1555,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"));
-#undef YYCASE_
+# undef YYCASE_
     }
 
   yysize1 = yysize + yystrlen (yyformat);
@@ -1592,7 +1593,6 @@ yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
   return 0;
 }
 #endif /* YYERROR_VERBOSE */
-\f
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
@@ -1765,7 +1765,7 @@ YYLTYPE yylloc;
 #endif
 
 /* User initialization code.  */
-/* Line 1230 of yacc.c  */
+/* Line 1430 of yacc.c  */
 #line 80 "src/parse-gram.y"
 {
   /* Bison's grammar can initial empty locations, hence a default
@@ -1773,7 +1773,7 @@ YYLTYPE yylloc;
   boundary_set (&yylloc.start, current_file, 1, 1);
   boundary_set (&yylloc.end, current_file, 1, 1);
 }
-/* Line 1230 of yacc.c  */
+/* Line 1430 of yacc.c  */
 #line 1778 "src/parse-gram.c"
   yylsp[0] = yylloc;
 
@@ -1905,7 +1905,7 @@ yybackup:
   if (yyn <= 0)
     {
       if (yytable_value_is_error (yyn))
-       goto yyerrlab;
+        goto yyerrlab;
       yyn = -yyn;
       goto yyreduce;
     }
@@ -1960,7 +1960,7 @@ yyreduce:
   switch (yyn)
     {
         case 6:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 267 "src/parse-gram.y"
     {
       code_props plain_code;
@@ -1971,106 +1971,106 @@ yyreduce:
                         plain_code.code, (yylsp[0]));
       code_scanner_last_string_free ();
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 1976 "src/parse-gram.c"
     break;
 
   case 7:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 277 "src/parse-gram.y"
     {
       muscle_percent_define_ensure ((yyvsp[0].uniqstr), (yylsp[0]), true);
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 1986 "src/parse-gram.c"
     break;
 
   case 8:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 281 "src/parse-gram.y"
     {
       muscle_percent_define_insert ((yyvsp[-1].uniqstr), (yylsp[-1]), (yyvsp[0].chars),
                                     MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 1997 "src/parse-gram.c"
     break;
 
   case 9:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 285 "src/parse-gram.y"
     { defines_flag = true; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2005 "src/parse-gram.c"
     break;
 
   case 10:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 287 "src/parse-gram.y"
     {
       defines_flag = true;
       spec_defines_file = xstrdup ((yyvsp[0].chars));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2016 "src/parse-gram.c"
     break;
 
   case 11:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 292 "src/parse-gram.y"
     {
       muscle_percent_define_insert ("parse.error", (yylsp[0]), "verbose",
                                     MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2027 "src/parse-gram.c"
     break;
 
   case 12:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 296 "src/parse-gram.y"
     { expected_sr_conflicts = (yyvsp[0].integer); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2035 "src/parse-gram.c"
     break;
 
   case 13:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 297 "src/parse-gram.y"
     { expected_rr_conflicts = (yyvsp[0].integer); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2043 "src/parse-gram.c"
     break;
 
   case 14:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 298 "src/parse-gram.y"
     { spec_file_prefix = (yyvsp[0].chars); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2051 "src/parse-gram.c"
     break;
 
   case 15:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 299 "src/parse-gram.y"
     { spec_file_prefix = (yyvsp[0].chars); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2059 "src/parse-gram.c"
     break;
 
   case 16:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 301 "src/parse-gram.y"
     {
       nondeterministic_parser = true;
       glr_parser = true;
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2070 "src/parse-gram.c"
     break;
 
   case 17:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 306 "src/parse-gram.y"
     {
       code_props action;
@@ -2080,92 +2080,92 @@ yyreduce:
       muscle_code_grow ("initial_action", action.code, (yylsp[0]));
       code_scanner_last_string_free ();
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2085 "src/parse-gram.c"
     break;
 
   case 18:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 314 "src/parse-gram.y"
     { language_argmatch ((yyvsp[0].chars), grammar_prio, (yylsp[-1])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2093 "src/parse-gram.c"
     break;
 
   case 19:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 315 "src/parse-gram.y"
     { spec_name_prefix = (yyvsp[0].chars); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2101 "src/parse-gram.c"
     break;
 
   case 20:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 316 "src/parse-gram.y"
     { spec_name_prefix = (yyvsp[0].chars); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2109 "src/parse-gram.c"
     break;
 
   case 21:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 317 "src/parse-gram.y"
     { no_lines_flag = true; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2117 "src/parse-gram.c"
     break;
 
   case 22:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 318 "src/parse-gram.y"
     { nondeterministic_parser = true; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2125 "src/parse-gram.c"
     break;
 
   case 23:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 319 "src/parse-gram.y"
     { spec_outfile = (yyvsp[0].chars); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2133 "src/parse-gram.c"
     break;
 
   case 24:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 320 "src/parse-gram.y"
     { spec_outfile = (yyvsp[0].chars); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2141 "src/parse-gram.c"
     break;
 
   case 25:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 321 "src/parse-gram.y"
     { current_param = (yyvsp[0].param); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2149 "src/parse-gram.c"
     break;
 
   case 26:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 321 "src/parse-gram.y"
     { current_param = param_none; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2157 "src/parse-gram.c"
     break;
 
   case 27:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 322 "src/parse-gram.y"
     { version_check (&(yylsp[0]), (yyvsp[0].chars)); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2165 "src/parse-gram.c"
     break;
 
   case 28:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 324 "src/parse-gram.y"
     {
       char const *skeleton_user = (yyvsp[0].chars);
@@ -2190,62 +2190,62 @@ yyreduce:
         }
       skeleton_arg (skeleton_user, grammar_prio, (yylsp[-1]));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2195 "src/parse-gram.c"
     break;
 
   case 29:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 347 "src/parse-gram.y"
     { token_table_flag = true; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2203 "src/parse-gram.c"
     break;
 
   case 30:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 348 "src/parse-gram.y"
     { report_flag |= report_states; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2211 "src/parse-gram.c"
     break;
 
   case 31:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 349 "src/parse-gram.y"
     { yacc_flag = true; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2219 "src/parse-gram.c"
     break;
 
   case 33:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 354 "src/parse-gram.y"
     { add_param (current_param, (yyvsp[0].code), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2227 "src/parse-gram.c"
     break;
 
   case 34:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 355 "src/parse-gram.y"
     { add_param (current_param, (yyvsp[0].code), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2235 "src/parse-gram.c"
     break;
 
   case 37:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 367 "src/parse-gram.y"
     {
       grammar_start_symbol_set ((yyvsp[0].symbol), (yylsp[0]));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2245 "src/parse-gram.c"
     break;
 
   case 38:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 371 "src/parse-gram.y"
     {
       symbol_list *list;
@@ -2253,12 +2253,12 @@ yyreduce:
        symbol_list_destructor_set (list, (yyvsp[-1].code), (yylsp[-1]));
       symbol_list_free ((yyvsp[0].list));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2258 "src/parse-gram.c"
     break;
 
   case 39:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 378 "src/parse-gram.y"
     {
       symbol_list *list;
@@ -2266,32 +2266,32 @@ yyreduce:
        symbol_list_printer_set (list, (yyvsp[-1].code), (yylsp[-1]));
       symbol_list_free ((yyvsp[0].list));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2271 "src/parse-gram.c"
     break;
 
   case 40:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 385 "src/parse-gram.y"
     {
       default_prec = true;
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2281 "src/parse-gram.c"
     break;
 
   case 41:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 389 "src/parse-gram.y"
     {
       default_prec = false;
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2291 "src/parse-gram.c"
     break;
 
   case 42:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 393 "src/parse-gram.y"
     {
       /* Do not invoke muscle_percent_code_grow here since it invokes
@@ -2299,89 +2299,89 @@ yyreduce:
       muscle_code_grow ("percent_code()", (yyvsp[0].chars), (yylsp[0]));
       code_scanner_last_string_free ();
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2304 "src/parse-gram.c"
     break;
 
   case 43:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 400 "src/parse-gram.y"
     {
       muscle_percent_code_grow ((yyvsp[-1].uniqstr), (yylsp[-1]), (yyvsp[0].chars), (yylsp[0]));
       code_scanner_last_string_free ();
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2315 "src/parse-gram.c"
     break;
 
   case 44:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 414 "src/parse-gram.y"
     {}
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2323 "src/parse-gram.c"
     break;
 
   case 45:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 415 "src/parse-gram.y"
     { muscle_code_grow ("union_name", (yyvsp[0].uniqstr), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2331 "src/parse-gram.c"
     break;
 
   case 46:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 420 "src/parse-gram.y"
     {
       union_seen = true;
       muscle_code_grow ("stype", (yyvsp[0].chars), (yylsp[0]));
       code_scanner_last_string_free ();
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2343 "src/parse-gram.c"
     break;
 
   case 47:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 431 "src/parse-gram.y"
     { current_class = nterm_sym; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2351 "src/parse-gram.c"
     break;
 
   case 48:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 432 "src/parse-gram.y"
     {
       current_class = unknown_sym;
       current_type = NULL;
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2362 "src/parse-gram.c"
     break;
 
   case 49:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 436 "src/parse-gram.y"
     { current_class = token_sym; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2370 "src/parse-gram.c"
     break;
 
   case 50:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 437 "src/parse-gram.y"
     {
       current_class = unknown_sym;
       current_type = NULL;
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2381 "src/parse-gram.c"
     break;
 
   case 51:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 442 "src/parse-gram.y"
     {
       symbol_list *list;
@@ -2390,12 +2390,12 @@ yyreduce:
        symbol_type_set (list->content.sym, (yyvsp[-1].uniqstr), (yylsp[-1]));
       symbol_list_free ((yyvsp[0].list));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2395 "src/parse-gram.c"
     break;
 
   case 52:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 453 "src/parse-gram.y"
     {
       symbol_list *list;
@@ -2408,202 +2408,202 @@ yyreduce:
       symbol_list_free ((yyvsp[0].list));
       current_type = NULL;
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2413 "src/parse-gram.c"
     break;
 
   case 53:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 467 "src/parse-gram.y"
     { (yyval.assoc) = left_assoc; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2421 "src/parse-gram.c"
     break;
 
   case 54:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 468 "src/parse-gram.y"
     { (yyval.assoc) = right_assoc; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2429 "src/parse-gram.c"
     break;
 
   case 55:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 469 "src/parse-gram.y"
     { (yyval.assoc) = non_assoc; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2437 "src/parse-gram.c"
     break;
 
   case 56:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 470 "src/parse-gram.y"
     { (yyval.assoc) = precedence_assoc; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2445 "src/parse-gram.c"
     break;
 
   case 57:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 474 "src/parse-gram.y"
     { current_type = NULL; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2453 "src/parse-gram.c"
     break;
 
   case 58:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 475 "src/parse-gram.y"
     { current_type = (yyvsp[0].uniqstr); tag_seen = true; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2461 "src/parse-gram.c"
     break;
 
   case 59:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 481 "src/parse-gram.y"
     { (yyval.list) = symbol_list_sym_new ((yyvsp[0].symbol), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2469 "src/parse-gram.c"
     break;
 
   case 60:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 483 "src/parse-gram.y"
     { (yyval.list) = symbol_list_prepend ((yyvsp[-1].list), symbol_list_sym_new ((yyvsp[0].symbol), (yylsp[0]))); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2477 "src/parse-gram.c"
     break;
 
   case 61:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 487 "src/parse-gram.y"
     { (yyval.symbol) = (yyvsp[0].symbol); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2485 "src/parse-gram.c"
     break;
 
   case 62:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 488 "src/parse-gram.y"
     { (yyval.symbol) = (yyvsp[-1].symbol); symbol_user_token_number_set ((yyvsp[-1].symbol), (yyvsp[0].integer), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2493 "src/parse-gram.c"
     break;
 
   case 63:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 494 "src/parse-gram.y"
     { (yyval.list) = symbol_list_sym_new ((yyvsp[0].symbol), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2501 "src/parse-gram.c"
     break;
 
   case 64:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 496 "src/parse-gram.y"
     { (yyval.list) = symbol_list_prepend ((yyvsp[-1].list), symbol_list_sym_new ((yyvsp[0].symbol), (yylsp[0]))); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2509 "src/parse-gram.c"
     break;
 
   case 65:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 500 "src/parse-gram.y"
     { (yyval.list) = (yyvsp[0].list); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2517 "src/parse-gram.c"
     break;
 
   case 66:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 501 "src/parse-gram.y"
     { (yyval.list) = symbol_list_prepend ((yyvsp[-1].list), (yyvsp[0].list)); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2525 "src/parse-gram.c"
     break;
 
   case 67:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 505 "src/parse-gram.y"
     { (yyval.list) = symbol_list_sym_new ((yyvsp[0].symbol), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2533 "src/parse-gram.c"
     break;
 
   case 68:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 506 "src/parse-gram.y"
     { (yyval.list) = symbol_list_type_new ((yyvsp[0].uniqstr), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2541 "src/parse-gram.c"
     break;
 
   case 69:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 507 "src/parse-gram.y"
     { (yyval.list) = symbol_list_default_tagged_new ((yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2549 "src/parse-gram.c"
     break;
 
   case 70:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 508 "src/parse-gram.y"
     { (yyval.list) = symbol_list_default_tagless_new ((yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2557 "src/parse-gram.c"
     break;
 
   case 71:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 514 "src/parse-gram.y"
     {
        current_type = (yyvsp[0].uniqstr);
        tag_seen = true;
      }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2568 "src/parse-gram.c"
     break;
 
   case 72:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 519 "src/parse-gram.y"
     {
        symbol_class_set ((yyvsp[0].symbol), current_class, (yylsp[0]), true);
        symbol_type_set ((yyvsp[0].symbol), current_type, (yylsp[0]));
      }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2579 "src/parse-gram.c"
     break;
 
   case 73:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 524 "src/parse-gram.y"
     {
       symbol_class_set ((yyvsp[-1].symbol), current_class, (yylsp[-1]), true);
       symbol_type_set ((yyvsp[-1].symbol), current_type, (yylsp[-1]));
       symbol_user_token_number_set ((yyvsp[-1].symbol), (yyvsp[0].integer), (yylsp[0]));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2591 "src/parse-gram.c"
     break;
 
   case 74:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 530 "src/parse-gram.y"
     {
       symbol_class_set ((yyvsp[-1].symbol), current_class, (yylsp[-1]), true);
       symbol_type_set ((yyvsp[-1].symbol), current_type, (yylsp[-1]));
       symbol_make_alias ((yyvsp[-1].symbol), (yyvsp[0].symbol), (yyloc));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2603 "src/parse-gram.c"
     break;
 
   case 75:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 536 "src/parse-gram.y"
     {
       symbol_class_set ((yyvsp[-2].symbol), current_class, (yylsp[-2]), true);
@@ -2611,144 +2611,144 @@ yyreduce:
       symbol_user_token_number_set ((yyvsp[-2].symbol), (yyvsp[-1].integer), (yylsp[-1]));
       symbol_make_alias ((yyvsp[-2].symbol), (yyvsp[0].symbol), (yyloc));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2616 "src/parse-gram.c"
     break;
 
   case 82:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 566 "src/parse-gram.y"
     {
       yyerrok;
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2626 "src/parse-gram.c"
     break;
 
   case 83:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 572 "src/parse-gram.y"
     { current_lhs = (yyvsp[-1].symbol); current_lhs_location = (yylsp[-1]);
     current_lhs_named_ref = (yyvsp[0].named_ref); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2635 "src/parse-gram.c"
     break;
 
   case 85:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 577 "src/parse-gram.y"
     { grammar_current_rule_end ((yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2643 "src/parse-gram.c"
     break;
 
   case 86:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 578 "src/parse-gram.y"
     { grammar_current_rule_end ((yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2651 "src/parse-gram.c"
     break;
 
   case 88:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 584 "src/parse-gram.y"
     { grammar_current_rule_begin (current_lhs, current_lhs_location,
                                  current_lhs_named_ref); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2660 "src/parse-gram.c"
     break;
 
   case 89:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 587 "src/parse-gram.y"
     { grammar_current_rule_symbol_append ((yyvsp[-1].symbol), (yylsp[-1]), (yyvsp[0].named_ref)); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2668 "src/parse-gram.c"
     break;
 
   case 90:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 589 "src/parse-gram.y"
     { grammar_current_rule_action_append ((yyvsp[-1].code), (yylsp[-1]), (yyvsp[0].named_ref), false); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2676 "src/parse-gram.c"
     break;
 
   case 91:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 591 "src/parse-gram.y"
     { grammar_current_rule_action_append ((yyvsp[0].code), (yylsp[0]), NULL, true); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2684 "src/parse-gram.c"
     break;
 
   case 92:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 593 "src/parse-gram.y"
     { grammar_current_rule_prec_set ((yyvsp[0].symbol), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2692 "src/parse-gram.c"
     break;
 
   case 93:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 595 "src/parse-gram.y"
     { grammar_current_rule_dprec_set ((yyvsp[0].integer), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2700 "src/parse-gram.c"
     break;
 
   case 94:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 597 "src/parse-gram.y"
     { grammar_current_rule_merge_set ((yyvsp[0].uniqstr), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2708 "src/parse-gram.c"
     break;
 
   case 95:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 601 "src/parse-gram.y"
     { (yyval.named_ref) = 0; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2716 "src/parse-gram.c"
     break;
 
   case 96:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 603 "src/parse-gram.y"
     { (yyval.named_ref) = named_ref_new((yyvsp[0].uniqstr), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2724 "src/parse-gram.c"
     break;
 
   case 98:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 614 "src/parse-gram.y"
     { (yyval.uniqstr) = uniqstr_new ((yyvsp[0].chars)); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2732 "src/parse-gram.c"
     break;
 
   case 99:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 619 "src/parse-gram.y"
     { (yyval.chars) = ""; }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2740 "src/parse-gram.c"
     break;
 
   case 100:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 620 "src/parse-gram.y"
     { (yyval.chars) = (yyvsp[0].uniqstr); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2748 "src/parse-gram.c"
     break;
 
   case 102:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 631 "src/parse-gram.y"
     {
       code_props plain_code;
@@ -2758,51 +2758,51 @@ yyreduce:
       gram_scanner_last_string_free ();
       (yyval.chars) = plain_code.code;
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2763 "src/parse-gram.c"
     break;
 
   case 103:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 651 "src/parse-gram.y"
     { (yyval.symbol) = symbol_from_uniqstr ((yyvsp[0].uniqstr), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2771 "src/parse-gram.c"
     break;
 
   case 104:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 653 "src/parse-gram.y"
     {
       (yyval.symbol) = symbol_get (char_name ((yyvsp[0].character)), (yylsp[0]));
       symbol_class_set ((yyval.symbol), token_sym, (yylsp[0]), false);
       symbol_user_token_number_set ((yyval.symbol), (yyvsp[0].character), (yylsp[0]));
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2783 "src/parse-gram.c"
     break;
 
   case 105:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 661 "src/parse-gram.y"
     { (yyval.symbol) = symbol_from_uniqstr ((yyvsp[0].uniqstr), (yylsp[0])); }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2791 "src/parse-gram.c"
     break;
 
   case 108:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 673 "src/parse-gram.y"
     {
       (yyval.symbol) = symbol_get (quotearg_style (c_quoting_style, (yyvsp[0].chars)), (yylsp[0]));
       symbol_class_set ((yyval.symbol), token_sym, (yylsp[0]), false);
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2802 "src/parse-gram.c"
     break;
 
   case 110:
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 682 "src/parse-gram.y"
     {
       code_props plain_code;
@@ -2812,12 +2812,12 @@ yyreduce:
       muscle_code_grow ("epilogue", plain_code.code, (yylsp[0]));
       code_scanner_last_string_free ();
     }
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2817 "src/parse-gram.c"
     break;
 
 
-/* Line 1443 of yacc.c  */
+/* Line 1646 of yacc.c  */
 #line 2822 "src/parse-gram.c"
       default: break;
     }
@@ -2871,11 +2871,12 @@ yyerrlab:
 #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");
-        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)
@@ -3052,7 +3053,7 @@ yyreturn:
   return YYID (yyresult);
 }
 
-/* Line 1680 of yacc.c  */
+/* Line 1903 of yacc.c  */
 #line 692 "src/parse-gram.y"
 
 
index fd1c8571a9cf095ab20086f4b1e19434c9c1f9e1..e391f1342fcd0d10c3ba461025550f21a3e35262 100644 (file)
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 2.4.537-34db.  */
+/* A Bison parser, made by GNU Bison 2.4.542-10bae.  */
 
 /* Interface for Bison's Yacc-like parsers in C
 
@@ -31,7 +31,7 @@
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 /* "%code requires" blocks.  */
-/* Line 1681 of yacc.c  */
+/* Line 1904 of yacc.c  */
 #line 202 "src/parse-gram.y"
 
 # ifndef PARAM_TYPE
@@ -46,7 +46,7 @@
 # endif
 
 
-/* Line 1681 of yacc.c  */
+/* Line 1904 of yacc.c  */
 #line 51 "src/parse-gram.h"
 
 /* Tokens.  */
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
 {
-/* Line 1681 of yacc.c  */
+/* Line 1904 of yacc.c  */
 #line 88 "src/parse-gram.y"
 
   assoc assoc;
@@ -188,13 +188,13 @@ typedef union YYSTYPE
   uniqstr uniqstr;
   unsigned char character;
 
-/* Line 1681 of yacc.c  */
+/* Line 1904 of yacc.c  */
 #line 226 "src/parse-gram.y"
 
   param_type param;
 
 
-/* Line 1681 of yacc.c  */
+/* Line 1904 of yacc.c  */
 #line 199 "src/parse-gram.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
index 655a666c0c0a5e0d0383417f62d2699b911d441b..16e1956f4973448cc5e0c8ccf025e8b42386564f 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])
 
+m4_pushdef([AT_EXPECTING], [m4_if($2, [correct], [[, expecting $end]])])
+
 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], [],
-         [syntax error, unexpected '>'
+         [syntax error, unexpected '>'AT_EXPECTING
 ])
 
 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
 
@@ -342,6 +348,18 @@ AT_CONSISTENT_ERRORS_CHECK([[%define lr.type canonical-lr]],
                            [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])
 
@@ -417,6 +435,16 @@ AT_CONSISTENT_ERRORS_CHECK([[%define lr.type canonical-lr]],
                            [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])
 
@@ -426,6 +454,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.  ##
 ## ------------------------- ##
index 241c4d06e526b2980df6b65723d96fbe8ef3eba2..254668545b11d5dbe862012c848b14f11adb890e 100644 (file)
@@ -1289,3 +1289,22 @@ input.y:5.19: invalid character after \-escape: \001
 ]])
 
 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 b3fdc29f10867d14d857b6a1ef83993af2204e7c..65d4ac236be73e7619e82328d4ba693563c1222f 100644 (file)
@@ -1469,3 +1469,186 @@ memory exhausted
 ]])
 
 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[
+%define parse.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