bug-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Bug with '#line' directive in bison 3.0.2


From: Akim Demaille
Subject: Re: Bug with '#line' directive in bison 3.0.2
Date: Sun, 4 Jan 2015 14:28:01 +0100

> Le 29 sept. 2014 à 03:43, Stephen Cameron <address@hidden> a écrit :
> 
> Hi,
> 
> I think I have found a bug in bison v. 3.0.2.
> 
> address@hidden ~/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.
> address@hidden ~/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 <address@hidden>
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         address@hidden
 Sergei Steshenko          address@hidden
 Shura                     address@hidden
 Stefano Lattarini         address@hidden
+Stephen Cameron           address@hidden
 Steve Murphy              address@hidden
 Sum Wu                    address@hidden
 Théophile Ranquet         address@hidden
@@ -133,6 +134,7 @@ Thiru Ramakrishnan        address@hidden
 Tim Josling               address@hidden
 Tim Landscheidt           address@hidden
 Tim Van Holder            address@hidden
+Tobias Frost              address@hidden
 Tom Lane                  address@hidden
 Tom Tromey                address@hidden
 Tommy Nordgren            address@hidden
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
address@hidden
address@hidden (@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
address@hidden if @code{%union} is used, otherwise @dots{}
address@hidden if @code{%union} is used, otherwise @dots{}
 @item
 @code{int} if type tags are used (i.e., @samp{%token <@var{type}>@dots{}} or
address@hidden <@var{type}>@dots{}} is used), otherwise @dots{}
address@hidden <@var{type}>@dots{}} is used), otherwise @dots{}
 @item
address@hidden""}
+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
 
 
address@hidden ================================================== 
api.value.union.name
address@hidden Directive {%define api.value.union.name} @var{name}
address@hidden @bullet
address@hidden Language(s):
+C
+
address@hidden Purpose:
+The tag of the generated @code{union} (@emph{not} the name of the
address@hidden).  This variable is set to @address@hidden when @samp{%union
address@hidden is used.  There is no clear reason to give this union a name.
+
address@hidden Accepted Values:
+Any valid identifier.
+
address@hidden Default Value:
address@hidden
+
address@hidden History:
+Introduced in Bison 3.0.3.
address@hidden itemize
address@hidden deffn
address@hidden 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
+])




reply via email to

[Prev in Thread] Current Thread [Next in Thread]