fix warnings for useless %printer/%destructor

The previous commit, which turns into a warning what used to be an
error:

    %printer {} foo;
    %%
    exp: '0';

has two shortcomings: the warning is way too long (foo is reported
to be useless later), and besides, it also turns into a warning much
more serious errors:

   %printer {} foo;
   %%
   exp: foo;

Reduce the amount to warnings in the first case, restore the error in
the second.

* src/symtab.h (status): Add a new inital state: undeclared.
* src/symtab.c (symbol_new): Initialize to undeclared.
(symbol_class_set): Simplify the logic of the code that neutralize
the "redeclared" warning after the "redefined" one.
(symbol_check_defined): "undeclared" is also an error.
* src/reader.c (grammar_current_rule_symbol_append): Symbols appearing
in a rule are "needed".
* src/symlist.c (symbol_list_destructor_set, symbol_list_printer_set):
An unknown symbol appearing in a %printer/%destructor is "used".
* src/reduce.c (nonterminals_reduce): Do not report as "useless" symbols
that are not used (e.g., those that for instance appeared only in a
%printer).
* tests/input.at (Undeclared symbols used for a printer or destructor):
Improve the cover the cases described above.
This commit is contained in:
Akim Demaille
2012-06-20 12:33:34 +02:00
parent 0d4b994cc2
commit 3b0b682fd6
6 changed files with 61 additions and 34 deletions

View File

@@ -470,6 +470,8 @@ grammar_current_rule_symbol_append (symbol *sym, location loc,
p = grammar_symbol_append (sym, loc); p = grammar_symbol_append (sym, loc);
if (name) if (name)
assign_named_ref(p, name); assign_named_ref(p, name);
if (sym->status == undeclared || sym->status == used)
sym->status = needed;
} }
/* Attach an ACTION to the current rule. */ /* Attach an ACTION to the current rule. */

View File

@@ -298,8 +298,10 @@ nonterminals_reduce (void)
if (!bitset_test (V, i)) if (!bitset_test (V, i))
{ {
nontermmap[i - ntokens] = n++; nontermmap[i - ntokens] = n++;
warn_at (symbols[i]->location, _("nonterminal useless in grammar: %s"), if (symbols[i]->status != used)
symbols[i]->tag); warn_at (symbols[i]->location,
_("nonterminal useless in grammar: %s"),
symbols[i]->tag);
} }

View File

@@ -232,7 +232,7 @@ symbol_list_destructor_set (symbol_list *node, char const *code, location loc)
{ {
case SYMLIST_SYMBOL: case SYMLIST_SYMBOL:
symbol_destructor_set (node->content.sym, &destructor); symbol_destructor_set (node->content.sym, &destructor);
if (node->content.sym->status == needed) if (node->content.sym->status == undeclared)
node->content.sym->status = used; node->content.sym->status = used;
break; break;
case SYMLIST_TYPE: case SYMLIST_TYPE:
@@ -258,7 +258,7 @@ symbol_list_printer_set (symbol_list *node, char const *code, location loc)
{ {
case SYMLIST_SYMBOL: case SYMLIST_SYMBOL:
symbol_printer_set (node->content.sym, &printer); symbol_printer_set (node->content.sym, &printer);
if (node->content.sym->status == needed) if (node->content.sym->status == undeclared)
node->content.sym->status = used; node->content.sym->status = used;
break; break;
case SYMLIST_TYPE: case SYMLIST_TYPE:

View File

@@ -85,7 +85,7 @@ symbol_new (uniqstr tag, location loc)
res->alias = NULL; res->alias = NULL;
res->class = unknown_sym; res->class = unknown_sym;
res->status = needed; res->status = undeclared;
if (nsyms == SYMBOL_NUMBER_MAXIMUM) if (nsyms == SYMBOL_NUMBER_MAXIMUM)
fatal (_("too many symbols in input grammar (limit is %d)"), fatal (_("too many symbols in input grammar (limit is %d)"),
@@ -358,10 +358,12 @@ symbol_precedence_set (symbol *sym, int prec, assoc a, location loc)
void void
symbol_class_set (symbol *sym, symbol_class class, location loc, bool declaring) symbol_class_set (symbol *sym, symbol_class class, location loc, bool declaring)
{ {
bool warned = false;
if (sym->class != unknown_sym && sym->class != class) if (sym->class != unknown_sym && sym->class != class)
{ {
complain_at (loc, _("symbol %s redefined"), sym->tag); complain_at (loc, _("symbol %s redefined"), sym->tag);
sym->status = needed; // Don't report both "redefined" and "redeclared".
warned = true;
} }
if (class == nterm_sym && sym->class != nterm_sym) if (class == nterm_sym && sym->class != nterm_sym)
@@ -373,7 +375,7 @@ symbol_class_set (symbol *sym, symbol_class class, location loc, bool declaring)
if (declaring) if (declaring)
{ {
if (sym->status == declared) if (sym->status == declared && !warned)
warn_at (loc, _("symbol %s redeclared"), sym->tag); warn_at (loc, _("symbol %s redeclared"), sym->tag);
sym->status = declared; sym->status = declared;
} }
@@ -421,18 +423,25 @@ symbol_check_defined (symbol *sym)
{ {
if (sym->class == unknown_sym) if (sym->class == unknown_sym)
{ {
if (sym->status == needed) switch (sym->status)
complain_at {
(sym->location, case used:
_("symbol %s is used, but is not defined as a token and has no" warn_at (sym->location,
" rules"), _("symbol %s is used, but is not defined as a token"
sym->tag); " and has no rules"),
else sym->tag);
warn_at break;
(sym->location, case undeclared:
_("symbol %s is used, but is not defined as a token and has no" case needed:
" rules"), complain_at (sym->location,
sym->tag); _("symbol %s is used, but is not defined as a token"
" and has no rules"),
sym->tag);
break;
case declared:
/* If declared, then sym->class != unknown_sym. */
assert (0);
}
sym->class = nterm_sym; sym->class = nterm_sym;
sym->number = nvars++; sym->number = nvars++;

View File

@@ -51,11 +51,27 @@ typedef int symbol_number;
typedef struct symbol symbol; typedef struct symbol symbol;
/* Declaration status of a symbol.
First, it is "undeclared". Then, if "undeclared" and used in a
%printer/%destructor, it is "used". If not "declared" by used in a
rule, it is "needed". Finally, if declared (via a rule for
nonterminals, or %oken), it is "declared".
When status are checked at the end, "declared" symbols are fine,
"used" symbols trigger warnings, otherwise it's an error.
*/
typedef enum typedef enum
{ {
needed, /**< found but not "defined". */ /** Used in the input file for an unknown reason (error). */
used, /**< used by %printer but not declared. */ undeclared,
declared, /**< defined with %type or %token. */ /** Used by %destructor/%printer but not defined (warning). */
used,
/** Used in the gramar (rules) but not defined (error). */
needed,
/** Defined with %type or %token (good). */
declared,
} status; } status;
/* When extending this structure, be sure to complete /* When extending this structure, be sure to complete

View File

@@ -271,26 +271,24 @@ input.y:5.10-24: previous declaration
AT_CLEANUP AT_CLEANUP
## ---------------------------------------------------- ## ## ----------------------------------------------------- ##
## Undeclared symbols used for a printer or destructor. ## ## Undeclared symbols used for a printer or destructor. ##
## ---------------------------------------------------- ## ## ----------------------------------------------------- ##
AT_SETUP([Undeclared symbols used for a printer or destructor]) AT_SETUP([Undeclared symbols used for a printer or destructor])
AT_DATA([[input.y]], AT_DATA([[input.y]],
[[%printer {} token1 [[%printer {} foo baz
%destructor {} token2 %destructor {} bar
%% %%
exp: "a"; exp: bar;
]]) ]])
AT_BISON_CHECK([input.y], [0], [], AT_BISON_CHECK([input.y], [1], [],
[[input.y:1.13-18: warning: symbol token1 is used, but is not defined as a token and has no rules [[input.y:2.16-18: symbol bar is used, but is not defined as a token and has no rules
input.y:2.16-21: warning: symbol token2 is used, but is not defined as a token and has no rules input.y:1.17-19: warning: symbol baz is used, but is not defined as a token and has no rules
input.y: warning: 2 nonterminals useless in grammar input.y:1.13-15: warning: symbol foo is used, but is not defined as a token and has no rules
input.y:1.13-18: warning: nonterminal useless in grammar: token1
input.y:2.16-21: warning: nonterminal useless in grammar: token2
]]) ]])
AT_CLEANUP AT_CLEANUP