static symgraph **prec_nodes;
+/*-----------------------------------.
+| Store which associativity is used. |
+`-----------------------------------*/
+
+bool *used_assoc = NULL;
+
/*---------------------------------.
| Create a new symbol, named TAG. |
`---------------------------------*/
{
if (s)
{
- fprintf (f, "\"%s\"", s->tag);
+ fputs (s->tag, f);
SYMBOL_ATTR_PRINT (type_name);
SYMBOL_CODE_PRINT (destructor);
SYMBOL_CODE_PRINT (printer);
}
else
- fprintf (f, "<NULL>");
+ fputs ("<NULL>", f);
}
#undef SYMBOL_ATTR_PRINT
}
+/*---------------------------------------.
+| Deep clear a linked / adjacency list). |
+`---------------------------------------*/
+
+static void
+linkedlist_free (symgraphlink *node)
+{
+ if (node)
+ {
+ while (node->next)
+ {
+ symgraphlink *tmp = node->next;
+ free (node);
+ node = tmp;
+ }
+ free (node);
+ }
+}
+
+/*----------------------------------------------.
+| Clear and destroy association tracking table. |
+`----------------------------------------------*/
+
+static void
+assoc_free (void)
+{
+ int i;
+ for (i = 0; i < nsyms; ++i)
+ {
+ linkedlist_free (prec_nodes[i]->pred);
+ linkedlist_free (prec_nodes[i]->succ);
+ free (prec_nodes[i]);
+ }
+ free (prec_nodes);
+}
+
+/*---------------------------------------.
+| Initialize association tracking table. |
+`---------------------------------------*/
+
+static void
+init_assoc (void)
+{
+ graphid i;
+ used_assoc = xcalloc(nsyms, sizeof(*used_assoc));
+ for (i = 0; i < nsyms; ++i)
+ used_assoc[i] = false;
+}
+
+/*------------------------------------------------------------------.
+| Test if the associativity for the symbols is defined and useless. |
+`------------------------------------------------------------------*/
+
+static inline bool
+is_assoc_useless (symbol *s)
+{
+ return s
+ && s->assoc != undef_assoc
+ && s->assoc != precedence_assoc
+ && !used_assoc[s->number];
+}
+
+/*-------------------------------.
+| Register a used associativity. |
+`-------------------------------*/
+
+void
+register_assoc (graphid i, graphid j)
+{
+ if (!used_assoc)
+ init_assoc ();
+ used_assoc[i] = true;
+ used_assoc[j] = true;
+}
+
/*--------------------------------------------------.
| Print a warning for unused precedence relations. |
`--------------------------------------------------*/
int i;
if (!prec_nodes)
init_prec_nodes ();
+ if (!used_assoc)
+ init_assoc ();
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);
+ && !prec_nodes[i]->succ)
+ {
+ if (is_assoc_useless (s))
+ complain (&s->location, Wprecedence,
+ _("useless precedence and associativity for %s"), s->tag);
+ else if (s->assoc == precedence_assoc)
+ complain (&s->location, Wprecedence,
+ _("useless precedence for %s"), s->tag);
+ }
+ else if (is_assoc_useless (s))
+ complain (&s->location, Wprecedence,
+ _("useless associativity for %s, use %%precedence"), s->tag);
}
+ free (used_assoc);
+ assoc_free ();
}