From 7c6e7bd300fc71c35b81592f9854abe87ffc9cdf Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 27 Oct 2020 06:12:27 +0000 Subject: [PATCH 01/13] doc: minor grammar fixes in counterexamples section * doc/bison.texi: Minor fixes in counterexamples section. --- doc/bison.texi | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/bison.texi b/doc/bison.texi index 48428f04..277aba29 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -9945,10 +9945,11 @@ very documentation. To solve a conflict, one must understand it: when does it occur? Is it because of a flaw in the grammar? Is it rather because LR(1) cannot cope with this grammar? -On difficulty is that conflicts occur in the @emph{automaton}, and it can be -tricky to related them to issues in the @emph{grammar} itself. With -experience and patience, analysis the detailed description of the automaton -(@pxref{Understanding}) allows to find example strings that reach these conflicts. +One difficulty is that conflicts occur in the @emph{automaton}, and it can +be tricky to relate them to issues in the @emph{grammar} itself. With +experience and patience, analysis of the detailed description of the +automaton (@pxref{Understanding}) allows one to find example strings that +reach these conflicts. That task is made much easier thanks to the generation of counterexamples, initially developed by Chinawat Isradisaikul and Andrew Myers @@ -10101,7 +10102,7 @@ sequence.y:8.3-45: @dwarning{warning}: rule useless in parser due to conflicts [ Each of these three conflicts, again, prove that the grammar is ambiguous. For instance, the second conflict (the reduce/reduce one) shows that the -grammar accept the empty input in two different ways. +grammar accepts the empty input in two different ways. @sp 1 From bd6b046ce7ffd6cc5f7c1c77e425c97df66cd329 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Sun, 1 Nov 2020 09:00:50 +0100 Subject: [PATCH 02/13] doc: fix incorrect section title Reported by Gaurav Singh . https://lists.gnu.org/r/bug-bison/2020-11/msg00000.html * doc/bison.texi (Rpcalc Expr): Rename as... (Rpcalc Exp): this, as the nterm is named 'exp'. --- doc/bison.texi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/bison.texi b/doc/bison.texi index 277aba29..416a8ec6 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -303,7 +303,7 @@ Grammar Rules for @code{rpcalc} * Rpcalc Input:: Explanation of the @code{input} nonterminal * Rpcalc Line:: Explanation of the @code{line} nonterminal -* Rpcalc Expr:: Explanation of the @code{expr} nonterminal +* Rpcalc Exp:: Explanation of the @code{exp} nonterminal Location Tracking Calculator: @code{ltcalc} @@ -1788,7 +1788,7 @@ rule are referred to as @code{$1}, @code{$2}, and so on. @menu * Rpcalc Input:: Explanation of the @code{input} nonterminal * Rpcalc Line:: Explanation of the @code{line} nonterminal -* Rpcalc Expr:: Explanation of the @code{expr} nonterminal +* Rpcalc Exp:: Explanation of the @code{exp} nonterminal @end menu @node Rpcalc Input @@ -1853,8 +1853,8 @@ uninitialized (its value will be unpredictable). This would be a bug if that value were ever used, but we don't use it: once rpcalc has printed the value of the user's input line, that value is no longer needed. -@node Rpcalc Expr -@subsubsection Explanation of @code{expr} +@node Rpcalc Exp +@subsubsection Explanation of @code{exp} The @code{exp} grouping has several rules, one for each kind of expression. The first rule handles the simplest expressions: those that are just From 98c35e0025f43838d4c451553a4cf8b345b047f8 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 10 Nov 2020 07:35:30 +0100 Subject: [PATCH 03/13] gnulib: update --- gnulib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnulib b/gnulib index 160d5e7d..839ed059 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit 160d5e7d9a64a29a52d4821fd0ef2136d7e2102a +Subproject commit 839ed059f49329993ed34699a6f6b6466f09cbe0 From c47bb87f9f1285309377adee7bb21263decc503c Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Tue, 10 Nov 2020 07:36:11 +0100 Subject: [PATCH 04/13] yacc.c: fix #definition of YYEMPTY When generating a C parser, YYEMPTY is present in enum yytokentype but there is no corresponding #define like there is for the other values. There is a special case for YYEMPTY in b4_token_enums but no corresponding case in b4_token_defines. * data/skeletons/c.m4 (b4_token_defines): Do define YYEMPTY. --- NEWS | 4 ++++ data/skeletons/c.m4 | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 32671d01..399d560d 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ GNU Bison NEWS * Noteworthy changes in release ?.? (????-??-??) [?] +** Bug fixes + + In Yacc mode, all the tokens are defined twice: once as an enum, and then + as a macro. YYEMPTY was missing its macro. * Noteworthy changes in release 3.7.3 (2020-10-13) [stable] diff --git a/data/skeletons/c.m4 b/data/skeletons/c.m4 index 2452ed2e..c8689038 100644 --- a/data/skeletons/c.m4 +++ b/data/skeletons/c.m4 @@ -509,10 +509,11 @@ m4_define([b4_token_define], # ---------------- # Output the definition of the tokens. m4_define([b4_token_defines], -[b4_any_token_visible_if([/* Token kinds. */ -m4_join([ +[[/* Token kinds. */ +#define ]b4_symbol([-2], [id])[ -2 +]m4_join([ ], b4_symbol_map([b4_token_define])) -])]) +]) # b4_token_enum(TOKEN-NUM) From 14c65a35f085acf2ae62bec29208f8de33aad66d Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 10 Nov 2020 08:19:33 +0100 Subject: [PATCH 05/13] %require: accept version numbers with three parts ("3.7.4") * src/parse-gram.y (str_to_version): Support three parts. * data/skeletons/location.cc, data/skeletons/stack.hh: Adjust. --- data/skeletons/location.cc | 2 +- data/skeletons/stack.hh | 2 +- src/parse-gram.c | 47 +++++++++++++++++++++++++------------- src/parse-gram.y | 47 +++++++++++++++++++++++++------------- 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/data/skeletons/location.cc b/data/skeletons/location.cc index 33c9e50d..c96381e9 100644 --- a/data/skeletons/location.cc +++ b/data/skeletons/location.cc @@ -22,7 +22,7 @@ m4_pushdef([b4_copyright_years], # b4_position_file # ---------------- # Name of the file containing the position class, if we want this file. -b4_defines_if([b4_required_version_if([302], [], +b4_defines_if([b4_required_version_if([30200], [], [m4_define([b4_position_file], [position.hh])])])]) diff --git a/data/skeletons/stack.hh b/data/skeletons/stack.hh index 0fd36258..38bff8ba 100644 --- a/data/skeletons/stack.hh +++ b/data/skeletons/stack.hh @@ -19,7 +19,7 @@ # b4_stack_file # ------------- # Name of the file containing the stack class, if we want this file. -b4_defines_if([b4_required_version_if([302], [], +b4_defines_if([b4_required_version_if([30200], [], [m4_define([b4_stack_file], [stack.hh])])]) diff --git a/src/parse-gram.c b/src/parse-gram.c index d8eb81cc..917fb35a 100644 --- a/src/parse-gram.c +++ b/src/parse-gram.c @@ -3032,11 +3032,9 @@ handle_pure_parser (location const *loc, char const *directive) } -/* Convert VERSION into an int (MAJOR * 100 + MINOR). Return -1 on - errors. - - Changes of behavior are only on minor version changes, so "3.0.5" - is the same as "3.0": 300. */ +/* Convert VERSION into an int (MAJOR * 10000 + MINOR * 100 + MICRO). + E.g., "3.7.4" => 30704, "3.8" => 30800. + Return -1 on errors. */ static int str_to_version (char const *version) { @@ -3044,18 +3042,35 @@ str_to_version (char const *version) int res = 0; errno = 0; char *cp = NULL; - long major = strtol (version, &cp, 10); - if (errno || cp == version || *cp != '.' || major < 0 - || INT_MULTIPLY_WRAPV (major, 100, &res)) - return -1; - ++cp; - char *cp1 = NULL; - long minor = strtol (cp, &cp1, 10); - if (errno || cp1 == cp || (*cp1 != '\0' && *cp1 != '.') - || ! (0 <= minor && minor < 100) - || INT_ADD_WRAPV (minor, res, &res)) - return -1; + { + long major = strtol (version, &cp, 10); + if (errno || cp == version || *cp != '.' || major < 0 + || INT_MULTIPLY_WRAPV (major, 10000, &res)) + return -1; + } + + { + ++cp; + char *prev = cp; + long minor = strtol (cp, &cp, 10); + if (errno || cp == prev || (*cp != '\0' && *cp != '.') + || ! (0 <= minor && minor < 100) + || INT_MULTIPLY_WRAPV (minor, 100, &minor) + || INT_ADD_WRAPV (minor, res, &res)) + return -1; + } + + if (*cp == '.') + { + ++cp; + char *prev = cp; + long micro = strtol (cp, &cp, 10); + if (errno || cp == prev || (*cp != '\0' && *cp != '.') + || ! (0 <= micro && micro < 100) + || INT_ADD_WRAPV (micro, res, &res)) + return -1; + } IGNORE_TYPE_LIMITS_END return res; diff --git a/src/parse-gram.y b/src/parse-gram.y index 925e0773..dc776130 100644 --- a/src/parse-gram.y +++ b/src/parse-gram.y @@ -1043,11 +1043,9 @@ handle_pure_parser (location const *loc, char const *directive) } -/* Convert VERSION into an int (MAJOR * 100 + MINOR). Return -1 on - errors. - - Changes of behavior are only on minor version changes, so "3.0.5" - is the same as "3.0": 300. */ +/* Convert VERSION into an int (MAJOR * 10000 + MINOR * 100 + MICRO). + E.g., "3.7.4" => 30704, "3.8" => 30800. + Return -1 on errors. */ static int str_to_version (char const *version) { @@ -1055,18 +1053,35 @@ str_to_version (char const *version) int res = 0; errno = 0; char *cp = NULL; - long major = strtol (version, &cp, 10); - if (errno || cp == version || *cp != '.' || major < 0 - || INT_MULTIPLY_WRAPV (major, 100, &res)) - return -1; - ++cp; - char *cp1 = NULL; - long minor = strtol (cp, &cp1, 10); - if (errno || cp1 == cp || (*cp1 != '\0' && *cp1 != '.') - || ! (0 <= minor && minor < 100) - || INT_ADD_WRAPV (minor, res, &res)) - return -1; + { + long major = strtol (version, &cp, 10); + if (errno || cp == version || *cp != '.' || major < 0 + || INT_MULTIPLY_WRAPV (major, 10000, &res)) + return -1; + } + + { + ++cp; + char *prev = cp; + long minor = strtol (cp, &cp, 10); + if (errno || cp == prev || (*cp != '\0' && *cp != '.') + || ! (0 <= minor && minor < 100) + || INT_MULTIPLY_WRAPV (minor, 100, &minor) + || INT_ADD_WRAPV (minor, res, &res)) + return -1; + } + + if (*cp == '.') + { + ++cp; + char *prev = cp; + long micro = strtol (cp, &cp, 10); + if (errno || cp == prev || (*cp != '\0' && *cp != '.') + || ! (0 <= micro && micro < 100) + || INT_ADD_WRAPV (micro, res, &res)) + return -1; + } IGNORE_TYPE_LIMITS_END return res; From d8b49e2b7360aa805297e110e9adb4c0b7f2f956 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Wed, 11 Nov 2020 08:19:31 +0100 Subject: [PATCH 06/13] style: make conversion of version string to int public * src/parse-gram.y (str_to_version): Rename as/move to... * src/strversion.h, src/strversion.c (strversion_to_int): these new files. --- src/local.mk | 2 ++ src/parse-gram.y | 50 ++---------------------------------- src/strversion.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ src/strversion.h | 28 ++++++++++++++++++++ 4 files changed, 99 insertions(+), 48 deletions(-) create mode 100644 src/strversion.c create mode 100644 src/strversion.h diff --git a/src/local.mk b/src/local.mk index 32d09d10..08ff62be 100644 --- a/src/local.mk +++ b/src/local.mk @@ -103,6 +103,8 @@ src_bison_SOURCES = \ src/state.h \ src/state-item.c \ src/state-item.h \ + src/strversion.c \ + src/strversion.h \ src/symlist.c \ src/symlist.h \ src/symtab.c \ diff --git a/src/parse-gram.y b/src/parse-gram.y index dc776130..7c146ea3 100644 --- a/src/parse-gram.y +++ b/src/parse-gram.y @@ -42,8 +42,6 @@ #include "system.h" #include - #include - #include #include #include #include @@ -57,6 +55,7 @@ #include "reader.h" #include "scan-code.h" #include "scan-gram.h" + #include "strversion.h" /* Pretend to be at least that version, to check features published in that version while developping it. */ @@ -1043,56 +1042,11 @@ handle_pure_parser (location const *loc, char const *directive) } -/* Convert VERSION into an int (MAJOR * 10000 + MINOR * 100 + MICRO). - E.g., "3.7.4" => 30704, "3.8" => 30800. - Return -1 on errors. */ -static int -str_to_version (char const *version) -{ - IGNORE_TYPE_LIMITS_BEGIN - int res = 0; - errno = 0; - char *cp = NULL; - - { - long major = strtol (version, &cp, 10); - if (errno || cp == version || *cp != '.' || major < 0 - || INT_MULTIPLY_WRAPV (major, 10000, &res)) - return -1; - } - - { - ++cp; - char *prev = cp; - long minor = strtol (cp, &cp, 10); - if (errno || cp == prev || (*cp != '\0' && *cp != '.') - || ! (0 <= minor && minor < 100) - || INT_MULTIPLY_WRAPV (minor, 100, &minor) - || INT_ADD_WRAPV (minor, res, &res)) - return -1; - } - - if (*cp == '.') - { - ++cp; - char *prev = cp; - long micro = strtol (cp, &cp, 10); - if (errno || cp == prev || (*cp != '\0' && *cp != '.') - || ! (0 <= micro && micro < 100) - || INT_ADD_WRAPV (micro, res, &res)) - return -1; - } - - IGNORE_TYPE_LIMITS_END - return res; -} - - static void handle_require (location const *loc, char const *version_quoted) { char *version = unquote (version_quoted); - required_version = str_to_version (version); + required_version = strversion_to_int (version); if (required_version == -1) { complain (loc, complaint, _("invalid version requirement: %s"), diff --git a/src/strversion.c b/src/strversion.c new file mode 100644 index 00000000..27c71d34 --- /dev/null +++ b/src/strversion.c @@ -0,0 +1,67 @@ +/* Convert version string to int. + + Copyright (C) 2020 Free Software Foundation, Inc. + + This file is part of Bison, the GNU Compiler Compiler. + + 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 3 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, see . */ + +#include +#include "system.h" + +#include "strversion.h" + +#include +#include + +int +strversion_to_int (char const *version) +{ + IGNORE_TYPE_LIMITS_BEGIN + int res = 0; + errno = 0; + char *cp = NULL; + + { + long major = strtol (version, &cp, 10); + if (errno || cp == version || *cp != '.' || major < 0 + || INT_MULTIPLY_WRAPV (major, 10000, &res)) + return -1; + } + + { + ++cp; + char *prev = cp; + long minor = strtol (cp, &cp, 10); + if (errno || cp == prev || (*cp != '\0' && *cp != '.') + || ! (0 <= minor && minor < 100) + || INT_MULTIPLY_WRAPV (minor, 100, &minor) + || INT_ADD_WRAPV (minor, res, &res)) + return -1; + } + + if (*cp == '.') + { + ++cp; + char *prev = cp; + long micro = strtol (cp, &cp, 10); + if (errno || cp == prev || (*cp != '\0' && *cp != '.') + || ! (0 <= micro && micro < 100) + || INT_ADD_WRAPV (micro, res, &res)) + return -1; + } + + IGNORE_TYPE_LIMITS_END + return res; +} diff --git a/src/strversion.h b/src/strversion.h new file mode 100644 index 00000000..6d8d6235 --- /dev/null +++ b/src/strversion.h @@ -0,0 +1,28 @@ +/* Convert version string to int. + + Copyright (C) 2020 Free Software Foundation, Inc. + + This file is part of Bison, the GNU Compiler Compiler. + + 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 3 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, see . */ + +#ifndef STRVERSION_H_ +# define STRVERSION_H_ + +/* Convert VERSION into an int (MAJOR * 10000 + MINOR * 100 + MICRO). + E.g., "3.7.4" => 30704, "3.8" => 30800. + Return -1 on errors. */ +int strversion_to_int (char const *version); + +#endif From d3c575a6c6639a129d5ca84b60cc693fbd0cde68 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Wed, 11 Nov 2020 08:22:45 +0100 Subject: [PATCH 07/13] regen --- src/parse-gram.c | 80 ++++++++++-------------------------------------- src/parse-gram.h | 2 +- 2 files changed, 18 insertions(+), 64 deletions(-) diff --git a/src/parse-gram.c b/src/parse-gram.c index 917fb35a..441fc97b 100644 --- a/src/parse-gram.c +++ b/src/parse-gram.c @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.7.14-eb26-dirty. */ +/* A Bison parser, made by GNU Bison 3.7.3.7-d831b. */ /* Bison implementation for Yacc-like parsers in C @@ -49,7 +49,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.7.14-eb26-dirty" +#define YYBISON_VERSION "3.7.3.7-d831b" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -218,8 +218,6 @@ typedef enum yysymbol_kind_t yysymbol_kind_t; #include "system.h" #include - #include - #include #include #include #include @@ -233,6 +231,7 @@ typedef enum yysymbol_kind_t yysymbol_kind_t; #include "reader.h" #include "scan-code.h" #include "scan-gram.h" + #include "strversion.h" /* Pretend to be at least that version, to check features published in that version while developping it. */ @@ -639,19 +638,19 @@ union yyalloc /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { - 0, 312, 312, 321, 322, 326, 327, 333, 337, 342, - 343, 344, 345, 346, 347, 348, 353, 358, 359, 360, - 361, 362, 363, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 375, 376, 385, 386, 390, 401, 405, 409, - 417, 427, 428, 438, 439, 445, 458, 458, 463, 463, - 468, 472, 482, 483, 484, 485, 489, 490, 495, 496, - 500, 501, 505, 506, 507, 520, 529, 533, 537, 545, - 546, 550, 563, 564, 569, 570, 571, 589, 593, 597, - 605, 607, 612, 619, 629, 633, 637, 645, 650, 662, - 663, 669, 670, 671, 678, 678, 686, 687, 688, 693, - 696, 698, 700, 702, 704, 706, 708, 710, 712, 717, - 718, 727, 751, 752, 753, 754, 766, 768, 792, 797, - 798, 803, 811, 812 + 0, 311, 311, 320, 321, 325, 326, 332, 336, 341, + 342, 343, 344, 345, 346, 347, 352, 357, 358, 359, + 360, 361, 362, 362, 363, 364, 365, 366, 367, 368, + 369, 370, 374, 375, 384, 385, 389, 400, 404, 408, + 416, 426, 427, 437, 438, 444, 457, 457, 462, 462, + 467, 471, 481, 482, 483, 484, 488, 489, 494, 495, + 499, 500, 504, 505, 506, 519, 528, 532, 536, 544, + 545, 549, 562, 563, 568, 569, 570, 588, 592, 596, + 604, 606, 611, 618, 628, 632, 636, 644, 649, 661, + 662, 668, 669, 670, 677, 677, 685, 686, 687, 692, + 695, 697, 699, 701, 703, 705, 707, 709, 711, 716, + 717, 726, 750, 751, 752, 753, 765, 767, 791, 796, + 797, 802, 810, 811 }; #endif @@ -3032,56 +3031,11 @@ handle_pure_parser (location const *loc, char const *directive) } -/* Convert VERSION into an int (MAJOR * 10000 + MINOR * 100 + MICRO). - E.g., "3.7.4" => 30704, "3.8" => 30800. - Return -1 on errors. */ -static int -str_to_version (char const *version) -{ - IGNORE_TYPE_LIMITS_BEGIN - int res = 0; - errno = 0; - char *cp = NULL; - - { - long major = strtol (version, &cp, 10); - if (errno || cp == version || *cp != '.' || major < 0 - || INT_MULTIPLY_WRAPV (major, 10000, &res)) - return -1; - } - - { - ++cp; - char *prev = cp; - long minor = strtol (cp, &cp, 10); - if (errno || cp == prev || (*cp != '\0' && *cp != '.') - || ! (0 <= minor && minor < 100) - || INT_MULTIPLY_WRAPV (minor, 100, &minor) - || INT_ADD_WRAPV (minor, res, &res)) - return -1; - } - - if (*cp == '.') - { - ++cp; - char *prev = cp; - long micro = strtol (cp, &cp, 10); - if (errno || cp == prev || (*cp != '\0' && *cp != '.') - || ! (0 <= micro && micro < 100) - || INT_ADD_WRAPV (micro, res, &res)) - return -1; - } - - IGNORE_TYPE_LIMITS_END - return res; -} - - static void handle_require (location const *loc, char const *version_quoted) { char *version = unquote (version_quoted); - required_version = str_to_version (version); + required_version = strversion_to_int (version); if (required_version == -1) { complain (loc, complaint, _("invalid version requirement: %s"), diff --git a/src/parse-gram.h b/src/parse-gram.h index 0cca9342..ad4534ff 100644 --- a/src/parse-gram.h +++ b/src/parse-gram.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.7.14-eb26-dirty. */ +/* A Bison parser, made by GNU Bison 3.7.3.7-d831b. */ /* Bison interface for Yacc-like parsers in C From 21c147b6e5372563b7c4741deadaddb9354f4b09 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Wed, 11 Nov 2020 08:42:16 +0100 Subject: [PATCH 08/13] yacc.c: provide the Bison version as an integral macro Suggested by Balazs Scheidler. https://github.com/akimd/bison/issues/55 * src/muscle-tab.c (muscle_init): Move/rename `b4_version` to/as... * src/output.c (prepare): `b4_version_string`. Also define `b4_version`. * data/skeletons/bison.m4, data/skeletons/c.m4, data/skeletons/d.m4, * data/skeletons/java.m4: Adjust. * doc/bison.texi: Document it. --- NEWS | 6 ++++++ data/skeletons/bison.m4 | 2 +- data/skeletons/c.m4 | 8 ++++---- data/skeletons/d.m4 | 8 ++++---- data/skeletons/java.m4 | 8 ++++---- doc/bison.texi | 6 ++++++ src/muscle-tab.c | 3 --- src/output.c | 4 ++++ src/parse-gram.c | 2 +- 9 files changed, 30 insertions(+), 17 deletions(-) diff --git a/NEWS b/NEWS index 399d560d..ebb3354a 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,12 @@ GNU Bison NEWS In Yacc mode, all the tokens are defined twice: once as an enum, and then as a macro. YYEMPTY was missing its macro. +** Changes + + The YYBISON macro in generated "regular C parsers" (from the "yacc.c" + skeleton) used to be defined to 1. It is now defined to the version of + Bison as an integer (e.g., 30704 for version 3.7.4). + * Noteworthy changes in release 3.7.3 (2020-10-13) [stable] ** Bug fixes diff --git a/data/skeletons/bison.m4 b/data/skeletons/bison.m4 index 8c5fbdf5..365ee72e 100644 --- a/data/skeletons/bison.m4 +++ b/data/skeletons/bison.m4 @@ -49,7 +49,7 @@ m4_define([m4_shift4], [m4_shift(m4_shift(m4_shift(m4_shift($@))))]) # b4_generated_by # --------------- m4_define([b4_generated_by], -[b4_comment([A Bison parser, made by GNU Bison b4_version.]) +[b4_comment([A Bison parser, made by GNU Bison b4_version_string.]) ]) # b4_copyright(TITLE, [YEARS]) diff --git a/data/skeletons/c.m4 b/data/skeletons/c.m4 index c8689038..07148ef8 100644 --- a/data/skeletons/c.m4 +++ b/data/skeletons/c.m4 @@ -58,11 +58,11 @@ m4_define([b4_cpp_guard_close], # b4_pull_flag if they use the values of the %define variables api.pure or # api.push-pull. m4_define([b4_identification], -[[/* Identify Bison output. */ -#define YYBISON 1 +[[/* Identify Bison output, and Bison version. */ +#define YYBISON ]b4_version[ -/* Bison version. */ -#define YYBISON_VERSION "]b4_version[" +/* Bison version string. */ +#define YYBISON_VERSION "]b4_version_string[" /* Skeleton name. */ #define YYSKELETON_NAME ]b4_skeleton[]m4_ifdef([b4_pure_flag], [[ diff --git a/data/skeletons/d.m4 b/data/skeletons/d.m4 index edb0c49e..0c283519 100644 --- a/data/skeletons/d.m4 +++ b/data/skeletons/d.m4 @@ -103,12 +103,12 @@ m4_define([b4_location_type_if], # b4_identification # ----------------- m4_define([b4_identification], -[/** Version number for the Bison executable that generated this parser. */ - public static immutable string yy_bison_version = "b4_version"; +[[/** Version number for the Bison executable that generated this parser. */ + public static immutable string yy_bison_version = "]b4_version_string["; /** Name of the skeleton that generated this parser. */ - public static immutable string yy_bison_skeleton = b4_skeleton; -]) + public static immutable string yy_bison_skeleton = ]b4_skeleton[; +]]) ## ------------ ## diff --git a/data/skeletons/java.m4 b/data/skeletons/java.m4 index e4e2fad8..7b4f7b5c 100644 --- a/data/skeletons/java.m4 +++ b/data/skeletons/java.m4 @@ -71,12 +71,12 @@ m4_define([b4_lexer_if], # b4_identification # ----------------- m4_define([b4_identification], -[ /** Version number for the Bison executable that generated this parser. */ - public static final String bisonVersion = "b4_version"; +[[ /** Version number for the Bison executable that generated this parser. */ + public static final String bisonVersion = "]b4_version_string["; /** Name of the skeleton that generated this parser. */ - public static final String bisonSkeleton = b4_skeleton; -]) + public static final String bisonSkeleton = ]b4_skeleton[; +]]) ## ------------ ## diff --git a/doc/bison.texi b/doc/bison.texi index 416a8ec6..d38801db 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -15434,6 +15434,12 @@ Macro to discard a value from the parser stack and fake a lookahead token. @xref{Action Features}. @end deffn +@deffn {Macro} YYBISON +The version of Bison as an integer, for instance 30704 for version 3.7.4. +Defined in @file{yacc.c} only. Before version 3.7.4, @code{YYBISON} was +defined to 1. +@end deffn + @deffn {Variable} yychar External integer variable that contains the integer value of the lookahead token. (In a pure parser, it is a local variable within diff --git a/src/muscle-tab.c b/src/muscle-tab.c index 9d1c266e..c0c66690 100644 --- a/src/muscle-tab.c +++ b/src/muscle-tab.c @@ -127,9 +127,6 @@ muscle_init (void) muscle_table = hash_xinitialize (HT_INITIAL_CAPACITY, NULL, hash_muscle, hash_compare_muscles, muscle_entry_free); - - /* Version and input file. */ - MUSCLE_INSERT_STRING ("version", VERSION); } diff --git a/src/output.c b/src/output.c index d550c470..753b1bd7 100644 --- a/src/output.c +++ b/src/output.c @@ -42,6 +42,7 @@ #include "scan-skel.h" #include "symtab.h" #include "tables.h" +#include "strversion.h" static struct obstack format_obstack; @@ -807,6 +808,9 @@ prepare (void) char const *cp = getenv ("BISON_USE_PUSH_FOR_PULL"); bool use_push_for_pull_flag = cp && *cp && strtol (cp, 0, 10); + /* Versions. */ + MUSCLE_INSERT_STRING ("version_string", VERSION); + MUSCLE_INSERT_INT ("version", strversion_to_int (VERSION)); MUSCLE_INSERT_INT ("required_version", required_version); /* Flags. */ diff --git a/src/parse-gram.c b/src/parse-gram.c index 441fc97b..cfca03b5 100644 --- a/src/parse-gram.c +++ b/src/parse-gram.c @@ -46,7 +46,7 @@ USER NAME SPACE" below. */ /* Identify Bison output. */ -#define YYBISON 1 +#define YYBISON 30703 /* Bison version. */ #define YYBISON_VERSION "3.7.3.7-d831b" From fe8c36ddcafdb6b49059fb023970cca8d2ca589a Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Wed, 11 Nov 2020 09:27:53 +0100 Subject: [PATCH 09/13] c++: style: follow the Bison m4 quoting pattern * data/skeletons/variant.hh: here. --- data/skeletons/variant.hh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/data/skeletons/variant.hh b/data/skeletons/variant.hh index c37bdd42..736a2677 100644 --- a/data/skeletons/variant.hh +++ b/data/skeletons/variant.hh @@ -133,10 +133,10 @@ m4_define([b4_value_type_declare], template T& emplace (U&&... u) - {]b4_parse_assert_if([ + {]b4_parse_assert_if([[ YY_ASSERT (!yytypeid_); YY_ASSERT (sizeof (T) <= size); - yytypeid_ = & typeid (T);])[ + yytypeid_ = & typeid (T);]])[ return *new (yyas_ ()) T (std::forward (u)...); } # else @@ -144,10 +144,10 @@ m4_define([b4_value_type_declare], template T& emplace () - {]b4_parse_assert_if([ + {]b4_parse_assert_if([[ YY_ASSERT (!yytypeid_); YY_ASSERT (sizeof (T) <= size); - yytypeid_ = & typeid (T);])[ + yytypeid_ = & typeid (T);]])[ return *new (yyas_ ()) T (); } @@ -155,10 +155,10 @@ m4_define([b4_value_type_declare], template T& emplace (const T& t) - {]b4_parse_assert_if([ + {]b4_parse_assert_if([[ YY_ASSERT (!yytypeid_); YY_ASSERT (sizeof (T) <= size); - yytypeid_ = & typeid (T);])[ + yytypeid_ = & typeid (T);]])[ return *new (yyas_ ()) T (t); } # endif @@ -185,10 +185,10 @@ m4_define([b4_value_type_declare], template T& as () YY_NOEXCEPT - {]b4_parse_assert_if([ + {]b4_parse_assert_if([[ YY_ASSERT (yytypeid_); YY_ASSERT (*yytypeid_ == typeid (T)); - YY_ASSERT (sizeof (T) <= size);])[ + YY_ASSERT (sizeof (T) <= size);]])[ return *yyas_ (); } @@ -196,10 +196,10 @@ m4_define([b4_value_type_declare], template const T& as () const YY_NOEXCEPT - {]b4_parse_assert_if([ + {]b4_parse_assert_if([[ YY_ASSERT (yytypeid_); YY_ASSERT (*yytypeid_ == typeid (T)); - YY_ASSERT (sizeof (T) <= size);])[ + YY_ASSERT (sizeof (T) <= size);]])[ return *yyas_ (); } @@ -214,9 +214,9 @@ m4_define([b4_value_type_declare], template void swap (self_type& that) YY_NOEXCEPT - {]b4_parse_assert_if([ + {]b4_parse_assert_if([[ YY_ASSERT (yytypeid_); - YY_ASSERT (*yytypeid_ == *that.yytypeid_);])[ + YY_ASSERT (*yytypeid_ == *that.yytypeid_);]])[ std::swap (as (), that.as ()); } From f4431ea11541ebb6a0f4d6cec8f120bd0639dd4a Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Wed, 11 Nov 2020 09:28:32 +0100 Subject: [PATCH 10/13] c++: don't use YY_ASSERT at all if parse.assert is disabled In some extreme situations (about 800 tokens), we generate a single-line assertion long enough for Visual C++ to discard the end of the line, thus falling into parse ends for the missing `);`. On a shorter example: YY_ASSERT (tok == token::TOK_YYEOF || tok == token::TOK_YYerror || tok == token::TOK_YYUNDEF || tok == token::TOK_ASSIGN || tok == token::TOK_MINUS || tok == token::TOK_PLUS || tok == token::TOK_STAR || tok == token::TOK_SLASH || tok == token::TOK_LPAREN || tok == token::TOK_RPAREN); Whether NDEBUG is used or not is irrelevant, the parser dies anyway. Reported by Jot Dot . https://lists.gnu.org/r/bug-bison/2020-11/msg00002.html We should avoid emitting lines so long. We probably should also use a range-based assertion (with extraneous parens to pacify fascist compilers): YY_ASSERT ((token::TOK_YYEOF <= tok && tok <= token::TOK_YYUNDEF) || (token::TOK_ASSIGN <= tok && ...) But anyway, we should simply not emit this assertion at all when not asked for. * data/skeletons/variant.hh: Do not define, nor use, YY_ASSERT when it is not enabled. --- NEWS | 8 ++++++++ data/skeletons/variant.hh | 17 +++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index ebb3354a..c5775a69 100644 --- a/NEWS +++ b/NEWS @@ -4,9 +4,17 @@ GNU Bison NEWS ** Bug fixes +*** Bug fixes in yacc.c + In Yacc mode, all the tokens are defined twice: once as an enum, and then as a macro. YYEMPTY was missing its macro. +*** Bug fixes in lalr1.cc + + The lalr1.cc skeleton used to emit internal assertions (using YY_ASSERT) + even when the `parse.assert` %define variable is not enabled. It no + longer does. + ** Changes The YYBISON macro in generated "regular C parsers" (from the "yacc.c" diff --git a/data/skeletons/variant.hh b/data/skeletons/variant.hh index 736a2677..1fe40145 100644 --- a/data/skeletons/variant.hh +++ b/data/skeletons/variant.hh @@ -71,12 +71,12 @@ m4_map([ b4_symbol_tag_comment], [$@])dnl # ------------------- # The needed includes for variants support. m4_define([b4_variant_includes], -[b4_parse_assert_if([[#include ]])[ +[b4_parse_assert_if([[#include #ifndef YY_ASSERT # include # define YY_ASSERT assert #endif -]]) +]])]) @@ -110,8 +110,8 @@ m4_define([b4_value_type_declare], template semantic_type (YY_RVREF (T) t)]b4_parse_assert_if([ : yytypeid_ (&typeid (T))])[ - { - YY_ASSERT (sizeof (T) <= size); + {]b4_parse_assert_if([[ + YY_ASSERT (sizeof (T) <= size);]])[ new (yyas_ ()) T (YY_MOVE (t)); } @@ -410,9 +410,6 @@ m4_define([_b4_token_constructor_define], : super_type(]b4_join([token_type (tok)], b4_symbol_if([$1], [has_type], [std::move (v)]), b4_locations_if([std::move (l)]))[) - { - YY_ASSERT (]m4_join([ || ], m4_map_sep([_b4_type_clause], [, ], [$@]))[); - } #else symbol_type (]b4_join( [int tok], @@ -422,10 +419,10 @@ m4_define([_b4_token_constructor_define], : super_type(]b4_join([token_type (tok)], b4_symbol_if([$1], [has_type], [v]), b4_locations_if([l]))[) - { - YY_ASSERT (]m4_join([ || ], m4_map_sep([_b4_type_clause], [, ], [$@]))[); - } #endif + {]b4_parse_assert_if([[ + YY_ASSERT (]m4_join([ || ], m4_map_sep([_b4_type_clause], [, ], [$@]))[); + ]])[} ]])]) From 8b424b865e7fc1932131beff5298dfde0623ce28 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Wed, 11 Nov 2020 11:39:02 +0100 Subject: [PATCH 11/13] lalr1.cc: YY_ASSERT should use api.prefix Working on the previous commit I realized that YY_ASSERT was used in the generated headers, so must follow api.prefix to avoid clashes when multiple C++ parser with variants are used. Actually many more macros should obey api.prefix (YY_CPLUSPLUS, YY_COPY, etc.). There was no complaint so far, so it's not urgent enough for 3.7.4, but it should be addressed in 3.8. * data/skeletons/variant.hh (b4_assert): New. Use it. * tests/local.at (AT_YYLEX_RETURN): Fix. * tests/headers.at: Make sure variant-based C++ parsers are checked too. This test did find that YY_ASSERT escaped renaming (before the fix in this commit). --- NEWS | 3 +++ data/skeletons/variant.hh | 45 ++++++++++++++++++++++----------------- tests/headers.at | 36 +++++++++++++++++++++++-------- tests/local.at | 2 +- 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/NEWS b/NEWS index c5775a69..8bdad6a6 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,9 @@ GNU Bison NEWS even when the `parse.assert` %define variable is not enabled. It no longer does. + The private internal macro YY_ASSERT now obeys the `api.prefix` %define + variable. + ** Changes The YYBISON macro in generated "regular C parsers" (from the "yacc.c" diff --git a/data/skeletons/variant.hh b/data/skeletons/variant.hh index 1fe40145..4734079b 100644 --- a/data/skeletons/variant.hh +++ b/data/skeletons/variant.hh @@ -20,6 +20,13 @@ ## variant. ## ## --------- ## +# b4_assert +# --------- +# The name of YY_ASSERT. +m4_define([b4_assert], + [b4_api_PREFIX[]_ASSERT]) + + # b4_symbol_variant(YYTYPE, YYVAL, ACTION, [ARGS]) # ------------------------------------------------ # Run some ACTION ("build", or "destroy") on YYVAL of symbol type @@ -72,9 +79,9 @@ m4_map([ b4_symbol_tag_comment], [$@])dnl # The needed includes for variants support. m4_define([b4_variant_includes], [b4_parse_assert_if([[#include -#ifndef YY_ASSERT +#ifndef ]b4_assert[ # include -# define YY_ASSERT assert +# define ]b4_assert[ assert #endif ]])]) @@ -111,7 +118,7 @@ m4_define([b4_value_type_declare], semantic_type (YY_RVREF (T) t)]b4_parse_assert_if([ : yytypeid_ (&typeid (T))])[ {]b4_parse_assert_if([[ - YY_ASSERT (sizeof (T) <= size);]])[ + ]b4_assert[ (sizeof (T) <= size);]])[ new (yyas_ ()) T (YY_MOVE (t)); } @@ -125,7 +132,7 @@ m4_define([b4_value_type_declare], /// Destruction, allowed only if empty. ~semantic_type () YY_NOEXCEPT {]b4_parse_assert_if([ - YY_ASSERT (!yytypeid_); + ]b4_assert[ (!yytypeid_); ])[} # if 201103L <= YY_CPLUSPLUS @@ -134,8 +141,8 @@ m4_define([b4_value_type_declare], T& emplace (U&&... u) {]b4_parse_assert_if([[ - YY_ASSERT (!yytypeid_); - YY_ASSERT (sizeof (T) <= size); + ]b4_assert[ (!yytypeid_); + ]b4_assert[ (sizeof (T) <= size); yytypeid_ = & typeid (T);]])[ return *new (yyas_ ()) T (std::forward (u)...); } @@ -145,8 +152,8 @@ m4_define([b4_value_type_declare], T& emplace () {]b4_parse_assert_if([[ - YY_ASSERT (!yytypeid_); - YY_ASSERT (sizeof (T) <= size); + ]b4_assert[ (!yytypeid_); + ]b4_assert[ (sizeof (T) <= size); yytypeid_ = & typeid (T);]])[ return *new (yyas_ ()) T (); } @@ -156,8 +163,8 @@ m4_define([b4_value_type_declare], T& emplace (const T& t) {]b4_parse_assert_if([[ - YY_ASSERT (!yytypeid_); - YY_ASSERT (sizeof (T) <= size); + ]b4_assert[ (!yytypeid_); + ]b4_assert[ (sizeof (T) <= size); yytypeid_ = & typeid (T);]])[ return *new (yyas_ ()) T (t); } @@ -186,9 +193,9 @@ m4_define([b4_value_type_declare], T& as () YY_NOEXCEPT {]b4_parse_assert_if([[ - YY_ASSERT (yytypeid_); - YY_ASSERT (*yytypeid_ == typeid (T)); - YY_ASSERT (sizeof (T) <= size);]])[ + ]b4_assert[ (yytypeid_); + ]b4_assert[ (*yytypeid_ == typeid (T)); + ]b4_assert[ (sizeof (T) <= size);]])[ return *yyas_ (); } @@ -197,9 +204,9 @@ m4_define([b4_value_type_declare], const T& as () const YY_NOEXCEPT {]b4_parse_assert_if([[ - YY_ASSERT (yytypeid_); - YY_ASSERT (*yytypeid_ == typeid (T)); - YY_ASSERT (sizeof (T) <= size);]])[ + ]b4_assert[ (yytypeid_); + ]b4_assert[ (*yytypeid_ == typeid (T)); + ]b4_assert[ (sizeof (T) <= size);]])[ return *yyas_ (); } @@ -215,8 +222,8 @@ m4_define([b4_value_type_declare], void swap (self_type& that) YY_NOEXCEPT {]b4_parse_assert_if([[ - YY_ASSERT (yytypeid_); - YY_ASSERT (*yytypeid_ == *that.yytypeid_);]])[ + ]b4_assert[ (yytypeid_); + ]b4_assert[ (*yytypeid_ == *that.yytypeid_);]])[ std::swap (as (), that.as ()); } @@ -421,7 +428,7 @@ m4_define([_b4_token_constructor_define], b4_locations_if([l]))[) #endif {]b4_parse_assert_if([[ - YY_ASSERT (]m4_join([ || ], m4_map_sep([_b4_type_clause], [, ], [$@]))[); + ]b4_assert[ (]m4_join([ || ], m4_map_sep([_b4_type_clause], [, ], [$@]))[); ]])[} ]])]) diff --git a/tests/headers.at b/tests/headers.at index bf48120b..73a43454 100644 --- a/tests/headers.at +++ b/tests/headers.at @@ -204,17 +204,20 @@ AT_SETUP([Several parsers]) # Generate and compile to *.o. Make sure there is no (allowed) YY* # nor yy* identifiers in the header after applying api.prefix. Check # that headers can be compiled by a C++ compiler. +# +# They should all use parse.assert to make sure that we don't even +# conflict of YY_ASSERT. m4_pushdef([AT_TEST], -[AT_BISON_OPTION_PUSHDEFS([%define api.prefix {$1_} $2]) +[AT_BISON_OPTION_PUSHDEFS([%define api.prefix {$1_} %define parse.assert $2]) AT_DATA_GRAMMAR([$1.y], [[%define api.prefix {$1_} +%define parse.assert $2 %define parse.error verbose -%union -{ - int integer; -} -%{ +]AT_VARIANT_IF([], +[%union {int integer;}])[ + +%code { #include /* printf. */ ]AT_PUSH_IF([[ #if defined __GNUC__ && (7 == __GNUC__ || 9 == __GNUC__) @@ -223,8 +226,10 @@ $2 ]])[ ]AT_YYERROR_DECLARE[ ]AT_YYLEX_DECLARE[ -%} +} + %% + exp: 'x' '1' { printf ("x1\n"); } | 'x' '2' { printf ("x2\n"); } @@ -235,9 +240,12 @@ exp: | 'x' '7' { printf ("x7\n"); } | 'x' '8' { printf ("x8\n"); } | 'x' '9' { printf ("x9\n"); } +| 'x' 'a' { printf ("xa\n"); } +| 'x' 'b' { printf ("xb\n"); } ; %% + ]AT_YYERROR_DEFINE[ ]AT_YYLEX_DEFINE(["$1"])[ ]]) @@ -270,6 +278,8 @@ extern "C" #endif #include "x5.hh" #include "x9.hh" +#include "xa.hh" +#include "xb.hh" #define RUN(S) \ do { \ @@ -292,6 +302,10 @@ main (void) RUN(x8_parse()); x9_::parser p9; RUN(p9.parse()); + xa_::parser pa; + RUN(pa.parse()); + xb_::parser pb; + RUN(pb.parse()); return 0; } ]])# main.cc @@ -304,7 +318,9 @@ AT_TEST([x5], [%locations %debug %language "c++"]) AT_TEST([x6], [%define api.pure]) AT_TEST([x7], [%define api.push-pull both]) AT_TEST([x8], [%define api.pure %define api.push-pull both]) -AT_TEST([x9], [%locations %code requires {#include "location.hh"} %define api.location.type {x5_::location} %debug %language "c++"]) +AT_TEST([x9], [%locations %code requires {#include "location.hh"} %define api.location.type {::x5_::location} %debug %language "c++"]) +AT_TEST([xa], [%locations %code requires {#include "location.hh"} %define api.location.type {::x5_::location} %language "c++" %define api.value.type variant]) +AT_TEST([xb], [%locations %define api.location.file none %language "c++" %define api.value.type variant]) #AT_TEST([x5], [%locations %language "c++" %glr-parser]) # Check that api.prefix works properly: @@ -340,6 +356,8 @@ AT_PERL_CHECK([[-n -0777 -e ' |YY_NULLPTR |YY_RVREF |YY_\w+_INCLUDED + |FILE\ \*yyo # Function argument. + |const\ yylocp # Function argument. )\b}{}gx; while (/^(.*YY.*)$/gm) { @@ -357,7 +375,7 @@ AT_PERL_CHECK([[-n -0777 -e ' # Do this late, so that other checks have been performed. AT_SKIP_IF_CANNOT_LINK_C_AND_CXX -AT_COMPILE_CXX([parser], [[x[1-9].o -DCC_IS_CXX=$CC_IS_CXX main.cc]]) +AT_COMPILE_CXX([parser], [[x[1-9a-b].o -DCC_IS_CXX=$CC_IS_CXX main.cc]]) AT_PARSER_CHECK([parser], [0], [[expout]]) m4_popdef([AT_TEST]) diff --git a/tests/local.at b/tests/local.at index a4782362..91e1e734 100644 --- a/tests/local.at +++ b/tests/local.at @@ -351,7 +351,7 @@ AT_TOKEN_CTOR_IF( [m4_pushdef([AT_LOC], [[(]AT_NAME_PREFIX[lloc)]]) m4_pushdef([AT_VAL], [[(]AT_NAME_PREFIX[lval)]]) m4_pushdef([AT_YYLEX_FORMALS], []) - m4_pushdef([AT_YYLEX_RETURN], [yy::parser::symbol_type]) + m4_pushdef([AT_YYLEX_RETURN], [AT_NAMESPACE::parser::symbol_type]) m4_pushdef([AT_YYLEX_ARGS], []) m4_pushdef([AT_USE_LEX_ARGS], []) m4_pushdef([AT_YYLEX_PRE_FORMALS], []) From 0264b4bca071cfac10a8909f30e0e5aa422b35d6 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Wed, 11 Nov 2020 15:21:55 +0100 Subject: [PATCH 12/13] c++: don't glue functions together * data/skeletons/bison.m4 (b4_type_foreach): Accept a separator. * data/skeletons/c++.m4: Use it. And fix an incorrect comment. --- data/skeletons/bison.m4 | 6 +++--- data/skeletons/c++.m4 | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/data/skeletons/bison.m4 b/data/skeletons/bison.m4 index 365ee72e..7ab1cb91 100644 --- a/data/skeletons/bison.m4 +++ b/data/skeletons/bison.m4 @@ -633,11 +633,11 @@ m4_define([_b4_type_action], ])]) -# b4_type_foreach(MACRO) -# ---------------------- +# b4_type_foreach(MACRO, [SEP]) +# ----------------------------- # Invoke MACRO(SYMBOL-NUMS) for each set of SYMBOL-NUMS for each type set. m4_define([b4_type_foreach], - [m4_map([$1], m4_defn([b4_type_names]))]) + [m4_map_sep([$1], [$2], m4_defn([b4_type_names]))]) diff --git a/data/skeletons/c++.m4 b/data/skeletons/c++.m4 index b7a2a3a8..78c66def 100644 --- a/data/skeletons/c++.m4 +++ b/data/skeletons/c++.m4 @@ -321,8 +321,9 @@ m4_define([b4_symbol_type_define], /// Copy constructor. basic_symbol (const basic_symbol& that);]b4_variant_if([[ - /// Constructor for valueless symbols, and symbols from each type. -]b4_type_foreach([b4_basic_symbol_constructor_define])], [[ + /// Constructors for typed symbols. +]b4_type_foreach([b4_basic_symbol_constructor_define], [ +])], [[ /// Constructor for valueless symbols. basic_symbol (typename Base::kind_type t]b4_locations_if([, YY_MOVE_REF (location_type) l])[); From d8cc6b073e2802d871a16dc62418a7eb62ed2216 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Wed, 11 Nov 2020 13:29:47 +0100 Subject: [PATCH 13/13] c++: shorten the assertions that check whether tokens are correct Before: YY_ASSERT (tok == token::YYEOF || tok == token::YYerror || tok == token::YYUNDEF || tok == 120 || tok == 49 || tok == 50 || tok == 51 || tok == 52 || tok == 53 || tok == 54 || tok == 55 || tok == 56 || tok == 57 || tok == 97 || tok == 98); After: YY_ASSERT (tok == token::YYEOF || (token::YYerror <= tok && tok <= token::YYUNDEF) || tok == 120 || (49 <= tok && tok <= 57) || (97 <= tok && tok <= 98)); Clauses are now also wrapped on several lines. This is nicer to read and diff, but also avoids pushing Visual C++ to its arbitrary limits (640K and lines of 16380 bytes ought to be enough for anybody, otherwise make an C2026 error). The useless parens are there for the dummy warnings about precedence (in the future, will we also have to put parens in `1+2*3`?). * data/skeletons/variant.hh (_b4_filter_tokens, b4_tok_in, b4_tok_in): New. (_b4_token_constructor_define): Use them. --- NEWS | 4 +++ data/skeletons/variant.hh | 68 +++++++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 8bdad6a6..27076634 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,10 @@ GNU Bison NEWS The private internal macro YY_ASSERT now obeys the `api.prefix` %define variable. + When there is a very large number of tokens, some assertions could be long + enough to hit arbitrary limits in Visual C++. They have been rewritten to + work around this limitation. + ** Changes The YYBISON macro in generated "regular C parsers" (from the "yacc.c" diff --git a/data/skeletons/variant.hh b/data/skeletons/variant.hh index 4734079b..2887ba61 100644 --- a/data/skeletons/variant.hh +++ b/data/skeletons/variant.hh @@ -395,11 +395,67 @@ m4_define([_b4_token_maker_define], ])]) -m4_define([_b4_type_clause], -[b4_symbol_if([$1], [is_token], - [b4_symbol_if([$1], [has_id], - [tok == token::b4_symbol([$1], [id])], - [tok == b4_symbol([$1], [code])])])]) +# b4_token_kind(SYMBOL-NUM) +# ------------------------- +# Some tokens don't have an ID. +m4_define([b4_token_kind], +[b4_symbol_if([$1], [has_id], + [token::b4_symbol([$1], [id])], + [b4_symbol([$1], [code])])]) + + +# _b4_tok_in(SYMBOL-NUM, ...) +# --------------------------- +# See b4_tok_in below. The SYMBOL-NUMs... are tokens only. +# +# We iterate over the tokens to group them by "range" of token numbers (not +# symbols numbers!). +# +# b4_fst is the start of that range. +# b4_prev is the previous value. +# b4_val is the current value. +# If b4_val is the successor of b4_prev in token numbers, update the latter, +# otherwise emit the code for range b4_fst .. b4_prev. +# $1 is also used as a terminator in the foreach, but it will not be printed. +# +m4_define([_b4_tok_in], +[m4_pushdef([b4_prev], [$1])dnl +m4_pushdef([b4_fst], [$1])dnl +m4_pushdef([b4_sep], [])dnl +m4_foreach([b4_val], m4_dquote(m4_shift($@, $1)), + [m4_if(b4_symbol(b4_val, [code]), m4_eval(b4_symbol(b4_prev, [code]) + 1), [], + [b4_sep[]m4_if(b4_fst, b4_prev, + [tok == b4_token_kind(b4_fst)], + [(b4_token_kind(b4_fst) <= tok && tok <= b4_token_kind(b4_prev))])[]dnl +m4_define([b4_fst], b4_val)dnl +m4_define([b4_sep], [ + || ])])dnl +m4_define([b4_prev], b4_val)])dnl +m4_popdef([b4_sep])dnl +m4_popdef([b4_fst])dnl +m4_popdef([b4_prev])dnl +]) + + +# _b4_filter_tokens(SYMBOL-NUM, ...) +# ---------------------------------- +# Expand as the list of tokens amongst SYMBOL-NUM. +m4_define([_b4_filter_tokens], +[m4_pushdef([b4_sep])dnl +m4_foreach([b4_val], [$@], + [b4_symbol_if(b4_val, [is_token], [b4_sep[]b4_val[]m4_define([b4_sep], [,])])])dnl +m4_popdef([b4_sep])dnl +]) + + +# b4_tok_in(SYMBOL-NUM, ...) +# --------------------------- +# A C++ conditional that checks that `tok` is a member of this list of symbol +# numbers. +m4_define([b4_tok_in], + [_$0(_b4_filter_tokens($@))]) + + # _b4_token_constructor_define(SYMBOL-NUM...) @@ -428,7 +484,7 @@ m4_define([_b4_token_constructor_define], b4_locations_if([l]))[) #endif {]b4_parse_assert_if([[ - ]b4_assert[ (]m4_join([ || ], m4_map_sep([_b4_type_clause], [, ], [$@]))[); + ]b4_assert[ (]b4_tok_in($@)[); ]])[} ]])])