[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] grammar: new syntax allowing for partial order symbol precedence
From: |
Valentin Tolmer |
Subject: |
[PATCH] grammar: new syntax allowing for partial order symbol precedence |
Date: |
Tue, 2 Jul 2013 15:52:58 +0200 |
From: nitnelave <address@hidden>
Extension of the syntax to be able to declare precedence relationships as
a partial order rather than a total one. Token precedence can now be
declared by groups, with no links between the groups.
%gprec arith {
%left '+' '-'
%left '*' '\'
}
%gprec bool {
%left OR
%left AND
}
Here, OR and '+' cannot be compared, and a state leading to this comparison
will raise an error, allowing to detect unwanted conflict reslution.
More precedence relationships can be declared with a syntax such as
%precr AND OR > '+'
%precr bool > '*' '/'
%precr AND = '*'
For now, the relations are not transitive.
* src/conflicts.c: Update conflict resolution and error reporting
* src/gram.h: Add a marker for the parser and lexer
* src/parse-gram.y: Extension of the syntax
* src/scan-gram.l: Change braces interpretation after %gprec
* src/symtab.c, src/symtab.h: Declaration and handling of the precedence
symbol groups, and the precedence graph created.
---
src/conflicts.c | 127 +++++++++--------
src/gram.h | 3 +
src/parse-gram.y | 74 ++++++++++
src/scan-gram.l | 17 +++
src/symtab.c | 408 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/symtab.h | 92 ++++++++++++
6 files changed, 663 insertions(+), 58 deletions(-)
diff --git a/src/conflicts.c b/src/conflicts.c
index 1840473..5dd36b1 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,11 @@ 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->tag,
+ symbols[token]->tag);
}
obstack_sgrow (&solved_conflicts_obstack, ".\n");
@@ -203,7 +210,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->tag));
+ break;
}
obstack_sgrow (&solved_conflicts_xml_obstack, "</resolution>\n");
@@ -263,66 +276,72 @@ 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]->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]->prec < redprec)
- {
- register_precedence (redrule->prec->number, i);
- log_resolution (redrule, i, reduce_resolution);
- flush_shift (s, i);
- }
- else if (symbols[i]->prec > redprec)
+ if (redprecsym && symbols[i]->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]->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]->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]->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]->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;
+ }
+ 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]->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);
}
}
diff --git a/src/gram.h b/src/gram.h
index c1dd9a6..4dd2a88 100644
--- a/src/gram.h
+++ b/src/gram.h
@@ -117,6 +117,9 @@ typedef int item_number;
extern item_number *ritem;
extern unsigned int nritems;
+/* Marker for the lexer and parser, to correctly interpret braces. */
+static int prec_braces = 0;
+
/* There is weird relationship between OT1H item_number and OTOH
symbol_number and rule_number: we store the latter in
item_number. symbol_number values are stored as-is, while
diff --git a/src/parse-gram.y b/src/parse-gram.y
index 1ec4b4d..c601b9f 100644
--- a/src/parse-gram.y
+++ b/src/parse-gram.y
@@ -130,6 +130,8 @@
%token PERCENT_PREC "%prec"
%token PERCENT_DPREC "%dprec"
+%token PERCENT_GPREC "%gprec"
+%token PERCENT_PRECR "%precr"
%token PERCENT_MERGE "%merge"
/*----------------------.
@@ -175,9 +177,12 @@
%token PIPE "|"
%token PROLOGUE "%{...%}"
%token SEMICOLON ";"
+%token SUPERIOR ">"
%token TAG "<tag>"
%token TAG_ANY "<*>"
%token TAG_NONE "<>"
+%token LBRACE "{"
+%token RBRACE "}"
%union {unsigned char character;}
%type <character> CHAR
@@ -214,6 +219,13 @@
%union {named_ref *named_ref;}
%type <named_ref> named_ref.opt
+%type <uniqstr> group_name.opt string_or_id
+
+%union {precedence_relation_comparator precedence_relation_comparator; }
+%type <precedence_relation_comparator> precedence_relation_comparator
+
+%type <list> precedence_relation_symbols precedence_symbol
+
/*---------.
| %param. |
`---------*/
@@ -365,6 +377,8 @@ params:
grammar_declaration:
precedence_declaration
+| precedence_group_declaration
+| precedence_relation_declaration
| symbol_declaration
| "%start" symbol
{
@@ -457,6 +471,27 @@ symbol_declaration:
}
;
+precedence_group_declaration:
+ "%gprec" group_name.opt
+ {
+ set_current_group ($2, &@2);
+ }
+ "{" precedence_declarations "}"
+ {
+ set_current_group (DEFAULT_GROUP_NAME, NULL);
+ }
+;
+
+group_name.opt:
+ %empty { $$ = new_anonymous_group_name (); }
+| variable /* Just a string, maybe there's a better way? */
+;
+
+precedence_declarations:
+ precedence_declaration
+| precedence_declarations precedence_declaration
+;
+
precedence_declaration:
precedence_declarator tag.opt symbols.prec
{
@@ -484,6 +519,45 @@ tag.opt:
| TAG { current_type = $1; tag_seen = true; }
;
+precedence_relation_declaration:
+ "%precr" precedence_relation_symbols
+ { prec_braces = 0; }
+ precedence_relation_comparator
+ precedence_relation_symbols
+ { declare_precedence_relation ($2, $5, $4, @4); }
+;
+
+precedence_relation_symbols:
+ precedence_symbol { $$ = $1; }
+| precedence_relation_symbols precedence_symbol
+ { $$ = symbol_list_append ($1, $2); }
+;
+
+precedence_symbol:
+ string_or_id
+ {
+ if (is_prec_group ($1))
+ $$ = expand_symbol_group (symgroup_from_uniqstr($1, &@1), @1);
+ else
+ $$ = symbol_list_sym_new (symbol_from_uniqstr ($1, @1), @1);
+ }
+| CHAR
+ {
+ $$ = symbol_list_sym_new (symbol_from_uniqstr (uniqstr_new (char_name
($1)), @1), @1);
+ }
+;
+
+string_or_id:
+ STRING { $$ = uniqstr_new (quotearg_style (c_quoting_style, $1)); }
+| ID { $$ = $1; }
+;
+
+precedence_relation_comparator:
+ ">" { $$ = prec_superior; }
+| "=" { $$ = prec_equal; }
+| ">" ">" { $$ = prec_superior_strict; }
+;
+
/* Just like symbols.1 but accept INT for the sake of POSIX. */
symbols.prec:
symbol.prec
diff --git a/src/scan-gram.l b/src/scan-gram.l
index 665e80d..f89647a 100644
--- a/src/scan-gram.l
+++ b/src/scan-gram.l
@@ -238,6 +238,11 @@ eqopt ([[:space:]]*=)?
"%param" RETURN_PERCENT_PARAM(both);
"%parse-param" RETURN_PERCENT_PARAM(parse);
"%prec" return PERCENT_PREC;
+ "%gprec" {
+ prec_braces = 1;
+ return PERCENT_GPREC;
+ }
+ "%precr" return PERCENT_PRECR;
"%precedence" return PERCENT_PRECEDENCE;
"%printer" return PERCENT_PRINTER;
"%pure-parser" RETURN_PERCENT_FLAG("api.pure");
@@ -273,10 +278,17 @@ eqopt ([[:space:]]*=)?
"=" return EQUAL;
"|" return PIPE;
";" return SEMICOLON;
+ "}" return RBRACE;
+ ">" return SUPERIOR;
{id} {
val->uniqstr = uniqstr_new (yytext);
id_loc = *loc;
+ if (prec_braces == 1)
+ {
+ prec_braces = 3;
+ return ID;
+ }
bracketed_id_str = NULL;
BEGIN SC_AFTER_IDENTIFIER;
}
@@ -307,6 +319,11 @@ eqopt ([[:space:]]*=)?
/* Code in between braces. */
"{" {
+ if (prec_braces & 1)
+ {
+ prec_braces = 4;
+ return LBRACE;
+ }
STRING_GROW;
nesting = 0;
code_start = loc->start;
diff --git a/src/symtab.c b/src/symtab.c
index 1c2372c..a160d2e 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,257 @@ 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 * l = malloc (sizeof *l);
+ l->target = to;
+ l->transitive = transitive;
+ l->next = NULL;
+ return l;
+}
+
+/*-------------------------------------.
+| Destructor for a simple symbol list. |
+`-------------------------------------*/
+
+static void
+free_symbol_list_prec (symbol_list * l)
+{
+ if (l)
+ {
+ free_symbol_list_prec (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;
+}
+
+/*-----------------------------------------.
+| 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 (&loc, fatal,
+ _("Contradicting declaration: %s > %s is in conflict with the \
+previous declaration of %s > %s"), from->symbol->tag, to->symbol->tag,
+ to->symbol->tag, from->symbol->tag);
+ else if (is_prec_equal (from, to))
+ complain (&loc, fatal,
+ _("Contradicting declaration: %s > %s is in conflict with the \
+previous declaration of %s = %s"), from->symbol->tag, to->symbol->tag,
+ from->symbol->tag, to->symbol->tag);
+ else
+ {
+ prec_link * l = prec_link_new (to, transitive);
+ if (from->sons)
+ {
+ prec_link *link = from->sons;
+ for (; link->next; link = link->next)
+ if (link->target == to)
+ {
+ complain (&loc, Wother,
+ _("Duplicate declaration of the precedence
relationship\
+ %s > %s"), from->symbol->tag, to->symbol->tag);
+ return;
+ }
+ link->next = l;
+ }
+ else
+ from->sons = l;
+ }
+}
+
+/*-------------------------------------------------.
+| Add a precedence relationship S1 == S2, one way. |
+`-------------------------------------------------*/
+
+static void
+create_prec_equal_link (prec_node * s1, prec_node *s2, bool transitive,
location loc)
+{
+ prec_link * l = prec_link_new (s2, transitive);
+ if (s1->equals)
+ {
+ prec_link *link = s1->equals;
+ for (; link->next; link = link->next)
+ if (link->target == s2)
+ {
+ complain (&loc, Wother,
+ _("Duplicate declaration of the precedence relationship\
+ %s = %s"), s1->symbol->tag, s2->symbol->tag);
+ }
+ link->next = l;
+ }
+ else
+ s1->equals = l;
+}
+
+
+/*---------------------------------------------------.
+| 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 (&loc, fatal,
+ _("Contradicting declaration: %s = %s is in conflict with the \
+previous declaration of %s > %s"), s1->symbol->tag, s2->symbol->tag,
+ s2->symbol->tag, s1->symbol->tag);
+ else if (is_prec_superior (s1, s2))
+ complain (&loc, fatal,
+ _("Contradicting declaration: %s = %s is in conflict with the \
+previous declaration of %s > %s"), s1->symbol->tag, s2->symbol->tag,
+ s1->symbol->tag, s2->symbol->tag);
+ create_prec_equal_link (s1, s2, transitive, loc);
+ create_prec_equal_link (s2, s1, transitive, loc);
+}
+
+/*---------------------------------------------------------------------.
+| Handle the precedence declaration between the elements of S1 and S2. |
+`---------------------------------------------------------------------*/
+
+void
+declare_precedence_relation (symbol_list *s1, symbol_list *s2,
+ precedence_relation_comparator c, location loc)
+{
+ void (*functionPtr) (prec_node *, prec_node *, bool, location);
+ bool transitive = true;
+ switch (c) {
+ case prec_superior_strict:
+ transitive = false;
+ case prec_superior:
+ functionPtr = &add_prec_link;
+ break;
+ case prec_equal:
+ functionPtr = &add_prec_equal_link;
+ break;
+ }
+ for (symbol_list *l1 = s1; l1; l1 = l1->next)
+ for (symbol_list *l2 = s2; l2; l2 = l2->next)
+ (*functionPtr)(l1->content.sym->prec_node, l2->content.sym->prec_node,
+ transitive, loc);
+}
+
+/*----------------------------------------------.
+| Get the list of symbols contained in a group. |
+`----------------------------------------------*/
+
+symbol_list *
+expand_symbol_group (symgroup * group, location loc)
+{
+ symbol_list * l = NULL;
+ for (symbol * s = group->symbol_list; s; s = s->group_next)
+ l = symbol_list_append (l, symbol_list_sym_new (s, loc));
+ return l;
+}
+
+/*------------------------------------------------------------------------.
+| 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 (symbol *s, bool same_line)
+{
+ prec_node_new (s);
+ if (!same_line)
+ for (symbol_list * l = current_prec_declaration; l; l = l->next)
+ {
+ symbol * symb = l->content.sym;
+ if (!current_group->symbol_list)
+ current_group->symbol_list = symb;
+ else
+ {
+ symbol * sym = current_group->symbol_list;
+ while (sym->group_next)
+ sym = sym->group_next;
+ sym->group_next = symb;
+ }
+ }
+
+ if (current_group->symbol_list)
+ for (symbol * sym = current_group->symbol_list; sym; sym = sym->group_next)
+ add_prec_link (s->prec_node, sym->prec_node, true, s->location);
+
+ if (!same_line)
+ {
+ free_symbol_list_prec (current_prec_declaration);
+ current_prec_declaration = malloc (sizeof *current_prec_declaration);
+ current_prec_declaration->content.sym = s;
+ 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->prec_node, true,
+ s->location);
+ if (!l->next)
+ break;
+ }
+ l->next = malloc (sizeof *l->next);
+ l->next->content.sym = s;
+ l->next->next = NULL;
+ }
+}
+
/*---------------------------------.
| Create a new symbol, named TAG. |
`---------------------------------*/
@@ -93,6 +345,12 @@ symbol_new (uniqstr tag, location loc)
res->class = unknown_sym;
res->status = undeclared;
+ res->group_next = NULL;
+ res->prec_node = malloc (sizeof *res->prec_node);
+ res->prec_node->symbol = res;
+ res->prec_node->sons = NULL;
+ res->prec_node->equals = NULL;
+
if (nsyms == SYMBOL_NUMBER_MAXIMUM)
complain (NULL, fatal, _("too many symbols in input grammar (limit is
%d)"),
SYMBOL_NUMBER_MAXIMUM);
@@ -334,6 +592,8 @@ symbol_precedence_set (symbol *sym, int prec, assoc a,
location loc)
sym->prec = prec;
sym->assoc = a;
sym->prec_location = loc;
+ add_to_current_group (sym, prec == current_prec_level);
+ current_prec_level = prec;
}
}
@@ -499,6 +759,8 @@ symbol_make_alias (symbol *sym, symbol *str, location loc)
str->alias = sym;
sym->alias = str;
str->number = sym->number;
+ free (str->prec_node);
+ str->prec_node = sym->prec_node;
symbol_type_set (str, sym->type_name, loc);
}
}
@@ -541,11 +803,9 @@ symbol_check_alias_consistency (symbol *this)
if (sym->prec || str->prec)
{
if (str->prec)
- symbol_precedence_set (sym, str->prec, str->assoc,
- str->prec_location);
+ sym->assoc = str->assoc;
else
- symbol_precedence_set (str, sym->prec, sym->assoc,
- sym->prec_location);
+ str->assoc = sym->assoc;
}
}
@@ -700,6 +960,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. |
`-------------------------------*/
@@ -717,6 +1009,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);
}
@@ -730,6 +1028,7 @@ symbol_from_uniqstr (const uniqstr key, location loc)
{
symbol probe;
symbol *entry;
+ uniqstr_assert (key);
probe.tag = key;
entry = hash_lookup (symbol_table, &probe);
@@ -1175,3 +1474,104 @@ print_precedence_warnings (void)
free (used_assoc);
assoc_free ();
}
+
+/*------------------------------------------------.
+| Counter to create unique anonymous group names. |
+`------------------------------------------------*/
+
+static int anon_group_counter = 0;
+
+/*-------------------------------------------------.
+| Return a new unique name for an anonymous group. |
+`-------------------------------------------------*/
+
+uniqstr new_anonymous_group_name (void)
+{
+ char * buff = xmalloc (20 * sizeof (*buff));
+ sprintf (buff, "__anon%i__", 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;
+}
+
+/*----------------------------------------.
+| Check if there is a group by that name. |
+`----------------------------------------*/
+
+bool
+is_prec_group (const uniqstr key)
+{
+ symgroup probe;
+ symgroup *entry;
+ probe.tag = key;
+ entry = hash_lookup (group_table, &probe);
+ return entry != NULL;
+}
+
+/*--------------------------------------------------------------------------.
+| 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)
+{
+ if (loc == NULL)
+ {
+ 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 ();
+ }
+ 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)
+ {
+ symbol * symb = l->content.sym;
+ if (!current_group->symbol_list)
+ current_group->symbol_list = symb;
+ else
+ {
+ symbol * sym = current_group->symbol_list;
+ for (; sym->group_next; sym = sym->group_next)
+ {}
+ sym->group_next = symb;
+ }
+ }
+ free_symbol_list_prec (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 bcc7495..930cbba 100644
--- a/src/symtab.h
+++ b/src/symtab.h
@@ -31,6 +31,8 @@
# include "scan-code.h"
# include "uniqstr.h"
+typedef struct symbol_list symbol_list;
+
/*----------.
| Symbols. |
`----------*/
@@ -61,6 +63,8 @@ typedef struct symbol symbol;
When status are checked at the end, "declared" symbols are fine,
"used" symbols trigger warnings, otherwise it's an error. */
+typedef struct prec_node prec_node;
+
typedef enum
{
/** Used in the input file for an unknown reason (error). */
@@ -113,10 +117,20 @@ struct symbol
symbol_number number;
location prec_location;
+
+ /* Not used anymore, to remove. */
int prec;
+
assoc assoc;
int user_token_number;
+ /* The next element in the symbol precedence group. */
+ symbol * group_next;
+
+ /* The graph node containing all the precedence information for this
+ symbol. */
+ prec_node * prec_node;
+
/* Points to the other in the symbol-string pair for an alias.
Special value USER_NUMBER_HAS_STRING_ALIAS in the symbol half of the
symbol-string pair for an alias. */
@@ -277,6 +291,84 @@ void print_precedence_warnings (void);
void register_assoc (graphid i, graphid j);
+
+/*------------------.
+| Groups of symbols |
+`------------------*/
+
+#define DEFAULT_GROUP_NAME uniqstr_new ("__default__")
+
+typedef struct symgroup symgroup;
+
+struct symgroup {
+ /** The name of the group. */
+ uniqstr tag;
+
+ /** The list of symbols in the group. */
+ symbol * symbol_list;
+
+ 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);
+
+/** Check if there is a symbol precedence group by that name. */
+bool
+is_prec_group (const uniqstr key);
+
+
+/*----------------------------------.
+| Graph of precedence relationships |
+`----------------------------------*/
+
+typedef struct prec_link prec_link;
+
+struct prec_link {
+ prec_node * target;
+ bool transitive;
+ prec_link *next;
+};
+
+struct prec_node {
+ symbol * symbol;
+ prec_link * sons;
+ prec_link * equals;
+};
+
+typedef enum precedence_relation_comparator precedence_relation_comparator;
+
+enum precedence_relation_comparator {
+ prec_equal,
+ prec_superior,
+ prec_superior_strict,
+};
+
+/** Declare a precedence relationship between the symbols of the two lists,
+ * as defined by the operator. */
+void
+declare_precedence_relation (symbol_list *l1, symbol_list *l2,
+ precedence_relation_comparator c, location loc);
+/** Return the list of symbols contained in the group. */
+symbol_list *
+expand_symbol_group (symgroup * group, location loc);
+
+/** 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. |
`-----------------*/
--
1.7.9.5