Subject: Re: bug#50469: [bison-3.8] bug or side effect to flex & automake

From: Akim Demaille <[email-masked]>
Date: Fri, 10 Sep 2021 18:40:57 +0200

Hi all,

> Le 9 sept. 2021 à 07:10, Akim Demaille <[email-masked]> a écrit :
> 
> Hi!
> 
>> Le 9 sept. 2021 à 00:32, Paul Eggert <[email-masked]> a écrit :
>> 
>> On 9/8/21 2:18 PM, Karl Berry wrote:
>>> Just an idea that I don't expect you to adopt, but just to mention --
>>> you could only institute the breaking change if POSIXLY_CORRECT.  That's
>>> why POSIXLY_CORRECT exists. -k
>> 
>> I like this idea. It insulates us against POSIX decisions and/or indecisions in this area.
> 
> Good with me.  I'll implement that, thanks Karl!

I will soon push the following commit, and wrap a 3.8.1.  Comments most welcome!

Cheers!

(a tarball is available here:

  https://www.lrde.epita.fr/~akim/private/bison/bison-3.8.3-84b7.tar.gz
  https://www.lrde.epita.fr/~akim/private/bison/bison-3.8.3-84b7.tar.lz
  https://www.lrde.epita.fr/~akim/private/bison/bison-3.8.3-84b7.tar.xz)

commit 5623009a76dd8f04b5c19bb5f6ae8e2bf258a51e
Author: Akim Demaille <[email-masked]>
Date:   Fri Sep 10 06:48:02 2021 +0200

    yacc: declare yyerror/yylex only when POSIXLY_CORRECT
    
    The recent changes to comply with POSIX are breaking Automake's test
    suite.
    Reported by Kiyoshi Kanazawa.
    <https://lists.gnu.org/r/bug-bison/2021-09/msg00005.html>
    
    To limit the impact of POSIX changes, bind them to $POSIXLY_CORRECT.
    Suggested by Karl Berry.
    <https://lists.gnu.org/r/bug-bison/2021-09/msg00009.html>
    
    The existing `maintainer-check-posix` Make target checks these
    changes.
    
    * src/getargs.h, src/getargs.c (set_yacc): New.
    Use it.
    * data/skeletons/bison.m4 (b4_posix_if): New.
    * data/skeletons/yacc.c (b4_declare_yyerror_and_yylex): Use it.
    * doc/bison.texi, tests/local.at: Adjust.

diff --git a/NEWS b/NEWS
index 71c4ae7c..8300548a 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,15 @@ GNU Bison NEWS
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+  The generation of prototypes for yylex and yyerror in Yacc mode is
+  breaking existing grammar files.
+
+  **Please don't use `-y`/`--yacc` simply to comply with Yacc's file name
+    conventions, rather, use `-o y.tab.c`.**
+
+  To avoid breaking too many grammars, the prototypes are now generated when
+  `-y/--yacc` is used *and* the `POSIXLY_CORRECT` environment variable is
+  defined.
 
 * Noteworthy changes in release 3.8 (2021-09-07) [stable]
 
@@ -4706,7 +4715,7 @@ LocalWords:  autocompletion bistromathic submessages Cayuela lexcalc hoc
 LocalWords:  yytoken YYUNDEF YYerror basename Automake's UTF ifdef ffile
 LocalWords:  gotos readline Imbimbo Wcounterexamples Wcex Nonunifying rcex
 LocalWords:  Vais xsltproc YYNOMEM YYLOCATION signedness YYBISON MITRE's
-LocalWords:  libreadline YYMALLOC YYFREE MSVC redefinitions
+LocalWords:  libreadline YYMALLOC YYFREE MSVC redefinitions POSIXLY
 
 Local Variables:
 ispell-dictionary: "american"
diff --git a/data/skeletons/bison.m4 b/data/skeletons/bison.m4
index 488ad610..037dadcf 100644
--- a/data/skeletons/bison.m4
+++ b/data/skeletons/bison.m4
@@ -1110,6 +1110,7 @@ b4_percent_define_if_define([token_ctor], [api.token.constructor])
 b4_percent_define_if_define([locations])     # Whether locations are tracked.
 b4_percent_define_if_define([parse.assert])
 b4_percent_define_if_define([parse.trace])
+b4_percent_define_if_define([posix])

 # b4_bison_locations_if([IF-TRUE])
diff --git a/data/skeletons/yacc.c b/data/skeletons/yacc.c
index d50f3aaf..64b9ac62 100644
--- a/data/skeletons/yacc.c
+++ b/data/skeletons/yacc.c
@@ -367,7 +367,7 @@ m4_define([b4_declare_yyparse],
 # 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_posix_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
diff --git a/doc/bison.texi b/doc/bison.texi
index 9a02fb95..a559649c 100644
--- a/doc/bison.texi
+++ b/doc/bison.texi
@@ -11877,7 +11877,10 @@ @node Tuning the Parser
 Generate @code{#define} statements in addition to an @code{enum} to
 associate token codes with token kind names.
 @item
-Generate prototypes for @code{yyerror} and @code{yylex} (since Bison 3.8):
+If the @code{POSIXLY_CORRECT} environment variable is defined, generate
+prototypes for @code{yyerror} and @code{yylex}@footnote{See
+@url{https://austingroupbugs.net/view.php?id=1388#c5220}.} (since Bison
+3.8):
 @example
 int yylex (void);
 void yyerror (const char *);
diff --git a/src/getargs.c b/src/getargs.c
index 697ad7eb..ef559296 100644
--- a/src/getargs.c
+++ b/src/getargs.c
@@ -71,6 +71,18 @@ struct bison_language const *language = &valid_languages[0];
 
 typedef int* (xargmatch_fn) (const char *context, const char *arg);
 
+void
+set_yacc (location loc)
+{
+  yacc_loc = loc;
+  if (getenv ("POSIXLY_CORRECT"))
+    muscle_percent_define_insert ("posix",
+                                  loc,
+                                  muscle_keyword, "",
+                                  MUSCLE_PERCENT_DEFINE_D);
+}
+
+
 /** Decode an option's key.
  *
  *  \param opt        option being decoded.
@@ -631,8 +643,7 @@ static struct option const long_options[] =
 };
 
 /* Build a location for the current command line argument. */
-static
-location
+static location
 command_line_location (void)
 {
   location res;
@@ -835,7 +846,7 @@ getargs (int argc, char *argv[])
 
       case 'y':
         warning_argmatch ("yacc", 0, 0);
-        yacc_loc = loc;
+        set_yacc (loc);
         break;
 
       case COLOR_OPTION:
diff --git a/src/getargs.h b/src/getargs.h
index a26aec2f..836c1290 100644
--- a/src/getargs.h
+++ b/src/getargs.h
@@ -140,6 +140,7 @@ void getargs (int argc, char *argv[]);
 /* Used by parse-gram.y.  */
 void language_argmatch (char const *arg, int prio, location loc);
 void skeleton_arg (const char *arg, int prio, location loc);
+void set_yacc (location loc);
 
 /** In the string \c s, replace all characters \c from by \c to.  */
 void tr (char *s, char from, char to);
diff --git a/src/parse-gram.c b/src/parse-gram.c
index 95fe43e0..3bc44dbd 100644
--- a/src/parse-gram.c
+++ b/src/parse-gram.c
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.7.5.297-b46a.  */
+/* A Bison parser, made by GNU Bison 3.8.  */
 
 /* Bison implementation for Yacc-like parsers in C
 
@@ -46,10 +46,10 @@
    USER NAME SPACE" below.  */
 
 /* Identify Bison output, and Bison version.  */
-#define YYBISON 30705
+#define YYBISON 30800
 
 /* Bison version string.  */
-#define YYBISON_VERSION "3.7.5.297-b46a"
+#define YYBISON_VERSION "3.8"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -3129,7 +3129,7 @@ handle_yacc (location const *loc)
   const char *directive = "%yacc";
   bison_directive (loc, directive);
   if (location_empty (yacc_loc))
-    yacc_loc = *loc;
+    set_yacc (*loc);
   else
     duplicate_directive (directive, yacc_loc, *loc);
 }
diff --git a/src/parse-gram.h b/src/parse-gram.h
index 10a63528..77849263 100644
--- a/src/parse-gram.h
+++ b/src/parse-gram.h
@@ -1,4 +1,4 @@
-/* A Bison parser, made by GNU Bison 3.7.5.297-b46a.  */
+/* A Bison parser, made by GNU Bison 3.8.  */
 
 /* Bison interface for Yacc-like parsers in C
 
@@ -215,6 +215,7 @@ struct GRAM_LTYPE

+
 int gram_parse (void);
 
 /* "%code provides" blocks.  */
diff --git a/src/parse-gram.y b/src/parse-gram.y
index 1de83d02..15180cb5 100644
--- a/src/parse-gram.y
+++ b/src/parse-gram.y
@@ -1112,7 +1112,7 @@ handle_yacc (location const *loc)
   const char *directive = "%yacc";
   bison_directive (loc, directive);
   if (location_empty (yacc_loc))
-    yacc_loc = *loc;
+    set_yacc (*loc);
   else
     duplicate_directive (directive, yacc_loc, *loc);
 }
diff --git a/tests/calc.at b/tests/calc.at
index 11801543..aeac8418 100644
--- a/tests/calc.at
+++ b/tests/calc.at
@@ -268,7 +268,7 @@ m4_define([AT_CALC_YYLEX(c)],

 m4_define([_AT_DATA_CALC_Y(c)],
-[AT_DATA_GRAMMAR([calc.y],
+[AT_DATA_GRAMMAR([calc.y.tmp],
 [[/* Infix notation calculator--calc */
 ]$4[
 %code requires
@@ -493,6 +493,18 @@ m4_define([_AT_DATA_CALC_Y(c)],
 [AT_CALC_YYLEX
 AT_CALC_MAIN])])
 
+# Remove the generated prototypes.
+AT_CHECK(
+  [AT_YACC_IF([[
+    if "$POSIXLY_CORRECT_IS_EXPORTED"; then
+      sed -e '/\/\* !POSIX \*\//d' calc.y.tmp >calc.y
+    else
+      mv calc.y.tmp calc.y
+    fi
+  ]],
+  [[mv calc.y.tmp calc.y]])
+])
+
 AT_HEADER_IF([AT_DATA_SOURCE([[calc-lex.]AT_LANG_EXT],
 [[#include "calc.]AT_LANG_HDR["
 
diff --git a/tests/local.at b/tests/local.at
index bc43ee1c..adde4e4c 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -687,8 +687,8 @@ m4_define([AT_YYERROR_DECLARE_EXTERN(c)],
 m4_define([AT_YYERROR_DECLARE(c)],
 [[#include <stdio.h>
 ]AT_LOCATION_PRINT_DECLARE[
-]AT_YACC_IF([], [[static ]AT_YYERROR_DECLARE_EXTERN])])
-
+/* !POSIX */ static ]AT_YYERROR_DECLARE_EXTERN[]dnl
+])
 
 # "%define parse.error custom" uses a different format, easy to check.
 # The "verbose" one can be computed from it (see _AT_CHECK_CALC_ERROR).
@@ -733,7 +733,7 @@ m4_define([AT_YYERROR_DEFINE(c)],
 ]])[
 
 /* A C error reporting function.  */
-]AT_YACC_IF([], [static])[
+/* !POSIX */ static
 ]AT_YYERROR_PROTOTYPE[
 {]m4_bpatsubst(m4_defn([AT_PARSE_PARAMS]),
               [[^,]+[^A-Za-z_0-9]\([A-Za-z_][A-Za-z_0-9]*\),* *], [