* src/getargs.c (skeleton_arg): Last arg is now location const *.

Rewrite to simplify the logic.
(language_argmatch): Likewise.

* doc/bison.texinfo (Decl Summary, Bison Options): Don't claim
Java is supported.
* src/complain.c (program_name): Remove decl; no longer needed.
* src/main.c (program_name): Remove; now belongs to getargs.

2006-12-18  Paolo Bonzini  <bonzini@gnu.org>

* NEWS: Document %language.

* data/Makefile.am (dist_pkgdata_DATA): Add c-skel.m4, c++-skel.m4.

* data/c-skel.m4, data/c++-skel.m4: New files.
* data/glr.c: Complain on push parsers.

* doc/bison.texinfo (C++ Parser Interface): Prefer %language
over %skeleton.
(Directives): Document %language and %skeleton.
(Command line): Document -L.

* examples/extexi: Rewrite %require directive.
* examples/calc++/Makefile.am: Pass VERSION to extexi.

* src/files.c (compute_exts_from_gc): Look in language structure
for .y extension.
(compute_file_name_parts): Check whether .tab should be added.
* src/getargs.c (valid_languages, skeleton_prio, language_prio):
(language, skeleton_arg, language_argmatch): New.
(long_options): Add --language.
(getargs): Use skeleton_arg, add -L/--language.
* src/getargs.h: Include location.h.
(struct bison_language, language, skeleton_arg, language_argmatch): New.
* src/output.c (prepare): Pick default skeleton from struct language.
Don't dispatch C skeletons here.
* src/parse-gram.y (PERCENT_LANGUAGE): New.
(prologue_declaration): Add "%language" rule, use skeleton_arg.
* src/scan-gram.l ("%language"): New rule.

* tests/calc.at: Test %skeleton and %language.
* tests/local.at (AT_SKEL_CC_IF): Look for %language.
(AT_GLR_IF): Look for %skeleton "glr.cc".
(AT_LALR1_CC_IF, AT_GLR_CC_IF): Rewrite.
(AT_YACC_IF): Reject %language.

2006-12-18  Paul Eggert  <eggert@cs.ucla.edu>
This commit is contained in:
Paul Eggert
2006-12-19 00:34:37 +00:00
parent db06f0ce72
commit 0e021770cc
19 changed files with 287 additions and 51 deletions

View File

@@ -1,3 +1,52 @@
2006-12-18 Paul Eggert <eggert@cs.ucla.edu>
* src/getargs.c (skeleton_arg): Last arg is now location const *.
Rewrite to simplify the logic.
(language_argmatch): Likewise.
* doc/bison.texinfo (Decl Summary, Bison Options): Don't claim
Java is supported.
* src/complain.c (program_name): Remove decl; no longer needed.
* src/main.c (program_name): Remove; now belongs to getargs.
2006-12-18 Paolo Bonzini <bonzini@gnu.org>
* NEWS: Document %language.
* data/Makefile.am (dist_pkgdata_DATA): Add c-skel.m4, c++-skel.m4.
* data/c-skel.m4, data/c++-skel.m4: New files.
* data/glr.c: Complain on push parsers.
* doc/bison.texinfo (C++ Parser Interface): Prefer %language
over %skeleton.
(Directives): Document %language and %skeleton.
(Command line): Document -L.
* examples/extexi: Rewrite %require directive.
* examples/calc++/Makefile.am: Pass VERSION to extexi.
* src/files.c (compute_exts_from_gc): Look in language structure
for .y extension.
(compute_file_name_parts): Check whether .tab should be added.
* src/getargs.c (valid_languages, skeleton_prio, language_prio):
(language, skeleton_arg, language_argmatch): New.
(long_options): Add --language.
(getargs): Use skeleton_arg, add -L/--language.
* src/getargs.h: Include location.h.
(struct bison_language, language, skeleton_arg, language_argmatch): New.
* src/output.c (prepare): Pick default skeleton from struct language.
Don't dispatch C skeletons here.
* src/parse-gram.y (PERCENT_LANGUAGE): New.
(prologue_declaration): Add "%language" rule, use skeleton_arg.
* src/scan-gram.l ("%language"): New rule.
* tests/calc.at: Test %skeleton and %language.
* tests/local.at (AT_SKEL_CC_IF): Look for %language.
(AT_GLR_IF): Look for %skeleton "glr.cc".
(AT_LALR1_CC_IF, AT_GLR_CC_IF): Rewrite.
(AT_YACC_IF): Reject %language.
2006-12-18 Paul Eggert <eggert@cs.ucla.edu>
* src/symtab.h (struct semantic_type): Remove the tag 'semantic_type',

7
NEWS
View File

@@ -6,6 +6,11 @@ Changes in version 2.3a+ (????-??-??):
* The -g and --graph options now output graphs in Graphviz DOT format,
not VCG format.
* An experimental directive %language specifies the language of the
generated parser, which can be C (the default) or C++. This
directive affects the skeleton used, and the names of the generated
files if the grammar file's name ends in ".y".
* The grammar file may now specify the name of the parser header file using
%defines. For example:
@@ -96,7 +101,7 @@ Changes in version 2.3a+ (????-??-??):
- `%start-header {CODE}', which only Bison 2.3a supported.
3. %provides {CODE}
This is the right place to write additional definitions you would like
Bison to expose externally. That is, this directive inserts your CODE
both into the parser header file and into the parser code file after

View File

@@ -16,8 +16,8 @@
## 02110-1301 USA
dist_pkgdata_DATA = README bison.m4 \
c.m4 yacc.c glr.c push.c \
c++.m4 location.cc lalr1.cc glr.cc
c-skel.m4 c.m4 yacc.c glr.c push.c \
c++-skel.m4 c++.m4 location.cc lalr1.cc glr.cc
m4sugardir = $(pkgdatadir)/m4sugar
dist_m4sugar_DATA = m4sugar/m4sugar.m4

29
data/c++-skel.m4 Normal file
View File

@@ -0,0 +1,29 @@
m4_divert(-1) -*- Autoconf -*-
# C++ skeleton dispatching for Bison.
# Copyright (C) 2006 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
b4_glr_if( [m4_define([b4_used_skeleton], [b4_pkgdatadir/[glr.cc]])])
b4_nondeterministic_if([m4_define([b4_used_skeleton], [b4_pkgdatadir/[glr.cc]])])
b4_push_if([m4_fatal([%push-parser is not supported by C++])])
m4_define_default([b4_used_skeleton], [b4_pkgdatadir/[lalr1.cc]])
m4_define_default([b4_skeleton], ["b4_basename(b4_used_skeleton)"])
m4_include(b4_used_skeleton)

28
data/c-skel.m4 Normal file
View File

@@ -0,0 +1,28 @@
m4_divert(-1) -*- Autoconf -*-
# C skeleton dispatching for Bison.
# Copyright (C) 2006 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA
b4_push_if( [m4_define([b4_used_skeleton], [b4_pkgdatadir/[push.c]])])
b4_glr_if( [m4_define([b4_used_skeleton], [b4_pkgdatadir/[glr.c]])])
b4_nondeterministic_if([m4_define([b4_used_skeleton], [b4_pkgdatadir/[glr.c]])])
m4_define_default([b4_used_skeleton], [b4_pkgdatadir/[yacc.c]])
m4_define_default([b4_skeleton], ["b4_basename(b4_used_skeleton)"])
m4_include(b4_used_skeleton)

View File

@@ -21,6 +21,9 @@ m4_divert(-1) -*- C -*-
m4_include(b4_pkgdatadir/[c.m4])
b4_push_if([
m4_fatal([Non-deterministic push parsers are not yet supported])])
## ---------------- ##
## Default values. ##
## ---------------- ##

View File

@@ -4619,6 +4619,11 @@ Specify a prefix to use for all Bison output file names. The names are
chosen as if the input file were named @file{@var{prefix}.y}.
@end deffn
@deffn {Directive} %language="@var{language}"
Specify the programming language for the generated parser. Currently
supported languages include C and C++.
@end deffn
@deffn {Directive} %locations
Generate the code processing the locations (@pxref{Action Features,
,Special Features for Use in Actions}). This mode is enabled as soon as
@@ -4681,6 +4686,11 @@ Require version @var{version} or higher of Bison. @xref{Require Decl, ,
Require a Version of Bison}.
@end deffn
@deffn {Directive} %skeleton "@var{file}"
Specify the skeleton to use. You probably don't need this option unless
you are developing Bison.
@end deffn
@deffn {Directive} %token-table
Generate an array of token names in the parser file. The name of the
array is @code{yytname}; @code{yytname[@var{i}]} is the name of the
@@ -7262,8 +7272,9 @@ Tuning the parser:
@table @option
@item -S @var{file}
@itemx --skeleton=@var{file}
Specify the skeleton to use. You probably don't need this option unless
you are developing Bison.
Specify the skeleton to use, as if @code{%skeleton} was specified
(@pxref{Decl Summary, , Bison Declaration Summary}). You probably
don't need this option unless you are developing Bison.
@item -t
@itemx --debug
@@ -7271,6 +7282,12 @@ In the parser file, define the macro @code{YYDEBUG} to 1 if it is not
already defined, so that the debugging facilities are compiled.
@xref{Tracing, ,Tracing Your Parser}.
@item -L @var{language}
@itemx --language=@var{language}
Specify the programming language for the generated parser, as if
@code{%language} was specified (@pxref{Decl Summary, , Bison Declaration
Summary}). Currently supported languages include C and C++.
@item --locations
Pretend that @code{%locations} was specified. @xref{Decl Summary}.
@@ -7433,14 +7450,24 @@ int yyparse (void);
@node C++ Bison Interface
@subsection C++ Bison Interface
@c - %skeleton "lalr1.cc"
@c - %language "C++"
@c - Always pure
@c - initial action
The C++ parser @acronym{LALR}(1) skeleton is named @file{lalr1.cc}. To
select it, you may either pass the option @option{--skeleton=lalr1.cc}
to Bison, or include the directive @samp{%skeleton "lalr1.cc"} in the
grammar preamble. When run, @command{bison} will create several
The C++ parser @acronym{LALR}(1) skeleton is selected using a
language directive, @samp{%language "C++"}, or the synonymous
command-line option @option{--language=c++}@footnote{For both
the grammar directive and the command-line option, the
language name is case-insensitive}. These were introduced
in Bison 2.3b; for compatibility with earlier versions, you
may also pass the option @option{--skeleton=lalr1.cc} to Bison
or include the directive @samp{%skeleton "lalr1.cc"} in the
grammar preamble. Specifying the language is however preferred,
because it is clearer and because it will automatically choose the
correct skeleton for @acronym{GLR} parsers (the C++ @acronym{GLR}
skeleton is still under development).
When run, @command{bison} will create several
entities in the @samp{yy} namespace. Use the @samp{%name-prefix}
directive to change the namespace name, see @ref{Decl Summary}. The
various classes are generated in the following files:
@@ -7828,8 +7855,8 @@ the grammar for.
@comment file: calc++-parser.yy
@example
%skeleton "lalr1.cc" /* -*- C++ -*- */
%require "2.1a"
%language "C++" /* -*- C++ -*- */
%require "2.3b"
%defines
%define "parser_class_name" "calcxx_parser"
@end example

View File

@@ -35,8 +35,8 @@ extexi = $(top_srcdir)/examples/extexi
# Extract in src.
$(calc_extracted): $(doc) $(extexi)
cd $(srcdir) && \
$(AWK) -f ../extexi ../../doc/bison.texinfo -- \
calc++-parser.yy \
$(AWK) -f ../extexi -v VERSION="@VERSION@" \
../../doc/bison.texinfo -- calc++-parser.yy \
calc++-scanner.ll calc++.cc calc++-driver.hh calc++-driver.cc

View File

@@ -111,6 +111,7 @@ function normalize(contents, i, lines, n, line, res) {
else
line = "";
gsub (/^%require "[^"]*"$/, "%require \"" VERSION "\"", line);
gsub (/^@result\{\}/, "", line);
gsub (/^@error\{\}/, "", line);
gsub ("@[{]", "{", line);

View File

@@ -30,10 +30,6 @@
#include "files.h"
#include "getargs.h"
/* The calling program should define program_name and set it to the
name of the executing program. */
extern char *program_name;
bool complaint_issued;

View File

@@ -153,12 +153,20 @@ tr (char *s, char from, char to)
static void
compute_exts_from_gf (const char *ext)
{
src_extension = xstrdup (ext);
header_extension = xstrdup (ext);
tr (src_extension, 'y', 'c');
tr (src_extension, 'Y', 'C');
tr (header_extension, 'y', 'h');
tr (header_extension, 'Y', 'H');
if (strcmp (ext, ".y") == 0)
{
src_extension = xstrdup (language->src_extension);
header_extension = xstrdup (language->header_extension);
}
else
{
src_extension = xstrdup (ext);
header_extension = xstrdup (ext);
tr (src_extension, 'y', 'c');
tr (src_extension, 'Y', 'C');
tr (header_extension, 'y', 'h');
tr (header_extension, 'Y', 'H');
}
}
/* Compute extensions from the given c source file extension. */
@@ -281,7 +289,10 @@ compute_file_name_parts (void)
xstrndup (base, (strlen (base) - (ext ? strlen (ext) : 0)));
}
all_but_ext = concat2 (all_but_tab_ext, TAB_EXT);
if (language->add_tab)
all_but_ext = concat2 (all_but_tab_ext, TAB_EXT);
else
all_but_ext = xstrdup (all_but_tab_ext);
/* Compute the extensions from the grammar file name. */
if (ext && !yacc_flag)

View File

@@ -66,10 +66,19 @@ int report_flag = report_none;
int trace_flag = trace_none;
int warnings_flag = warnings_none;
static struct bison_language const valid_languages[] = {
{ "c", "c-skel.m4", ".c", ".h", true },
{ "c++", "c++-skel.m4", ".cc", ".hh", true },
{ "", "", "", "", false }
};
static int skeleton_prio = 2;
const char *skeleton = NULL;
static int language_prio = 2;
struct bison_language const *language = &valid_languages[0];
const char *include = NULL;
extern char *program_name;
char *program_name;
/** Decode an option's set of keys.
@@ -323,12 +332,63 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
}
/*-------------------------------------.
| --skeleton and --language handling. |
`--------------------------------------*/
void
skeleton_arg (char const *arg, int prio, location const *loc)
{
if (prio < skeleton_prio)
{
skeleton_prio = prio;
skeleton = arg;
}
else if (prio == skeleton_prio)
{
char const *msg =
_("multiple skeleton declarations are invalid");
if (loc)
complain_at (*loc, msg);
else
complain (msg);
}
}
void
language_argmatch (char const *arg, int prio, location const *loc)
{
char const *msg;
if (prio < language_prio)
{
int i;
for (i = 0; valid_languages[i].language[0]; i++)
if (strcasecmp (arg, valid_languages[i].language) == 0)
{
language_prio = prio;
language = &valid_languages[i];
return;
}
msg = _("invalid language `%s'");
}
else if (language_prio == prio)
msg = _("multiple language declarations are invalid");
else
return;
if (loc)
complain_at (*loc, msg, arg);
else
complain (msg, arg);
}
/*----------------------.
| Process the options. |
`----------------------*/
/* Shorts options. */
static char const short_options[] = "yvegdhr:ltknVo:b:p:S:T::W";
static char const short_options[] = "yvegdhr:L:ltknVo:b:p:S:T::W";
/* Values for long options that do not have single-letter equivalents. */
enum
@@ -374,6 +434,7 @@ static struct option const long_options[] =
{ "no-parser", no_argument, 0, 'n' },
{ "raw", no_argument, 0, 0 },
{ "skeleton", required_argument, 0, 'S' },
{ "language", required_argument, 0, 'L' },
{ "token-table", no_argument, 0, 'k' },
{0, 0, 0, 0}
@@ -414,8 +475,12 @@ getargs (int argc, char *argv[])
case 'h':
usage (EXIT_SUCCESS);
case 'L':
language_argmatch (optarg, 0, NULL);
break;
case 'S':
skeleton = AS_FILE_NAME (optarg);
skeleton_arg (AS_FILE_NAME (optarg), 0, NULL);
break;
case 'I':

View File

@@ -22,6 +22,10 @@
#ifndef GETARGS_H_
# define GETARGS_H_
#include "location.h"
extern char *program_name;
/* flags set by % directives */
/* for -S */
@@ -65,6 +69,18 @@ extern bool push_parser;
extern bool nondeterministic_parser;
/* --language. */
struct bison_language
{
char language[sizeof "c++"];
char skeleton[sizeof "c++-skel.m4"];
char src_extension[sizeof ".cc"];
char header_extension[sizeof ".hh"];
bool add_tab;
};
extern struct bison_language const *language;
/*-----------.
| --report. |
`-----------*/
@@ -126,4 +142,8 @@ extern int warnings_flag;
*/
void getargs (int argc, char *argv[]);
/* Used by parse-gram.y. */
void language_argmatch (char const *arg, int prio, location const *loc);
void skeleton_arg (const char *arg, int prio, location const *loc);
#endif /* !GETARGS_H_ */

View File

@@ -50,9 +50,6 @@
#include "tables.h"
#include "uniqstr.h"
/* The name this program was run with, for messages. */
char *program_name;
int

View File

@@ -622,16 +622,13 @@ prepare (void)
muscle_insert ("pre_prologue", obstack_finish (&pre_prologue_obstack));
muscle_insert ("post_prologue", obstack_finish (&post_prologue_obstack));
/* Find the right skeleton file. */
if (!skeleton)
{
if (glr_parser || nondeterministic_parser)
skeleton = "glr.c";
else
skeleton = "yacc.c";
}
/* Find the right skeleton file, and add muscles about the skeletons. */
if (skeleton)
MUSCLE_INSERT_C_STRING ("skeleton", skeleton);
else
skeleton = language->skeleton;
/* About the skeletons. */
/* About the skeletons. */
{
char const *pkgdatadir = getenv ("BISON_PKGDATADIR");
/* b4_pkgdatadir is used inside m4_include in the skeletons, so digraphs
@@ -639,7 +636,6 @@ prepare (void)
his Bison installation path. */
MUSCLE_INSERT_STRING_RAW ("pkgdatadir",
pkgdatadir ? pkgdatadir : PKGDATADIR);
MUSCLE_INSERT_C_STRING ("skeleton", skeleton);
}
}

View File

@@ -143,6 +143,7 @@ static int current_prec = 0;
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"
@@ -245,6 +246,7 @@ prologue_declaration:
{
muscle_code_grow ("initial_action", translate_symbol_action ($2, @2), @2);
}
| "%language" STRING { language_argmatch ($2, 1, &@1); }
| "%lex-param" "{...}" { add_param ("lex_param", $2, @2); }
| "%locations" { locations_flag = true; }
| "%name-prefix" STRING { spec_name_prefix = $2; }
@@ -257,7 +259,7 @@ prologue_declaration:
| "%pure-parser" { pure_parser = true; }
| "%push-parser" { push_parser = true; pure_parser = true; }
| "%require" STRING { version_check (&@2, $2); }
| "%skeleton" STRING { skeleton = $2; }
| "%skeleton" STRING { skeleton_arg ($2, 1, &@1); }
| "%token-table" { token_table_flag = true; }
| "%verbose" { report_flag = report_states; }
| "%yacc" { yacc_flag = true; }

View File

@@ -172,6 +172,7 @@ splice (\\[ \f\t\v]*\n)*
"%fixed"[-_]"output"[-_]"files" return PERCENT_YACC;
"%initial-action" return PERCENT_INITIAL_ACTION;
"%glr-parser" return PERCENT_GLR_PARSER;
"%language" return PERCENT_LANGUAGE;
"%left" return PERCENT_LEFT;
"%lex-param" return PERCENT_LEX_PARAM;
"%locations" return PERCENT_LOCATIONS;

View File

@@ -628,12 +628,15 @@ AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines %name-
AT_BANNER([[Simple LALR(1) C++ Calculator.]])
# First let's try using %skeleton
AT_CHECK_CALC([%skeleton "lalr1.cc" %defines %locations])
# AT_CHECK_CALC_LALR1_CC([BISON-OPTIONS])
# ---------------------------------------
# Start a testing chunk which compiles `calc' grammar with
# the C++ skeleton, and performs several tests over the parser.
m4_define([AT_CHECK_CALC_LALR1_CC],
[AT_CHECK_CALC([%skeleton "lalr1.cc" %defines %locations] $@)])
[AT_CHECK_CALC([%language "C++" %defines %locations] $@)])
AT_CHECK_CALC_LALR1_CC([])
AT_CHECK_CALC_LALR1_CC([%error-verbose %name-prefix "calc" %verbose %yacc])
@@ -652,12 +655,15 @@ AT_CHECK_CALC_LALR1_CC([%pure-parser %error-verbose %debug %name-prefix "calc" %
AT_BANNER([[Simple GLR C++ Calculator.]])
# Again, we try also using %skeleton.
AT_CHECK_CALC([%skeleton "glr.cc" %defines %locations])
# AT_CHECK_CALC_GLR_CC([BISON-OPTIONS])
# -------------------------------------
# Start a testing chunk which compiles `calc' grammar with
# the GLR C++ skeleton, and performs several tests over the parser.
m4_define([AT_CHECK_CALC_GLR_CC],
[AT_CHECK_CALC([%skeleton "glr.cc" %defines %locations] $@)])
[AT_CHECK_CALC([%language "C++" %glr-parser %defines %locations] $@)])
AT_CHECK_CALC_GLR_CC([])
AT_CHECK_CALC_GLR_CC([%error-verbose %name-prefix "calc" %verbose %yacc])

View File

@@ -41,17 +41,17 @@ m4_define([AT_BISON_OPTION_PUSHDEFS],
m4_define([_AT_BISON_OPTION_PUSHDEFS],
[m4_if([$1$2], $[1]$[2], [],
[m4_fatal([$0: Invalid arguments: $@])])dnl
m4_pushdef([AT_LALR1_CC_IF],
[m4_bmatch([$3], ["lalr1.cc"], [$1], [$2])])
m4_pushdef([AT_GLR_CC_IF],
[m4_bmatch([$3], ["glr.cc"], [$1], [$2])])
m4_pushdef([AT_SKEL_CC_IF],
[m4_bmatch([$3], ["\(glr\|lalr1\).cc"], [$1], [$2])])
[m4_bmatch([$3], [%language "[Cc]\+\+"\|%skeleton "[a-z0-9]+\.cc"], [$1], [$2])])
m4_pushdef([AT_GLR_IF],
[m4_bmatch([$3], [%glr-parser], [$1], [$2])])
[m4_bmatch([$3], [%glr-parser\|%skeleton "glr\.], [$1], [$2])])
m4_pushdef([AT_LALR1_CC_IF],
[AT_SKEL_CC_IF([AT_GLR_IF([$2], [$1])], [$2])])
m4_pushdef([AT_GLR_CC_IF],
[AT_SKEL_CC_IF([AT_GLR_IF([$1], [$2])], [$2])])
# Using yacc.c?
m4_pushdef([AT_YACC_IF],
[m4_bmatch([$3], [%glr-parser\|%skeleton], [$2], [$1])])
[m4_bmatch([$3], [%language\|%glr-parser\|%skeleton], [$2], [$1])])
m4_pushdef([AT_PARAM_IF],
[m4_bmatch([$3], [%parse-param], [$1], [$2])])
m4_pushdef([AT_LOCATION_IF],