diagnostics: factor and enhance messages about duplicate rule directives

When reporting a duplicate directive on a rule, point to its first
occurrence:

one.y:11.10-15: error: only one %empty allowed per rule
   %empty {} %empty
             ^^^^^^
one.y:11.3-8: previous declaration
   %empty {} %empty
   ^^^^^^

And consistently discard the second one.

* src/complain.h, src/complain.c (duplicate_directive): New.
* src/reader.c: Use it where appropriate.
* src/symlist.h, src/symlist.c (symbol_list): Add a dprec_location member.
* tests/actions.at: Adjust expected output.
This commit is contained in:
Akim Demaille
2013-02-17 12:47:35 +01:00
parent 4c9b8f1318
commit 0fe5a72a26
6 changed files with 44 additions and 12 deletions

View File

@@ -365,3 +365,13 @@ deprecated_directive (location const *loc, char const *old, char const *upd)
_("deprecated directive: %s, use %s"), _("deprecated directive: %s, use %s"),
quote (old), quote_n (1, upd)); quote (old), quote_n (1, upd));
} }
void
duplicate_directive (char const *directive,
location first, location second)
{
unsigned i = 0;
complain (&second, complaint, _("only one %s allowed per rule"), directive);
i += SUB_INDENT;
complain_indent (&first, complaint, &i, _("previous declaration"));
}

View File

@@ -123,6 +123,10 @@ void complain_indent (location const *loc, warnings flags, unsigned *indent,
void deprecated_directive (location const *loc, void deprecated_directive (location const *loc,
char const *obsolete, char const *updated); char const *obsolete, char const *updated);
/** Report a repeated directive for a rule. */
void duplicate_directive (char const *directive,
location first, location second);
/** Warnings treated as errors shouldn't stop the execution as regular errors /** Warnings treated as errors shouldn't stop the execution as regular errors
should (because due to their nature, it is safe to go on). Thus, there are should (because due to their nature, it is safe to go on). Thus, there are
three possible execution statuses. */ three possible execution statuses. */

View File

@@ -442,8 +442,10 @@ grammar_current_rule_prec_set (symbol *precsym, location loc)
token. */ token. */
symbol_class_set (precsym, token_sym, loc, false); symbol_class_set (precsym, token_sym, loc, false);
if (current_rule->ruleprec) if (current_rule->ruleprec)
complain (&loc, complaint, _("only one %s allowed per rule"), "%prec"); duplicate_directive ("%prec",
current_rule->ruleprec = precsym; current_rule->ruleprec->location, loc);
else
current_rule->ruleprec = precsym;
} }
/* Set %empty for the current rule. */ /* Set %empty for the current rule. */
@@ -456,7 +458,8 @@ grammar_current_rule_empty_set (location loc)
if (warning_is_unset (Wempty_rule)) if (warning_is_unset (Wempty_rule))
warning_argmatch ("empty-rule", 0, 0); warning_argmatch ("empty-rule", 0, 0);
if (current_rule->percent_empty_loc.start.file) if (current_rule->percent_empty_loc.start.file)
complain (&loc, complaint, _("only one %s allowed per rule"), "%empty"); duplicate_directive ("%empty",
current_rule->percent_empty_loc, loc);
else else
current_rule->percent_empty_loc = loc; current_rule->percent_empty_loc = loc;
} }
@@ -473,8 +476,13 @@ grammar_current_rule_dprec_set (int dprec, location loc)
complain (&loc, complaint, _("%s must be followed by positive number"), complain (&loc, complaint, _("%s must be followed by positive number"),
"%dprec"); "%dprec");
else if (current_rule->dprec != 0) else if (current_rule->dprec != 0)
complain (&loc, complaint, _("only one %s allowed per rule"), "%dprec"); duplicate_directive ("%dprec",
current_rule->dprec = dprec; current_rule->dprec_location, loc);
else
{
current_rule->dprec = dprec;
current_rule->dprec_location = loc;
}
} }
/* Attach a merge function NAME with argument type TYPE to current /* Attach a merge function NAME with argument type TYPE to current
@@ -487,9 +495,13 @@ grammar_current_rule_merge_set (uniqstr name, location loc)
complain (&loc, Wother, _("%s affects only GLR parsers"), complain (&loc, Wother, _("%s affects only GLR parsers"),
"%merge"); "%merge");
if (current_rule->merger != 0) if (current_rule->merger != 0)
complain (&loc, complaint, _("only one %s allowed per rule"), "%merge"); duplicate_directive ("%merge",
current_rule->merger = get_merge_function (name); current_rule->merger_declaration_location, loc);
current_rule->merger_declaration_location = loc; else
{
current_rule->merger = get_merge_function (name);
current_rule->merger_declaration_location = loc;
}
} }
/* Attach SYM to the current rule. If needed, move the previous /* Attach SYM to the current rule. If needed, move the previous

View File

@@ -47,7 +47,9 @@ symbol_list_sym_new (symbol *sym, location loc)
res->percent_empty_loc = empty_location; res->percent_empty_loc = empty_location;
code_props_none_init (&res->action_props); code_props_none_init (&res->action_props);
res->dprec = 0; res->dprec = 0;
res->dprec_location = empty_location;
res->merger = 0; res->merger = 0;
res->merger_declaration_location = empty_location;
res->next = NULL; res->next = NULL;

View File

@@ -83,6 +83,7 @@ typedef struct symbol_list
location percent_empty_loc; location percent_empty_loc;
int dprec; int dprec;
location dprec_location;
int merger; int merger;
location merger_declaration_location; location merger_declaration_location;

View File

@@ -114,14 +114,17 @@ AT_SETUP([Invalid uses of %empty])
AT_DATA_GRAMMAR([[one.y]], AT_DATA_GRAMMAR([[one.y]],
[[%% [[%%
exp: exp:
%empty %empty {} %empty {} %empty
; ;
]]) ]])
AT_BISON_CHECK([-fcaret one.y], [1], [], AT_BISON_CHECK([-fcaret one.y], [1], [],
[[one.y:11.10-15: error: only one %empty allowed per rule [[one.y:11.13-18: error: only one %empty allowed per rule
%empty %empty {} %empty {} %empty
^^^^^^ ^^^^^^
one.y:11.3-8: previous declaration
%empty {} %empty
^^^^^^
]]) ]])
AT_DATA_GRAMMAR([[two.y]], AT_DATA_GRAMMAR([[two.y]],