]> git.saurik.com Git - bison.git/blobdiff - src/parse-gram.y
maint: factor the handling of %printer and %destructor
[bison.git] / src / parse-gram.y
index eb034b0823a18240fa325f12a3bb6f421ba04c35..c932ba548272474cc6e0f567e78060cc172360b8 100644 (file)
@@ -38,7 +38,7 @@
 static YYLTYPE lloc_default (YYLTYPE const *, int);
 
 #define YY_LOCATION_PRINT(File, Loc) \
 static YYLTYPE lloc_default (YYLTYPE const *, int);
 
 #define YY_LOCATION_PRINT(File, Loc) \
-         location_print (File, Loc)
+          location_print (File, Loc)
 
 static void version_check (location const *loc, char const *version);
 
 
 static void version_check (location const *loc, char const *version);
 
@@ -46,58 +46,51 @@ static void version_check (location const *loc, char const *version);
    FIXME: depends on the undocumented availability of YYLLOC.  */
 #undef  yyerror
 #define yyerror(Msg) \
    FIXME: depends on the undocumented availability of YYLLOC.  */
 #undef  yyerror
 #define yyerror(Msg) \
-       gram_error (&yylloc, Msg)
+        gram_error (&yylloc, Msg)
 static void gram_error (location const *, char const *);
 
 static char const *char_name (char);
 static void gram_error (location const *, char const *);
 
 static char const *char_name (char);
+%}
 
 
-/** Add a lex-param or a parse-param.
- *
- * \param type  \a lex_param or \a parse_param
- * \param decl  the formal argument
- * \param loc   the location in the source.
- */
-static void add_param (char const *type, char *decl, location loc);
-
-
-static symbol_class current_class = unknown_sym;
-static uniqstr current_type = NULL;
-static symbol *current_lhs_symbol;
-static location current_lhs_location;
-static named_ref *current_lhs_named_ref;
-static int current_prec = 0;
-
-/** Set the new current left-hand side symbol, possibly common
- * to several right-hand side parts of rule.
- */
-static
-void
-current_lhs(symbol *sym, location loc, named_ref *ref)
+%code
 {
 {
-  current_lhs_symbol = sym;
-  current_lhs_location = loc;
-  /* In order to simplify memory management, named references for lhs
-     are always assigned by deep copy into the current symbol_list
-     node.  This is because a single named-ref in the grammar may
-     result in several uses when the user factors lhs between several
-     rules using "|".  Therefore free the parser's original copy.  */
-  free (current_lhs_named_ref);
-  current_lhs_named_ref = ref;
-}
-
+  static int current_prec = 0;
+  static location current_lhs_location;
+  static named_ref *current_lhs_named_ref;
+  static symbol *current_lhs_symbol;
+  static symbol_class current_class = unknown_sym;
+  static uniqstr current_type = NULL;
+
+  /** Set the new current left-hand side symbol, possibly common
+   * to several right-hand side parts of rule.
+   */
+  static
+  void
+  current_lhs(symbol *sym, location loc, named_ref *ref)
+  {
+    current_lhs_symbol = sym;
+    current_lhs_location = loc;
+    /* In order to simplify memory management, named references for lhs
+       are always assigned by deep copy into the current symbol_list
+       node.  This is because a single named-ref in the grammar may
+       result in several uses when the user factors lhs between several
+       rules using "|".  Therefore free the parser's original copy.  */
+    free (current_lhs_named_ref);
+    current_lhs_named_ref = ref;
+  }
 
 
-#define YYTYPE_INT16 int_fast16_t
-#define YYTYPE_INT8 int_fast8_t
-#define YYTYPE_UINT16 uint_fast16_t
-#define YYTYPE_UINT8 uint_fast8_t
-%}
+  #define YYTYPE_INT16 int_fast16_t
+  #define YYTYPE_INT8 int_fast8_t
+  #define YYTYPE_UINT16 uint_fast16_t
+  #define YYTYPE_UINT8 uint_fast8_t
+}
 
 %debug
 %verbose
 %defines
 %locations
 %pure-parser
 
 %debug
 %verbose
 %defines
 %locations
 %pure-parser
-%error-verbose
+%define parse.error "verbose"
 %define parse.lac full
 %name-prefix="gram_"
 %expect 0
 %define parse.lac full
 %name-prefix="gram_"
 %expect 0
@@ -112,15 +105,15 @@ current_lhs(symbol *sym, location loc, named_ref *ref)
 
 %union
 {
 
 %union
 {
+  assoc assoc;
+  char *code;
+  char const *chars;
+  int integer;
+  named_ref *named_ref;
   symbol *symbol;
   symbol_list *list;
   symbol *symbol;
   symbol_list *list;
-  int integer;
-  char const *chars;
-  char *code;
-  assoc assoc;
   uniqstr uniqstr;
   unsigned char character;
   uniqstr uniqstr;
   unsigned char character;
-  named_ref *named_ref;
 };
 
 /* Define the tokens together with their human representation.  */
 };
 
 /* Define the tokens together with their human representation.  */
@@ -138,40 +131,36 @@ current_lhs(symbol *sym, location loc, named_ref *ref)
 %token PERCENT_LEFT        "%left"
 %token PERCENT_RIGHT       "%right"
 %token PERCENT_NONASSOC    "%nonassoc"
 %token PERCENT_LEFT        "%left"
 %token PERCENT_RIGHT       "%right"
 %token PERCENT_NONASSOC    "%nonassoc"
+%token PERCENT_PRECEDENCE  "%precedence"
 
 %token PERCENT_PREC          "%prec"
 %token PERCENT_DPREC         "%dprec"
 %token PERCENT_MERGE         "%merge"
 
 
 %token PERCENT_PREC          "%prec"
 %token PERCENT_DPREC         "%dprec"
 %token PERCENT_MERGE         "%merge"
 
-
 /*----------------------.
 | Global Declarations.  |
 `----------------------*/
 
 %token
   PERCENT_CODE            "%code"
 /*----------------------.
 | Global Declarations.  |
 `----------------------*/
 
 %token
   PERCENT_CODE            "%code"
-  PERCENT_DEBUG           "%debug"
   PERCENT_DEFAULT_PREC    "%default-prec"
   PERCENT_DEFINE          "%define"
   PERCENT_DEFINES         "%defines"
   PERCENT_ERROR_VERBOSE   "%error-verbose"
   PERCENT_EXPECT          "%expect"
   PERCENT_DEFAULT_PREC    "%default-prec"
   PERCENT_DEFINE          "%define"
   PERCENT_DEFINES         "%defines"
   PERCENT_ERROR_VERBOSE   "%error-verbose"
   PERCENT_EXPECT          "%expect"
-  PERCENT_EXPECT_RR      "%expect-rr"
+  PERCENT_EXPECT_RR       "%expect-rr"
+  PERCENT_FLAG            "%<flag>"
   PERCENT_FILE_PREFIX     "%file-prefix"
   PERCENT_GLR_PARSER      "%glr-parser"
   PERCENT_INITIAL_ACTION  "%initial-action"
   PERCENT_LANGUAGE        "%language"
   PERCENT_FILE_PREFIX     "%file-prefix"
   PERCENT_GLR_PARSER      "%glr-parser"
   PERCENT_INITIAL_ACTION  "%initial-action"
   PERCENT_LANGUAGE        "%language"
-  PERCENT_LEX_PARAM       "%lex-param"
-  PERCENT_LOCATIONS       "%locations"
   PERCENT_NAME_PREFIX     "%name-prefix"
   PERCENT_NO_DEFAULT_PREC "%no-default-prec"
   PERCENT_NO_LINES        "%no-lines"
   PERCENT_NONDETERMINISTIC_PARSER
   PERCENT_NAME_PREFIX     "%name-prefix"
   PERCENT_NO_DEFAULT_PREC "%no-default-prec"
   PERCENT_NO_LINES        "%no-lines"
   PERCENT_NONDETERMINISTIC_PARSER
-                         "%nondeterministic-parser"
+                          "%nondeterministic-parser"
   PERCENT_OUTPUT          "%output"
   PERCENT_OUTPUT          "%output"
-  PERCENT_PARSE_PARAM     "%parse-param"
-  PERCENT_PURE_PARSER     "%pure-parser"
-  PERCENT_REQUIRE        "%require"
+  PERCENT_REQUIRE         "%require"
   PERCENT_SKELETON        "%skeleton"
   PERCENT_START           "%start"
   PERCENT_TOKEN_TABLE     "%token-table"
   PERCENT_SKELETON        "%skeleton"
   PERCENT_START           "%start"
   PERCENT_TOKEN_TABLE     "%token-table"
@@ -180,6 +169,7 @@ current_lhs(symbol *sym, location loc, named_ref *ref)
 ;
 
 %token BRACED_CODE     "{...}"
 ;
 
 %token BRACED_CODE     "{...}"
+%token BRACED_PREDICATE "%?{...}"
 %token BRACKETED_ID    "[identifier]"
 %token CHAR            "char"
 %token EPILOGUE        "epilogue"
 %token BRACKETED_ID    "[identifier]"
 %token CHAR            "char"
 %token EPILOGUE        "epilogue"
@@ -190,9 +180,9 @@ current_lhs(symbol *sym, location loc, named_ref *ref)
 %token PIPE            "|"
 %token PROLOGUE        "%{...%}"
 %token SEMICOLON       ";"
 %token PIPE            "|"
 %token PROLOGUE        "%{...%}"
 %token SEMICOLON       ";"
-%token TYPE            "type"
-%token TYPE_TAG_ANY    "<*>"
-%token TYPE_TAG_NONE   "<>"
+%token TAG             "<tag>"
+%token TAG_ANY         "<*>"
+%token TAG_NONE        "<>"
 
 %type <character> CHAR
 %printer { fputs (char_name ($$), stderr); } CHAR
 
 %type <character> CHAR
 %printer { fputs (char_name ($$), stderr); } CHAR
@@ -200,17 +190,18 @@ current_lhs(symbol *sym, location loc, named_ref *ref)
 /* braceless is not to be used for rule or symbol actions, as it
    calls code_props_plain_init.  */
 %type <chars> STRING "%{...%}" EPILOGUE braceless content.opt
 /* braceless is not to be used for rule or symbol actions, as it
    calls code_props_plain_init.  */
 %type <chars> STRING "%{...%}" EPILOGUE braceless content.opt
-%type <code> "{...}"
+%type <code> "{...}" "%?{...}"
 %printer { fputs (quotearg_style (c_quoting_style, $$), stderr); }
 %printer { fputs (quotearg_style (c_quoting_style, $$), stderr); }
-        STRING
+         STRING
 %printer { fprintf (stderr, "{\n%s\n}", $$); }
 %printer { fprintf (stderr, "{\n%s\n}", $$); }
-        braceless content.opt "{...}" "%{...%}" EPILOGUE
+         braceless content.opt "{...}" "%{...%}" EPILOGUE
 
 
-%type <uniqstr> BRACKETED_ID ID ID_COLON TYPE variable
+%type <uniqstr> BRACKETED_ID ID ID_COLON PERCENT_FLAG TAG variable
 %printer { fputs ($$, stderr); } <uniqstr>
 %printer { fprintf (stderr, "[%s]", $$); } BRACKETED_ID
 %printer { fprintf (stderr, "%s:", $$); } ID_COLON
 %printer { fputs ($$, stderr); } <uniqstr>
 %printer { fprintf (stderr, "[%s]", $$); } BRACKETED_ID
 %printer { fprintf (stderr, "%s:", $$); } ID_COLON
-%printer { fprintf (stderr, "<%s>", $$); } TYPE
+%printer { fprintf (stderr, "%%%s", $$); } PERCENT_FLAG
+%printer { fprintf (stderr, "<%s>", $$); } TAG
 
 %type <integer> INT
 %printer { fprintf (stderr, "%d", $$); } <integer>
 
 %type <integer> INT
 %printer { fprintf (stderr, "%d", $$); } <integer>
@@ -223,6 +214,56 @@ current_lhs(symbol *sym, location loc, named_ref *ref)
 %type <list>  symbols.1 symbols.prec generic_symlist generic_symlist_item
 %type <named_ref> named_ref.opt
 
 %type <list>  symbols.1 symbols.prec generic_symlist generic_symlist_item
 %type <named_ref> named_ref.opt
 
+/*---------.
+| %param.  |
+`---------*/
+%code requires
+{
+# ifndef PARAM_TYPE
+#  define PARAM_TYPE
+  typedef enum
+  {
+    param_none   = 0,
+    param_lex    = 1 << 0,
+    param_parse  = 1 << 1,
+    param_both   = param_lex | param_parse
+  } param_type;
+# endif
+};
+%code
+{
+  /** Add a lex-param and/or a parse-param.
+   *
+   * \param type  where to push this formal argument.
+   * \param decl  the formal argument.  Destroyed.
+   * \param loc   the location in the source.
+   */
+  static void add_param (param_type type, char *decl, location loc);
+  static param_type current_param = param_none;
+};
+%union
+{
+  param_type param;
+}
+%token <param> PERCENT_PARAM "%param";
+%printer
+{
+  switch ($$)
+    {
+#define CASE(In, Out)                                           \
+      case param_ ## In: fputs ("%" #Out, stderr); break
+      CASE(lex,   lex-param);
+      CASE(parse, parse-param);
+      CASE(both,  param);
+#undef CASE
+      case param_none: aver (false); break;
+    }
+} <param>;
+
+
+                     /*==========\
+                     | Grammar.  |
+                     \==========*/
 %%
 
 input:
 %%
 
 input:
@@ -230,9 +271,9 @@ input:
 ;
 
 
 ;
 
 
-       /*------------------------------------.
-       | Declarations: before the first %%.  |
-       `------------------------------------*/
+        /*------------------------------------.
+        | Declarations: before the first %%.  |
+        `------------------------------------*/
 
 prologue_declarations:
   /* Nothing */
 
 prologue_declarations:
   /* Nothing */
@@ -251,7 +292,10 @@ prologue_declaration:
                         plain_code.code, @1);
       code_scanner_last_string_free ();
     }
                         plain_code.code, @1);
       code_scanner_last_string_free ();
     }
-| "%debug"                         { debug_flag = true; }
+| "%<flag>"
+    {
+      muscle_percent_define_ensure ($1, @1, true);
+    }
 | "%define" variable content.opt
     {
       muscle_percent_define_insert ($2, @2, $3,
 | "%define" variable content.opt
     {
       muscle_percent_define_insert ($2, @2, $3,
@@ -263,9 +307,13 @@ prologue_declaration:
       defines_flag = true;
       spec_defines_file = xstrdup ($2);
     }
       defines_flag = true;
       spec_defines_file = xstrdup ($2);
     }
-| "%error-verbose"                 { error_verbose = true; }
+| "%error-verbose"
+    {
+      muscle_percent_define_insert ("parse.error", @1, "verbose",
+                                    MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
+    }
 | "%expect" INT                    { expected_sr_conflicts = $2; }
 | "%expect" INT                    { expected_sr_conflicts = $2; }
-| "%expect-rr" INT                { expected_rr_conflicts = $2; }
+| "%expect-rr" INT                 { expected_rr_conflicts = $2; }
 | "%file-prefix" STRING            { spec_file_prefix = $2; }
 | "%file-prefix" "=" STRING        { spec_file_prefix = $3; } /* deprecated */
 | "%glr-parser"
 | "%file-prefix" STRING            { spec_file_prefix = $2; }
 | "%file-prefix" "=" STRING        { spec_file_prefix = $3; } /* deprecated */
 | "%glr-parser"
@@ -282,36 +330,19 @@ prologue_declaration:
       muscle_code_grow ("initial_action", action.code, @2);
       code_scanner_last_string_free ();
     }
       muscle_code_grow ("initial_action", action.code, @2);
       code_scanner_last_string_free ();
     }
-| "%language" STRING           { language_argmatch ($2, grammar_prio, @1); }
-| "%lex-param" "{...}"         { add_param ("lex_param", $2, @2); }
-| "%locations"                  { locations_flag = true; }
+| "%language" STRING            { language_argmatch ($2, grammar_prio, @1); }
 | "%name-prefix" STRING         { spec_name_prefix = $2; }
 | "%name-prefix" "=" STRING     { spec_name_prefix = $3; } /* deprecated */
 | "%no-lines"                   { no_lines_flag = true; }
 | "%name-prefix" STRING         { spec_name_prefix = $2; }
 | "%name-prefix" "=" STRING     { spec_name_prefix = $3; } /* deprecated */
 | "%no-lines"                   { no_lines_flag = true; }
-| "%nondeterministic-parser"   { nondeterministic_parser = true; }
+| "%nondeterministic-parser"    { nondeterministic_parser = true; }
 | "%output" STRING              { spec_outfile = $2; }
 | "%output" "=" STRING          { spec_outfile = $3; }  /* deprecated */
 | "%output" STRING              { spec_outfile = $2; }
 | "%output" "=" STRING          { spec_outfile = $3; }  /* deprecated */
-| "%parse-param" "{...}"       { add_param ("parse_param", $2, @2); }
-| "%pure-parser"
-    {
-      /* %pure-parser is deprecated in favor of `%define api.pure', so use
-         `%define api.pure' in a backward-compatible manner here.  First, don't
-         complain if %pure-parser is specified multiple times.  */
-      if (!muscle_find_const ("percent_define(api.pure)"))
-        muscle_percent_define_insert ("api.pure", @1, "",
-                                      MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
-      /* In all cases, use api.pure now so that the backend doesn't complain if
-         the skeleton ignores api.pure, but do warn now if there's a previous
-         conflicting definition from an actual %define.  */
-      if (!muscle_percent_define_flag_if ("api.pure"))
-        muscle_percent_define_insert ("api.pure", @1, "",
-                                      MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE);
-    }
+| "%param" { current_param = $1; } params { current_param = param_none; }
 | "%require" STRING             { version_check (&@2, $2); }
 | "%skeleton" STRING
     {
       char const *skeleton_user = $2;
 | "%require" STRING             { version_check (&@2, $2); }
 | "%skeleton" STRING
     {
       char const *skeleton_user = $2;
-      if (mbschr (skeleton_user, '/'))
+      if (strchr (skeleton_user, '/'))
         {
           size_t dir_length = strlen (current_file);
           char *skeleton_build;
         {
           size_t dir_length = strlen (current_file);
           char *skeleton_build;
@@ -338,6 +369,16 @@ prologue_declaration:
 | /*FIXME: Err?  What is this horror doing here? */ ";"
 ;
 
 | /*FIXME: Err?  What is this horror doing here? */ ";"
 ;
 
+params:
+   params "{...}"  { add_param (current_param, $2, @2); }
+| "{...}"          { add_param (current_param, $1, @1); }
+;
+
+
+/*----------------------.
+| grammar_declaration.  |
+`----------------------*/
+
 grammar_declaration:
   precedence_declaration
 | symbol_declaration
 grammar_declaration:
   precedence_declaration
 | symbol_declaration
@@ -349,14 +390,14 @@ grammar_declaration:
     {
       symbol_list *list;
       for (list = $3; list; list = list->next)
     {
       symbol_list *list;
       for (list = $3; list; list = list->next)
-       symbol_list_destructor_set (list, $2, @2);
+        symbol_list_code_props_set (list, destructor, @2, $2);
       symbol_list_free ($3);
     }
 | "%printer" "{...}" generic_symlist
     {
       symbol_list *list;
       for (list = $3; list; list = list->next)
       symbol_list_free ($3);
     }
 | "%printer" "{...}" generic_symlist
     {
       symbol_list *list;
       for (list = $3; list; list = list->next)
-       symbol_list_printer_set (list, $2, @2);
+        symbol_list_code_props_set (list, printer, @2, $2);
       symbol_list_free ($3);
     }
 | "%default-prec"
       symbol_list_free ($3);
     }
 | "%default-prec"
@@ -382,9 +423,9 @@ grammar_declaration:
 ;
 
 
 ;
 
 
-/*----------*
- | %union.  |
- *----------*/
+/*---------.
+| %union.  |
+`---------*/
 
 %token PERCENT_UNION "%union";
 
 
 %token PERCENT_UNION "%union";
 
@@ -416,40 +457,41 @@ symbol_declaration:
       current_class = unknown_sym;
       current_type = NULL;
     }
       current_class = unknown_sym;
       current_type = NULL;
     }
-| "%type" TYPE symbols.1
+| "%type" TAG symbols.1
     {
       symbol_list *list;
       tag_seen = true;
       for (list = $3; list; list = list->next)
     {
       symbol_list *list;
       tag_seen = true;
       for (list = $3; list; list = list->next)
-       symbol_type_set (list->content.sym, $2, @2);
+        symbol_type_set (list->content.sym, $2, @2);
       symbol_list_free ($3);
     }
 ;
 
 precedence_declaration:
       symbol_list_free ($3);
     }
 ;
 
 precedence_declaration:
-  precedence_declarator type.opt symbols.prec
+  precedence_declarator tag.opt symbols.prec
     {
       symbol_list *list;
       ++current_prec;
       for (list = $3; list; list = list->next)
     {
       symbol_list *list;
       ++current_prec;
       for (list = $3; list; list = list->next)
-       {
-         symbol_type_set (list->content.sym, current_type, @2);
-         symbol_precedence_set (list->content.sym, current_prec, $1, @1);
-       }
+        {
+          symbol_type_set (list->content.sym, current_type, @2);
+          symbol_precedence_set (list->content.sym, current_prec, $1, @1);
+        }
       symbol_list_free ($3);
       current_type = NULL;
     }
 ;
 
 precedence_declarator:
       symbol_list_free ($3);
       current_type = NULL;
     }
 ;
 
 precedence_declarator:
-  "%left"     { $$ = left_assoc; }
-| "%right"    { $$ = right_assoc; }
-| "%nonassoc" { $$ = non_assoc; }
+  "%left"       { $$ = left_assoc; }
+| "%right"      { $$ = right_assoc; }
+| "%nonassoc"   { $$ = non_assoc; }
+| "%precedence" { $$ = precedence_assoc; }
 ;
 
 ;
 
-type.opt:
+tag.opt:
   /* Nothing. */ { current_type = NULL; }
   /* Nothing. */ { current_type = NULL; }
-| TYPE           { current_type = $1; tag_seen = true; }
+| TAG            { current_type = $1; tag_seen = true; }
 ;
 
 /* Just like symbols.1 but accept INT for the sake of POSIX.  */
 ;
 
 /* Just like symbols.1 but accept INT for the sake of POSIX.  */
@@ -479,15 +521,15 @@ generic_symlist:
 ;
 
 generic_symlist_item:
 ;
 
 generic_symlist_item:
-  symbol            { $$ = symbol_list_sym_new ($1, @1); }
-| TYPE              { $$ = symbol_list_type_new ($1, @1); }
-| "<*>"             { $$ = symbol_list_default_tagged_new (@1); }
-| "<>"             { $$ = symbol_list_default_tagless_new (@1); }
+  symbol    { $$ = symbol_list_sym_new ($1, @1); }
+| TAG       { $$ = symbol_list_type_new ($1, @1); }
+| "<*>"     { $$ = symbol_list_default_tagged_new (@1); }
+| "<>"      { $$ = symbol_list_default_tagless_new (@1); }
 ;
 
 /* One token definition.  */
 symbol_def:
 ;
 
 /* One token definition.  */
 symbol_def:
-  TYPE
+  TAG
      {
        current_type = $1;
        tag_seen = true;
      {
        current_type = $1;
        tag_seen = true;
@@ -525,9 +567,9 @@ symbol_defs.1:
 ;
 
 
 ;
 
 
-       /*------------------------------------------.
-       | The grammar section: between the two %%.  |
-       `------------------------------------------*/
+        /*------------------------------------------.
+        | The grammar section: between the two %%.  |
+        `------------------------------------------*/
 
 grammar:
   rules_or_grammar_declaration
 
 grammar:
   rules_or_grammar_declaration
@@ -562,16 +604,18 @@ rhses.1:
 rhs:
   /* Nothing.  */
     { grammar_current_rule_begin (current_lhs_symbol, current_lhs_location,
 rhs:
   /* Nothing.  */
     { grammar_current_rule_begin (current_lhs_symbol, current_lhs_location,
-                                 current_lhs_named_ref); }
+                                  current_lhs_named_ref); }
 | rhs symbol named_ref.opt
     { grammar_current_rule_symbol_append ($2, @2, $3); }
 | rhs "{...}" named_ref.opt
 | rhs symbol named_ref.opt
     { grammar_current_rule_symbol_append ($2, @2, $3); }
 | rhs "{...}" named_ref.opt
-    { grammar_current_rule_action_append ($2, @2, $3); }
+    { grammar_current_rule_action_append ($2, @2, $3, false); }
+| rhs "%?{...}"
+    { grammar_current_rule_action_append ($2, @2, NULL, true); }
 | rhs "%prec" symbol
     { grammar_current_rule_prec_set ($3, @3); }
 | rhs "%dprec" INT
     { grammar_current_rule_dprec_set ($3, @3); }
 | rhs "%prec" symbol
     { grammar_current_rule_prec_set ($3, @3); }
 | rhs "%dprec" INT
     { grammar_current_rule_dprec_set ($3, @3); }
-| rhs "%merge" TYPE
+| rhs "%merge" TAG
     { grammar_current_rule_merge_set ($3, @3); }
 ;
 
     { grammar_current_rule_merge_set ($3, @3); }
 ;
 
@@ -581,10 +625,9 @@ named_ref.opt:
   BRACKETED_ID   { $$ = named_ref_new($1, @1); }
 ;
 
   BRACKETED_ID   { $$ = named_ref_new($1, @1); }
 ;
 
-
-/*----------------------------*
- | variable and content.opt.  |
- *---------------------------*/
+/*---------------------------.
+| variable and content.opt.  |
+`---------------------------*/
 
 /* The STRING form of variable is deprecated and is not M4-friendly.
    For example, M4 fails for `%define "[" "value"'.  */
 
 /* The STRING form of variable is deprecated and is not M4-friendly.
    For example, M4 fails for `%define "[" "value"'.  */
@@ -601,9 +644,9 @@ content.opt:
 ;
 
 
 ;
 
 
-/*-------------*
- | braceless.  |
- *-------------*/
+/*------------.
+| braceless.  |
+`------------*/
 
 braceless:
   "{...}"
 
 braceless:
   "{...}"
@@ -618,9 +661,9 @@ braceless:
 ;
 
 
 ;
 
 
-/*---------------*
- | Identifiers.  |
- *---------------*/
+/*--------------.
+| Identifiers.  |
+`--------------*/
 
 /* Identifiers are returned as uniqstr values by the scanner.
    Depending on their use, we may need to make them genuine symbols.  */
 
 /* Identifiers are returned as uniqstr values by the scanner.
    Depending on their use, we may need to make them genuine symbols.  */
@@ -693,49 +736,51 @@ lloc_default (YYLTYPE const *rhs, int n)
   for (i = 1; i <= n; i++)
     if (! equal_boundaries (rhs[i].start, rhs[i].end))
       {
   for (i = 1; i <= n; i++)
     if (! equal_boundaries (rhs[i].start, rhs[i].end))
       {
-       loc.start = rhs[i].start;
-       break;
+        loc.start = rhs[i].start;
+        break;
       }
 
   return loc;
 }
 
 
       }
 
   return loc;
 }
 
 
-/* Add a lex-param or a parse-param (depending on TYPE) with
-   declaration DECL and location LOC.  */
-
 static void
 static void
-add_param (char const *type, char *decl, location loc)
+add_param (param_type type, char *decl, location loc)
 {
   static char const alphanum[26 + 26 + 1 + 10] =
     "abcdefghijklmnopqrstuvwxyz"
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     "_"
     "0123456789";
 {
   static char const alphanum[26 + 26 + 1 + 10] =
     "abcdefghijklmnopqrstuvwxyz"
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     "_"
     "0123456789";
+
   char const *name_start = NULL;
   char const *name_start = NULL;
-  char *p;
-
-  /* Stop on last actual character.  */
-  for (p = decl; p[1]; p++)
-    if ((p == decl
-        || ! memchr (alphanum, p[-1], sizeof alphanum))
-       && memchr (alphanum, p[0], sizeof alphanum - 10))
-      name_start = p;
-
-  /* Strip the surrounding '{' and '}', and any blanks just inside
-     the braces.  */
-  while (*--p == ' ' || *p == '\t')
-    continue;
-  p[1] = '\0';
-  while (*++decl == ' ' || *decl == '\t')
-    continue;
+  {
+    char *p;
+    /* Stop on last actual character.  */
+    for (p = decl; p[1]; p++)
+      if ((p == decl
+           || ! memchr (alphanum, p[-1], sizeof alphanum))
+          && memchr (alphanum, p[0], sizeof alphanum - 10))
+        name_start = p;
+
+    /* Strip the surrounding '{' and '}', and any blanks just inside
+       the braces.  */
+    while (*--p == ' ' || *p == '\t')
+      continue;
+    p[1] = '\0';
+    while (*++decl == ' ' || *decl == '\t')
+      continue;
+  }
 
   if (! name_start)
     complain_at (loc, _("missing identifier in parameter declaration"));
   else
     {
       char *name = xmemdup0 (name_start, strspn (name_start, alphanum));
 
   if (! name_start)
     complain_at (loc, _("missing identifier in parameter declaration"));
   else
     {
       char *name = xmemdup0 (name_start, strspn (name_start, alphanum));
-      muscle_pair_list_grow (type, decl, name);
+      if (type & param_lex)
+        muscle_pair_list_grow ("lex_param", decl, name);
+      if (type & param_parse)
+        muscle_pair_list_grow ("parse_param", decl, name);
       free (name);
     }
 
       free (name);
     }