X-Git-Url: https://git.saurik.com/bison.git/blobdiff_plain/7d6bad195977b0204fc8406cac57cf5a4f1c769b..b805eca764fa0a7f0b5693931a2289fc74689f40:/src/symtab.c diff --git a/src/symtab.c b/src/symtab.c index 9014acf2..d3ad2fbb 100644 --- a/src/symtab.c +++ b/src/symtab.c @@ -46,6 +46,17 @@ symbol *accept = NULL; symbol *startsymbol = NULL; location startsymbol_location; +/*---------------------------. +| Precedence relation graph. | +`---------------------------*/ + +static symgraph **prec_nodes; + +/*-----------------------------------. +| Store which associativity is used. | +`-----------------------------------*/ + +bool *used_assoc = NULL; /*---------------------------------. | Create a new symbol, named TAG. | @@ -971,3 +982,149 @@ 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); +} + + +/*---------------------------------------. +| 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. | +`--------------------------------------------------*/ + +void +print_precedence_warnings (void) +{ + 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) + { + 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); + } +}