grammar: warn about unused precedence for symbols

Symbols with precedence but no associativity, and whose precedence is
never used, can be declared with %token instead.  The used precedence
relationships are recorded and a warning about useless ones is issued.

* src/conflicts.c (resolve_sr_conflict): Record precedence relation.
* src/symtab.c, src/symtab.h (prec_nodes, init_prec_nodes)
(symgraphlink_new, register_precedence_second_symbol)
(print_precedence_warnings): New.
Record relationships in a graph and warn about useless ones.
* src/main.c (main): Print precedence warnings.
* tests/conflicts.at: New.
This commit is contained in:
Valentin Tolmer
2013-01-29 14:55:53 +01:00
committed by Akim Demaille
parent fbecd2ab59
commit 284bc49c83
6 changed files with 211 additions and 1 deletions

View File

@@ -46,6 +46,11 @@ symbol *accept = NULL;
symbol *startsymbol = NULL;
location startsymbol_location;
/*---------------------------.
| Precedence relation graph. |
`---------------------------*/
static symgraph **prec_nodes;
/*---------------------------------.
| Create a new symbol, named TAG. |
@@ -971,3 +976,100 @@ symbols_pack (void)
_("the start symbol %s is a token"),
startsymbol->tag);
}
/*---------------------------------.
| Initialize relation graph nodes. |
`---------------------------------*/
static void
init_prec_nodes (void)
{
int i;
prec_nodes = xcalloc (nsyms, sizeof *prec_nodes);
for (i = 0; i < nsyms; ++i)
{
prec_nodes[i] = xmalloc (sizeof *prec_nodes[i]);
symgraph *s = prec_nodes[i];
s->id = i;
s->succ = 0;
s->pred = 0;
}
}
/*----------------.
| Create a link. |
`----------------*/
static symgraphlink *
symgraphlink_new (graphid id, symgraphlink *next)
{
symgraphlink *l = xmalloc (sizeof *l);
l->id = id;
l->next = next;
return l;
}
/*------------------------------------------------------------------.
| Register the second symbol of the precedence relation, and return |
| whether this relation is new. Use only in register_precedence. |
`------------------------------------------------------------------*/
static bool
register_precedence_second_symbol (symgraphlink **first, graphid sym)
{
if (!*first || sym < (*first)->id)
*first = symgraphlink_new (sym, *first);
else
{
symgraphlink *slist = *first;
while (slist->next && slist->next->id <= sym)
slist = slist->next;
if (slist->id == sym)
/* Relation already present. */
return false;
slist->next = symgraphlink_new (sym, slist->next);
}
return true;
}
/*------------------------------------------------------------------.
| Register a new relation between symbols as used. The first symbol |
| has a greater precedence than the second one. |
`------------------------------------------------------------------*/
void
register_precedence (graphid first, graphid snd)
{
if (!prec_nodes)
init_prec_nodes ();
register_precedence_second_symbol (&(prec_nodes[first]->succ), snd);
register_precedence_second_symbol (&(prec_nodes[snd]->pred), first);
}
/*--------------------------------------------------.
| Print a warning for unused precedence relations. |
`--------------------------------------------------*/
void
print_precedence_warnings (void)
{
int i;
if (!prec_nodes)
init_prec_nodes ();
for (i = 0; i < nsyms; ++i)
{
symbol *s = symbols[i];
if (s
&& s->prec != 0
&& !prec_nodes[i]->pred
&& !prec_nodes[i]->succ
&& s->assoc == precedence_assoc)
complain (&s->location, Wother,
_("useless precedence for %s"), s->tag);
}
}