> Le 29 sept. 2014 à 03:43, Stephen Cameron <stephenmcame...@gmail.com> a écrit > : > > Hi, > > I think I have found a bug in bison v. 3.0.2. > > scameron@spacenerd ~/github/simple-expression-parser $ yacc --version > bison (GNU Bison) 3.0.2 > Written by Robert Corbett and Richard Stallman. > > Copyright (C) 2013 Free Software Foundation, Inc. > This is free software; see the source for copying conditions. There is NO > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. > scameron@spacenerd ~/github/simple-expression-parser $ > > Note that is the version of bison shipped with e.g. Linux Mint 17. > > Below is some output (y.tab.h) of yacc (bison) v 3.0.2 > > Notice the '#line' directive which does not start at the beginning of a > line: > > "union #line 49 "expression-parser.y" /* yacc.c:1909 */" > > gcc will not compile this. I think that means it's a bug in bison. > Earlier versions of bison produce correct output (e.g. v. 2.5 works > correctly, and the '#line' directive begins on a new line.) > > -------8<--------8<-------8<-------8<--------8<-------8<-------8<--------8<-------8< > [...] > /* Value type. */ > #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED > typedef union #line 49 "expression-parser.y" /* yacc.c:1909 */ > valtype > YYSTYPE; > union #line 49 "expression-parser.y" /* yacc.c:1909 */ > valtype > > { > #line 49 "expression-parser.y" /* yacc.c:1909 */ > > struct parser_value_type { > double dval; > long long ival; > int has_dval; > int has_error; > } v; > > #line 77 "y.tab.h" /* yacc.c:1909 */ > }; > # define YYSTYPE_IS_TRIVIAL 1 > [...] > -------8<--------8<-------8<-------8<--------8<-------8<-------8<--------8<-------8< > > The program which caused this is a simple arithmetic expression parser > (basic yacc 101 stuff). It is here: > https://github.com/smcameron/simple-expression-parser
Hi! I'm sorry about this issue. I will apply the following patch, which should address your issue. I'm curious though: why exactly do you provide a tag name to the %union? What is wrong with just using YYSTYPE? commit 9e0f2feae1ca02c97c56ca03dd974afdf87748d6 Author: Akim Demaille <a...@lrde.epita.fr> Date: Sun Jan 4 14:16:23 2015 +0100 %union: fix the support for named %union Bison supports a union tag, for obscure reasons. But it does a poor job at it, especially since Bison 3.0. Reported by Stephen Cameron and Tobias Frost. It did not ensure that the name was not given several times. An easy way to do this is to make the %union tag be handled as a %define variable, as they cannot be defined several times. Since Bison 3.0, the synclines were wrongly placed, resulting in invalid code. Addressing this issue, because of the way the union tag was stored (as a code muscle), would have been tedious. Unless we rather define the %union tag as a %percent variable, whose synclines are easier to manipulate. So replace the b4_union_name muscle by the api.value.union.name %define variable, document, and check. * data/bison.m4: Make sure that api.value.union.name has a keyword value. * data/c++.m4: Make sure that api.value.union.name is not defined. * data/c.m4 (b4_union_name): No longer use it, use api.value.union.name. * doc/bison.texi (%define Summary): Document it. * src/parse-gram.y (union_name): No longer define b4_uion_name, but api.value.union.name. * tests/input.at (Redefined %union name): New. * tests/synclines.at (%union name syncline): New. * tests/types.at: Check named %unions. diff --git a/THANKS b/THANKS index 4559a90..943cbb1 100644 --- a/THANKS +++ b/THANKS @@ -126,6 +126,7 @@ Sebastien Fricker sebastien.fric...@gmail.com Sergei Steshenko sergst...@yahoo.com Shura debil_u...@ngs.ru Stefano Lattarini stefano.lattar...@gmail.com +Stephen Cameron stephenmcame...@gmail.com Steve Murphy m...@parsetree.com Sum Wu s...@geekhouse.org Théophile Ranquet theophile.ranq...@gmail.com @@ -133,6 +134,7 @@ Thiru Ramakrishnan thiru.ramakrish...@gmail.com Tim Josling t...@melbpc.org.au Tim Landscheidt t...@tim-landscheidt.de Tim Van Holder tim.van.hol...@pandora.be +Tobias Frost t...@debian.org Tom Lane t...@sss.pgh.pa.us Tom Tromey tro...@cygnus.com Tommy Nordgren tommy.nordg...@chello.se diff --git a/data/bison.m4 b/data/bison.m4 index c443032..967aaaa 100644 --- a/data/bison.m4 +++ b/data/bison.m4 @@ -1061,3 +1061,6 @@ b4_percent_define_ifdef([api.value.type], [['%s' and '%s' cannot be used together]], [%yacc], [%define api.value.type "union"])])])]) + +# api.value.union.name. +b4_percent_define_check_kind([api.value.union.name], [keyword]) diff --git a/data/c++.m4 b/data/c++.m4 index 4927899..e4559be 100644 --- a/data/c++.m4 +++ b/data/c++.m4 @@ -17,6 +17,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +# Sanity checks, before defaults installed by c.m4. +b4_percent_define_ifdef([[api.value.union.name]], + [b4_complain_at(b4_percent_define_get_loc([[api.value.union.name]]), + [named %union is invalid in C++])]) + m4_include(b4_pkgdatadir/[c.m4]) # b4_comment(TEXT, [PREFIX]) diff --git a/data/c.m4 b/data/c.m4 index 1f1a23f..16713de 100644 --- a/data/c.m4 +++ b/data/c.m4 @@ -97,7 +97,8 @@ m4_define([b4_api_PREFIX], m4_define_default([b4_prefix], [b4_api_prefix]) # If the %union is not named, its name is YYSTYPE. -m4_define_default([b4_union_name], [b4_api_PREFIX[]STYPE]) +b4_percent_define_default([[api.value.union.name]], + [b4_api_PREFIX[][STYPE]]) ## ------------------------ ## @@ -608,10 +609,9 @@ m4_copy_force([b4_symbol_value_union], [b4_symbol_value]) ]) -# ---------------- # -# api.value.type. # -# ---------------- # - +# -------------------------- # +# api.value.type = variant. # +# -------------------------- # # b4_value_type_setup_variant # --------------------------- @@ -686,11 +686,12 @@ typedef ]b4_percent_define_get([[api.value.type]])[ ]b4_api_PREFIX[STYPE; [m4_bmatch(b4_percent_define_get([[api.value.type]]), [union\|union-directive], [[#if ! defined ]b4_api_PREFIX[STYPE && ! defined ]b4_api_PREFIX[STYPE_IS_DECLARED -typedef union ]b4_union_name[ ]b4_api_PREFIX[STYPE; -union ]b4_union_name[ +]b4_percent_define_get_syncline([[api.value.union.name]])[ +union ]b4_percent_define_get([[api.value.union.name]])[ { ]b4_user_union_members[ }; +typedef union ]b4_percent_define_get([[api.value.union.name]])[ ]b4_api_PREFIX[STYPE; # define ]b4_api_PREFIX[STYPE_IS_TRIVIAL 1 # define ]b4_api_PREFIX[STYPE_IS_DECLARED 1 #endif diff --git a/doc/bison.texi b/doc/bison.texi index 665664b..f33fc15 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -3851,7 +3851,7 @@ example: @noindent specifies the union tag @code{value}, so the corresponding C type is @code{union value}. If you do not specify a tag, it defaults to -@code{YYSTYPE}. +@code{YYSTYPE} (@pxref{%define Summary,,api.value.union.name}). As another extension to POSIX, you may specify multiple @code{%union} declarations; their contents are concatenated. However, only the first @@ -6014,12 +6014,12 @@ Use this @var{type} as semantic value. @item Default Value: @itemize @minus @item -@code{%union} if @code{%union} is used, otherwise @dots{} +@code{union-directive} if @code{%union} is used, otherwise @dots{} @item @code{int} if type tags are used (i.e., @samp{%token <@var{type}>@dots{}} or -@samp{%token <@var{type}>@dots{}} is used), otherwise @dots{} +@samp{%type <@var{type}>@dots{}} is used), otherwise @dots{} @item -@code{""} +undefined. @end itemize @item History: @@ -6030,6 +6030,30 @@ introduced in Bison 3.0. Was introduced for Java only in 2.3b as @c api.value.type +@c ================================================== api.value.union.name +@deffn Directive {%define api.value.union.name} @var{name} +@itemize @bullet +@item Language(s): +C + +@item Purpose: +The tag of the generated @code{union} (@emph{not} the name of the +@code{typedef}). This variable is set to @code{@var{id}} when @samp{%union +@var{id}} is used. There is no clear reason to give this union a name. + +@item Accepted Values: +Any valid identifier. + +@item Default Value: +@code{YYSTYPE}. + +@item History: +Introduced in Bison 3.0.3. +@end itemize +@end deffn +@c api.value.type + + @c ================================================== location_type @deffn Directive {%define location_type} Obsoleted by @code{api.location.type} since Bison 2.7. diff --git a/src/parse-gram.y b/src/parse-gram.y index 741d743..6a68071 100644 --- a/src/parse-gram.y +++ b/src/parse-gram.y @@ -421,7 +421,9 @@ code_props_type: union_name: %empty {} -| ID { muscle_code_grow ("union_name", $1, @1); } +| ID { muscle_percent_define_insert ("api.value.union.name", + @1, muscle_keyword, $1, + MUSCLE_PERCENT_DEFINE_GRAMMAR_FILE); } ; grammar_declaration: diff --git a/tests/input.at b/tests/input.at index cec82dd..33da53d 100644 --- a/tests/input.at +++ b/tests/input.at @@ -1904,6 +1904,51 @@ m4_popdef([AT_TEST]) AT_CLEANUP +## ----------------------- ## +## Redefined %union name. ## +## ----------------------- ## + +AT_SETUP([[Redefined %union name]]) + +# AT_TEST(DIRECTIVES, ERROR) +# -------------------------- +m4_pushdef([AT_TEST], +[AT_DATA([[input.y]], +[$1 +%% +exp: %empty; +]) + +AT_BISON_CHECK([[input.y]], [[1]], [[]], +[$2]) +]) + +AT_TEST([[%union foo {}; +%union {}; +%union foo {}; +%define api.value.union.name foo]], +[[input.y:3.8-10: error: %define variable 'api.value.union.name' redefined +input.y:1.8-10: previous definition +input.y:4.9-28: error: %define variable 'api.value.union.name' redefined +input.y:3.8-10: previous definition +]]) + +AT_TEST([[%define api.value.union.name {foo}]], +[[input.y:1.9-28: error: %define variable 'api.value.union.name' requires keyword values +input.y:1.9-28: error: %define variable 'api.value.union.name' is not used +]]) + +AT_TEST([[%define api.value.union.name "foo"]], +[[input.y:1.9-28: error: %define variable 'api.value.union.name' requires keyword values +input.y:1.9-28: error: %define variable 'api.value.union.name' is not used +]]) + +m4_popdef([AT_TEST]) +AT_CLEANUP + + + + ## -------------- ## ## Stray $ or @. ## ## -------------- ## diff --git a/tests/synclines.at b/tests/synclines.at index 72d5d85..77499b7 100644 --- a/tests/synclines.at +++ b/tests/synclines.at @@ -182,6 +182,35 @@ exp: '0'; ]) +## ---------------------- ## +## %union name syncline. ## +## ---------------------- ## + +# Check that invalid union names are properly reported in the +# source file. +AT_SETUP([%union name syncline]) +AT_BISON_OPTION_PUSHDEFS +AT_DATA([[input.y]], +[[%union break +{ + char dummy; +} +%{ +]AT_YYERROR_DECLARE_EXTERN[ +]AT_YYLEX_DECLARE_EXTERN[ +%} +%% +exp: '0'; +%% +]]) + +AT_BISON_CHECK([-o input.c input.y]) +AT_SYNCLINES_COMPILE([input.c]) +AT_CHECK([[grep '^input.y:1' stdout]], 0, [ignore]) +AT_BISON_OPTION_POPDEFS +AT_CLEANUP + + ## ----------------------- ## ## Postprologue syncline. ## ## ----------------------- ## diff --git a/tests/types.at b/tests/types.at index 29f51e2..8ddf694 100644 --- a/tests/types.at +++ b/tests/types.at @@ -197,18 +197,23 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]], AT_VAL.fval = .2f], [10 0.2]) - # A %union. - AT_TEST([%skeleton "]b4_skel[" - %union { float fval; int ival; };], - [%token <ival> '1'; - %token <fval> '2';], - ['1' '2' { printf ("%d %2.1f\n", $1, $2); }], - ["12"], - [if (res == '1') - AT_VAL.ival = 10; - else - AT_VAL.fval = 0.2f], - [10 0.2]) + # A %union and a named %union. In C++ named %union is an error. + m4_foreach([b4_union], + [m4_bmatch(b4_skel, [\.cc$], + [[%union]], + [[%union], [%union foo], + [%define api.value.union.name foo; %union]])], + [AT_TEST([%skeleton "]b4_skel[" + ]b4_union[ { float fval; int ival; };], + [%token <ival> '1'; + %token <fval> '2';], + ['1' '2' { printf ("%d %2.1f\n", $1, $2); }], + ["12"], + [if (res == '1') + AT_VAL.ival = 10; + else + AT_VAL.fval = 0.2f], + [10 0.2])]) # A Bison-defined union. # The tokens names are not available directly in C++, we use their @@ -249,3 +254,22 @@ m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc]], m4_popdef([AT_TEST]) m4_popdef([_AT_TEST]) + + +## ------------------- ## +## C++: Named %union. ## +## ------------------- ## + +m4_foreach([b4_skel], [[lalr1.cc], [glr.cc]], +[AT_SETUP([b4_skel: Named %union]) +AT_DATA([input.y], +[%skeleton "]b4_skel[" +%union foo { float fval; int ival; }; +%% +exp: %empty; +]) +AT_BISON_CHECK([input.y], 1, [], +[[input.y:2.8-10: error: named %union is invalid in C++ +]]) +AT_CLEANUP +])