commit b6b397b7f0a764f29f8b60f7d9eb7696473aa556 Author: Akim Demaille <[email protected]> Date: Wed Jan 16 07:45:54 2019 +0100 fixits: report duplicate %yacc directives We should use -ffixit and --update to clean files with duplicate directives. And we should complain only once about duplicate obsolete directives: keep only the "duplicate" warning. Let's start with %yacc. For instance on: %fixed-output_files %fixed-output-files %yacc %% exp: This run of bison: $ bison /tmp/foo.y -u foo.y:1.1-19: warning: deprecated directive, use '%fixed-output-files' [-Wdeprecated] %fixed-output_files ^~~~~~~~~~~~~~~~~~~ foo.y:2.1-19: warning: duplicate directive [-Wother] %fixed-output-files ^~~~~~~~~~~~~~~~~~~ foo.y:1.1-19: previous declaration %fixed-output_files ^~~~~~~~~~~~~~~~~~~ foo.y:3.1-5: warning: duplicate directive [-Wother] %yacc ^~~~~ foo.y:1.1-19: previous declaration %fixed-output_files ^~~~~~~~~~~~~~~~~~~ bison: file 'foo.y' was updated (backup: 'foo.y~') gives: %fixed-output-files %% exp: * src/location.h, src/location.c (location_empty): New. * src/complain.h, src/complain.c (duplicate_directive): New. * src/getargs.h, src/getargs.c (yacc_flag): Instead of a Boolean, be the location of the definition. Update dependencies. * src/scan-gram.l (%yacc, %fixed-output-files): Move the handling of its warnings to... * src/parse-gram.y (do_yacc): This new function. * tests/input.at (Deprecated Directives): Adjust expectations. diff --git a/src/complain.c b/src/complain.c index 3f8c5118..6b6b2c0b 100644 --- a/src/complain.c +++ b/src/complain.c @@ -399,6 +399,19 @@ deprecated_directive (location const *loc, char const *old, char const *upd) fixits_register (loc, upd); } +void +duplicate_directive (char const *directive, + location first, location second) +{ + if (feature_flag & feature_caret) + complain (&second, Wother, _("duplicate directive")); + else + complain (&second, Wother, _("duplicate directive: %s"), directive); + unsigned i = SUB_INDENT; + complain_indent (&first, complaint, &i, _("previous declaration")); + fixits_register (&second, ""); +} + void duplicate_rule_directive (char const *directive, location first, location second) diff --git a/src/complain.h b/src/complain.h index e5f6d7e6..266992f6 100644 --- a/src/complain.h +++ b/src/complain.h @@ -126,6 +126,10 @@ void bison_directive (location const *loc, char const *directive); void deprecated_directive (location const *loc, char const *obsolete, char const *updated); +/** Report a repeated directive. */ +void duplicate_directive (char const *directive, + location first, location second); + /** Report a repeated directive for a rule. */ void duplicate_rule_directive (char const *directive, location first, location second); diff --git a/src/files.c b/src/files.c index 7c33b23d..f805524c 100644 --- a/src/files.c +++ b/src/files.c @@ -285,7 +285,7 @@ compute_file_name_parts (void) last_component (spec_file_prefix) - spec_file_prefix); all_but_tab_ext = xstrdup (spec_file_prefix); } - else if (yacc_flag) + else if (! location_empty (yacc_loc)) { /* If --yacc, then the output is 'y.tab.c'. */ dir_prefix = xstrdup (""); @@ -306,7 +306,7 @@ compute_file_name_parts (void) all_but_ext = xstrdup (all_but_tab_ext); /* Compute the extensions from the grammar file name. */ - if (ext && !yacc_flag) + if (ext && location_empty (yacc_loc)) compute_exts_from_gf (ext); } } diff --git a/src/getargs.c b/src/getargs.c index 83ebcb09..a66e4c66 100644 --- a/src/getargs.c +++ b/src/getargs.c @@ -41,7 +41,7 @@ bool graph_flag = false; bool xml_flag = false; bool no_lines_flag = false; bool token_table_flag = false; -bool yacc_flag = false; /* for -y */ +location yacc_loc = EMPTY_LOCATION_INIT; bool update_flag = false; /* for -u */ bool nondeterministic_parser = false; @@ -709,7 +709,7 @@ getargs (int argc, char *argv[]) case 'y': warning_argmatch ("error=yacc", 0, 6); - yacc_flag = true; + yacc_loc = command_line_location (); break; case LOCATIONS_OPTION: diff --git a/src/getargs.h b/src/getargs.h index f44f2183..c5adb848 100644 --- a/src/getargs.h +++ b/src/getargs.h @@ -39,7 +39,7 @@ extern bool graph_flag; /* for -g */ extern bool xml_flag; /* for -x */ extern bool no_lines_flag; /* for -l */ extern bool token_table_flag; /* for -k */ -extern bool yacc_flag; /* for -y */ +extern location yacc_loc; /* for -y */ extern bool update_flag; /* for -u */ /* GLR_PARSER is true if the input file says to use the GLR diff --git a/src/location.c b/src/location.c index 4ec12a70..6876890c 100644 --- a/src/location.c +++ b/src/location.c @@ -216,6 +216,13 @@ location_caret (location loc, FILE *out) } } +bool +location_empty (location loc) +{ + return !loc.start.file && !loc.start.line && !loc.start.column + && !loc.end.file && !loc.end.line && !loc.end.column; +} + void boundary_set_from_string (boundary *bound, char *loc_str) { diff --git a/src/location.h b/src/location.h index 26d6af61..39e0507d 100644 --- a/src/location.h +++ b/src/location.h @@ -126,6 +126,9 @@ location_cmp (location a, location b) return res; } +/* Whether this is the empty location. */ +bool location_empty (location loc); + /* LOC_STR must be formatted as 'file:line.column', it will be modified. */ void boundary_set_from_string (boundary *bound, char *loc_str); diff --git a/src/output.c b/src/output.c index 6a9553c5..da600ae5 100644 --- a/src/output.c +++ b/src/output.c @@ -665,7 +665,7 @@ prepare (void) MUSCLE_INSERT_BOOL ("tag_seen_flag", tag_seen); MUSCLE_INSERT_BOOL ("token_table_flag", token_table_flag); MUSCLE_INSERT_BOOL ("use_push_for_pull_flag", use_push_for_pull_flag); - MUSCLE_INSERT_BOOL ("yacc_flag", yacc_flag); + MUSCLE_INSERT_BOOL ("yacc_flag", !location_empty (yacc_loc)); /* File names. */ if (spec_name_prefix) diff --git a/src/parse-gram.y b/src/parse-gram.y index e0496d5a..aa1a450f 100644 --- a/src/parse-gram.y +++ b/src/parse-gram.y @@ -95,6 +95,9 @@ /* Handle a %skeleton directive. */ static void do_skeleton (location const *loc, char const *skel); + /* Handle a %yacc directive. */ + static void do_yacc (location const *loc, char const *directive); + static void gram_error (location const *, char const *); /* A string that describes a char (e.g., 'a' -> "'a'"). */ @@ -201,8 +204,9 @@ %type <uniqstr> BRACKETED_ID ID ID_COLON - PERCENT_ERROR_VERBOSE PERCENT_FLAG PERCENT_NAME_PREFIX TAG - tag tag.opt variable + PERCENT_ERROR_VERBOSE PERCENT_FLAG PERCENT_NAME_PREFIX + PERCENT_YACC + TAG tag tag.opt variable %printer { fputs ($$, yyo); } <uniqstr> %printer { fprintf (yyo, "[%s]", $$); } BRACKETED_ID %printer { fprintf (yyo, "%s:", $$); } ID_COLON @@ -329,7 +333,7 @@ prologue_declaration: | "%skeleton" STRING { do_skeleton (&@2, $2); } | "%token-table" { token_table_flag = true; } | "%verbose" { report_flag |= report_states; } -| "%yacc" { yacc_flag = true; } +| "%yacc" { do_yacc (&@$, $1); } | error ";" { current_class = unknown_sym; yyerrok; } | /*FIXME: Err? What is this horror doing here? */ ";" ; @@ -956,6 +960,25 @@ do_skeleton (location const *loc, char const *skel) skeleton_arg (skeleton_user, grammar_prio, *loc); } +static void +do_yacc (location const *loc, char const *directive) +{ + bison_directive (loc, directive); + bool warned = false; + + if (location_empty (yacc_loc)) + yacc_loc = *loc; + else + { + duplicate_directive (directive, yacc_loc, *loc); + warned = true; + } + + if (!warned + && STRNEQ (directive, "%fixed-output-files") + && STRNEQ (directive, "%yacc")) + deprecated_directive (loc, directive, "%fixed-output-files"); +} static void gram_error (location const *loc, char const *msg) diff --git a/src/scan-gram.l b/src/scan-gram.l index 2eaa1606..e1536f5c 100644 --- a/src/scan-gram.l +++ b/src/scan-gram.l @@ -229,7 +229,7 @@ eqopt ({sp}=)? "%expect" return BISON_DIRECTIVE (EXPECT); "%expect-rr" return BISON_DIRECTIVE (EXPECT_RR); "%file-prefix" return BISON_DIRECTIVE (FILE_PREFIX); - "%fixed-output-files" return BISON_DIRECTIVE (YACC); + "%fixed-output-files" RETURN_VALUE (PERCENT_YACC, uniqstr_new (yytext)); "%initial-action" return BISON_DIRECTIVE (INITIAL_ACTION); "%glr-parser" return BISON_DIRECTIVE (GLR_PARSER); "%language" return BISON_DIRECTIVE (LANGUAGE); @@ -259,7 +259,7 @@ eqopt ({sp}=)? "%type" return PERCENT_TYPE; "%union" return PERCENT_UNION; "%verbose" return BISON_DIRECTIVE (VERBOSE); - "%yacc" return BISON_DIRECTIVE (YACC); + "%yacc" RETURN_VALUE (PERCENT_YACC, uniqstr_new (yytext)); /* Deprecated since Bison 3.0 (2013-07-25), but the warning is issued only since Bison 3.3. */ @@ -274,7 +274,7 @@ eqopt ({sp}=)? "%error"[-_]"verbose" RETURN_VALUE (PERCENT_ERROR_VERBOSE, uniqstr_new (yytext)); "%expect"[-_]"rr" DEPRECATED ("%expect-rr"); "%file-prefix"{eqopt} DEPRECATED ("%file-prefix"); - "%fixed"[-_]"output"[-_]"files" DEPRECATED ("%fixed-output-files"); + "%fixed"[-_]"output"[-_]"files" RETURN_VALUE (PERCENT_YACC, uniqstr_new (yytext)); "%no"[-_]"default"[-_]"prec" DEPRECATED ("%no-default-prec"); "%no"[-_]"lines" DEPRECATED ("%no-lines"); "%output"{eqopt} DEPRECATED ("%output"); diff --git a/tests/input.at b/tests/input.at index f4a2cbbb..3314d680 100644 --- a/tests/input.at +++ b/tests/input.at @@ -2526,8 +2526,12 @@ input.y:14.1-15.2: warning: deprecated directive: '%file-prefix\n =', use '%file fix-it:"input.y":{14:1-15:3}:"%file-prefix" input.y:17.1-19: warning: deprecated directive: '%fixed-output_files', use '%fixed-output-files' [-Wdeprecated] fix-it:"input.y":{17:1-17:20}:"%fixed-output-files" -input.y:18.1-19: warning: deprecated directive: '%fixed_output-files', use '%fixed-output-files' [-Wdeprecated] -fix-it:"input.y":{18:1-18:20}:"%fixed-output-files" +input.y:18.1-19: warning: duplicate directive: %fixed_output-files [-Wother] +input.y:17.1-19: previous declaration +fix-it:"input.y":{18:1-18:20}:"" +input.y:19.1-19: warning: duplicate directive: %fixed-output-files [-Wother] +input.y:17.1-19: previous declaration +fix-it:"input.y":{19:1-19:20}:"" input.y:20.1-19: warning: deprecated directive: '%name-prefix= "foo"', use '%define api.prefix {foo}' [-Wdeprecated] fix-it:"input.y":{20:1-20:20}:"%define api.prefix {foo}" input.y:21.1-16: warning: deprecated directive: '%no-default_prec', use '%no-default-prec' [-Wdeprecated] @@ -2550,12 +2554,12 @@ fix-it:"input.y":{29:1-29:19}:"%define api.prefix {bar}" input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother] ]]) -AT_CHECK([[sed -e '/^fix-it:/d' errors-all >experr]]) -AT_BISON_CHECK([[input.y]], [[1]], [[]], [experr]) - AT_CHECK([cp errors-all experr]) AT_BISON_CHECK([[-ffixit input.y]], [[1]], [[]], [experr]) +AT_CHECK([[sed -e '/^fix-it:/d' errors-all >experr]]) +AT_BISON_CHECK([[input.y]], [[1]], [[]], [experr]) + # Update the input file. AT_CHECK([cp input.y input.y.orig]) AT_CHECK([sed -e '/fix-it/d' <errors-all >experr]) @@ -2583,8 +2587,6 @@ AT_CHECK([cat input.y], [], %file-prefix "bar" %fixed-output-files -%fixed-output-files -%fixed-output-files %define api.prefix {foo} %no-default-prec %no-default-prec @@ -2599,10 +2601,10 @@ exp : '0' ]]) AT_BISON_CHECK([[-fcaret input.y]], [[1]], [], -[[input.y:27.1-24: error: %define variable 'api.prefix' redefined +[[input.y:25.1-24: error: %define variable 'api.prefix' redefined %define api.prefix {bar} ^~~~~~~~~~~~~~~~~~~~~~~~ -input.y:19.1-24: previous definition +input.y:17.1-24: previous definition %define api.prefix {foo} ^~~~~~~~~~~~~~~~~~~~~~~~ input.y: warning: fix-its can be applied. Rerun with option '--update'. [-Wother]
