diff --git a/NEWS b/NEWS index f2c3a86d..678cb528 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,33 @@ GNU Bison NEWS The Java skeleton (lalr1.java) now supports LAC, via the %define variable parse.lac. +* Noteworthy changes in release ?.? (????-??-??) [?] + +** 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. + + 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" + 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] diff --git a/data/skeletons/bison.m4 b/data/skeletons/bison.m4 index c9df0e02..7f9fb80a 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]) @@ -651,11 +651,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 931e220a..f4834c64 100644 --- a/data/skeletons/c++.m4 +++ b/data/skeletons/c++.m4 @@ -320,8 +320,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])[); diff --git a/data/skeletons/c.m4 b/data/skeletons/c.m4 index eddc76a2..3693e469 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], [[ @@ -520,10 +520,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) diff --git a/data/skeletons/d.m4 b/data/skeletons/d.m4 index 8d454d1c..7a501678 100644 --- a/data/skeletons/d.m4 +++ b/data/skeletons/d.m4 @@ -122,12 +122,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/data/skeletons/location.cc b/data/skeletons/location.cc index dc1be6db..059c0a8a 100644 --- a/data/skeletons/location.cc +++ b/data/skeletons/location.cc @@ -22,8 +22,8 @@ m4_pushdef([b4_copyright_years], # b4_position_file # ---------------- # Name of the file containing the position class, if we want this file. -b4_header_if([b4_required_version_if([302], [], - [m4_define([b4_position_file], [position.hh])])])]) +b4_header_if([b4_required_version_if([30200], [], + [m4_define([b4_position_file], [position.hh])])])]) # b4_location_file diff --git a/data/skeletons/stack.hh b/data/skeletons/stack.hh index 4e379e19..7ba9e5f9 100644 --- a/data/skeletons/stack.hh +++ b/data/skeletons/stack.hh @@ -19,8 +19,8 @@ # b4_stack_file # ------------- # Name of the file containing the stack class, if we want this file. -b4_header_if([b4_required_version_if([302], [], - [m4_define([b4_stack_file], [stack.hh])])]) +b4_header_if([b4_required_version_if([30200], [], + [m4_define([b4_stack_file], [stack.hh])])]) # b4_stack_define diff --git a/data/skeletons/variant.hh b/data/skeletons/variant.hh index a4f7e38a..13c07674 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 @@ -71,12 +78,12 @@ 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 +[b4_parse_assert_if([[#include +#ifndef ]b4_assert[ # include -# define YY_ASSERT assert +# define ]b4_assert[ assert #endif -]]) +]])]) @@ -110,8 +117,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([[ + ]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 @@ -133,10 +140,10 @@ m4_define([b4_value_type_declare], template T& emplace (U&&... u) - {]b4_parse_assert_if([ - YY_ASSERT (!yytypeid_); - YY_ASSERT (sizeof (T) <= size); - yytypeid_ = & typeid (T);])[ + {]b4_parse_assert_if([[ + ]b4_assert[ (!yytypeid_); + ]b4_assert[ (sizeof (T) <= size); + yytypeid_ = & typeid (T);]])[ return *new (yyas_ ()) T (std::forward (u)...); } # else @@ -144,10 +151,10 @@ m4_define([b4_value_type_declare], template T& emplace () - {]b4_parse_assert_if([ - YY_ASSERT (!yytypeid_); - YY_ASSERT (sizeof (T) <= size); - yytypeid_ = & typeid (T);])[ + {]b4_parse_assert_if([[ + ]b4_assert[ (!yytypeid_); + ]b4_assert[ (sizeof (T) <= size); + yytypeid_ = & typeid (T);]])[ return *new (yyas_ ()) T (); } @@ -155,10 +162,10 @@ m4_define([b4_value_type_declare], template T& emplace (const T& t) - {]b4_parse_assert_if([ - YY_ASSERT (!yytypeid_); - YY_ASSERT (sizeof (T) <= size); - yytypeid_ = & typeid (T);])[ + {]b4_parse_assert_if([[ + ]b4_assert[ (!yytypeid_); + ]b4_assert[ (sizeof (T) <= size); + yytypeid_ = & typeid (T);]])[ return *new (yyas_ ()) T (t); } # endif @@ -185,10 +192,10 @@ m4_define([b4_value_type_declare], template T& as () YY_NOEXCEPT - {]b4_parse_assert_if([ - YY_ASSERT (yytypeid_); - YY_ASSERT (*yytypeid_ == typeid (T)); - YY_ASSERT (sizeof (T) <= size);])[ + {]b4_parse_assert_if([[ + ]b4_assert[ (yytypeid_); + ]b4_assert[ (*yytypeid_ == typeid (T)); + ]b4_assert[ (sizeof (T) <= size);]])[ return *yyas_ (); } @@ -196,10 +203,10 @@ m4_define([b4_value_type_declare], template const T& as () const YY_NOEXCEPT - {]b4_parse_assert_if([ - YY_ASSERT (yytypeid_); - YY_ASSERT (*yytypeid_ == typeid (T)); - YY_ASSERT (sizeof (T) <= size);])[ + {]b4_parse_assert_if([[ + ]b4_assert[ (yytypeid_); + ]b4_assert[ (*yytypeid_ == typeid (T)); + ]b4_assert[ (sizeof (T) <= size);]])[ return *yyas_ (); } @@ -214,9 +221,9 @@ m4_define([b4_value_type_declare], template void swap (self_type& that) YY_NOEXCEPT - {]b4_parse_assert_if([ - YY_ASSERT (yytypeid_); - YY_ASSERT (*yytypeid_ == *that.yytypeid_);])[ + {]b4_parse_assert_if([[ + ]b4_assert[ (yytypeid_); + ]b4_assert[ (*yytypeid_ == *that.yytypeid_);]])[ std::swap (as (), that.as ()); } @@ -388,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...) @@ -410,9 +473,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 +482,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([[ + ]b4_assert[ (]b4_tok_in($@)[); + ]])[} ]])]) diff --git a/doc/bison.texi b/doc/bison.texi index 4a1b090c..8e9472e2 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -15837,6 +15837,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/gnulib b/gnulib index 160d5e7d..839ed059 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit 160d5e7d9a64a29a52d4821fd0ef2136d7e2102a +Subproject commit 839ed059f49329993ed34699a6f6b6466f09cbe0 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/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 a0685dd5..2ed4a5be 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; @@ -829,6 +830,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 ff19886f..872758ce 100644 --- a/src/parse-gram.c +++ b/src/parse-gram.c @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.7.2.67-44c6. */ +/* A Bison parser, made by GNU Bison 3.7.3.118-d0ea7-dirty. */ /* Bison implementation for Yacc-like parsers in C @@ -45,11 +45,11 @@ define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ -/* Identify Bison output. */ -#define YYBISON 1 +/* Identify Bison output, and Bison version. */ +#define YYBISON 30703 -/* Bison version. */ -#define YYBISON_VERSION "3.7.2.67-44c6" +/* Bison version string. */ +#define YYBISON_VERSION "3.7.3.118-d0ea7-dirty" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -220,8 +220,6 @@ typedef enum yysymbol_kind_t yysymbol_kind_t; #include "system.h" #include - #include - #include #include #include #include @@ -235,6 +233,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. */ @@ -647,19 +646,19 @@ union yyalloc /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { - 0, 311, 311, 320, 321, 325, 326, 332, 336, 341, - 342, 343, 344, 345, 346, 351, 356, 357, 358, 359, - 360, 361, 361, 362, 363, 364, 365, 366, 367, 368, - 369, 373, 374, 383, 384, 388, 399, 403, 407, 415, - 425, 426, 436, 437, 443, 456, 456, 461, 461, 466, - 466, 471, 481, 482, 483, 484, 489, 490, 494, 495, - 500, 501, 505, 506, 510, 511, 512, 525, 534, 538, - 542, 550, 551, 555, 568, 569, 574, 575, 576, 594, - 598, 602, 610, 612, 617, 624, 634, 638, 642, 650, - 656, 669, 670, 676, 677, 678, 685, 685, 693, 694, - 695, 700, 703, 705, 707, 709, 711, 713, 715, 717, - 719, 724, 725, 734, 758, 759, 760, 761, 773, 775, - 799, 804, 805, 810, 818, 819 + 0, 310, 310, 319, 320, 324, 325, 331, 335, 340, + 341, 342, 343, 344, 345, 350, 355, 356, 357, 358, + 359, 360, 360, 361, 362, 363, 364, 365, 366, 367, + 368, 372, 373, 382, 383, 387, 398, 402, 406, 414, + 424, 425, 435, 436, 442, 455, 455, 460, 460, 465, + 465, 470, 480, 481, 482, 483, 488, 489, 493, 494, + 499, 500, 504, 505, 509, 510, 511, 524, 533, 537, + 541, 549, 550, 554, 567, 568, 573, 574, 575, 593, + 597, 601, 609, 611, 616, 623, 633, 637, 641, 649, + 655, 668, 669, 675, 676, 677, 684, 684, 692, 693, + 694, 699, 702, 704, 706, 708, 710, 712, 714, 716, + 718, 723, 724, 733, 757, 758, 759, 760, 772, 774, + 798, 803, 804, 809, 817, 818 }; #endif @@ -3063,41 +3062,11 @@ 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. */ -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, 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; - - 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 8fd3aa5f..b679374e 100644 --- a/src/parse-gram.h +++ b/src/parse-gram.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.7.2.67-44c6. */ +/* A Bison parser, made by GNU Bison 3.7.3.118-d0ea7-dirty. */ /* Bison interface for Yacc-like parsers in C diff --git a/src/parse-gram.y b/src/parse-gram.y index 598639b4..ebebd89f 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. */ @@ -1053,41 +1052,11 @@ 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. */ -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, 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; - - 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 diff --git a/tests/headers.at b/tests/headers.at index 38eb8066..009c9b5b 100644 --- a/tests/headers.at +++ b/tests/headers.at @@ -203,17 +203,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__) @@ -222,8 +225,10 @@ $2 ]])[ ]AT_YYERROR_DECLARE[ ]AT_YYLEX_DECLARE[ -%} +} + %% + exp: 'x' '1' { printf ("x1\n"); } | 'x' '2' { printf ("x2\n"); } @@ -234,9 +239,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"])[ ]]) @@ -269,6 +277,8 @@ extern "C" #endif #include "x5.hh" #include "x9.hh" +#include "xa.hh" +#include "xb.hh" #define RUN(S) \ do { \ @@ -291,6 +301,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 @@ -303,7 +317,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: @@ -339,6 +355,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) { @@ -356,7 +374,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 e1f37ba2..a982d6ca 100644 --- a/tests/local.at +++ b/tests/local.at @@ -366,7 +366,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], [])