[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 2/7] conflicts: switch to partial order precedence system
From: |
Valentin Tolmer |
Subject: |
[PATCH 2/7] conflicts: switch to partial order precedence system |
Date: |
Thu, 1 Aug 2013 16:04:50 +0200 |
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
---
src/AnnotationList.c | 4 +-
src/conflicts.c | 133 +++++++++-------
src/gram.c | 4 +-
src/print-xml.c | 3 +-
src/symtab.c | 431 ++++++++++++++++++++++++++++++++++++++++++++++++--
src/symtab.h | 24 ++-
tests/existing.at | 8 +-
7 files changed, 528 insertions(+), 79 deletions(-)
diff --git a/src/AnnotationList.c b/src/AnnotationList.c
index 9f0adb9..b1cfab1 100644
--- a/src/AnnotationList.c
+++ b/src/AnnotationList.c
@@ -740,7 +740,7 @@ AnnotationList__computeDominantContribution (AnnotationList
const *self,
if (reduce_precedence
&& (reduce_precedence < shift_precedence
|| (reduce_precedence == shift_precedence
- && token->content->assoc == right_assoc)))
+ && token->content->prec_node->assoc == right_assoc)))
continue;
if (!AnnotationList__stateMakesContribution (self, nitems, ci,
lookaheads))
@@ -748,7 +748,7 @@ AnnotationList__computeDominantContribution (AnnotationList
const *self,
/* This uneliminated reduction contributes, so see if it can cause
an error action. */
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
shift after a potential %nonassoc. */
diff --git a/src/conflicts.c b/src/conflicts.c
index 30a2cab..b8f1dcc 100644
--- a/src/conflicts.c
+++ b/src/conflicts.c
@@ -53,7 +53,8 @@ enum conflict_resolution
reduce_resolution,
left_resolution,
right_resolution,
- nonassoc_resolution
+ nonassoc_resolution,
+ uncomparable_resolution
};
@@ -90,6 +91,7 @@ log_resolution (rule *r, symbol_number token,
break;
case nonassoc_resolution:
+ case uncomparable_resolution:
obstack_printf (&solved_conflicts_obstack,
_(" Conflict between rule %d and token %s"
" resolved as an error"),
@@ -132,6 +134,12 @@ log_resolution (rule *r, symbol_number token,
" (%%nonassoc %s)",
symbols[token]->tag);
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");
@@ -161,6 +169,7 @@ log_resolution (rule *r, symbol_number token,
xml_escape (symbols[token]->tag));
break;
+ case uncomparable_resolution:
case nonassoc_resolution:
obstack_printf (&solved_conflicts_xml_obstack,
" <resolution rule=\"%d\" symbol=\"%s\""
@@ -203,7 +212,13 @@ log_resolution (rule *r, symbol_number token,
obstack_printf (&solved_conflicts_xml_obstack,
"%%nonassoc %s",
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");
@@ -243,7 +258,6 @@ flush_reduce (bitset lookahead_tokens, int token)
bitset_reset (lookahead_tokens, token);
}
-
/*------------------------------------------------------------------.
| Attempt to resolve shift-reduce conflict for one rule by means of |
| 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;
/* Find the rule to reduce by to get precedence of reduction. */
rule *redrule = reds->rules[ruleno];
- int redprec = redrule->prec->prec;
+ prec_node *redprecsym = redrule->prec->prec_node;
bitset lookahead_tokens = reds->lookahead_tokens[ruleno];
for (i = 0; i < ntokens; i++)
if (bitset_test (lookahead_tokens, i)
- && bitset_test (lookahead_set, i)
- && symbols[i]->content->prec)
+ && bitset_test (lookahead_set, i))
{
- /* Shift-reduce conflict occurs for token number i
- 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);
- log_resolution (redrule, i, reduce_resolution);
- flush_shift (s, i);
- }
- else if (symbols[i]->content->prec > redprec)
+ if (redprecsym && symbols[i]->content->prec_node)
{
- register_precedence (i, redrule->prec->number);
- log_resolution (redrule, i, shift_resolution);
- flush_reduce (lookahead_tokens, i);
+ /* Shift-reduce conflict occurs for token number i
+ and it has a precedence.
+ The precedence of shifting is that of token i. */
+ if (is_prec_superior (redprecsym, symbols[i]->content->prec_node))
+ {
+ register_precedence (redrule->prec->number, i);
+ log_resolution (redrule, i, reduce_resolution);
+ flush_shift (s, 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
- /* 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->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;
- }
+ log_resolution (redrule, i, uncomparable_resolution);
}
}
@@ -354,7 +375,7 @@ set_conflicts (state *s, symbol **errors)
check for shift-reduce conflict, and try to resolve using
precedence. */
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))
resolve_sr_conflict (s, i, errors, &nerrs);
diff --git a/src/gram.c b/src/gram.c
index 790ec3a..66f550c 100644
--- a/src/gram.c
+++ b/src/gram.c
@@ -239,7 +239,7 @@ grammar_dump (FILE *out, const char *title)
for (i = ntokens; i < nsyms; i++)
fprintf (out, "%5d %5d %5d %s\n",
i,
- symbols[i]->content->prec, symbols[i]->content->assoc,
+ symbols[i]->content->prec,
symbols[i]->content->prec_node->assoc,
symbols[i]->tag);
fprintf (out, "\n\n");
}
@@ -262,7 +262,7 @@ grammar_dump (FILE *out, const char *title)
fprintf (out, "%3d (%2d, %2d, %2d, %2u-%2u) %2d ->",
i,
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,
rhs_itemno,
rhs_itemno + rhs_count - 1,
diff --git a/src/print-xml.c b/src/print-xml.c
index 3ddaeba..60eaf36 100644
--- a/src/print-xml.c
+++ b/src/print-xml.c
@@ -392,7 +392,8 @@ print_grammar (FILE *out, int level)
{
char const *tag = symbols[token_translations[i]]->tag;
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);
fprintf (out,
"<terminal symbol-number=\"%d\" token-number=\"%d\""
diff --git a/src/symtab.c b/src/symtab.c
index f6761c4..aa7c5e8 100644
--- a/src/symtab.c
+++ b/src/symtab.c
@@ -26,6 +26,7 @@
#include "complain.h"
#include "gram.h"
#include "symtab.h"
+#include "symlist.h"
/*-------------------------------------------------------------------.
| Symbols sorted by tag. Allocated by the first invocation of |
@@ -58,6 +59,256 @@ static symgraph **prec_nodes;
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. |
`--------------------------*/
@@ -78,12 +329,14 @@ sym_content_new (symbol *s)
res->number = NUMBER_UNDEFINED;
res->prec = 0;
- res->assoc = undef_assoc;
res->user_token_number = USER_NUMBER_UNDEFINED;
res->class = unknown_sym;
res->status = undeclared;
+ res->group_next = NULL;
+ res->prec_node = prec_node_new (s);
+
return res;
}
@@ -116,6 +369,28 @@ symbol_new (uniqstr tag, location loc)
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. |
`--------------------*/
@@ -123,6 +398,7 @@ symbol_new (uniqstr tag, location loc)
static void
sym_content_free (sym_content *sym)
{
+ prec_node_free (sym->prec_node);
free (sym);
}
@@ -367,14 +643,16 @@ symbol_precedence_set (symbol *sym, int prec, assoc a,
location loc)
sym_content *s = sym->content;
if (a != undef_assoc)
{
- if (s->prec)
+ if (s->prec_node->assoc != undef_assoc)
symbol_redeclaration (sym, assoc_to_string (a),
- s->prec_location, loc);
+ s->prec_node->prec_location, loc);
else
{
s->prec = prec;
- s->assoc = a;
- s->prec_location = loc;
+ s->prec_node->assoc = a;
+ 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);
}
+/*-------------------------------------.
+| 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. |
`-------------------------------*/
@@ -701,6 +1011,12 @@ symbols_new (void)
hash_semantic_type_hasher,
hash_semantic_type_comparator,
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 (semantic_type_table);
+ hash_free (group_table);
free (symbols);
free (symbols_sorted);
free (semantic_types_sorted);
+ symbol_list_prec_free (current_prec_declaration);
}
@@ -1102,8 +1420,8 @@ static inline bool
is_assoc_useless (symbol *s)
{
return s
- && s->content->assoc != undef_assoc
- && s->content->assoc != precedence_assoc
+ && s->content->prec_node->assoc != undef_assoc
+ && s->content->prec_node->assoc != precedence_assoc
&& !used_assoc[s->content->number];
}
@@ -1136,21 +1454,110 @@ print_precedence_warnings (void)
{
symbol *s = symbols[i];
if (s
- && s->content->prec != 0
&& !prec_nodes[i]->pred
&& !prec_nodes[i]->succ)
{
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);
- else if (s->content->assoc == precedence_assoc)
- complain (&s->content->prec_location, Wprecedence,
+ else if (s->content->prec_node->assoc == precedence_assoc)
+ complain (&s->content->prec_node->prec_location, Wprecedence,
_("useless precedence for %s"), s->tag);
}
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);
}
free (used_assoc);
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);
+}
diff --git a/src/symtab.h b/src/symtab.h
index 18e6805..5c042b0 100644
--- a/src/symtab.h
+++ b/src/symtab.h
@@ -129,9 +129,10 @@ struct sym_content
code_props props[CODE_PROPS_SIZE];
symbol_number number;
- location prec_location;
+
+ /* Not used anymore, to remove. */
int prec;
- assoc assoc;
+
int user_token_number;
symbol_class class;
@@ -317,6 +318,18 @@ struct symgroup
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 |
`----------------------------------*/
@@ -348,6 +361,13 @@ enum prec_rel_comparator
prec_superior,
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. |
`-----------------*/
diff --git a/tests/existing.at b/tests/existing.at
index a1b95ac..a883225 100644
--- a/tests/existing.at
+++ b/tests/existing.at
@@ -484,7 +484,7 @@ dnl - 61 -> 328: reduce -> shift on '*', '/', and '%'
NAME [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
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)]
'$' [reduce using rule 152 (opt_variable)]
-@@ -5399,7 +5399,7 @@
+@@ -5405,7 +5405,7 @@
156 | . '$' non_post_simp_exp
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)]
'$' [reduce using rule 152 (opt_variable)]
-@@ -6214,7 +6214,7 @@
+@@ -6220,7 +6220,7 @@
156 | . '$' non_post_simp_exp
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)]
'$' [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 .
$default reduce using rule 45 (statement)
--
1.7.9.5
- [PATCH 0/7] new partial order precedence syntax, Valentin Tolmer, 2013/08/01
- [PATCH 7/7] news: new syntax (%gprec and %precr), Valentin Tolmer, 2013/08/01
- [PATCH 6/7] regen, Valentin Tolmer, 2013/08/01
- [PATCH 2/7] conflicts: switch to partial order precedence system,
Valentin Tolmer <=
- [PATCH 5/7] tests: new tests for %gprec and %precr, Valentin Tolmer, 2013/08/01
- [PATCH 1/7] introduction of the new structures to prepare for partial order precedence, Valentin Tolmer, 2013/08/01
- [PATCH 3/7] syntax: introducing %gprec for precedence groups, Valentin Tolmer, 2013/08/01
- [PATCH 4/7] syntax: introducing %precr to add specific precedence relations, Valentin Tolmer, 2013/08/01