mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-19 01:03:04 +00:00
conflicts: switch to partial order precedence system
Even though it is not yet fully deployed, this commit lays the ground for the partial order precedence system, by changing to a graph-based order and introducing precedence groups (only the default one can be used for now). * src/symtab.h (struct symbol): Removed extra fields * src/symtab.h: New function declarations * src/symtab.c: New functions for precedence and groups, new hash table for groups * src/AnnotationList.c, src/conflicts.c, src/gram.c, src/print-xml.c, * src/symtab.c: Adaptation to the new prec_node structure * tests/existing.at (GAWK LALR): Fix
This commit is contained in:
@@ -740,7 +740,7 @@ AnnotationList__computeDominantContribution (AnnotationList const *self,
|
|||||||
if (reduce_precedence
|
if (reduce_precedence
|
||||||
&& (reduce_precedence < shift_precedence
|
&& (reduce_precedence < shift_precedence
|
||||||
|| (reduce_precedence == shift_precedence
|
|| (reduce_precedence == shift_precedence
|
||||||
&& token->content->assoc == right_assoc)))
|
&& token->content->prec_node->assoc == right_assoc)))
|
||||||
continue;
|
continue;
|
||||||
if (!AnnotationList__stateMakesContribution (self, nitems, ci,
|
if (!AnnotationList__stateMakesContribution (self, nitems, ci,
|
||||||
lookaheads))
|
lookaheads))
|
||||||
@@ -748,7 +748,7 @@ AnnotationList__computeDominantContribution (AnnotationList const *self,
|
|||||||
/* This uneliminated reduction contributes, so see if it can cause
|
/* This uneliminated reduction contributes, so see if it can cause
|
||||||
an error action. */
|
an error action. */
|
||||||
if (reduce_precedence == shift_precedence
|
if (reduce_precedence == shift_precedence
|
||||||
&& token->content->assoc == non_assoc)
|
&& token->content->prec_node->assoc == non_assoc)
|
||||||
{
|
{
|
||||||
/* It's not possible to find split-stable domination over
|
/* It's not possible to find split-stable domination over
|
||||||
shift after a potential %nonassoc. */
|
shift after a potential %nonassoc. */
|
||||||
|
|||||||
133
src/conflicts.c
133
src/conflicts.c
@@ -53,7 +53,8 @@ enum conflict_resolution
|
|||||||
reduce_resolution,
|
reduce_resolution,
|
||||||
left_resolution,
|
left_resolution,
|
||||||
right_resolution,
|
right_resolution,
|
||||||
nonassoc_resolution
|
nonassoc_resolution,
|
||||||
|
uncomparable_resolution
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -90,6 +91,7 @@ log_resolution (rule *r, symbol_number token,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case nonassoc_resolution:
|
case nonassoc_resolution:
|
||||||
|
case uncomparable_resolution:
|
||||||
obstack_printf (&solved_conflicts_obstack,
|
obstack_printf (&solved_conflicts_obstack,
|
||||||
_(" Conflict between rule %d and token %s"
|
_(" Conflict between rule %d and token %s"
|
||||||
" resolved as an error"),
|
" resolved as an error"),
|
||||||
@@ -132,6 +134,12 @@ log_resolution (rule *r, symbol_number token,
|
|||||||
" (%%nonassoc %s)",
|
" (%%nonassoc %s)",
|
||||||
symbols[token]->tag);
|
symbols[token]->tag);
|
||||||
break;
|
break;
|
||||||
|
case uncomparable_resolution:
|
||||||
|
obstack_printf (&solved_conflicts_obstack,
|
||||||
|
" (%s uncomparable with %s)",
|
||||||
|
r->prec->symbol->tag,
|
||||||
|
symbols[token]->tag);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
obstack_sgrow (&solved_conflicts_obstack, ".\n");
|
obstack_sgrow (&solved_conflicts_obstack, ".\n");
|
||||||
@@ -161,6 +169,7 @@ log_resolution (rule *r, symbol_number token,
|
|||||||
xml_escape (symbols[token]->tag));
|
xml_escape (symbols[token]->tag));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case uncomparable_resolution:
|
||||||
case nonassoc_resolution:
|
case nonassoc_resolution:
|
||||||
obstack_printf (&solved_conflicts_xml_obstack,
|
obstack_printf (&solved_conflicts_xml_obstack,
|
||||||
" <resolution rule=\"%d\" symbol=\"%s\""
|
" <resolution rule=\"%d\" symbol=\"%s\""
|
||||||
@@ -203,7 +212,13 @@ log_resolution (rule *r, symbol_number token,
|
|||||||
obstack_printf (&solved_conflicts_xml_obstack,
|
obstack_printf (&solved_conflicts_xml_obstack,
|
||||||
"%%nonassoc %s",
|
"%%nonassoc %s",
|
||||||
xml_escape (symbols[token]->tag));
|
xml_escape (symbols[token]->tag));
|
||||||
break;
|
break;
|
||||||
|
case uncomparable_resolution:
|
||||||
|
obstack_printf (&solved_conflicts_xml_obstack,
|
||||||
|
"%s uncomparable with %s",
|
||||||
|
xml_escape_n (0, symbols[token]->tag),
|
||||||
|
xml_escape_n (1, r->prec->symbol->tag));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
obstack_sgrow (&solved_conflicts_xml_obstack, "</resolution>\n");
|
obstack_sgrow (&solved_conflicts_xml_obstack, "</resolution>\n");
|
||||||
@@ -243,7 +258,6 @@ flush_reduce (bitset lookahead_tokens, int token)
|
|||||||
bitset_reset (lookahead_tokens, token);
|
bitset_reset (lookahead_tokens, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------.
|
/*------------------------------------------------------------------.
|
||||||
| Attempt to resolve shift-reduce conflict for one rule by means of |
|
| Attempt to resolve shift-reduce conflict for one rule by means of |
|
||||||
| precedence declarations. It has already been checked that the |
|
| precedence declarations. It has already been checked that the |
|
||||||
@@ -263,66 +277,73 @@ resolve_sr_conflict (state *s, int ruleno, symbol **errors, int *nerrs)
|
|||||||
reductions *reds = s->reductions;
|
reductions *reds = s->reductions;
|
||||||
/* Find the rule to reduce by to get precedence of reduction. */
|
/* Find the rule to reduce by to get precedence of reduction. */
|
||||||
rule *redrule = reds->rules[ruleno];
|
rule *redrule = reds->rules[ruleno];
|
||||||
int redprec = redrule->prec->prec;
|
prec_node *redprecsym = redrule->prec->prec_node;
|
||||||
bitset lookahead_tokens = reds->lookahead_tokens[ruleno];
|
bitset lookahead_tokens = reds->lookahead_tokens[ruleno];
|
||||||
|
|
||||||
for (i = 0; i < ntokens; i++)
|
for (i = 0; i < ntokens; i++)
|
||||||
if (bitset_test (lookahead_tokens, i)
|
if (bitset_test (lookahead_tokens, i)
|
||||||
&& bitset_test (lookahead_set, i)
|
&& bitset_test (lookahead_set, i))
|
||||||
&& symbols[i]->content->prec)
|
|
||||||
{
|
{
|
||||||
/* Shift-reduce conflict occurs for token number i
|
if (redprecsym && symbols[i]->content->prec_node)
|
||||||
and it has a precedence.
|
|
||||||
The precedence of shifting is that of token i. */
|
|
||||||
if (symbols[i]->content->prec < redprec)
|
|
||||||
{
|
{
|
||||||
register_precedence (redrule->prec->number, i);
|
/* Shift-reduce conflict occurs for token number i
|
||||||
log_resolution (redrule, i, reduce_resolution);
|
and it has a precedence.
|
||||||
flush_shift (s, i);
|
The precedence of shifting is that of token i. */
|
||||||
}
|
if (is_prec_superior (redprecsym, symbols[i]->content->prec_node))
|
||||||
else if (symbols[i]->content->prec > redprec)
|
{
|
||||||
{
|
register_precedence (redrule->prec->number, i);
|
||||||
register_precedence (i, redrule->prec->number);
|
log_resolution (redrule, i, reduce_resolution);
|
||||||
log_resolution (redrule, i, shift_resolution);
|
flush_shift (s, i);
|
||||||
flush_reduce (lookahead_tokens, i);
|
}
|
||||||
|
else if (is_prec_superior (symbols[i]->content->prec_node,
|
||||||
|
redprecsym))
|
||||||
|
{
|
||||||
|
register_precedence (i, redrule->prec->number);
|
||||||
|
log_resolution (redrule, i, shift_resolution);
|
||||||
|
flush_reduce (lookahead_tokens, i);
|
||||||
|
}
|
||||||
|
else if (is_prec_equal (redprecsym, symbols[i]->content->prec_node))
|
||||||
|
/* Matching precedence levels.
|
||||||
|
For non-defined associativity, keep both: unexpected
|
||||||
|
associativity conflict.
|
||||||
|
For left associativity, keep only the reduction.
|
||||||
|
For right associativity, keep only the shift.
|
||||||
|
For nonassociativity, keep neither. */
|
||||||
|
|
||||||
|
switch (symbols[i]->content->prec_node->assoc)
|
||||||
|
{
|
||||||
|
case undef_assoc:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case precedence_assoc:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case right_assoc:
|
||||||
|
register_assoc (i, redrule->prec->number);
|
||||||
|
log_resolution (redrule, i, right_resolution);
|
||||||
|
flush_reduce (lookahead_tokens, i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case left_assoc:
|
||||||
|
register_assoc (i, redrule->prec->number);
|
||||||
|
log_resolution (redrule, i, left_resolution);
|
||||||
|
flush_shift (s, i);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case non_assoc:
|
||||||
|
register_assoc (i, redrule->prec->number);
|
||||||
|
log_resolution (redrule, i, nonassoc_resolution);
|
||||||
|
flush_shift (s, i);
|
||||||
|
flush_reduce (lookahead_tokens, i);
|
||||||
|
/* Record an explicit error for this token. */
|
||||||
|
errors[(*nerrs)++] = symbols[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_resolution (redrule, i, uncomparable_resolution);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* Matching precedence levels.
|
log_resolution (redrule, i, uncomparable_resolution);
|
||||||
For non-defined associativity, keep both: unexpected
|
|
||||||
associativity conflict.
|
|
||||||
For left associativity, keep only the reduction.
|
|
||||||
For right associativity, keep only the shift.
|
|
||||||
For nonassociativity, keep neither. */
|
|
||||||
|
|
||||||
switch (symbols[i]->content->assoc)
|
|
||||||
{
|
|
||||||
case undef_assoc:
|
|
||||||
abort ();
|
|
||||||
|
|
||||||
case precedence_assoc:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case right_assoc:
|
|
||||||
register_assoc (i, redrule->prec->number);
|
|
||||||
log_resolution (redrule, i, right_resolution);
|
|
||||||
flush_reduce (lookahead_tokens, i);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case left_assoc:
|
|
||||||
register_assoc (i, redrule->prec->number);
|
|
||||||
log_resolution (redrule, i, left_resolution);
|
|
||||||
flush_shift (s, i);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case non_assoc:
|
|
||||||
register_assoc (i, redrule->prec->number);
|
|
||||||
log_resolution (redrule, i, nonassoc_resolution);
|
|
||||||
flush_shift (s, i);
|
|
||||||
flush_reduce (lookahead_tokens, i);
|
|
||||||
/* Record an explicit error for this token. */
|
|
||||||
errors[(*nerrs)++] = symbols[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +375,7 @@ set_conflicts (state *s, symbol **errors)
|
|||||||
check for shift-reduce conflict, and try to resolve using
|
check for shift-reduce conflict, and try to resolve using
|
||||||
precedence. */
|
precedence. */
|
||||||
for (i = 0; i < reds->num; ++i)
|
for (i = 0; i < reds->num; ++i)
|
||||||
if (reds->rules[i]->prec && reds->rules[i]->prec->prec
|
if (reds->rules[i]->prec /* && reds->rules[i]->prec->prec */
|
||||||
&& !bitset_disjoint_p (reds->lookahead_tokens[i], lookahead_set))
|
&& !bitset_disjoint_p (reds->lookahead_tokens[i], lookahead_set))
|
||||||
resolve_sr_conflict (s, i, errors, &nerrs);
|
resolve_sr_conflict (s, i, errors, &nerrs);
|
||||||
|
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ grammar_dump (FILE *out, const char *title)
|
|||||||
for (i = ntokens; i < nsyms; i++)
|
for (i = ntokens; i < nsyms; i++)
|
||||||
fprintf (out, "%5d %5d %5d %s\n",
|
fprintf (out, "%5d %5d %5d %s\n",
|
||||||
i,
|
i,
|
||||||
symbols[i]->content->prec, symbols[i]->content->assoc,
|
symbols[i]->content->prec, symbols[i]->content->prec_node->assoc,
|
||||||
symbols[i]->tag);
|
symbols[i]->tag);
|
||||||
fprintf (out, "\n\n");
|
fprintf (out, "\n\n");
|
||||||
}
|
}
|
||||||
@@ -262,7 +262,7 @@ grammar_dump (FILE *out, const char *title)
|
|||||||
fprintf (out, "%3d (%2d, %2d, %2d, %2u-%2u) %2d ->",
|
fprintf (out, "%3d (%2d, %2d, %2d, %2u-%2u) %2d ->",
|
||||||
i,
|
i,
|
||||||
rule_i->prec ? rule_i->prec->prec : 0,
|
rule_i->prec ? rule_i->prec->prec : 0,
|
||||||
rule_i->prec ? rule_i->prec->assoc : 0,
|
rule_i->prec ? rule_i->prec->prec_node->assoc : 0,
|
||||||
rule_i->useful,
|
rule_i->useful,
|
||||||
rhs_itemno,
|
rhs_itemno,
|
||||||
rhs_itemno + rhs_count - 1,
|
rhs_itemno + rhs_count - 1,
|
||||||
|
|||||||
@@ -392,7 +392,8 @@ print_grammar (FILE *out, int level)
|
|||||||
{
|
{
|
||||||
char const *tag = symbols[token_translations[i]]->tag;
|
char const *tag = symbols[token_translations[i]]->tag;
|
||||||
int precedence = symbols[token_translations[i]]->content->prec;
|
int precedence = symbols[token_translations[i]]->content->prec;
|
||||||
assoc associativity = symbols[token_translations[i]]->content->assoc;
|
assoc associativity = symbols[token_translations[i]]->content->prec_node
|
||||||
|
->assoc;
|
||||||
xml_indent (out, level + 2);
|
xml_indent (out, level + 2);
|
||||||
fprintf (out,
|
fprintf (out,
|
||||||
"<terminal symbol-number=\"%d\" token-number=\"%d\""
|
"<terminal symbol-number=\"%d\" token-number=\"%d\""
|
||||||
|
|||||||
431
src/symtab.c
431
src/symtab.c
@@ -26,6 +26,7 @@
|
|||||||
#include "complain.h"
|
#include "complain.h"
|
||||||
#include "gram.h"
|
#include "gram.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
|
#include "symlist.h"
|
||||||
|
|
||||||
/*-------------------------------------------------------------------.
|
/*-------------------------------------------------------------------.
|
||||||
| Symbols sorted by tag. Allocated by the first invocation of |
|
| Symbols sorted by tag. Allocated by the first invocation of |
|
||||||
@@ -58,6 +59,256 @@ static symgraph **prec_nodes;
|
|||||||
|
|
||||||
bool *used_assoc = NULL;
|
bool *used_assoc = NULL;
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------.
|
||||||
|
| The current precedence group of symbols. Used by the parser. |
|
||||||
|
`-------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static symgroup *current_group = NULL;
|
||||||
|
|
||||||
|
/*-------------------------------------------------------.
|
||||||
|
| The list of symbols declared in the current statement. |
|
||||||
|
`-------------------------------------------------------*/
|
||||||
|
|
||||||
|
static symbol_list *current_prec_declaration = NULL;
|
||||||
|
|
||||||
|
/*-------------------------------------------------.
|
||||||
|
| A counter to distinguish precedence declarations |
|
||||||
|
`-------------------------------------------------*/
|
||||||
|
|
||||||
|
static int current_prec_level = 0;
|
||||||
|
|
||||||
|
/*-----------------------------.
|
||||||
|
| Constructor for a prec_link. |
|
||||||
|
`-----------------------------*/
|
||||||
|
|
||||||
|
static prec_link *
|
||||||
|
prec_link_new (prec_node *to, bool transitive)
|
||||||
|
{
|
||||||
|
prec_link *res = malloc (sizeof *res);
|
||||||
|
res->target = to;
|
||||||
|
res->transitive = transitive;
|
||||||
|
res->next = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------.
|
||||||
|
| Destructor for a simple symbol list. |
|
||||||
|
`-------------------------------------*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
symbol_list_prec_free (symbol_list *l)
|
||||||
|
{
|
||||||
|
if (l)
|
||||||
|
{
|
||||||
|
symbol_list_prec_free (l->next);
|
||||||
|
free (l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------.
|
||||||
|
| Check if PARENT has a higher priority than SON. |
|
||||||
|
`------------------------------------------------*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_prec_superior (prec_node *parent, prec_node *son)
|
||||||
|
{
|
||||||
|
prec_link *l;
|
||||||
|
for (l = parent->sons; l; l = l->next)
|
||||||
|
if (l->target == son)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------.
|
||||||
|
| Check if S1 has the same priority as S2. |
|
||||||
|
`-----------------------------------------*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_prec_equal (prec_node *s1, prec_node *s2)
|
||||||
|
{
|
||||||
|
prec_link *l;
|
||||||
|
if (s1 == s2)
|
||||||
|
return true;
|
||||||
|
for (l = s1->equals; l; l = l->next)
|
||||||
|
if (l->target == s2)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
complain_contradicting_prec (location *loc, uniqstr s1, uniqstr s2, char c1,
|
||||||
|
char c2)
|
||||||
|
{
|
||||||
|
complain (loc, Wprecedence, _("contradicting declaration: %s %c %s is in "
|
||||||
|
"conflict with the previous declaration: %s %c %s"), s1, c1, s2,
|
||||||
|
s1, c2, s2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------.
|
||||||
|
| Compare LINK with TARGET, and return whether they are equal. |
|
||||||
|
| In case of equality, complain of the duplicate precedence declaration. |
|
||||||
|
`-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_prec_target (prec_node *l, prec_node *target, uniqstr from, char c,
|
||||||
|
location loc)
|
||||||
|
{
|
||||||
|
if (l == target)
|
||||||
|
{
|
||||||
|
complain (&loc, Wprecedence, _("duplicate declaration of the precedence "
|
||||||
|
"relationship %s %c %s"), from, c,
|
||||||
|
target->symbol->tag);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------.
|
||||||
|
| Add a precedence relationship FROM > TO. |
|
||||||
|
`-----------------------------------------*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_prec_link (prec_node *from, prec_node *to, bool transitive, location loc)
|
||||||
|
{
|
||||||
|
if (is_prec_superior (to, from))
|
||||||
|
complain_contradicting_prec(&loc, from->symbol->tag, to->symbol->tag,
|
||||||
|
'>', '<');
|
||||||
|
else if (is_prec_equal (from, to))
|
||||||
|
complain_contradicting_prec(&loc, from->symbol->tag, to->symbol->tag,
|
||||||
|
'>', '=');
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (from->sons)
|
||||||
|
{
|
||||||
|
if (is_prec_target (from->sons->target, to, from->symbol->tag, '>',
|
||||||
|
loc))
|
||||||
|
return;
|
||||||
|
|
||||||
|
prec_link *son = from->sons;
|
||||||
|
for (; son->next; son = son->next)
|
||||||
|
if (is_prec_target (son->next->target, to, from->symbol->tag, '>',
|
||||||
|
loc))
|
||||||
|
return;
|
||||||
|
son->next = prec_link_new (to, transitive);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
from->sons = prec_link_new (to, transitive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------.
|
||||||
|
| Add a precedence relationship S1 == S2, one way. |
|
||||||
|
`-------------------------------------------------*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_prec_equal_link (prec_node *s1, prec_node *s2, bool transitive,
|
||||||
|
location loc)
|
||||||
|
{
|
||||||
|
if (s1->equals)
|
||||||
|
{
|
||||||
|
if (is_prec_target (s1->equals->target, s2, s1->symbol->tag, '=',
|
||||||
|
loc))
|
||||||
|
return;
|
||||||
|
prec_link *eq = s1->equals;
|
||||||
|
for (; eq->next; eq = eq->next)
|
||||||
|
if (is_prec_target (eq->next->target, s2, s1->symbol->tag, '=',
|
||||||
|
loc))
|
||||||
|
return;
|
||||||
|
eq->next = prec_link_new (s2, transitive);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s1->equals = prec_link_new (s2, transitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------.
|
||||||
|
| Add a precedence relationship S1 == S2, both ways. |
|
||||||
|
`---------------------------------------------------*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_prec_equal_link (prec_node *s1, prec_node *s2, bool transitive,
|
||||||
|
location loc)
|
||||||
|
{
|
||||||
|
if (is_prec_superior (s2, s1))
|
||||||
|
complain_contradicting_prec(&loc, s1->symbol->tag, s2->symbol->tag,
|
||||||
|
'=', '>');
|
||||||
|
else if (is_prec_superior (s1, s2))
|
||||||
|
complain_contradicting_prec(&loc, s1->symbol->tag, s2->symbol->tag,
|
||||||
|
'=', '<');
|
||||||
|
create_prec_equal_link (s1, s2, transitive, loc);
|
||||||
|
create_prec_equal_link (s2, s1, transitive, loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------.
|
||||||
|
| Add a symbol to the current declaration group, and declare the implicit |
|
||||||
|
| precedence links. SAME_LINE is true if the symbol was declared in the |
|
||||||
|
| same statement as the previous one (same precedence level). |
|
||||||
|
`------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void
|
||||||
|
add_to_current_group (sym_content *s, bool same_line)
|
||||||
|
{
|
||||||
|
if (!same_line)
|
||||||
|
for (symbol_list *l = current_prec_declaration; l; l = l->next)
|
||||||
|
{
|
||||||
|
sym_content *symb = l->content.sym->content;
|
||||||
|
if (!current_group->symbol_list)
|
||||||
|
current_group->symbol_list = symb;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sym_content *sym = current_group->symbol_list;
|
||||||
|
while (sym->group_next)
|
||||||
|
sym = sym->group_next;
|
||||||
|
sym->group_next = symb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_group->symbol_list)
|
||||||
|
for (sym_content *sym = current_group->symbol_list; sym;
|
||||||
|
sym = sym->group_next)
|
||||||
|
add_prec_link (s->prec_node, sym->prec_node, true,
|
||||||
|
s->prec_node->prec_location);
|
||||||
|
|
||||||
|
if (!same_line)
|
||||||
|
{
|
||||||
|
symbol_list_prec_free (current_prec_declaration);
|
||||||
|
current_prec_declaration = malloc (sizeof *current_prec_declaration);
|
||||||
|
current_prec_declaration->content.sym = s->symbol;
|
||||||
|
current_prec_declaration->next = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
symbol_list *l = current_prec_declaration;
|
||||||
|
for (; true; l = l->next)
|
||||||
|
{
|
||||||
|
add_prec_equal_link (s->prec_node, l->content.sym->content->prec_node,
|
||||||
|
true, s->prec_node->prec_location);
|
||||||
|
if (!l->next)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l->next = malloc (sizeof *l->next);
|
||||||
|
l->next->content.sym = s->symbol;
|
||||||
|
l->next->next = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------.
|
||||||
|
| Create a new prec_node for the symbol s. |
|
||||||
|
`-----------------------------------------*/
|
||||||
|
|
||||||
|
static prec_node *
|
||||||
|
prec_node_new (symbol * s)
|
||||||
|
{
|
||||||
|
prec_node * res = malloc (sizeof *res);
|
||||||
|
res->symbol = s;
|
||||||
|
res->assoc = undef_assoc;
|
||||||
|
res->sons = NULL;
|
||||||
|
res-> equals = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------.
|
/*--------------------------.
|
||||||
| Create a new sym_content. |
|
| Create a new sym_content. |
|
||||||
`--------------------------*/
|
`--------------------------*/
|
||||||
@@ -78,12 +329,14 @@ sym_content_new (symbol *s)
|
|||||||
|
|
||||||
res->number = NUMBER_UNDEFINED;
|
res->number = NUMBER_UNDEFINED;
|
||||||
res->prec = 0;
|
res->prec = 0;
|
||||||
res->assoc = undef_assoc;
|
|
||||||
res->user_token_number = USER_NUMBER_UNDEFINED;
|
res->user_token_number = USER_NUMBER_UNDEFINED;
|
||||||
|
|
||||||
res->class = unknown_sym;
|
res->class = unknown_sym;
|
||||||
res->status = undeclared;
|
res->status = undeclared;
|
||||||
|
|
||||||
|
res->group_next = NULL;
|
||||||
|
res->prec_node = prec_node_new (s);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +369,28 @@ symbol_new (uniqstr tag, location loc)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
prec_link_free (prec_link * l)
|
||||||
|
{
|
||||||
|
if (l)
|
||||||
|
{
|
||||||
|
prec_link_free (l->next);
|
||||||
|
free (l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------.
|
||||||
|
| Free one prec_node. |
|
||||||
|
`--------------------*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
prec_node_free (prec_node * n)
|
||||||
|
{
|
||||||
|
prec_link_free (n->sons);
|
||||||
|
prec_link_free (n->equals);
|
||||||
|
free (n);
|
||||||
|
}
|
||||||
|
|
||||||
/*--------------------.
|
/*--------------------.
|
||||||
| Free a sym_content. |
|
| Free a sym_content. |
|
||||||
`--------------------*/
|
`--------------------*/
|
||||||
@@ -123,6 +398,7 @@ symbol_new (uniqstr tag, location loc)
|
|||||||
static void
|
static void
|
||||||
sym_content_free (sym_content *sym)
|
sym_content_free (sym_content *sym)
|
||||||
{
|
{
|
||||||
|
prec_node_free (sym->prec_node);
|
||||||
free (sym);
|
free (sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,14 +643,16 @@ symbol_precedence_set (symbol *sym, int prec, assoc a, location loc)
|
|||||||
sym_content *s = sym->content;
|
sym_content *s = sym->content;
|
||||||
if (a != undef_assoc)
|
if (a != undef_assoc)
|
||||||
{
|
{
|
||||||
if (s->prec)
|
if (s->prec_node->assoc != undef_assoc)
|
||||||
symbol_redeclaration (sym, assoc_to_string (a),
|
symbol_redeclaration (sym, assoc_to_string (a),
|
||||||
s->prec_location, loc);
|
s->prec_node->prec_location, loc);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s->prec = prec;
|
s->prec = prec;
|
||||||
s->assoc = a;
|
s->prec_node->assoc = a;
|
||||||
s->prec_location = loc;
|
s->prec_node->prec_location = loc;
|
||||||
|
add_to_current_group (s, prec == current_prec_level);
|
||||||
|
current_prec_level = prec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,6 +962,38 @@ hash_semantic_type_hasher (void const *m, size_t tablesize)
|
|||||||
return hash_semantic_type (m, tablesize);
|
return hash_semantic_type (m, tablesize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------.
|
||||||
|
| Symbol precedence group hash table. |
|
||||||
|
`-------------------------------------*/
|
||||||
|
|
||||||
|
static struct hash_table *group_table = NULL;
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
hash_compare_group (const symgroup *m1, const symgroup *m2)
|
||||||
|
{
|
||||||
|
/* Since tags are unique, we can compare the pointers themselves. */
|
||||||
|
return UNIQSTR_EQ (m1->tag, m2->tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
hash_group_comparator (void const *m1, void const *m2)
|
||||||
|
{
|
||||||
|
return hash_compare_group (m1, m2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
hash_group (const symgroup *m, size_t tablesize)
|
||||||
|
{
|
||||||
|
/* Since tags are unique, we can hash the pointer itself. */
|
||||||
|
return ((uintptr_t) m->tag) % tablesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
hash_group_hasher (void const *m, size_t tablesize)
|
||||||
|
{
|
||||||
|
return hash_group (m, tablesize);
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------.
|
/*-------------------------------.
|
||||||
| Create the symbol hash table. |
|
| Create the symbol hash table. |
|
||||||
`-------------------------------*/
|
`-------------------------------*/
|
||||||
@@ -701,6 +1011,12 @@ symbols_new (void)
|
|||||||
hash_semantic_type_hasher,
|
hash_semantic_type_hasher,
|
||||||
hash_semantic_type_comparator,
|
hash_semantic_type_comparator,
|
||||||
free);
|
free);
|
||||||
|
group_table = hash_initialize (HT_INITIAL_CAPACITY,
|
||||||
|
NULL,
|
||||||
|
hash_group_hasher,
|
||||||
|
hash_group_comparator,
|
||||||
|
free);
|
||||||
|
set_current_group (DEFAULT_GROUP_NAME, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -815,9 +1131,11 @@ symbols_free (void)
|
|||||||
{
|
{
|
||||||
hash_free (symbol_table);
|
hash_free (symbol_table);
|
||||||
hash_free (semantic_type_table);
|
hash_free (semantic_type_table);
|
||||||
|
hash_free (group_table);
|
||||||
free (symbols);
|
free (symbols);
|
||||||
free (symbols_sorted);
|
free (symbols_sorted);
|
||||||
free (semantic_types_sorted);
|
free (semantic_types_sorted);
|
||||||
|
symbol_list_prec_free (current_prec_declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1102,8 +1420,8 @@ static inline bool
|
|||||||
is_assoc_useless (symbol *s)
|
is_assoc_useless (symbol *s)
|
||||||
{
|
{
|
||||||
return s
|
return s
|
||||||
&& s->content->assoc != undef_assoc
|
&& s->content->prec_node->assoc != undef_assoc
|
||||||
&& s->content->assoc != precedence_assoc
|
&& s->content->prec_node->assoc != precedence_assoc
|
||||||
&& !used_assoc[s->content->number];
|
&& !used_assoc[s->content->number];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1136,21 +1454,110 @@ print_precedence_warnings (void)
|
|||||||
{
|
{
|
||||||
symbol *s = symbols[i];
|
symbol *s = symbols[i];
|
||||||
if (s
|
if (s
|
||||||
&& s->content->prec != 0
|
|
||||||
&& !prec_nodes[i]->pred
|
&& !prec_nodes[i]->pred
|
||||||
&& !prec_nodes[i]->succ)
|
&& !prec_nodes[i]->succ)
|
||||||
{
|
{
|
||||||
if (is_assoc_useless (s))
|
if (is_assoc_useless (s))
|
||||||
complain (&s->content->prec_location, Wprecedence,
|
complain (&s->content->prec_node->prec_location, Wprecedence,
|
||||||
_("useless precedence and associativity for %s"), s->tag);
|
_("useless precedence and associativity for %s"), s->tag);
|
||||||
else if (s->content->assoc == precedence_assoc)
|
else if (s->content->prec_node->assoc == precedence_assoc)
|
||||||
complain (&s->content->prec_location, Wprecedence,
|
complain (&s->content->prec_node->prec_location, Wprecedence,
|
||||||
_("useless precedence for %s"), s->tag);
|
_("useless precedence for %s"), s->tag);
|
||||||
}
|
}
|
||||||
else if (is_assoc_useless (s))
|
else if (is_assoc_useless (s))
|
||||||
complain (&s->content->prec_location, Wprecedence,
|
complain (&s->content->prec_node->prec_location, Wprecedence,
|
||||||
_("useless associativity for %s, use %%precedence"), s->tag);
|
_("useless associativity for %s, use %%precedence"), s->tag);
|
||||||
}
|
}
|
||||||
free (used_assoc);
|
free (used_assoc);
|
||||||
assoc_free ();
|
assoc_free ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------.
|
||||||
|
| Counter to create unique anonymous group names. |
|
||||||
|
`------------------------------------------------*/
|
||||||
|
|
||||||
|
static unsigned int anon_group_counter = 0;
|
||||||
|
|
||||||
|
/*-------------------------------------------------.
|
||||||
|
| Return a new unique name for an anonymous group. |
|
||||||
|
`-------------------------------------------------*/
|
||||||
|
|
||||||
|
uniqstr new_anonymous_group_name (void)
|
||||||
|
{
|
||||||
|
char buff[20];
|
||||||
|
snprintf (buff, 20, "__anon%u__", anon_group_counter++);
|
||||||
|
return uniqstr_new (buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------.
|
||||||
|
| Constructor for a symbol precedence group. |
|
||||||
|
`-------------------------------------------*/
|
||||||
|
|
||||||
|
symgroup *
|
||||||
|
symgroup_new (const uniqstr tag, location loc)
|
||||||
|
{
|
||||||
|
symgroup *group = xmalloc (sizeof (*group));
|
||||||
|
group->tag = tag;
|
||||||
|
group->symbol_list = NULL;
|
||||||
|
group->location = loc;
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------.
|
||||||
|
| Get the symbol precedence group by that name. If not present, a new group |
|
||||||
|
| is created and inserted in the table, with the location information |
|
||||||
|
| provided, if any. |
|
||||||
|
`--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
symgroup *
|
||||||
|
symgroup_from_uniqstr (const uniqstr key, location *loc)
|
||||||
|
{
|
||||||
|
bool null_loc = loc == NULL;
|
||||||
|
if (null_loc)
|
||||||
|
{
|
||||||
|
loc = malloc (sizeof *loc);
|
||||||
|
boundary_set (&loc->start, uniqstr_new (""), 1, 1);
|
||||||
|
boundary_set (&loc->end, uniqstr_new (""), 1, 1);
|
||||||
|
}
|
||||||
|
symgroup probe;
|
||||||
|
symgroup *entry;
|
||||||
|
|
||||||
|
probe.tag = key;
|
||||||
|
entry = hash_lookup (group_table, &probe);
|
||||||
|
|
||||||
|
if (!entry)
|
||||||
|
{
|
||||||
|
/* First insertion in the hash. */
|
||||||
|
entry = symgroup_new (key, *loc);
|
||||||
|
if (!hash_insert (group_table, entry))
|
||||||
|
xalloc_die ();
|
||||||
|
}
|
||||||
|
if (null_loc)
|
||||||
|
free (loc);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------.
|
||||||
|
| Change the current group to the one designated by the name, and create it |
|
||||||
|
| if necessary. The location information is used for creation if available. |
|
||||||
|
`--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void set_current_group (const uniqstr tag, location *loc)
|
||||||
|
{
|
||||||
|
for (symbol_list *l = current_prec_declaration; l; l = l->next)
|
||||||
|
{
|
||||||
|
sym_content *symb = l->content.sym->content;
|
||||||
|
if (!current_group->symbol_list)
|
||||||
|
current_group->symbol_list = symb;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sym_content *sym = current_group->symbol_list;
|
||||||
|
for (; sym->group_next; sym = sym->group_next)
|
||||||
|
{}
|
||||||
|
sym->group_next = symb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
symbol_list_prec_free (current_prec_declaration);
|
||||||
|
current_prec_declaration = NULL;
|
||||||
|
current_group = symgroup_from_uniqstr (tag, loc);
|
||||||
|
}
|
||||||
|
|||||||
24
src/symtab.h
24
src/symtab.h
@@ -129,9 +129,10 @@ struct sym_content
|
|||||||
code_props props[CODE_PROPS_SIZE];
|
code_props props[CODE_PROPS_SIZE];
|
||||||
|
|
||||||
symbol_number number;
|
symbol_number number;
|
||||||
location prec_location;
|
|
||||||
|
/* Not used anymore, to remove. */
|
||||||
int prec;
|
int prec;
|
||||||
assoc assoc;
|
|
||||||
int user_token_number;
|
int user_token_number;
|
||||||
|
|
||||||
symbol_class class;
|
symbol_class class;
|
||||||
@@ -317,6 +318,18 @@ struct symgroup
|
|||||||
location location;
|
location location;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
/** Get a dummy name for an anonymous group. */
|
||||||
|
uniqstr new_anonymous_group_name (void);
|
||||||
|
|
||||||
|
/** Set the current group in the token precedence declaration to a new group
|
||||||
|
* with this name */
|
||||||
|
void set_current_group (const uniqstr name, location *loc);
|
||||||
|
|
||||||
|
/** Get or create the group by that name. The location information is used for
|
||||||
|
* creation when available. */
|
||||||
|
symgroup *
|
||||||
|
symgroup_from_uniqstr (const uniqstr key, location *loc);
|
||||||
|
|
||||||
/*----------------------------------.
|
/*----------------------------------.
|
||||||
| Graph of precedence relationships |
|
| Graph of precedence relationships |
|
||||||
`----------------------------------*/
|
`----------------------------------*/
|
||||||
@@ -348,6 +361,13 @@ enum prec_rel_comparator
|
|||||||
prec_superior,
|
prec_superior,
|
||||||
prec_superior_strict,
|
prec_superior_strict,
|
||||||
};
|
};
|
||||||
|
/** Check if s1 and s2 have the same precedence level. */
|
||||||
|
bool is_prec_equal (prec_node * s1, prec_node * s2);
|
||||||
|
|
||||||
|
/** Check if from > to . */
|
||||||
|
bool is_prec_superior (prec_node * from, prec_node * to);
|
||||||
|
|
||||||
|
|
||||||
/*-----------------.
|
/*-----------------.
|
||||||
| Semantic types. |
|
| Semantic types. |
|
||||||
`-----------------*/
|
`-----------------*/
|
||||||
|
|||||||
@@ -484,7 +484,7 @@ dnl - 61 -> 328: reduce -> shift on '*', '/', and '%'
|
|||||||
|
|
||||||
NAME [reduce using rule 152 (opt_variable)]
|
NAME [reduce using rule 152 (opt_variable)]
|
||||||
'$' [reduce using rule 152 (opt_variable)]
|
'$' [reduce using rule 152 (opt_variable)]
|
||||||
@@ -5379,7 +5379,7 @@
|
@@ -5385,7 +5385,7 @@
|
||||||
156 | . '$' non_post_simp_exp
|
156 | . '$' non_post_simp_exp
|
||||||
|
|
||||||
NAME shift, and go to state 9
|
NAME shift, and go to state 9
|
||||||
@@ -493,7 +493,7 @@ dnl - 61 -> 328: reduce -> shift on '*', '/', and '%'
|
|||||||
|
|
||||||
NAME [reduce using rule 152 (opt_variable)]
|
NAME [reduce using rule 152 (opt_variable)]
|
||||||
'$' [reduce using rule 152 (opt_variable)]
|
'$' [reduce using rule 152 (opt_variable)]
|
||||||
@@ -5399,7 +5399,7 @@
|
@@ -5405,7 +5405,7 @@
|
||||||
156 | . '$' non_post_simp_exp
|
156 | . '$' non_post_simp_exp
|
||||||
|
|
||||||
NAME shift, and go to state 9
|
NAME shift, and go to state 9
|
||||||
@@ -502,7 +502,7 @@ dnl - 61 -> 328: reduce -> shift on '*', '/', and '%'
|
|||||||
|
|
||||||
NAME [reduce using rule 152 (opt_variable)]
|
NAME [reduce using rule 152 (opt_variable)]
|
||||||
'$' [reduce using rule 152 (opt_variable)]
|
'$' [reduce using rule 152 (opt_variable)]
|
||||||
@@ -6214,7 +6214,7 @@
|
@@ -6220,7 +6220,7 @@
|
||||||
156 | . '$' non_post_simp_exp
|
156 | . '$' non_post_simp_exp
|
||||||
|
|
||||||
NAME shift, and go to state 9
|
NAME shift, and go to state 9
|
||||||
@@ -511,7 +511,7 @@ dnl - 61 -> 328: reduce -> shift on '*', '/', and '%'
|
|||||||
|
|
||||||
NAME [reduce using rule 152 (opt_variable)]
|
NAME [reduce using rule 152 (opt_variable)]
|
||||||
'$' [reduce using rule 152 (opt_variable)]
|
'$' [reduce using rule 152 (opt_variable)]
|
||||||
@@ -11099,3 +11099,274 @@
|
@@ -11117,3 +11117,274 @@
|
||||||
45 statement: LEX_FOR '(' opt_exp semi opt_nls exp semi opt_nls opt_exp r_paren opt_nls statement .
|
45 statement: LEX_FOR '(' opt_exp semi opt_nls exp semi opt_nls opt_exp r_paren opt_nls statement .
|
||||||
|
|
||||||
$default reduce using rule 45 (statement)
|
$default reduce using rule 45 (statement)
|
||||||
|
|||||||
Reference in New Issue
Block a user