bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Purity of yyerror etc.


From: Akim Demaille
Subject: Re: Purity of yyerror etc.
Date: 03 Nov 2002 17:50:15 +0100
User-agent: Gnus/5.0808 (Gnus v5.8.8) XEmacs/21.4 (Honest Recruiter)

| Often, when I am thinking of making a patch like that, I find it
| useful to write the patch for the documentation.  It's quite helpful
| to have a clear description of how things will change for the users,
| and the documentation exercise often suggests ways to improve or
| simplify the behavior.

Yes, I agree.  I include below the patch I'm applying, with the
documentation changes, and a better test suite.  The test suite become
itself tricky, precisely because of backward compatibility issues :(

| Anyway, there seem to be several issues here:
| 
| 1.  yyval/yyloc/b4_pure_args versus yylval/yylloc/b4_lpure_args
| 
|     What is this issue?  Can it be stated briefly?  Why have two
|     forms?

glr.c uses both couples, depending on the functions.  Usually one uses
yylval and yylloc when referring to the lookahead, as opposed to yyval
and yyloc for other values, e.g., $$.  In glr.c I'm not sure whether
the distinction is grounded or not, but I preserved it.  Another patch
can map all the yylloc and yylval onto yyval and yyloc if we feel like
it.
 
| 2.  %parse-param versus %pure (and perhaps %location?)
| 
|     Why are there two somewhat-different options here?  Is it some
|     backward-compatibility issue?  If so, what is the preferred option
|     these days, and how does it differ from the old-fashioned way?
|     And what does %pure have to do with %location?

There lies the mess...

1. %pure means that the communication with the scanner is pure,
   but also hides yylval and yylloc.

The fact that yylloc is now local, instead of being global, is a
issue.  A painful one actually: yyerror _needs_ it to report errors.
So it is perfectly clear (to me) that %location + %pure => yyerror
receives yylloc.  But, and this is the painful part, these options
are not new, and therefore work backward compatibility, we cannot
apply this rule to yacc.c.  But we can for glr.c, and I did.

2. if you want a pure parser, you _need_ to pass something to yyparse

So I took adavantage of this last fact to decide _when_ to pass yylloc
to yyerror in yacc.c: %pure + %location + parse-param.

Of course one could have introduced another %yyerror-with-locations,
but this is ugly, and gives too much room for the past into the
present.  I have preferred the current scheme where everything is
almost normal.

| 3.  yacc.c versus glr.c
| 
|     yacc.c needs to support older features for historical reasons,
|     but glr.c doesn't.  Which features are these?

That above, plus YYPARSE_PARAM< YYLEX_PARAM.

| > It results in a program that can have many arguments in function calls.
| 
| Why not instead pass a single argument that specifies the parsing context?

There is no comon set of argument used, plus that's really
obfuscation.

I'm installing the following patch, which is a good starting point.
We can change things if we want to, but at least the doc is there, and
the test suite too.

There is one issue I'm not happy with: the syntax of %parse-param and
%lex-param.  I would much prefer keeping { }, and maybe < > for
relations with the language underneath (currenly only C), and " " for
Bison string tokens.  So maybe something like:

%parse-param { ast_t *ast } {ast}

or

%parse-param <ast> { ast_t *ast }

I don't know.  But I don't like

%parse-param "ast_t *ast", "ast"


Index: ChangeLog
from  Akim Demaille  <address@hidden>

        * data/c.m4 (b4_identification, b4_user_args, b4_parse_param):
        New.
        * data/yacc.m4 (b4_pure_args, b4_Pure_args): New.
        (b4_parse_param): Remove.
        Use b4_identification.
        Propagate b4_pure_args where needed to pass them to yyerror.
        * data/glr.m4 (b4_parse_param): Remove.
        (b4_user_formals, b4_pure_args, b4_pure_formals, b4_lpure_args)
        (b4_lpure_formals): New.
        Use b4_identification.
        (YY_USER_FORMALS, YY_USER_ARGS): Remove, replaced by
        b4_user_formals and b4_user_args.
        (yyexpandGLRStack, yyFail, yyaddDeferredAction, yyglrShiftDefer)
        (yyreportAmbiguity): When using a pure parser, also need
        the location, and the parse-params.
        Adjust callers.
        (yyuserAction, yyglrShift, yyreportParseError, yyrecoverParseError):
        When using a pure parser, also need the parse-params.
        Adjust callers.
        * tests/calc.at: Test pure (%pure-parser) and absolutely pure
        (%pure-parser + %parse-param) LALR and GLR parsers.
        (AT_CHECK_PUSHDEFS, AT_CHECK_POPDEFS): New, define AT_PARAM_IF,
        AT_LOCATION_IF, AT_PURE_IF, AT_GLR_IF, AAT_PURE_AND_LOC_IF,
        AT_GLR_OR_PARAM_IF, AT_YYERROR_ARG_LOC_IF, AT_YYERROR_SEES_LOC_IF.
        (_AT_DATA_CALC_Y): Equip for purity of yyerror.
        (_AT_CHECK_CALC_ERROR): Use AT_YYERROR_SEES_LOC_IF.
        * tests/cxx-type.at (_AT_TEST_GLR_CALC): Equip for yyerror purity.
        * doc/bison.texinfo: Untabify the whole file.
        (Parser Function): Document %parse-param, deprecate YYPARSE_PARAM.
        (Pure Calling): Document %lex-param, deprecate YYLEX_PARAM.
        (Error Reporting): Adjust to these new directives.
        Document %error-verbose, deprecate YYERROR_VERBOSE.
        
Index: NEWS
--- NEWS Sun, 27 Oct 2002 13:07:36 +0100 akim
+++ NEWS Sun, 03 Nov 2002 14:53:13 +0100 akim
@@ -8,6 +8,14 @@
   ago, but nobody noticed until we recently asked someone to try
   building Bison with a K&R C compiler.
 
+* %error-verbose
+  This new directive is preferred over YYERROR_VERBOSE.
+
+* %lex-param, %parse-param
+  These new directives are preferred over PARSE_PARAM and LEX_PARAM.
+  In addition, they provide a means for yyerror to remain pure, and
+  to access to the current location.
+
 Changes in version 1.75, 2002-10-14:
 
 * Bison should now work on 64-bit hosts.
Index: doc/bison.texinfo
--- doc/bison.texinfo Sun, 03 Nov 2002 13:26:54 +0100 akim
+++ doc/bison.texinfo Sun, 03 Nov 2002 15:09:15 +0100 akim
@@ -682,7 +682,7 @@ @node GLR Parsers
 user-defined function on the resulting values to produce an arbitrary
 merged result.
 
-Let's consider an example, vastly simplified from C++.
+Let's consider an example, vastly simplified from a C++ grammar.
 
 @example
 address@hidden
@@ -706,20 +706,20 @@ @node GLR Parsers
      | decl      %dprec 2
      ;
 
-expr : ID              @{ printf ("%s ", $$); @}
+expr : ID               @{ printf ("%s ", $$); @}
      | TYPENAME '(' expr ')'
-                       @{ printf ("%s <cast> ", $1); @}
-     | expr '+' expr   @{ printf ("+ "); @}
-     | expr '=' expr   @{ printf ("= "); @}
+                        @{ printf ("%s <cast> ", $1); @}
+     | expr '+' expr    @{ printf ("+ "); @}
+     | expr '=' expr    @{ printf ("= "); @}
      ;
 
 decl : TYPENAME declarator ';'
-                       @{ printf ("%s <declare> ", $1); @}
+                        @{ printf ("%s <declare> ", $1); @}
      | TYPENAME declarator '=' expr ';'
-                       @{ printf ("%s <init-declare> ", $1); @}
+                        @{ printf ("%s <init-declare> ", $1); @}
      ;
 
-declarator : ID                @{ printf ("\"%s\" ", $1); @}
+declarator : ID         @{ printf ("\"%s\" ", $1); @}
      | '(' declarator ')'
      ;
 @end example
@@ -3559,10 +3559,11 @@ directives:
 Rename the external symbols used in the parser so that they start with
 @var{prefix} instead of @samp{yy}.  The precise list of symbols renamed
 is @code{yyparse}, @code{yylex}, @code{yyerror}, @code{yynerrs},
address@hidden, @code{yychar}, @code{yydebug}, and possible
address@hidden  For example, if you use @samp{%name-prefix="c_"}, the
-names become @code{c_parse}, @code{c_lex}, and so on.  @xref{Multiple
-Parsers, ,Multiple Parsers in the Same Program}.
address@hidden, @code{yylloc}, @code{yychar}, @code{yydebug}, and
+possible @code{yylloc}.  For example, if you use
address@hidden"c_"}, the names become @code{c_parse}, @code{c_lex},
+and so on.  @xref{Multiple Parsers, ,Multiple Parsers in the Same
+Program}.
 
 @item %no-parser
 Do not include any C code in the parser file; generate tables only.  The
@@ -3659,9 +3660,9 @@ @node Multiple Parsers
 names that do not conflict.
 
 The precise list of symbols renamed is @code{yyparse}, @code{yylex},
address@hidden, @code{yynerrs}, @code{yylval}, @code{yychar} and
address@hidden  For example, if you use @samp{-p c}, the names become
address@hidden, @code{clex}, and so on.
address@hidden, @code{yynerrs}, @code{yylval}, @code{yylloc},
address@hidden and @code{yydebug}.  For example, if you use @samp{-p c},
+the names become @code{cparse}, @code{clex}, and so on.
 
 @strong{All the other variables and macros associated with Bison are not
 renamed.} These others are not global; there is no conflict if the same
@@ -3706,23 +3707,65 @@ @node Parser Function
 write an action which directs @code{yyparse} to return immediately
 without reading further.
 
+
address@hidden int yyparse (void)
 The value returned by @code{yyparse} is 0 if parsing was successful (return
 is due to end-of-input).
 
 The value is 1 if parsing failed (return is due to a syntax error).
address@hidden deftypefun
 
 In an action, you can cause immediate return from @code{yyparse} by using
 these macros:
 
address@hidden @code
address@hidden YYACCEPT
address@hidden YYACCEPT
 @findex YYACCEPT
 Return immediately with value 0 (to report success).
address@hidden defmac
 
address@hidden YYABORT
address@hidden YYABORT
 @findex YYABORT
 Return immediately with value 1 (to report failure).
address@hidden table
address@hidden defmac
+
+If you use a reentrant parser, you can optionally pass additional
+parameter information to it in a reentrant way.  To do so, use the
+declaration @code{%parse-param}:
+
address@hidden {Directive} %parse-param @var{argument-declaration} 
@var{argument-name}
address@hidden %parse-param
+Declare that @code{argument-name} is an additional @code{yyparse}
+argument.  This argument is also passed to @code{yyerror}.  The
address@hidden is used when declaring functions or
+prototypes.
address@hidden deffn
+
+Here's an example.  Write this in the parser:
+
address@hidden
+%parse-param "int *nastiness"  "nastiness"
+%parse-param "int *randomness" "randomness"
address@hidden example
+
address@hidden
+Then call the parser like this:
+
address@hidden
address@hidden
+  int nastiness, randomness;
+  @dots{}  /* @r{Store proper data in @code{nastiness} and @code{randomness}.} 
 */
+  value = yyparse (&nastiness, &randomness);
+  @dots{}
address@hidden
address@hidden example
+
address@hidden
+In the grammar actions, use expressions like this to refer to the data:
+
address@hidden
+exp: @dots{}    @{ @dots{}; *randomness += 1; @dots{} @}
address@hidden example
+
 
 @node Lexical
 @section The Lexical Analyzer Function @code{yylex}
@@ -3927,85 +3970,47 @@ @node Pure Calling
 this case, omit the second argument; @code{yylex} will be called with
 only one argument.
 
address@hidden YYPARSE_PARAM
-If you use a reentrant parser, you can optionally pass additional
-parameter information to it in a reentrant way.  To do so, define the
-macro @code{YYPARSE_PARAM} as a variable name.  This modifies the
address@hidden function to accept one argument, of type @code{void *},
-with that name.
-
-When you call @code{yyparse}, pass the address of an object, casting the
-address to @code{void *}.  The grammar actions can refer to the contents
-of the object by casting the pointer value back to its proper type and
-then dereferencing it.  Here's an example.  Write this in the parser:
 
address@hidden
address@hidden
-struct parser_control
address@hidden
-  int nastiness;
-  int randomness;
address@hidden;
+If you wish to pass the additional parameter data to @code{yylex}, use
address@hidden just like @code{%parse-param} (@pxref{Parser
+Function}).
 
-#define YYPARSE_PARAM parm
address@hidden
address@hidden example
address@hidden {Directive} lex-param @var{argument-declaration} 
@var{argument-name}
address@hidden %lex-param
+Declare that @code{argument-name} is an additional @code{yylex}
+argument.
address@hidden deffn
 
address@hidden
-Then call the parser like this:
+For instance:
 
 @example
-struct parser_control
address@hidden
-  int nastiness;
-  int randomness;
address@hidden;
-
address@hidden
-
address@hidden
-  struct parser_control foo;
-  @dots{}  /* @r{Store proper data in @code{foo}.}  */
-  value = yyparse ((void *) &foo);
-  @dots{}
address@hidden
+%parse-param "int *nastiness"  "nastiness"
+%lex-param   "int *nastiness"  "nastiness"
+%parse-param "int *randomness" "randomness"
 @end example
 
 @noindent
-In the grammar actions, use expressions like this to refer to the data:
+results in the following signature:
 
 @example
-((struct parser_control *) parm)->randomness
+int yylex   (int *nastiness);
+int yyparse (int *nastiness, int *randomness);
 @end example
 
address@hidden YYLEX_PARAM
-If you wish to pass the additional parameter data to @code{yylex},
-define the macro @code{YYLEX_PARAM} just like @code{YYPARSE_PARAM}, as
-shown here:
+If @code{%pure-parser} is added:
 
 @example
address@hidden
-struct parser_control
address@hidden
-  int nastiness;
-  int randomness;
address@hidden;
-
-#define YYPARSE_PARAM parm
-#define YYLEX_PARAM parm
address@hidden
+int yylex   (YYSTYPE *lvalp, int *nastiness);
+int yyparse (int *nastiness, int *randomness);
 @end example
 
-You should then define @code{yylex} to accept one additional
-argument---the value of @code{parm}.  (This makes either two or three
-arguments in total, depending on whether an argument of type
address@hidden is passed.)  You can declare the argument as a pointer to
-the proper object type, or you can declare it as @code{void *} and
-access the contents as shown above.
-
-You can use @samp{%pure-parser} to request a reentrant parser without
-also using @code{YYPARSE_PARAM}.  Then you should call @code{yyparse}
-with no arguments, as usual.
address@hidden
+and finally, if both @code{%pure-parser} and @code{%locations} are used:
+
address@hidden
+int yylex   (YYSTYPE *lvalp, YYLTYPE *llocp, int *nastiness);
+int yyparse (int *nastiness, int *randomness);
address@hidden example
 
 @node Error Reporting
 @section The Error Reporting Function @code{yyerror}
@@ -4026,13 +4031,11 @@ @node Error Reporting
 receives one argument.  For a parse error, the string is normally
 @address@hidden"parse error"}}.
 
address@hidden YYERROR_VERBOSE
-If you define the macro @code{YYERROR_VERBOSE} in the Bison declarations
-section (@pxref{Bison Declarations, ,The Bison Declarations Section}),
-then Bison provides a more verbose and specific error message string
-instead of just plain @address@hidden"parse error"}}.  It doesn't matter what
-definition you use for @code{YYERROR_VERBOSE}, just whether you define
-it.
address@hidden %error-verbose
+If you invoke the directive @code{%error-verbose} in the Bison
+declarations section (@pxref{Bison Declarations, ,The Bison Declarations
+Section}), then Bison provides a more verbose and specific error message
+string instead of just plain @address@hidden"parse error"}}.
 
 The parser can detect one other kind of error: stack overflow.  This
 happens when the input contains constructions that are very deeply
@@ -4061,6 +4064,50 @@ @node Error Reporting
 (@pxref{Error Recovery}).  If recovery is impossible, @code{yyparse} will
 immediately return 1.
 
+Oviously, in location tracking pure parsers, @code{yyerror} should have
+an access to the current location.  This is indeed the case for the GLR
+parsers, but not for the Yacc parser, for historical reasons.  I.e., if
address@hidden %pure-parser} is passed then the prototypes for
address@hidden are:
+
address@hidden
+void yyerror (const char *msg);                 /* Yacc parsers.  */
+void yyerror (const char *msg, YYLTYPE *locp);  /* GLR parsers.   */
address@hidden example
+
+If @samp{%parse-param "int *nastiness"  "nastiness"} is used, then:
+
address@hidden
+void yyerror (int *randomness);  /* Yacc parsers.  */
+void yyerror (int *randomness);  /* GLR parsers.   */
address@hidden example
+
+Finally, GLR and Yacc parsers share the same @code{yyerror} calling
+convention for absolutely pure parsers, i.e., when the calling
+convention of @code{yylex} @emph{and} the calling convention of
address@hidden are pure.  I.e.:
+
address@hidden
+/* Location tracking.  */
+%locations
+/* Pure yylex.  */
+%pure-parser
+%lex-param   "int *nastiness"  "nastiness"
+/* Pure yyparse.  */
+%parse-param "int *nastiness"  "nastiness"
+%parse-param "int *randomness" "randomness"
address@hidden example
+
address@hidden
+results in the following signatures for all the parser kinds:
+
address@hidden
+int yylex (YYSTYPE *lvalp, YYLTYPE *llocp, int *nastiness);
+int yyparse (int *nastiness, int *randomness);
+void yyerror (const char *msg, YYLTYPE *locp,
+              int *nastiness, int *randomness);
address@hidden example
+
 @vindex yynerrs
 The variable @code{yynerrs} contains the number of syntax errors
 encountered so far.  Normally this variable is global; but if you
@@ -5450,9 +5497,9 @@ calc.y:11.8-12: warning: useless rule: u
 
     $accept  ->  . exp $   (rule 0)
 
-    NUM        shift, and go to state 1
+    NUM         shift, and go to state 1
 
-    exp        go to state 2
+    exp         go to state 2
 @end example
 
 This reads as follows: ``state 0 corresponds to being at the very
@@ -5499,7 +5546,7 @@ calc.y:11.8-12: warning: useless rule: u
 
     exp  ->  NUM .   (rule 5)
 
-    $default   reduce using rule 5 (exp)
+    $default    reduce using rule 5 (exp)
 @end example
 
 @noindent
@@ -5517,11 +5564,11 @@ calc.y:11.8-12: warning: useless rule: u
     exp  ->  exp . '*' exp   (rule 3)
     exp  ->  exp . '/' exp   (rule 4)
 
-    $          shift, and go to state 3
-    '+'        shift, and go to state 4
-    '-'        shift, and go to state 5
-    '*'        shift, and go to state 6
-    '/'        shift, and go to state 7
+    $           shift, and go to state 3
+    '+'         shift, and go to state 4
+    '-'         shift, and go to state 5
+    '*'         shift, and go to state 6
+    '/'         shift, and go to state 7
 @end example
 
 @noindent
@@ -5540,7 +5587,7 @@ calc.y:11.8-12: warning: useless rule: u
 
     $accept  ->  exp $ .   (rule 0)
 
-    $default   accept
+    $default    accept
 @end example
 
 @noindent
@@ -5555,33 +5602,33 @@ calc.y:11.8-12: warning: useless rule: u
 
     exp  ->  exp '+' . exp   (rule 1)
 
-    NUM        shift, and go to state 1
+    NUM         shift, and go to state 1
 
-    exp        go to state 8
+    exp         go to state 8
 
 state 5
 
     exp  ->  exp '-' . exp   (rule 2)
 
-    NUM        shift, and go to state 1
+    NUM         shift, and go to state 1
 
-    exp        go to state 9
+    exp         go to state 9
 
 state 6
 
     exp  ->  exp '*' . exp   (rule 3)
 
-    NUM        shift, and go to state 1
+    NUM         shift, and go to state 1
 
-    exp        go to state 10
+    exp         go to state 10
 
 state 7
 
     exp  ->  exp '/' . exp   (rule 4)
 
-    NUM        shift, and go to state 1
+    NUM         shift, and go to state 1
 
-    exp        go to state 11
+    exp         go to state 11
 @end example
 
 As was announced in beginning of the report, @samp{State 8 contains 1
@@ -5596,11 +5643,11 @@ calc.y:11.8-12: warning: useless rule: u
     exp  ->  exp . '*' exp   (rule 3)
     exp  ->  exp . '/' exp   (rule 4)
 
-    '*'        shift, and go to state 6
-    '/'        shift, and go to state 7
+    '*'         shift, and go to state 6
+    '/'         shift, and go to state 7
 
-    '/'        [reduce using rule 1 (exp)]
-    $default   reduce using rule 1 (exp)
+    '/'         [reduce using rule 1 (exp)]
+    $default    reduce using rule 1 (exp)
 @end example
 
 Indeed, there are two actions associated to the lookahead @samp{/}:
@@ -5657,11 +5704,11 @@ calc.y:11.8-12: warning: useless rule: u
     exp  ->  exp . '*' exp   (rule 3)
     exp  ->  exp . '/' exp   (rule 4)
 
-    '*'        shift, and go to state 6
-    '/'        shift, and go to state 7
+    '*'         shift, and go to state 6
+    '/'         shift, and go to state 7
 
-    '/'        [reduce using rule 2 (exp)]
-    $default   reduce using rule 2 (exp)
+    '/'         [reduce using rule 2 (exp)]
+    $default    reduce using rule 2 (exp)
 
 state 10
 
@@ -5671,10 +5718,10 @@ calc.y:11.8-12: warning: useless rule: u
     exp  ->  exp '*' exp .   (rule 3)
     exp  ->  exp . '/' exp   (rule 4)
 
-    '/'        shift, and go to state 7
+    '/'         shift, and go to state 7
 
-    '/'        [reduce using rule 3 (exp)]
-    $default   reduce using rule 3 (exp)
+    '/'         [reduce using rule 3 (exp)]
+    $default    reduce using rule 3 (exp)
 
 state 11
 
@@ -5684,16 +5731,16 @@ calc.y:11.8-12: warning: useless rule: u
     exp  ->  exp . '/' exp   (rule 4)
     exp  ->  exp '/' exp .   (rule 4)
 
-    '+'        shift, and go to state 4
-    '-'        shift, and go to state 5
-    '*'        shift, and go to state 6
-    '/'        shift, and go to state 7
-
-    '+'        [reduce using rule 4 (exp)]
-    '-'        [reduce using rule 4 (exp)]
-    '*'        [reduce using rule 4 (exp)]
-    '/'        [reduce using rule 4 (exp)]
-    $default   reduce using rule 4 (exp)
+    '+'         shift, and go to state 4
+    '-'         shift, and go to state 5
+    '*'         shift, and go to state 6
+    '/'         shift, and go to state 7
+
+    '+'         [reduce using rule 4 (exp)]
+    '-'         [reduce using rule 4 (exp)]
+    '*'         [reduce using rule 4 (exp)]
+    '/'         [reduce using rule 4 (exp)]
+    $default    reduce using rule 4 (exp)
 @end example
 
 @noindent
@@ -6171,18 +6218,21 @@ @node Table of Symbols
 @code{yyparse} return 1.  @xref{Error Recovery}.
 
 @item YYERROR_VERBOSE
-Macro that you define with @code{#define} in the Bison declarations
-section to request verbose, specific error message strings when
address@hidden is called.
+An obsolete macro that you define with @code{#define} in the Bison
+declarations section to request verbose, specific error message strings
+when @code{yyerror} is called.  It doesn't matter what definition you
+use for @code{YYERROR_VERBOSE}, just whether you define it.  Using
address@hidden is preferred.
 
 @item YYINITDEPTH
 Macro for specifying the initial size of the parser stack.
 @xref{Stack Overflow}.
 
 @item YYLEX_PARAM
-Macro for specifying an extra argument (or list of extra arguments) for
address@hidden to pass to @code{yylex}.  @xref{Pure Calling,, Calling
-Conventions for Pure Parsers}.
+An obsolete macro for specifying an extra argument (or list of extra
+arguments) for @code{yyparse} to pass to @code{yylex}.  he use of this
+macro is deprecated, and is supported only for Yacc like parsers.
address@hidden Calling,, Calling Conventions for Pure Parsers}.
 
 @item YYLTYPE
 Macro for the data type of @code{yylloc}; a structure with four
@@ -6196,8 +6246,10 @@ @node Table of Symbols
 @xref{Stack Overflow}.
 
 @item YYPARSE_PARAM
-Macro for specifying the name of a parameter that @code{yyparse} should
-accept.  @xref{Pure Calling,, Calling Conventions for Pure Parsers}.
+An obsolete macro for specifying the name of a parameter that
address@hidden should accept.  The use of this macro is deprecated, and
+is supported only for Yacc like parsers.  @xref{Pure Calling,, Calling
+Conventions for Pure Parsers}.
 
 @item YYRECOVERING
 Macro whose value indicates whether the parser is recovering from a
@@ -6278,6 +6330,10 @@ @node Table of Symbols
 time to resolve reduce/reduce conflicts.  @xref{GLR Parsers, ,Writing
 @acronym{GLR} Parsers}.
 
address@hidden %error-verbose
+Bison declaration to request verbose, specific error message strings
+when @code{yyerror} is called.
+
 @item %file-prefix="@var{prefix}"
 Bison declaration to set the prefix of the output files.  @xref{Decl
 Summary}.
@@ -6298,6 +6354,11 @@ @node Table of Symbols
 Bison declaration to assign left associativity to token(s).
 @xref{Precedence Decl, ,Operator Precedence}.
 
address@hidden %lex-param "@var{argument-declaration}" "@var{argument-name}"
+Bison declaration to specifying an additional parameter that
address@hidden should accept.  @xref{Pure Calling,, Calling Conventions
+for Pure Parsers}.
+
 @item %merge
 Bison declaration to assign a merging function to a rule.  If there is a
 reduce/reduce conflict with a rule having the same merging function, the
@@ -6318,6 +6379,11 @@ @node Table of Symbols
 @item %output="@var{filename}"
 Bison declaration to set the name of the parser file.  @xref{Decl
 Summary}.
+
address@hidden %parse-param "@var{argument-declaration}" "@var{argument-name}"
+Bison declaration to specifying an additional parameter that
address@hidden should accept.  @xref{Parser Function,, The Parser
+Function @code{yyparse}}.
 
 @item %prec
 Bison declaration to assign a precedence to a specific rule.
Index: data/c.m4
--- data/c.m4 Sun, 03 Nov 2002 13:26:54 +0100 akim
+++ data/c.m4 Sun, 03 Nov 2002 16:07:56 +0100 akim
@@ -19,9 +19,9 @@
 # 02111-1307  USA
 
 
-## ----------- ##
-## Copyright.  ##
-## ----------- ##
+## ---------------- ##
+## Identification.  ##
+## ---------------- ##
 
 # b4_copyright(TITLE, YEARS)
 # --------------------------
@@ -45,6 +45,45 @@ m4_define([b4_copyright],
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */])
+
+
+# b4_identification
+# -----------------
+m4_define([b4_identification],
+[/* Identify Bison output.  */
+[#]define YYBISON 1
+
+/* Skeleton name.  */
+[#]define YYSKELETON_NAME "b4_skeleton"
+
+/* Pure parsers.  */
+[#]define YYPURE b4_pure
+
+/* Using locations.  */
+[#]define YYLSP_NEEDED b4_locations_flag
+])
+
+
+
+## ------------------------ ##
+## Pure/impure interfaces.  ##
+## ------------------------ ##
+
+
+# b4_user_args
+# ------------
+m4_define([b4_user_args],
+[m4_ifset([b4_parse_param], [, b4_c_args(b4_parse_param)])])
+
+
+# b4_parse_param
+# --------------
+# If defined, b4_parse_param arrives double quoted, but below we prefer
+# it to be single quoted.
+m4_define_default([b4_parse_param])
+m4_define([b4_parse_param],
+b4_parse_param))
+
 
 
 ## ------------ ##
Index: data/yacc.c
--- data/yacc.c Sun, 03 Nov 2002 13:26:54 +0100 akim
+++ data/yacc.c Sun, 03 Nov 2002 15:15:00 +0100 akim
@@ -33,19 +33,37 @@ m4_define_default([b4_stack_depth_init],
 # Location type.
 m4_define_default([b4_location_type], [yyltype])
 
+
+## ------------------------ ##
+## Pure/impure interfaces.  ##
+## ------------------------ ##
+
+
+# b4_Pure_if(IF-TRUE, IF-FALSE)
+# -----------------------------
+# Expand IF-TRUE, if %pure-parser and %parse-param, IF-FALSE otherwise.
+m4_define([b4_Pure_if],
+[b4_pure_if([m4_ifset([b4_parse_param],
+                      [$1], [$2])],
+            [$2])])
+
+
+# b4_pure_args
+# ------------
+# Arguments passed to yyerror: user args plus yylloc.
+m4_define([b4_pure_args],
+[b4_Pure_if([b4_location_if([, &yylloc])])[]b4_user_args])
+
+
+# b4_lex_param
+# ------------
 # Accumule in b4_lex_param all the yylex arguments.
-# Yes, this is quite ugly...
+# b4_lex_param arrives quoted twice, but we want to keep only one level.
 m4_define([b4_lex_param],
 m4_dquote(b4_pure_if([[[[YYSTYPE *]], [[&yylval]]][]dnl
 b4_location_if([, [[YYLTYPE *], [&yylloc]]])])dnl
 m4_ifdef([b4_lex_param], [, ]b4_lex_param)))
 
-# Yes, this is quite ugly...
-m4_define_default([b4_parse_param])
-m4_ifdef([b4_parse_param],
-[m4_define([b4_parse_param],
-          b4_parse_param)])
-
 
 
 ## ------------ ##
@@ -56,7 +74,7 @@ m4_define_default([b4_parse_param])
 # ---------------------
 # Return the smallest int type able to handle numbers ranging from
 # MIN to MAX (included).  We overwrite the version from c.m4 which relies
-# on `signed char' which is not portable to old K&R compilers.
+# on "signed char" which is not portable to old K&R compilers.
 m4_define([b4_int_type],
 [m4_if(b4_ints_in($@,      [0],   [255]), [1], [unsigned char],
        b4_ints_in($@,   [-128],   [127]), [1], [yysigned_char],
@@ -178,15 +196,7 @@ m4_define([b4_symbol_actions],
    define necessary library symbols; they are noted "INFRINGES ON
    USER NAME SPACE" below.  */
 
-/* Identify Bison output.  */
-#define YYBISON        1
-
-/* Pure parsers.  */
-#define YYPURE b4_pure
-
-/* Using locations.  */
-#define YYLSP_NEEDED b4_locations_flag
-
+b4_identification
 m4_if(b4_prefix[], [yy], [],
 [/* If NAME_PREFIX is specified substitute the variables and functions
    names.  */
@@ -519,7 +529,7 @@ m4_define([b4_symbol_actions],
     }                                                          \
   else                                                         \
     {                                                          \
-      yyerror ("syntax error: cannot back up");                        \
+      yyerror ("syntax error: cannot back up"b4_pure_args);    \
       YYERROR;                                                 \
     }                                                          \
 while (0)
@@ -1125,15 +1135,15 @@ yyerrlab:
                        yycount++;
                      }
                }
-             yyerror (yymsg);
+             yyerror (yymsg]b4_pure_args[);
              YYSTACK_FREE (yymsg);
            }
          else
-           yyerror ("parse error; also virtual memory exhausted");
+           yyerror ("parse error; also virtual memory 
exhausted"]b4_pure_args[);
        }
       else
 #endif /* YYERROR_VERBOSE */
-       yyerror ("parse error");
+       yyerror ("parse error"]b4_pure_args[);
     }
   goto yyerrlab1;
 
@@ -1248,7 +1258,7 @@ yyabortlab:
 | yyoverflowlab -- parser overflow comes here.  |
 `----------------------------------------------*/
 yyoverflowlab:
-  yyerror ("parser stack overflow");
+  yyerror ("parser stack overflow"]b4_pure_args[);
   yyresult = 2;
   /* Fall through.  */
 #endif
Index: data/glr.c
--- data/glr.c Sun, 03 Nov 2002 13:26:54 +0100 akim
+++ data/glr.c Sun, 03 Nov 2002 13:45:24 +0100 akim
@@ -31,6 +31,15 @@ m4_define_default([b4_stack_depth_init],
 # Location type.
 m4_define_default([b4_location_type], [yyltype])
 
+
+
+## ------------------------ ##
+## Pure/impure interfaces.  ##
+## ------------------------ ##
+
+
+# b4_lex_param
+# ------------
 # Accumule in b4_lex_param all the yylex arguments.
 # Yes, this is quite ugly...
 m4_define([b4_lex_param],
@@ -38,12 +47,39 @@ m4_define([b4_lex_param],
 b4_location_if([, [[YYLTYPE *], [yyllocp]]])])dnl
 m4_ifdef([b4_lex_param], [, ]b4_lex_param)))
 
-# Yes, this is quite ugly...
-  m4_define_default([b4_parse_param])
-m4_ifdef([b4_parse_param],
-[m4_define([b4_parse_param],
-          b4_parse_param)])
 
+# b4_user_formals
+# ---------------
+m4_define([b4_user_formals],
+[m4_ifset([b4_parse_param], [, b4_c_ansi_formals(b4_parse_param)])])
+
+
+# b4_pure_args
+# ------------
+# Arguments passed to yyerror: user args plus yylloc.
+m4_define([b4_pure_args],
+[b4_pure_if([b4_location_if([, yylocp])])[]b4_user_args])
+
+
+# b4_pure_formals
+# ---------------
+# Arguments passed to yyerror: user formals plus yyllocp.
+m4_define([b4_pure_formals],
+[b4_pure_if([b4_location_if([, YYLTYPE *yylocp])])[]b4_user_formals])
+
+
+# b4_lpure_args
+# -------------
+# Same as above, but on the lookahead, hence yyllocp instead of yylocp.
+m4_define([b4_lpure_args],
+[b4_pure_if([b4_location_if([, yyllocp])])[]b4_user_args])
+
+
+# b4_lpure_formals
+# ----------------
+# Same as above, but on the lookahead, hence yyllocp instead of yylocp.
+m4_define([b4_lpure_formals],
+[b4_pure_if([b4_location_if([YYLTYPE *yyllocp])])[]b4_user_formals])
 
 
 ## ----------------- ##
@@ -119,24 +155,15 @@ m4_define_default([b4_header_guard],
 [
 /* This is the parser code for GLR (Generalized LR) parser. */
 
-/* FIXME: minimize these */
 #include <assert.h>
-#include <setjmp.h>
-#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
+#include <setjmp.h>
 
-/* Identify Bison output.  */
-#define YYBISON        1
-
-/* Pure parsers.  */
-#define YYPURE ]b4_pure[
-
-/* Using locations.  */
-#define YYLSP_NEEDED ]b4_locations_flag[
-
-]m4_if(b4_prefix[], [yy], [],
+]b4_identification
+m4_if(b4_prefix[], [yy], [],
 [/* If NAME_PREFIX is specified substitute the variables and functions
    names.  */
 #define yyparse b4_prefix[]parse
@@ -378,16 +405,9 @@ m4_define_default([b4_header_guard],
 
 
 /* Prevent warning if -Wmissing-prototypes.  */
-]b4_c_ansi_function_decl([yyparse], [int], b4_parse_param)
+]b4_c_ansi_function_decl([yyparse], [int], b4_parse_param)[
 
-m4_ifset([b4_parse_param],
-[#define YY_USER_FORMALS , b4_c_ansi_formals(b4_parse_param)
-#define YY_USER_ARGS    , b4_c_args(b4_parse_param)],
-[#define YY_USER_FORMALS
-#define YY_USER_ARGS])
-
-
-[/* Error token number */
+/* Error token number */
 #define YYTERROR 1
 
 /* YYLLOC_DEFAULT -- Compute the default location (before the actions
@@ -548,11 +568,11 @@ m4_define_default([b4_header_guard],
 };
 
 static void yyinitGLRStack (yyGLRStack* yystack, size_t yysize);
-static void yyexpandGLRStack (yyGLRStack* yystack);
+static void yyexpandGLRStack (yyGLRStack* yystack]b4_pure_formals[);
 static void yyfreeGLRStack (yyGLRStack* yystack);
 
 static void
-yyFail (yyGLRStack* yystack, const char* yyformat, ...)
+yyFail (yyGLRStack* yystack]b4_pure_formals[, const char* yyformat, ...)
 {
   if (yyformat != NULL)
     {
@@ -561,7 +581,7 @@ m4_define_default([b4_header_guard],
       va_start (yyap, yyformat);
       yystack->yyerrflag = 1;
       vsprintf (yymsg, yyformat, yyap);
-      yyerror (yymsg);
+      yyerror (yymsg]b4_pure_args[);
     }
   longjmp (yystack->yyexception_buffer, 1);
 }
@@ -584,7 +604,7 @@ m4_define_default([b4_header_guard],
 static YYRESULTTAG
 yyuserAction (yyRuleNum yyn, int yyrhslen, yyGLRStackItem* yyvsp,
              YYSTYPE* yyvalp, YYLTYPE* yylocp, yyGLRStack* yystack
-             YY_USER_FORMALS)
+              ]b4_user_formals[)
 {
   /* Avoid `unused' warnings in there are no $n. */
   (void) yystack;
@@ -616,7 +636,7 @@ m4_define_default([b4_header_guard],
 # undef YYBACKUP
 # define YYBACKUP(Token, Value)                                                
     \
   do {                                                                      \
-    yyerror ("syntax error: cannot back up");                               \
+    yyerror ("syntax error: cannot back up"]b4_pure_args[);                 \
     YYERROR;                                                                \
   } while (0)
 
@@ -644,7 +664,7 @@ m4_define_default([b4_header_guard],
 yyuserMerge (int yyn, YYSTYPE* yy0, YYSTYPE* yy1)
 {
   YYSTYPE yyval = *yy0;
-  /* `Use' the arguments. */
+  /* `Use' the arguments.  */
   (void) yy0;
   (void) yy1;
 
@@ -655,7 +675,7 @@ m4_define_default([b4_header_guard],
   return yyval;
 }
 [
-                               /* Bison grammar-table manipulation */
+                             /* Bison grammar-table manipulation.  */
 
 /** Number of symbols composing the right hand side of rule #RULE. */
 static inline int
@@ -751,7 +771,7 @@ m4_define_default([b4_header_guard],
 
 static void
 yyaddDeferredAction (yyGLRStack* yystack, yyGLRState* yystate,
-                    yyGLRState* rhs, yyRuleNum yyrule)
+                    yyGLRState* rhs, yyRuleNum yyrule]b4_pure_formals[)
 {
   yySemanticOption* yynewItem;
   yynewItem = &yystack->yynextFree->yyoption;
@@ -763,7 +783,7 @@ m4_define_default([b4_header_guard],
   yynewItem->yynext = yystate->yysemantics.yyfirstVal;
   yystate->yysemantics.yyfirstVal = yynewItem;
   if (yystack->yyspaceLeft < YYHEADROOM)
-    yyexpandGLRStack (yystack);
+    yyexpandGLRStack (yystack]b4_pure_args[);
 }
 
                                /* GLRStacks */
@@ -808,7 +828,7 @@ m4_define_default([b4_header_guard],
     allocation, so that we can avoid having external pointers exist
     across an allocation. */
 static void
-yyexpandGLRStack (yyGLRStack* yystack)
+yyexpandGLRStack (yyGLRStack* yystack]b4_pure_formals[)
 {
 #if YYSTACKEXPANDABLE
   yyGLRStack yynewStack;
@@ -817,7 +837,8 @@ m4_define_default([b4_header_guard],
   size_t yyn;
   yysize = yystack->yynextFree - yystack->yyitems;
   if (YYMAXDEPTH <= yysize)
-    yyFail (yystack, "parsing stack overflow (%d items)", yysize);
+    yyFail (yystack][]b4_pure_args[,
+           "parsing stack overflow (%d items)", yysize);
   yynewSize = 2*yysize;
   if (YYMAXDEPTH < yynewSize)
     yynewSize = YYMAXDEPTH;
@@ -864,8 +885,8 @@ m4_define_default([b4_header_guard],
 
 #else
 
-  yyFail (yystack, "parsing stack overflow (%d items)", yysize);
-
+  yyFail (yystack][]b4_lpure_args[,
+          "parsing stack overflow (%d items)", yysize);
 #endif
 }
 
@@ -937,7 +958,7 @@ m4_define_default([b4_header_guard],
  * LRSTATE, at input position POSN, with (resolved) semantic value SVAL. */
 static inline void
 yyglrShift (yyGLRStack* yystack, int yyk, yyStateNum yylrState, size_t yyposn,
-           YYSTYPE yysval, YYLTYPE* yylocp)
+           YYSTYPE yysval, YYLTYPE* yylocp]b4_user_formals[)
 {
   yyGLRStackItem* yynewItem;
 
@@ -953,7 +974,7 @@ m4_define_default([b4_header_guard],
   yynewItem->yystate.yysemantics.yysval = yysval;
   yynewItem->yystate.yyloc = *yylocp;
   if (yystack->yyspaceLeft < YYHEADROOM)
-    yyexpandGLRStack (yystack);
+    yyexpandGLRStack (yystack]b4_pure_args[);
 }
 
 /** Shift to a new state on stack #K of STACK, to a new state
@@ -961,7 +982,7 @@ m4_define_default([b4_header_guard],
  * the (unresolved) semantic value of RHS under the action for RULE. */
 static inline void
 yyglrShiftDefer (yyGLRStack* yystack, int yyk, yyStateNum yylrState,
-                size_t yyposn, yyGLRState* rhs, yyRuleNum yyrule)
+                size_t yyposn, yyGLRState* rhs, yyRuleNum 
yyrule]b4_pure_formals[)
 {
   yyGLRStackItem* yynewItem;
 
@@ -975,7 +996,7 @@ m4_define_default([b4_header_guard],
   yystack->yytops.yystates[yyk] = &yynewItem->yystate;
   yystack->yynextFree += 1;
   yystack->yyspaceLeft -= 1;
-  yyaddDeferredAction (yystack, &yynewItem->yystate, rhs, yyrule);
+  yyaddDeferredAction (yystack, &yynewItem->yystate, rhs, 
yyrule]b4_pure_args[);
 }
 
 /** Pop the symbols consumed by reduction #RULE from the top of stack
@@ -986,7 +1007,7 @@ m4_define_default([b4_header_guard],
  *  for userAction. */
 static inline int
 yydoAction (yyGLRStack* yystack, int yyk, yyRuleNum yyrule,
-           YYSTYPE* yyvalp, YYLTYPE* yylocp YY_USER_FORMALS)
+           YYSTYPE* yyvalp, YYLTYPE* yylocp]b4_user_formals[)
 {
   int yynrhs = yyrhsLength (yyrule);
 
@@ -1009,7 +1030,7 @@ m4_define_default([b4_header_guard],
          *yylocp = rhs[1-yynrhs].yystate.yyloc;
        }
       return yyuserAction (yyrule, yynrhs, rhs,
-                          yyvalp, yylocp, yystack YY_USER_ARGS);
+                          yyvalp, yylocp, yystack]b4_user_args[);
     }
   else
     {
@@ -1037,7 +1058,7 @@ m4_define_default([b4_header_guard],
          *yylocp = yyrhsVals[0].yystate.yyloc;
        }
       return yyuserAction (yyrule, yynrhs, yyrhsVals + (yynrhs-1),
-                          yyvalp, yylocp, yystack YY_USER_ARGS);
+                          yyvalp, yylocp, yystack]b4_user_args[);
     }
 }
 
@@ -1080,7 +1101,7 @@ m4_define_default([b4_header_guard],
  */
 static inline YYRESULTTAG
 yyglrReduce (yyGLRStack* yystack, size_t yyk, yyRuleNum yyrule,
-             bool yyforceEval YY_USER_FORMALS)
+             bool yyforceEval]b4_pure_formals[)
 {
   size_t yyposn = yystack->yytops.yystates[yyk]->yyposn;
 
@@ -1090,11 +1111,11 @@ m4_define_default([b4_header_guard],
       YYLTYPE yyloc;
 
       YY_REDUCE_PRINT (yyk, yyrule);
-      YYCHK (yydoAction (yystack, yyk, yyrule, &yysval, &yyloc YY_USER_ARGS));
+      YYCHK (yydoAction (yystack, yyk, yyrule, &yysval, &yyloc]b4_user_args[));
       yyglrShift (yystack, yyk,
                  yyLRgotoState (yystack->yytops.yystates[yyk]->yylrState,
                                 yylhsNonterm (yyrule)),
-               yyposn, yysval, &yyloc);
+                 yyposn, yysval, &yyloc]b4_user_args[);
       YYDPRINTF ((stderr, "Stack %d entering state %d\n",
                  yyk, yystack->yytops.yystates[yyk]->yylrState));
     }
@@ -1126,7 +1147,7 @@ m4_define_default([b4_header_guard],
              {
                if (yyp->yylrState == yynewLRState && yyp->yypred == yys)
                  {
-                   yyaddDeferredAction (yystack, yyp, yys0, yyrule);
+                   yyaddDeferredAction (yystack, yyp, yys0, 
yyrule]b4_pure_args[);
                    yymarkStackDeleted (yystack, yyk);
                    YYDPRINTF ((stderr, "Merging stack %d into stack %d.\n",
                                yyk, yyi));
@@ -1136,7 +1157,7 @@ m4_define_default([b4_header_guard],
              }
          }
       yystack->yytops.yystates[yyk] = yys;
-      yyglrShiftDefer (yystack, yyk, yynewLRState, yyposn, yys0, yyrule);
+      yyglrShiftDefer (yystack, yyk, yynewLRState, yyposn, yys0, 
yyrule]b4_pure_args[);
     }
   return 0;
 }
@@ -1236,23 +1257,23 @@ m4_define_default([b4_header_guard],
 
 static YYRESULTTAG yyresolveValue (yySemanticOption* yyoptionList,
                                   yyGLRStack* yystack, YYSTYPE* yyvalp,
-                                  YYLTYPE* yylocp YY_USER_FORMALS);
+                                  YYLTYPE* yylocp]b4_user_formals[);
 
 static YYRESULTTAG
-yyresolveStates (yyGLRState* yys, int yyn, yyGLRStack* yystack YY_USER_FORMALS)
+yyresolveStates (yyGLRState* yys, int yyn, yyGLRStack* 
yystack]b4_user_formals[)
 {
   YYRESULTTAG yyflag;
   if (0 < yyn)
     {
       assert (yys->yypred != NULL);
-      yyflag = yyresolveStates (yys->yypred, yyn-1, yystack YY_USER_ARGS);
+      yyflag = yyresolveStates (yys->yypred, yyn-1, yystack]b4_user_args[);
       if (yyflag != yyok)
        return yyflag;
       if (! yys->yyresolved)
        {
          yyflag = yyresolveValue (yys->yysemantics.yyfirstVal, yystack,
                                   &yys->yysemantics.yysval, &yys->yyloc
-                                  YY_USER_ARGS);
+                                 ]b4_user_args[);
          if (yyflag != yyok)
            return yyflag;
          yys->yyresolved = yytrue;
@@ -1263,14 +1284,14 @@ m4_define_default([b4_header_guard],
 
 static YYRESULTTAG
 yyresolveAction (yySemanticOption* yyopt, yyGLRStack* yystack,
-                YYSTYPE* yyvalp, YYLTYPE* yylocp YY_USER_FORMALS)
+                YYSTYPE* yyvalp, YYLTYPE* yylocp]b4_user_formals[)
 {
   yyGLRStackItem yyrhsVals[YYMAXRHS];
   int yynrhs, yyi;
   yyGLRState* yys;
 
   yynrhs = yyrhsLength (yyopt->yyrule);
-  YYCHK (yyresolveStates (yyopt->yystate, yynrhs, yystack YY_USER_ARGS));
+  YYCHK (yyresolveStates (yyopt->yystate, yynrhs, yystack]b4_user_args[));
   for (yyi = yynrhs-1, yys = yyopt->yystate; 0 <= yyi;
        yyi -= 1, yys = yys->yypred)
     {
@@ -1280,7 +1301,7 @@ m4_define_default([b4_header_guard],
       yyrhsVals[yyi].yystate.yyloc = yys->yyloc;
     }
   return yyuserAction (yyopt->yyrule, yynrhs, yyrhsVals + (yynrhs-1),
-                      yyvalp, yylocp, yystack YY_USER_ARGS);
+                      yyvalp, yylocp, yystack]b4_user_args[);
 }
 
 #if YYDEBUG
@@ -1331,7 +1352,7 @@ m4_define_default([b4_header_guard],
 
 static void
 yyreportAmbiguity (yySemanticOption* yyx0, yySemanticOption* yyx1,
-                  yyGLRStack* yystack)
+                  yyGLRStack* yystack]b4_pure_formals[)
 {
   /* `Unused' warnings.  */
   (void) yyx0;
@@ -1345,7 +1366,7 @@ m4_define_default([b4_header_guard],
   yyreportTree (yyx1, 2);
   YYFPRINTF (stderr, "\n");
 #endif
-  yyFail (yystack, "ambiguity detected");
+  yyFail (yystack][]b4_pure_args[, "ambiguity detected");
 }
 
 
@@ -1353,7 +1374,7 @@ m4_define_default([b4_header_guard],
  *  actions, and return the result. */
 static YYRESULTTAG
 yyresolveValue (yySemanticOption* yyoptionList, yyGLRStack* yystack,
-               YYSTYPE* yyvalp, YYLTYPE* yylocp YY_USER_FORMALS)
+               YYSTYPE* yyvalp, YYLTYPE* yylocp]b4_user_formals[)
 {
   yySemanticOption* yybest;
   yySemanticOption* yyp;
@@ -1369,7 +1390,7 @@ m4_define_default([b4_header_guard],
        switch (yypreference (yybest, yyp))
          {
          case 0:
-           yyreportAmbiguity (yybest, yyp, yystack);
+           yyreportAmbiguity (yybest, yyp, yystack]b4_pure_args[);
            break;
          case 1:
            yymerge = 1;
@@ -1386,25 +1407,25 @@ m4_define_default([b4_header_guard],
   if (yymerge)
     {
       int yyprec = yydprec[yybest->yyrule];
-      YYCHK (yyresolveAction (yybest, yystack, yyvalp, yylocp YY_USER_ARGS));
+      YYCHK (yyresolveAction (yybest, yystack, yyvalp, yylocp]b4_user_args[));
       for (yyp = yybest->yynext; yyp != NULL; yyp = yyp->yynext)
        {
          if (yyprec == yydprec[yyp->yyrule])
            {
              YYSTYPE yyval1;
              YYLTYPE yydummy;
-             YYCHK (yyresolveAction (yyp, yystack, &yyval1, &yydummy 
YY_USER_ARGS));
+             YYCHK (yyresolveAction (yyp, yystack, &yyval1, 
&yydummy]b4_user_args[));
              *yyvalp = yyuserMerge (yymerger[yyp->yyrule], yyvalp, &yyval1);
            }
        }
       return yyok;
     }
   else
-    return yyresolveAction (yybest, yystack, yyvalp, yylocp YY_USER_ARGS);
+    return yyresolveAction (yybest, yystack, yyvalp, yylocp]b4_user_args[);
 }
 
 static YYRESULTTAG
-yyresolveStack (yyGLRStack* yystack YY_USER_FORMALS)
+yyresolveStack (yyGLRStack* yystack]b4_user_formals[)
 {
   if (yystack->yysplitPoint != NULL)
     {
@@ -1416,7 +1437,7 @@ m4_define_default([b4_header_guard],
           yys = yys->yypred, yyn += 1)
        ;
       YYCHK (yyresolveStates (yystack->yytops.yystates[0], yyn, yystack
-                             YY_USER_ARGS));
+                            ]b4_user_args[));
     }
   return yyok;
 }
@@ -1454,7 +1475,7 @@ m4_define_default([b4_header_guard],
 static YYRESULTTAG
 yyprocessOneStack (yyGLRStack* yystack, int yyk,
                   size_t yyposn, YYSTYPE* yylvalp, YYLTYPE* yyllocp
-                  YY_USER_FORMALS)
+                 ]b4_user_formals[)
 {
   int yyaction;
   const short* yyconflicts;
@@ -1475,7 +1496,7 @@ m4_define_default([b4_header_guard],
              yymarkStackDeleted (yystack, yyk);
              return yyok;
            }
-         YYCHK (yyglrReduce (yystack, yyk, yyrule, yyfalse YY_USER_ARGS));
+         YYCHK (yyglrReduce (yystack, yyk, yyrule, yyfalse]b4_lpure_args[));
        }
       else
        {
@@ -1495,9 +1516,9 @@ m4_define_default([b4_header_guard],
              YYDPRINTF ((stderr, "Splitting off stack %d from %d.\n",
                          yynewStack, yyk));
              YYCHK (yyglrReduce (yystack, yynewStack,
-                                 *yyconflicts, yyfalse YY_USER_ARGS));
+                                 *yyconflicts, yyfalse]b4_lpure_args[));
              YYCHK (yyprocessOneStack (yystack, yynewStack, yyposn,
-                                       yylvalp, yyllocp YY_USER_ARGS));
+                                       yylvalp, yyllocp]b4_user_args[));
              yyconflicts += 1;
            }
 
@@ -1505,7 +1526,8 @@ m4_define_default([b4_header_guard],
            {
              YYDPRINTF ((stderr, "Shifting token %s on stack %d, ",
                          yytokenName (*yytokenp), yyk));
-             yyglrShift (yystack, yyk, yyaction, yyposn+1, *yylvalp, yyllocp);
+             yyglrShift (yystack, yyk, yyaction, yyposn+1,
+                         *yylvalp, yyllocp]b4_user_args[);
              YYDPRINTF ((stderr, "which is now in state #%d\n",
                          yystack->yytops.yystates[yyk]->yylrState));
              break;
@@ -1517,14 +1539,15 @@ m4_define_default([b4_header_guard],
              break;
            }
          else
-           YYCHK (yyglrReduce (yystack, yyk, -yyaction, yyfalse YY_USER_ARGS));
+           YYCHK (yyglrReduce (yystack, yyk, -yyaction, 
yyfalse]b4_lpure_args[));
        }
     }
   return yyok;
 }
 
 static void
-yyreportParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp)
+yyreportParseError (yyGLRStack* yystack,
+                   YYSTYPE* yylvalp, YYLTYPE* yyllocp]b4_user_formals[)
 {
   /* `Unused' warnings. */
   (void) yylvalp;
@@ -1568,12 +1591,12 @@ m4_define_default([b4_header_guard],
                    yyprefix = " or ";
                  }
            }
-         yyerror (yymsg);
+         yyerror (yymsg]b4_lpure_args[);
          free (yymsg);
        }
       else
 #endif
-       yyerror ("parse error");
+       yyerror ("parse error"]b4_lpure_args[);
       yynerrs += 1;
     }
 }
@@ -1582,7 +1605,8 @@ m4_define_default([b4_header_guard],
    YYLVALP, and YYLLOCP point to the syntactic category, semantic
    value, and location of the lookahead.  */
 static void
-yyrecoverParseError (yyGLRStack* yystack, YYSTYPE* yylvalp, YYLTYPE* yyllocp)
+yyrecoverParseError (yyGLRStack* yystack,
+                    YYSTYPE* yylvalp, YYLTYPE* yyllocp]b4_user_formals[)
 {
   yySymbol* const yytokenp = yystack->yytokenp;
   size_t yyk;
@@ -1596,7 +1620,7 @@ m4_define_default([b4_header_guard],
     while (yytrue)
       {
        if (*yytokenp == YYEOF)
-         yyFail (yystack, NULL);
+         yyFail (yystack][]b4_lpure_args[, NULL);
        if (*yytokenp != YYEMPTY)
          YYDPRINTF ((stderr, "Discarding token %s\n",
                      yytokenName (*yytokenp)));
@@ -1607,7 +1631,7 @@ m4_define_default([b4_header_guard],
        yyj = yypact[yystack->yytops.yystates[0]->yylrState];
        if (yyj == YYPACT_NINF)
          /* Something's not right; we shouldn't be here.  */
-         yyFail (yystack, NULL);
+         yyFail (yystack][]b4_lpure_args[, NULL);
        yyj += *yytokenp;
        if (yyj < 0 || YYLAST < yyj || yycheck[yyj] != *yytokenp)
          {
@@ -1623,7 +1647,7 @@ m4_define_default([b4_header_guard],
     if (yystack->yytops.yystates[yyk] != NULL)
       break;
   if (yyk >= yystack->yytops.yysize)
-    yyFail (yystack, NULL);
+    yyFail (yystack][]b4_lpure_args[, NULL);
   for (yyk += 1; yyk < yystack->yytops.yysize; yyk += 1)
     yymarkStackDeleted (yystack, yyk);
   yyremoveDeletes (yystack);
@@ -1637,7 +1661,8 @@ m4_define_default([b4_header_guard],
          yycheck[yyj] == YYTERROR && yyisShiftAction (yytable[yyj]))
        {
          yyglrShift (yystack, 0, yytable[yyj],
-                     yystack->yytops.yystates[0]->yyposn, *yylvalp, yyllocp);
+                     yystack->yytops.yystates[0]->yyposn,
+                     *yylvalp, yyllocp]b4_user_args[);
          break;
        }
       yystack->yytops.yystates[0] = yystack->yytops.yystates[0]->yypred;
@@ -1645,7 +1670,7 @@ m4_define_default([b4_header_guard],
       yystack->yyspaceLeft += 1;
     }
   if (yystack->yytops.yystates[0] == NULL)
-    yyFail (yystack, NULL);
+    yyFail (yystack][]b4_lpure_args[, NULL);
 }
 
 #define YYCHK1(YYE)                                                         \
@@ -1693,7 +1718,7 @@ m4_define_default([b4_header_guard],
   if (setjmp (yystack.yyexception_buffer) != 0)
     goto yyDone;
 
-  yyglrShift (&yystack, 0, 0, 0, yyval_default, &yyloc_default);
+  yyglrShift (&yystack, 0, 0, 0, yyval_default, &yyloc_default]b4_user_args[);
   yytoken = YYEMPTY;
   yyposn = 0;
 
@@ -1718,10 +1743,10 @@ m4_define_default([b4_header_guard],
              yyrule = yydefaultAction (yystate);
              if (yyrule == 0)
                {
-                 yyreportParseError (&yystack, yylvalp, yyllocp);
+                 yyreportParseError (&yystack, yylvalp, yyllocp]b4_user_args[);
                  goto yyuser_error;
                }
-             YYCHK1 (yyglrReduce (&yystack, 0, yyrule, yytrue YY_USER_ARGS));
+             YYCHK1 (yyglrReduce (&yystack, 0, yyrule, yytrue]b4_lpure_args[));
            }
          else
            {
@@ -1743,7 +1768,8 @@ m4_define_default([b4_header_guard],
                  if (yytoken != YYEOF)
                    yytoken = YYEMPTY;
                  yyposn += 1;
-                 yyglrShift (&yystack, 0, yyaction, yyposn, yylval, yyllocp);
+                 yyglrShift (&yystack, 0, yyaction, yyposn,
+                             yylval, yyllocp]b4_user_args[);
                  if (0 < yystack.yyerrState)
                    yystack.yyerrState -= 1;
                  YYDPRINTF ((stderr, "Entering state %d\n",
@@ -1751,11 +1777,11 @@ m4_define_default([b4_header_guard],
                }
              else if (yyisErrorAction (yyaction))
                {
-                 yyreportParseError (&yystack, yylvalp, yyllocp);
+                 yyreportParseError (&yystack, yylvalp, yyllocp]b4_user_args[);
                  goto yyuser_error;
                }
              else
-               YYCHK1 (yyglrReduce (&yystack, 0, -yyaction, yytrue 
YY_USER_ARGS));
+               YYCHK1 (yyglrReduce (&yystack, 0, -yyaction, 
yytrue]b4_lpure_args[));
            }
        }
 
@@ -1765,7 +1791,7 @@ m4_define_default([b4_header_guard],
          int yyn = yystack.yytops.yysize;
          for (yys = 0; yys < yyn; yys += 1)
            YYCHK1 (yyprocessOneStack (&yystack, yys, yyposn,
-                                      yylvalp, yyllocp YY_USER_ARGS));
+                                      yylvalp, yyllocp]b4_user_args[));
          yytoken = YYEMPTY;
          yyposn += 1;
          yyremoveDeletes (&yystack);
@@ -1773,15 +1799,15 @@ m4_define_default([b4_header_guard],
            {
              yyundeleteLastStack (&yystack);
              if (yystack.yytops.yysize == 0)
-               yyFail (&yystack, "parse error");
-             YYCHK1 (yyresolveStack (&yystack YY_USER_ARGS));
+               yyFail (&yystack][]b4_lpure_args[, "parse error");
+             YYCHK1 (yyresolveStack (&yystack]b4_user_args[));
              YYDPRINTF ((stderr, "Returning to deterministic operation.\n"));
-             yyreportParseError (&yystack, yylvalp, yyllocp);
+             yyreportParseError (&yystack, yylvalp, yyllocp]b4_user_args[);
              goto yyuser_error;
            }
          else if (yystack.yytops.yysize == 1)
            {
-             YYCHK1 (yyresolveStack (&yystack YY_USER_ARGS));
+             YYCHK1 (yyresolveStack (&yystack]b4_user_args[));
              YYDPRINTF ((stderr, "Returning to deterministic operation.\n"));
              yycompressStack (&yystack);
              break;
@@ -1789,7 +1815,7 @@ m4_define_default([b4_header_guard],
        }
       continue;
     yyuser_error:
-      yyrecoverParseError (&yystack, yylvalp, yyllocp);
+      yyrecoverParseError (&yystack, yylvalp, yyllocp]b4_user_args[);
       yyposn = yystack.yytops.yystates[0]->yyposn;
     }
  yyDone:
Index: tests/calc.at
--- tests/calc.at Sun, 03 Nov 2002 13:26:54 +0100 akim
+++ tests/calc.at Sun, 03 Nov 2002 17:33:27 +0100 akim
@@ -26,8 +26,8 @@
 # ------------------------- #
 
 
-# _AT_DATA_CALC_Y($1, $2, $3, [CPP-DIRECTIVES])
-# ---------------------------------------------
+# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES])
+# -----------------------------------------------
 # Produce `calc.y'.  Don't call this macro directly, because it contains
 # some occurrences of `$1' etc. which will be interpreted by m4.  So
 # you should call it with $1, $2, and $3 as arguments, which is what
@@ -37,7 +37,7 @@ m4_define([_AT_DATA_CALC_Y],
        [m4_fatal([$0: Invalid arguments: address@hidden)])dnl
 AT_DATA([calc.y],
 [[/* Infix notation calculator--calc */
-
+]$4[
 %{
 #include <config.h>
 /* We don't need perfect functions for these tests. */
@@ -63,9 +63,6 @@ m4_define([_AT_DATA_CALC_Y],
 
 %}
 
-%parse-param "value_t *result", "result"
-%parse-param "int *count",      "count"
-
 /* Exercise %union. */
 %union
 {
@@ -81,16 +78,14 @@ m4_define([_AT_DATA_CALC_Y],
 #  define VAL     (yylval)
 #endif
 
+#define YYLLOC_FORMAL   ]AT_LOCATION_IF([, YYLTYPE *yylloc])[
+#define YYLLOC_ARG      ]AT_LOCATION_IF([, yylloc])[
+#define USE_YYLLOC      ]AT_LOCATION_IF([(void) yylloc;])[
+
 #if YYPURE
-#  if YYLSP_NEEDED
-#    define LEX_FORMALS     YYSTYPE *yylval, YYLTYPE *yylloc
-#    define LEX_ARGS        yylval, yylloc
-#    define USE_LEX_ARGS    (void) yylval; (void) yylloc;
-#  else
-#    define LEX_FORMALS     YYSTYPE *yylval
-#    define LEX_ARGS        yylval
-#    define USE_LEX_ARGS    (void) yylval
-#  endif
+#  define LEX_FORMALS     YYSTYPE *yylval YYLLOC_FORMAL
+#  define LEX_ARGS        yylval          YYLLOC_ARG
+#  define USE_LEX_ARGS    (void) yylval;  USE_YYLLOC
 #  define LEX_PRE_FORMALS   LEX_FORMALS,
 #  define LEX_PRE_ARGS      LEX_ARGS,
 #else
@@ -102,7 +97,13 @@ m4_define([_AT_DATA_CALC_Y],
 #endif
 
 static int power (int base, int exponent);
-static void yyerror (const char *s);
+/* yyerror receives the location if:
+   - %location & %pure & %glr
+   - %location & %pure & %yacc & %parse-param. */
+static void yyerror (const char *s
+                     ]AT_YYERROR_ARG_LOC_IF([, YYLTYPE *yylloc])[
+                     ]AT_PARAM_IF([, value_t *result, int *count])[
+                     );
 static int yylex (LEX_FORMALS);
 static int yygetc (LEX_FORMALS);
 static void yyungetc (LEX_PRE_FORMALS int c);
@@ -119,27 +120,25 @@ m4_define([_AT_DATA_CALC_Y],
 %left NEG     /* negation--unary minus */
 %right '^'    /* exponentiation        */
 
-]$4[
-
 /* Grammar follows */
 %%
 input:
   line
-| input line         { ++*count; ++global_count; }
+| input line         { ]AT_PARAM_IF([++*count; ++global_count;])[ }
 ;
 
 line:
   '\n'
-| exp '\n'           { *result = global_result = $1; }
+| exp '\n'           { ]AT_PARAM_IF([*result = global_result = $1;])[ }
 ;
 
 exp:
   NUM                { $$ = $1;             }
 | exp '=' exp
   {
-     if ($1 != $3)
-       fprintf (stderr, "calc: error: %d != %d\n", $1, $3);
-     $$ = $1;
+    if ($1 != $3)
+      fprintf (stderr, "calc: error: %d != %d\n", $1, $3);
+    $$ = $1;
   }
 | exp '+' exp        { $$ = $1 + $3;        }
 | exp '-' exp        { $$ = $1 - $3;        }
@@ -155,26 +154,28 @@ exp:
 FILE *yyin;
 
 static void
-yyerror (const char *s)
+yyerror (const char *s
+         ]AT_YYERROR_ARG_LOC_IF([, YYLTYPE *yylloc])[
+         ]AT_PARAM_IF([, value_t *result, int *count])[)
 {
-#if YYLSP_NEEDED
+]AT_YYERROR_SEES_LOC_IF([
   fprintf (stderr, "%d.%d-%d.%d: ",
           LOC.first_line, LOC.first_column,
           LOC.last_line, LOC.last_column);
-#endif
+])[
   fprintf (stderr, "%s\n", s);
 }
 
 
-#if YYLSP_NEEDED
+]AT_LOCATION_IF([
 static YYLTYPE last_yylloc;
-#endif
+])[
 static int
 yygetc (LEX_FORMALS)
 {
   int res = getc (yyin);
   USE_LEX_ARGS;
-#if YYLSP_NEEDED
+]AT_LOCATION_IF([
   last_yylloc = LOC;
   if (res == '\n')
     {
@@ -183,7 +184,7 @@ exp:
     }
   else
     LOC.last_column++;
-#endif
+])[
   return res;
 }
 
@@ -192,10 +193,10 @@ exp:
 yyungetc (LEX_PRE_FORMALS int c)
 {
   USE_LEX_ARGS;
-#if YYLSP_NEEDED
+]AT_LOCATION_IF([
   /* Wrong when C == `\n'. */
   LOC = last_yylloc;
-#endif
+])[
   ungetc (c, yyin);
 }
 
@@ -241,24 +242,24 @@ exp:
   if (init)
     {
       init = 0;
-#if YYLSP_NEEDED
+]AT_LOCATION_IF([
       LOC.last_column = 1;
       LOC.last_line = 1;
-#endif
+])[
     }
 
-#if YYLSP_NEEDED
+]AT_LOCATION_IF([
   LOC.first_column = LOC.last_column;
   LOC.first_line = LOC.last_line;
-#endif
+])[
 
   /* Skip white space.  */
   while ((c = yygetc (LEX_ARGS)) == ' ' || c == '\t')
     {
-#if YYLSP_NEEDED
+]AT_LOCATION_IF([
       LOC.first_column = LOC.last_column;
       LOC.first_line = LOC.last_line;
-#endif
+])[
     }
 
   /* process numbers   */
@@ -309,7 +310,7 @@ exp:
 #if YYDEBUG
   yydebug = 1;
 #endif
-  yyparse (&result, &count);
+  yyparse (]AT_PARAM_IF([&result, &count])[);
   assert (global_result == result);
   assert (global_count  == count);
 
@@ -352,8 +353,8 @@ m4_define([_AT_CHECK_CALC],
 
 
 # _AT_CHECK_CALC_ERROR(BISON-OPTIONS, INPUT, [NUM-DEBUG-LINES],
-#                      [ERROR-LOCATION], [IF-YYERROR-VERBOSE])
-# ------------------------------------------------------------
+#                      [VERBOSE-AND-LOCATED-ERROR-MESSAGE])
+# -------------------------------------------------------------
 # Run `calc' on INPUT, and expect a `parse error' message.
 #
 # If INPUT starts with a slash, it is used as absolute input file name,
@@ -402,7 +403,7 @@ m4_define([_AT_CHECK_CALC_ERROR],
 [$4
 ])
 # 3. If locations are not used, remove them.
-m4_bmatch([$1], [%locations], [],
+AT_YYERROR_SEES_LOC_IF([],
 [[sed 's/^[-0-9.]*: //' expout >at-expout
 mv at-expout expout]])
 # 4. If error-verbose is not used, strip the`, unexpected....' part.
@@ -414,6 +415,55 @@ m4_define([_AT_CHECK_CALC_ERROR],
 ])
 
 
+# AT_CALC_PUSHDEFS($1, $2, [BISON-OPTIONS])
+# -----------------------------------------
+# This macro works around the impossibility to define macros
+# inside macros, because issuing `[$1]' is not possible in M4 :(.
+# This sucks hard, GNU M4 should really provide M5 like $$1.
+m4_define([AT_CHECK_PUSHDEFS],
+[m4_if([$1$2], $[1]$[2], [],
+       [m4_fatal([$0: Invalid arguments: address@hidden)])dnl
+m4_pushdef([AT_PARAM_IF],
+[m4_bmatch([$3], [%parse-param], [$1], [$2])])
+m4_dumpdef([AT_PARAM_IF])
+m4_pushdef([AT_LOCATION_IF],
+[m4_bmatch([$3], [%locations], [$1], [$2])])
+m4_pushdef([AT_PURE_IF],
+[m4_bmatch([$3], [%pure-parser], [$1], [$2])])
+m4_pushdef([AT_GLR_IF],
+[m4_bmatch([$3], [%glr-parser], [$1], [$2])])
+m4_pushdef([AT_PURE_AND_LOC_IF],
+[m4_bmatch([$3], [%locations.*%pure-parser\|%pure-parser.*%locations],
+           [$1], [$2])])
+m4_pushdef([AT_GLR_OR_PARAM_IF],
+[m4_bmatch([$3], [%glr-parser\|%parse-param], [$1], [$2])])
+
+# yyerror receives the location if %location & %pure & (%glr or %parse-param).
+m4_pushdef([AT_YYERROR_ARG_LOC_IF],
+[AT_GLR_OR_PARAM_IF([AT_PURE_AND_LOC_IF([$1], [$2])],
+                    [$2])])
+# yyerror cannot see the locations if !glr & pure.
+m4_pushdef([AT_YYERROR_SEES_LOC_IF],
+[AT_LOCATION_IF([AT_GLR_IF([$1],
+                           [AT_PURE_IF([$2], [$1])])],
+                [$2])])
+])
+
+
+# AT_CALC_POPDEFS
+# ---------------
+m4_define([AT_CHECK_POPDEFS],
+[m4_popdef([AT_YYERROR_SEES_LOC_IF])
+m4_popdef([AT_YYERROR_ARG_LOC_IF])
+m4_popdef([AT_GLR_OR_PARAM_IF])
+m4_popdef([AT_PURE_AND_LOC_IF])
+m4_popdef([AT_GLR_IF])
+m4_popdef([AT_LOCATION_IF])
+m4_popdef([AT_PARAM_IF])
+])
+
+
+
 # AT_CHECK_CALC([BISON-OPTIONS])
 # ------------------------------
 # Start a testing chunk which compiles `calc' grammar with
@@ -422,6 +472,8 @@ m4_define([AT_CHECK_CALC],
 [# We use integers to avoid dependencies upon the precision of doubles.
 AT_SETUP([Calculator $1])
 
+AT_CHECK_PUSHDEFS($[1], $[2], [$1])
+
 AT_DATA_CALC_Y([$1])
 
 # Specify the output files to avoid problems on different file systems.
@@ -473,6 +525,8 @@ m4_define([AT_CHECK_CALC],
 1.15-1.16: parse error, unexpected "number"
 calc: error: 0 != 1])
 
+AT_CHECK_POPDEFS
+
 AT_CLEANUP
 ])# AT_CHECK_CALC
 
@@ -508,7 +562,9 @@ m4_define([AT_CHECK_CALC_LALR],
 AT_CHECK_CALC_LALR([%debug])
 AT_CHECK_CALC_LALR([%error-verbose %debug %locations %defines 
%name-prefix="calc" %verbose %yacc])
 
-# AT_CHECK_CALC_LALR([%pure-parser %error-verbose %debug %locations %defines 
%name-prefix="calc" %verbose %yacc])
+AT_CHECK_CALC_LALR([%pure-parser %error-verbose %debug %locations %defines 
%name-prefix="calc" %verbose %yacc])
+
+AT_CHECK_CALC_LALR([%pure-parser %error-verbose %debug %locations %defines 
%name-prefix="calc" %verbose %yacc %parse-param "value_t *result", "result" 
%parse-param "int *count", "count"])
 
 
 # ----------------------- #
@@ -541,4 +597,6 @@ m4_define([AT_CHECK_CALC_GLR],
 AT_CHECK_CALC_GLR([%debug])
 AT_CHECK_CALC_GLR([%error-verbose %debug %locations %defines 
%name-prefix="calc" %verbose %yacc])
 
-# AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines 
%name-prefix="calc" %verbose %yacc])
+AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines 
%name-prefix="calc" %verbose %yacc])
+
+AT_CHECK_CALC_GLR([%pure-parser %error-verbose %debug %locations %defines 
%name-prefix="calc" %verbose %yacc %parse-param "value_t *result", "result" 
%parse-param "int *count", "count"])
Index: tests/cxx-type.at
--- tests/cxx-type.at Sun, 03 Nov 2002 13:26:54 +0100 akim
+++ tests/cxx-type.at Sat, 02 Nov 2002 18:06:14 +0100 akim
@@ -36,7 +36,11 @@ m4_define([_AT_TEST_GLR_CALC],
 ]m4_bmatch([$2], [stmtMerge],
 [ static YYSTYPE stmtMerge (YYSTYPE x0, YYSTYPE x1);])[
   #define YYINITDEPTH 10
-  int yyerror (const char *s);
+  int yyerror (const char *s
+#if YYPURE && YYLSP_NEEDED
+               , YYLTYPE *yylocation
+#endif
+              );
 
   #if YYPURE
 ]m4_bmatch([$1], [location],
@@ -130,7 +134,7 @@ m4_define([_AT_TEST_GLR_CALC],
          break;
        default:
          if (isalpha (c))
-           { 
+           {
              i = 0;
 
              do
@@ -153,8 +157,15 @@ m4_define([_AT_TEST_GLR_CALC],
 }
 
 int
-yyerror (const char *s)
+yyerror (const char *s
+#if YYPURE && YYLSP_NEEDED
+        , YYLTYPE *yylocation
+#endif
+        )
 {
+#if YYPURE && YYLSP_NEEDED
+  (void) *yylocation;
+#endif
   fprintf (stderr, "%s\n", s);
   return 0;
 }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]