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.
This commit is contained in:
Akim Demaille
2012-11-06 15:34:51 +01:00
parent 3237f57096
commit a1d1ab50a0
6 changed files with 99 additions and 22 deletions

3
NEWS
View File

@@ -16,6 +16,9 @@ GNU Bison NEWS
Nul characters are correctly displayed in error messages. 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] * Noteworthy changes in release 2.6.4 (2012-10-23) [stable]
Bison 2.6.3's --version was incorrect. This release fixes this issue. Bison 2.6.3's --version was incorrect. This release fixes this issue.

View File

@@ -673,12 +673,11 @@ m4_define([b4_yy_location_print_define],
#endif]]) #endif]])
]) ])
# b4_yyloc_default_define # b4_yyloc_default
# ----------------------- # ----------------
# Define yyloc_default, which can be used to initialize location # Expand to a possible default value for yylloc.
# variables. m4_define([b4_yyloc_default],
m4_define([b4_yyloc_default_define], [[
[[static YYLTYPE yyloc_default
# if defined ]b4_api_PREFIX[LTYPE_IS_TRIVIAL && ]b4_api_PREFIX[LTYPE_IS_TRIVIAL # if defined ]b4_api_PREFIX[LTYPE_IS_TRIVIAL && ]b4_api_PREFIX[LTYPE_IS_TRIVIAL
= { ]m4_join([, ], = { ]m4_join([, ],
m4_defn([b4_location_initial_line]), 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_line]),
m4_defn([b4_location_initial_column]))[ } m4_defn([b4_location_initial_column]))[ }
# endif # endif
;]dnl ]])
])

View File

@@ -226,8 +226,8 @@ b4_percent_code_get([[top]])[
right-hand sides. Unlike the standard yacc.c template, here we set right-hand sides. Unlike the standard yacc.c template, here we set
the default value of $$ to a zeroed-out value. Since the default the default value of $$ to a zeroed-out value. Since the default
value is undefined, this behavior is technically correct. */ value is undefined, this behavior is technically correct. */
static YYSTYPE yyval_default;]b4_locations_if([ static YYSTYPE yyval_default;]b4_locations_if([[
b4_yyloc_default_define])[ static YYLTYPE yyloc_default][]b4_yyloc_default;])[
/* Copy the second part of user declarations. */ /* Copy the second part of user declarations. */
]b4_user_post_prologue ]b4_user_post_prologue

View File

@@ -87,12 +87,17 @@ m4_define([b4_yy_symbol_print_generate],
]b4_parse_param_use[]dnl ]b4_parse_param_use[]dnl
[ yyparser.yy_symbol_print_ (yytype, yyvaluep]b4_locations_if([, yylocationp])[); [ 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 # Hijack the post prologue to insert early definition of YYLLOC_DEFAULT
# and declaration of yyerror. # and declaration of yyerror.
m4_append([b4_post_prologue], ]m4_append([b4_post_prologue],
[b4_syncline([@oline@], [@ofile@])[ [b4_syncline([@oline@], [@ofile@])[
]b4_yylloc_default_define[ ]b4_yylloc_default_define[
#define YYRHSLOC(Rhs, K) ((Rhs)[K].yystate.yyloc) #define YYRHSLOC(Rhs, K) ((Rhs)[K].yystate.yyloc)

View File

@@ -181,8 +181,7 @@ int yychar;
#else #else
/* Default value used for initialization, for pacifying older GCCs /* Default value used for initialization, for pacifying older GCCs
or non-GCC compilers. */ or non-GCC compilers. */
static YYSTYPE yyval_default;]b4_locations_if([ static YYSTYPE yyval_default;
b4_yyloc_default_define])[
# define YY_INITIAL_VALUE(Value) = Value # define YY_INITIAL_VALUE(Value) = Value
#endif]])[ #endif]])[
#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
@@ -197,7 +196,8 @@ b4_yyloc_default_define])[
YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);]b4_locations_if([[ YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);]b4_locations_if([[
/* Location data for the lookahead symbol. */ /* 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. */ /* Number of syntax errors so far. */
int yynerrs;]])]) int yynerrs;]])])
@@ -265,7 +265,7 @@ typedef struct ]b4_prefix[pstate ]b4_prefix[pstate;
[[b4_prefix[pstate *ps]], [[ps]]]b4_pure_if([, [[b4_prefix[pstate *ps]], [[ps]]]b4_pure_if([,
[[[int pushed_char]], [[pushed_char]]], [[[int pushed_char]], [[pushed_char]]],
[[b4_api_PREFIX[STYPE const *pushed_val]], [[pushed_val]]]b4_locations_if([, [[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_parse_param]))
b4_pull_if([b4_c_function_decl([b4_prefix[pull_parse]], [[int]], b4_pull_if([b4_c_function_decl([b4_prefix[pull_parse]], [[int]],
[[b4_prefix[pstate *ps]], [[ps]]]m4_ifset([b4_parse_param], [, [[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([[ yypstate *yyps_local;]b4_pure_if([[
int yychar; int yychar;
YYSTYPE yylval;]b4_locations_if([[ YYSTYPE yylval;]b4_locations_if([[
YYLTYPE yylloc;]])])[ YYLTYPE yylloc][]b4_yyloc_default[;]])])[
if (yyps) if (yyps)
yyps_local = yyps; yyps_local = yyps;
else else
@@ -1489,7 +1489,7 @@ b4_c_function_def([[yyparse]], [[int]], b4_parse_param)[
[[[yypstate *yyps]], [[yyps]]]b4_pure_if([, [[[yypstate *yyps]], [[yyps]]]b4_pure_if([,
[[[int yypushed_char]], [[yypushed_char]]], [[[int yypushed_char]], [[yypushed_char]]],
[[[YYSTYPE const *yypushed_val]], [[yypushed_val]]]b4_locations_if([, [[[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]))], [[ b4_parse_param]))], [[
@@ -1556,16 +1556,17 @@ b4_c_function_def([[yyparse]], [[int]], b4_parse_param)[
yyerrstatus = 0; yyerrstatus = 0;
yynerrs = 0; yynerrs = 0;
yychar = YYEMPTY; /* Cause a token to be read. */ 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], [], 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. */ /* User initialization code. */
b4_user_initial_action b4_user_initial_action
b4_dollar_popdef[]dnl b4_dollar_popdef[]dnl
m4_ifdef([b4_dollar_dollar_used],[[ yyvsp[0] = yylval; m4_ifdef([b4_dollar_dollar_used],[[ yyvsp[0] = yylval;
]])dnl
m4_ifdef([b4_at_dollar_used], [[ yylsp[0] = yylloc;
]])])dnl ]])])dnl
b4_locations_if([[ yylsp[0] = ]b4_push_if([b4_pure_if([*])yypushed_loc], [yylloc])[;
]])dnl
[ goto yysetstate; [ goto yysetstate;
/*------------------------------------------------------------. /*------------------------------------------------------------.

View File

@@ -69,6 +69,76 @@ AT_PARSER_CHECK([./input], 0,
AT_CLEANUP 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 <stdio.h>
# include <stdlib.h> // 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])