yacc: comply with recent POSIX updates: declare yyerror and yylex

In POSIX Yacc mode, declare yyerror and yylex unless already #defined,
or if YYERROR_IS_DECLARED/YYLEX_IS_DECLARED are defined (for
consistency with Bison's YYSTYPE_IS_DECLARED/YYLTYPE_IS_DECLARED).
See <https://austingroupbugs.net/view.php?id=1388#c5220>.

* data/skeletons/c.m4 (b4_function_declare): Resurect.
(b4_lex_formals): Since we will possibly expose this prototype
in the header, take the prefix into account.
* data/skeletons/yacc.c (b4_declare_yyerror_and_yylex): New.
(b4_shared_declarations): Use it.

* tests/local.at (AT_YACC_IF): New.
When in Yacc mode, set the `yacc` Autotest keyword.
(AT_YYERROR_DECLARE(c)): Don't declare in Yacc mode,
to avoid clashes (since this signature is static).
(AT_YYERROR_DEFINE(c)): Don't define as static in Yacc mode.
* tests/regression.at (Early token definitions with --yacc): Specify
that we are in Yacc mode.
This commit is contained in:
Akim Demaille
2021-08-05 08:39:24 +02:00
parent dabde7c560
commit 3c5f73fe51
8 changed files with 95 additions and 30 deletions

8
NEWS
View File

@@ -9,6 +9,14 @@ GNU Bison NEWS
now generates a *.gv file by default, instead of *.dot. A transition now generates a *.gv file by default, instead of *.dot. A transition
started in Bison 3.4. started in Bison 3.4.
To comply with the latest POSIX standard, in Yacc compatibility mode
(options `-y`/`--yacc`) Bison now generates prototypes for yyerror and
yylex. In some situations, this is breaking compatibility: if the user
has already declared these functions but with some differences (e.g., to
declare them as static, or to use specific attributes), the generated
parser will fail to compile. To disable these prototypes, #define yyerror
(to `yyerror`), and likewise for yylex.
** Deprecated features ** Deprecated features
Support for the YYPRINT macro is removed. It worked only with yacc.c and Support for the YYPRINT macro is removed. It worked only with yacc.c and

4
TODO
View File

@@ -1,8 +1,4 @@
* Soon * Soon
** POSIX updates
See the recent changes about function prototypes in POSIX Yacc. Implement
them.
** scan-code ** scan-code
The default case is scanning char-per-char. The default case is scanning char-per-char.

View File

@@ -112,8 +112,8 @@ b4_percent_define_default([[api.symbol.prefix]], [[YYSYMBOL_]])
# All the yylex formal arguments. # All the yylex formal arguments.
# b4_lex_param arrives quoted twice, but we want to keep only one level. # b4_lex_param arrives quoted twice, but we want to keep only one level.
m4_define([b4_lex_formals], m4_define([b4_lex_formals],
[b4_pure_if([[[[YYSTYPE *yylvalp]], [[&yylval]]][]dnl [b4_pure_if([[[b4_api_PREFIX[STYPE *yylvalp]], [[&yylval]]][]dnl
b4_locations_if([, [[YYLTYPE *yyllocp], [&yylloc]]])])dnl b4_locations_if([, [b4_api_PREFIX[LTYPE *yyllocp], [&yylloc]]])])dnl
m4_ifdef([b4_lex_param], [, ]b4_lex_param)]) m4_ifdef([b4_lex_param], [, ]b4_lex_param)])
@@ -662,6 +662,14 @@ m4_define([b4_formal],
[$1]) [$1])
# b4_function_declare(NAME, RETURN-VALUE, [DECL1, NAME1], ...)
# ------------------------------------------------------------
# Declare the function NAME.
m4_define([b4_function_declare],
[$2 $1 (b4_formals(m4_shift2($@)));[]dnl
])
## --------------------- ## ## --------------------- ##
## Calling C functions. ## ## Calling C functions. ##

View File

@@ -102,6 +102,16 @@ m4_define([b4_yyerror_arg_loc_if],
[1], [m4_ifset([b4_parse_param], [$1])], [1], [m4_ifset([b4_parse_param], [$1])],
[2], [$1])])]) [2], [$1])])])
# b4_yyerror_formals
# ------------------
m4_define([b4_yyerror_formals],
[b4_pure_if([b4_locations_if([, [[const ]b4_api_PREFIX[LTYPE *yyllocp], [&yylloc]]])[]dnl
m4_ifdef([b4_parse_param], [, b4_parse_param])[]dnl
,])dnl
[[const char *msg], [msg]]])
# b4_yyerror_args # b4_yyerror_args
# --------------- # ---------------
# Arguments passed to yyerror: user args plus yylloc. # Arguments passed to yyerror: user args plus yylloc.
@@ -352,17 +362,32 @@ m4_define([b4_declare_yyparse],
]) ])
# b4_declare_yyerror_and_yylex
# ----------------------------
# Comply with POSIX Yacc.
# <https://austingroupbugs.net/view.php?id=1388#c5220>
m4_define([b4_declare_yyerror_and_yylex],
[b4_yacc_if([[#if !defined ]b4_prefix[error && !defined ]b4_api_PREFIX[ERROR_IS_DECLARED
]b4_function_declare([b4_prefix[error]], void, b4_yyerror_formals)[
#endif
#if !defined ]b4_prefix[lex && !defined ]b4_api_PREFIX[LEX_IS_DECLARED
]b4_function_declare([b4_prefix[lex]], int, b4_lex_formals)[
#endif
]])dnl
])
# b4_shared_declarations # b4_shared_declarations
# ---------------------- # ----------------------
# Declaration that might either go into the header (if --header) # Declarations that might either go into the header (if --header)
# or open coded in the parser body. # or into the implementation file.
m4_define([b4_shared_declarations], m4_define([b4_shared_declarations],
[b4_cpp_guard_open([b4_spec_mapped_header_file])[ [b4_cpp_guard_open([b4_spec_mapped_header_file])[
]b4_declare_yydebug[ ]b4_declare_yydebug[
]b4_percent_code_get([[requires]])[ ]b4_percent_code_get([[requires]])[
]b4_token_enums_defines[ ]b4_token_enums_defines[
]b4_declare_yylstype[ ]b4_declare_yylstype[
]b4_declare_yyerror_and_yylex[
]b4_declare_yyparse[ ]b4_declare_yyparse[
]b4_percent_code_get([[provides]])[ ]b4_percent_code_get([[provides]])[
]b4_cpp_guard_close([b4_spec_mapped_header_file])[]dnl ]b4_cpp_guard_close([b4_spec_mapped_header_file])[]dnl

View File

@@ -6117,11 +6117,13 @@ states and what is done for each type of lookahead token in that state.
@end deffn @end deffn
@deffn {Directive} %yacc @deffn {Directive} %yacc
Pretend the option @option{--yacc} was given, i.e., imitate Yacc, including Pretend the option @option{--yacc} was given
its naming conventions. Only makes sense with the @file{yacc.c} (@pxref{option-yacc,,@option{--yacc}}), i.e., imitate Yacc, including its
naming conventions. Only makes sense with the @file{yacc.c}
skeleton. @xref{Tuning the Parser}, for more. skeleton. @xref{Tuning the Parser}, for more.
Of course @code{%yacc} is a Bison extension@dots{} Of course, being a Bison extension, @code{%yacc} is somewhat
self-contradictory@dots{}
@end deffn @end deffn
@@ -11832,8 +11834,9 @@ Pretend that @code{%locations} was specified. @xref{Decl Summary}.
@item -p @var{prefix} @item -p @var{prefix}
@itemx --name-prefix=@var{prefix} @itemx --name-prefix=@var{prefix}
Pretend that @code{%name-prefix "@var{prefix}"} was specified (@pxref{Decl Pretend that @code{%name-prefix "@var{prefix}"} was specified (@pxref{Decl
Summary}). Obsoleted by @option{-Dapi.prefix=@var{prefix}}. @xref{Multiple Summary}). The option @option{-p} is specified by POSIX. When POSIX
Parsers}. compatibility is not a requirement, @option{-Dapi.prefix=@var{prefix}} is a
better option (@pxref{Multiple Parsers}).
@item -l @item -l
@itemx --no-lines @itemx --no-lines
@@ -11865,26 +11868,46 @@ This is similar to how most shells resolve commands.
Pretend that @code{%token-table} was specified. @xref{Decl Summary}. Pretend that @code{%token-table} was specified. @xref{Decl Summary}.
@item -y @item -y
@itemx --yacc @itemx @anchor{option-yacc} --yacc
Act more like the traditional @command{yacc} command. This can cause Act more like the traditional @command{yacc} command:
different diagnostics to be generated (it implies @option{-Wyacc}), and may @itemize
change behavior in other minor ways. Most importantly, imitate Yacc's @item
output file name conventions, so that the parser implementation file is Generate different diagnostics (it implies @option{-Wyacc}).
called @file{y.tab.c}, and the other outputs are called @file{y.output} and @item
@file{y.tab.h}. Also, generate @code{#define} statements in addition to an Generate @code{#define} statements in addition to an @code{enum} to
@code{enum} to associate token codes with token kind names. Thus, the associate token codes with token kind names.
following shell script can substitute for Yacc, and the Bison distribution @item
contains such a script for compatibility with POSIX: Generate prototypes for @code{yyerror} and @code{yylex} (since Bison 3.8):
@example @example
#! /bin/sh int yylex (void);
bison -y "$@@" void yyerror (const char *);
@end example @end example
As a Bison extension, additional arguments required by @code{%pure-parser},
@code{%locations}, @code{%lex-param} and @code{%parse-param} are taken into
account. You may disable @code{yyerror}'s prototype with @samp{#define
yyerror yyerror} (as specified by POSIX), or with @samp{#define
YYERROR_IS_DECLARED} (a Bison extension). Likewise for @code{yylex}.
@item
Imitate Yacc's output file name conventions, so that the parser
implementation file is called @file{y.tab.c}, and the other outputs are
called @file{y.output} and @file{y.tab.h}. Do not use @option{--yacc} just
to change the output file names since it also triggers all the
aforementioned behavior changes; rather use @samp{-o y.tab.c}.
@end itemize
The @option{-y}/@option{--yacc} option is intended for use with traditional The @option{-y}/@option{--yacc} option is intended for use with traditional
Yacc grammars. This option only makes sense for the default C skeleton, Yacc grammars. This option only makes sense for the default C skeleton,
@file{yacc.c}. If your grammar uses Bison extensions Bison cannot be @file{yacc.c}. If your grammar uses Bison extensions Bison cannot be
Yacc-compatible, even if this option is specified. Yacc-compatible, even if this option is specified.
Thus, the following shell script can substitute for Yacc, and the Bison
distribution contains such a @command{yacc} script for compatibility with
POSIX:
@example
#! /bin/sh
bison -y "$@@"
@end example
@end table @end table
@node Output Files @node Output Files

View File

@@ -27,6 +27,7 @@ synonyms.
- report: for automaton dumps - report: for automaton dumps
- %union - %union
- variant - variant
- yacc: POSIX yacc (%yacc)
# Calculator # Calculator
The grammar features several special directives: The grammar features several special directives:

View File

@@ -275,6 +275,8 @@ m4_pushdef([AT_MULTISTART_IF],
[m4_bmatch([$3], [%start [_a-zA-Z]+ [_a-zA-Z]+], [$1], [$2])]) [m4_bmatch([$3], [%start [_a-zA-Z]+ [_a-zA-Z]+], [$1], [$2])])
m4_pushdef([AT_PARAM_IF], m4_pushdef([AT_PARAM_IF],
[m4_bmatch([$3], [%parse-param], [$1], [$2])]) [m4_bmatch([$3], [%parse-param], [$1], [$2])])
m4_pushdef([AT_YACC_IF],
[m4_bmatch([$3], [%yacc], [$1], [$2])])
# Comma-terminated list of formals parse-parameters. # Comma-terminated list of formals parse-parameters.
# E.g., %parse-param { int x } %parse-param {int y} -> "int x, int y, ". # E.g., %parse-param { int x } %parse-param {int y} -> "int x, int y, ".
@@ -427,6 +429,7 @@ AT_LOCATION_TYPE_SPAN_IF(
AT_GLR_IF([AT_KEYWORDS([glr])]) AT_GLR_IF([AT_KEYWORDS([glr])])
AT_MULTISTART_IF([AT_KEYWORDS([multistart])]) AT_MULTISTART_IF([AT_KEYWORDS([multistart])])
AT_PUSH_IF([AT_KEYWORDS([push])]) AT_PUSH_IF([AT_KEYWORDS([push])])
AT_YACC_IF([AT_KEYWORDS([yacc])])
])# _AT_BISON_OPTION_PUSHDEFS ])# _AT_BISON_OPTION_PUSHDEFS
@@ -466,6 +469,7 @@ m4_popdef([AT_VALUE_UNION_IF])
m4_popdef([AT_PUSH_IF]) m4_popdef([AT_PUSH_IF])
m4_popdef([AT_PURE_IF]) m4_popdef([AT_PURE_IF])
m4_popdef([AT_PARSER_CLASS]) m4_popdef([AT_PARSER_CLASS])
m4_popdef([AT_YACC_IF])
m4_popdef([AT_PARAM_IF]) m4_popdef([AT_PARAM_IF])
m4_popdef([AT_MULTISTART_IF]) m4_popdef([AT_MULTISTART_IF])
m4_popdef([AT_LEXPARAM_IF]) m4_popdef([AT_LEXPARAM_IF])
@@ -683,7 +687,7 @@ m4_define([AT_YYERROR_DECLARE_EXTERN(c)],
m4_define([AT_YYERROR_DECLARE(c)], m4_define([AT_YYERROR_DECLARE(c)],
[[#include <stdio.h> [[#include <stdio.h>
]AT_LOCATION_PRINT_DECLARE[ ]AT_LOCATION_PRINT_DECLARE[
static ]AT_YYERROR_DECLARE_EXTERN]) ]AT_YACC_IF([], [[static ]AT_YYERROR_DECLARE_EXTERN])])
# "%define parse.error custom" uses a different format, easy to check. # "%define parse.error custom" uses a different format, easy to check.
@@ -729,7 +733,7 @@ yyreport_syntax_error (const yypcontext_t *ctx]AT_PARAM_IF([, AT_PARSE_PARAMS])[
]])[ ]])[
/* A C error reporting function. */ /* A C error reporting function. */
static ]AT_YACC_IF([], [static])[
]AT_YYERROR_PROTOTYPE[ ]AT_YYERROR_PROTOTYPE[
{]m4_bpatsubst(m4_defn([AT_PARSE_PARAMS]), {]m4_bpatsubst(m4_defn([AT_PARSE_PARAMS]),
[[^,]+[^A-Za-z_0-9]\([A-Za-z_][A-Za-z_0-9]*\),* *], [ [[^,]+[^A-Za-z_0-9]\([A-Za-z_][A-Za-z_0-9]*\),* *], [

View File

@@ -87,7 +87,7 @@ AT_SETUP([Early token definitions with --yacc])
# Found in GCJ: they expect the tokens to be defined before the user # Found in GCJ: they expect the tokens to be defined before the user
# prologue, so that they can use the token definitions in it. # prologue, so that they can use the token definitions in it.
AT_BISON_OPTION_PUSHDEFS AT_BISON_OPTION_PUSHDEFS([%yacc])
# Not AT_DATA_GRAMMAR, which uses %code, which is not supported by Yacc. # Not AT_DATA_GRAMMAR, which uses %code, which is not supported by Yacc.
AT_DATA([input.y], AT_DATA([input.y],
@@ -112,7 +112,7 @@ exp: MY_TOKEN;
]]) ]])
AT_BISON_OPTION_POPDEFS AT_BISON_OPTION_POPDEFS
AT_BISON_CHECK([-y -o input.c input.y]) AT_BISON_CHECK([--yacc -o input.c input.y])
AT_COMPILE([input.o]) AT_COMPILE([input.o])
AT_CLEANUP AT_CLEANUP