From a1d1ab50a00a4d28d6ba7b227ddc6628d5734ce3 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Tue, 6 Nov 2012 15:34:51 +0100 Subject: [PATCH] glr.cc, yacc.c: initialize yylloc properly There are several issues to address here. One is that yylloc should be initialized when possible. Another is that the push parser needs to update yypushed_loc when the user modified it. And if the parser starts by a reduction of an empty, it uses the first location on the stack, which, therefore, must also be initialized to this initial location. This is getting complex, especially since because initializing a global (impure interface) is different from initializing a local variable. To simplify, the local yylloc is not initialized during its definition. * data/c.m4 (b4_yyloc_default_define): Replace by... (b4_yyloc_default): this. Adjust dependencies. * data/glr.cc: Initialize yylloc. * data/yacc.c (b4_declare_scanner_communication_variables): Initialize yylloc during its definition. Don't define yyloc_default. (yypush_parse): The location formal is not const, as we might initialize it. (yyparse): Define yyloc_default. Use it before running the user initial action. Possibly update the first location on the stack, and the pushed location after the user initial action. * tests/actions.at (Initial locations): Check that the initial location is correct. --- NEWS | 3 +++ data/c.m4 | 14 +++++----- data/glr.c | 4 +-- data/glr.cc | 9 +++++-- data/yacc.c | 21 ++++++++------- tests/actions.at | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 99 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index 37b8e2c0..3d21470a 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,9 @@ GNU Bison NEWS Nul characters are correctly displayed in error messages. + When possible, yylloc is correctly initialized before calling yylex. It + is no longer necessary to initialize it in the %initial-action. + * Noteworthy changes in release 2.6.4 (2012-10-23) [stable] Bison 2.6.3's --version was incorrect. This release fixes this issue. diff --git a/data/c.m4 b/data/c.m4 index a1013ccc..8bd96b85 100644 --- a/data/c.m4 +++ b/data/c.m4 @@ -673,12 +673,11 @@ m4_define([b4_yy_location_print_define], #endif]]) ]) -# b4_yyloc_default_define -# ----------------------- -# Define yyloc_default, which can be used to initialize location -# variables. -m4_define([b4_yyloc_default_define], -[[static YYLTYPE yyloc_default +# b4_yyloc_default +# ---------------- +# Expand to a possible default value for yylloc. +m4_define([b4_yyloc_default], +[[ # if defined ]b4_api_PREFIX[LTYPE_IS_TRIVIAL && ]b4_api_PREFIX[LTYPE_IS_TRIVIAL = { ]m4_join([, ], m4_defn([b4_location_initial_line]), @@ -686,5 +685,4 @@ m4_define([b4_yyloc_default_define], m4_defn([b4_location_initial_line]), m4_defn([b4_location_initial_column]))[ } # endif - ;]dnl -]) +]]) diff --git a/data/glr.c b/data/glr.c index a2992e08..9bd95228 100644 --- a/data/glr.c +++ b/data/glr.c @@ -226,8 +226,8 @@ b4_percent_code_get([[top]])[ right-hand sides. Unlike the standard yacc.c template, here we set the default value of $$ to a zeroed-out value. Since the default value is undefined, this behavior is technically correct. */ -static YYSTYPE yyval_default;]b4_locations_if([ -b4_yyloc_default_define])[ +static YYSTYPE yyval_default;]b4_locations_if([[ +static YYLTYPE yyloc_default][]b4_yyloc_default;])[ /* Copy the second part of user declarations. */ ]b4_user_post_prologue diff --git a/data/glr.cc b/data/glr.cc index 826bc80e..104bf785 100644 --- a/data/glr.cc +++ b/data/glr.cc @@ -87,12 +87,17 @@ m4_define([b4_yy_symbol_print_generate], ]b4_parse_param_use[]dnl [ yyparser.yy_symbol_print_ (yytype, yyvaluep]b4_locations_if([, yylocationp])[); } -]]) +]])[ +# Hijack the initial action to initialize the locations. +]b4_locations_if([b4_percent_define_ifdef([[location_type]], [], +[m4_define([b4_initial_action], +[yylloc.initialize ();]m4_ifdef([b4_initial_action], [ +m4_defn([b4_initial_action])]))])])[ # Hijack the post prologue to insert early definition of YYLLOC_DEFAULT # and declaration of yyerror. -m4_append([b4_post_prologue], +]m4_append([b4_post_prologue], [b4_syncline([@oline@], [@ofile@])[ ]b4_yylloc_default_define[ #define YYRHSLOC(Rhs, K) ((Rhs)[K].yystate.yyloc) diff --git a/data/yacc.c b/data/yacc.c index e82264ff..b9a4fb18 100644 --- a/data/yacc.c +++ b/data/yacc.c @@ -181,8 +181,7 @@ int yychar; #else /* Default value used for initialization, for pacifying older GCCs or non-GCC compilers. */ -static YYSTYPE yyval_default;]b4_locations_if([ -b4_yyloc_default_define])[ +static YYSTYPE yyval_default; # define YY_INITIAL_VALUE(Value) = Value #endif]])[ #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN @@ -197,7 +196,8 @@ b4_yyloc_default_define])[ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);]b4_locations_if([[ /* Location data for the lookahead symbol. */ -YYLTYPE yylloc YY_INITIAL_VALUE(yyloc_default);]])b4_pure_if([], [[ +YYLTYPE yylloc][]b4_yyloc_default[; +]])b4_pure_if([], [[ /* Number of syntax errors so far. */ int yynerrs;]])]) @@ -265,7 +265,7 @@ typedef struct ]b4_prefix[pstate ]b4_prefix[pstate; [[b4_prefix[pstate *ps]], [[ps]]]b4_pure_if([, [[[int pushed_char]], [[pushed_char]]], [[b4_api_PREFIX[STYPE const *pushed_val]], [[pushed_val]]]b4_locations_if([, - [[b4_api_PREFIX[LTYPE const *pushed_loc]], [[pushed_loc]]]])])m4_ifset([b4_parse_param], [, + [[b4_api_PREFIX[LTYPE *pushed_loc]], [[pushed_loc]]]])])m4_ifset([b4_parse_param], [, b4_parse_param])) b4_pull_if([b4_c_function_decl([b4_prefix[pull_parse]], [[int]], [[b4_prefix[pstate *ps]], [[ps]]]m4_ifset([b4_parse_param], [, @@ -1409,7 +1409,7 @@ b4_c_function_def([[yyparse]], [[int]], b4_parse_param)[ yypstate *yyps_local;]b4_pure_if([[ int yychar; YYSTYPE yylval;]b4_locations_if([[ - YYLTYPE yylloc;]])])[ + YYLTYPE yylloc][]b4_yyloc_default[;]])])[ if (yyps) yyps_local = yyps; else @@ -1489,7 +1489,7 @@ b4_c_function_def([[yyparse]], [[int]], b4_parse_param)[ [[[yypstate *yyps]], [[yyps]]]b4_pure_if([, [[[int yypushed_char]], [[yypushed_char]]], [[[YYSTYPE const *yypushed_val]], [[yypushed_val]]]b4_locations_if([, - [[[YYLTYPE const *yypushed_loc]], [[yypushed_loc]]]])])m4_ifset([b4_parse_param], [, + [[[YYLTYPE *yypushed_loc]], [[yypushed_loc]]]])])m4_ifset([b4_parse_param], [, b4_parse_param]))], [[ @@ -1556,16 +1556,17 @@ b4_c_function_def([[yyparse]], [[int]], b4_parse_param)[ yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ -]m4_ifdef([b4_initial_action],[ +]m4_ifdef([b4_initial_action], [ b4_dollar_pushdef([m4_define([b4_dollar_dollar_used])yylval], [], - [m4_define([b4_at_dollar_used])yylloc])dnl + [m4_define([b4_at_dollar_used])dnl +b4_push_if([b4_pure_if([*])yypushed_loc], [yylloc])])dnl /* User initialization code. */ b4_user_initial_action b4_dollar_popdef[]dnl m4_ifdef([b4_dollar_dollar_used],[[ yyvsp[0] = yylval; -]])dnl -m4_ifdef([b4_at_dollar_used], [[ yylsp[0] = yylloc; ]])])dnl +b4_locations_if([[ yylsp[0] = ]b4_push_if([b4_pure_if([*])yypushed_loc], [yylloc])[; +]])dnl [ goto yysetstate; /*------------------------------------------------------------. diff --git a/tests/actions.at b/tests/actions.at index fc70f48a..0e02239f 100644 --- a/tests/actions.at +++ b/tests/actions.at @@ -69,6 +69,76 @@ AT_PARSER_CHECK([./input], 0, AT_CLEANUP +## ------------------ ## +## Initial location. ## +## ------------------ ## + +# AT_TEST(SKELETON-NAME, DIRECTIVES) +# ---------------------------------- +# Check the the initial location is correct. +m4_pushdef([AT_TEST], +[AT_SETUP([Initial location: $1 $2]) + +AT_BISON_OPTION_PUSHDEFS([%locations %skeleton "$1" $2 %parse-param { int x }]) +AT_DATA_GRAMMAR([[input.y]], +[[%defines /* FIXME: Required by lalr1.cc in Bison 2.6. */ +%locations +%debug +%skeleton "$1" +$2 +%parse-param { int x } // Useless, but used to force yyerror purity. +%code +{ +# include +# include // getenv +]AT_YYERROR_DECLARE[ +]AT_YYLEX_DECLARE[ +} +%% +exp: { ]AT_SKEL_CC_IF([[std::cerr << @$ << std::endl]], + [[YY_LOCATION_PRINT(stderr, @$); fputc ('\n', stderr)]])[; } +%% +]AT_YYERROR_DEFINE[ + +]AT_YYLEX_PROTOTYPE[ +{]AT_PURE_IF([ + YYUSE(lvalp); + YYUSE(llocp);], [AT_SKEL_CC_IF([ + YYUSE(lvalp); + YYUSE(llocp);])])[ + return 'x'; +} + +int +main (void) +{]AT_SKEL_CC_IF([[ + yy::parser p (0); + p.set_debug_level (!!getenv("YYDEBUG")); + return p.parse ();]], [[ + yydebug = !!getenv("YYDEBUG"); + return !!yyparse (0);]])[ +} +]]) + +AT_FULL_COMPILE([input]) +AT_PARSER_CHECK([./input], 1, [], +[[1.1 +1.1: syntax error +]]) +AT_BISON_OPTION_POPDEFS +AT_CLEANUP +]) + +## FIXME: test Java, and iterate over skeletons. +AT_TEST([yacc.c]) +AT_TEST([yacc.c], [%define api.pure]) +AT_TEST([yacc.c], [%define api.push-pull both]) +AT_TEST([yacc.c], [%define api.push-pull both %define api.pure]) +AT_TEST([glr.c]) +AT_TEST([lalr1.cc]) +AT_TEST([glr.cc]) + +m4_popdef([AT_TEST]) -- 2.45.2