[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] grammar: new syntax allowing for partial order symbol preced
From: |
Akim Demaille |
Subject: |
Re: [PATCH] grammar: new syntax allowing for partial order symbol precedence |
Date: |
Tue, 2 Jul 2013 17:28:33 +0200 |
hi Valentin,
I have to read this in depth, and to toy with it. But some
stylistic issues:
> More precedence relationships can be declared with a syntax such as
>
> %precr AND OR > '+'
> %precr bool > '*' '/'
> %precr AND = '*'
I confess I prefer using < in general, but I guess this way
it makes your life easier when dealing with the handling of
"<" and "<tag>".
Note that current system presents precedences in the increasing
order, the opposite of yours.
> @@ -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);
> }
Add the missing break.
> @@ -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;
prec_node *redprecsym
> 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);
Wouldn't it be time to extract a small function in here?
> }
> 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;
What are its values? Why the magic "& 1"?
> @@ -175,9 +177,12 @@
> %token PIPE "|"
> %token PROLOGUE "%{...%}"
> %token SEMICOLON ";"
> +%token SUPERIOR ">"
Don't name it this way, it's not its English name. Make it GT,
one of its traditional names in parsers.
> +%union {precedence_relation_comparator precedence_relation_comparator; }
These names are _really_ long.
> +%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);
> + }
> +;
You should add some comments in the grammar, so that we understand
what each symbol denotes.
> +
> +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;
> + }
The indentation does not match the remainder of the code.
> + "%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;
Magic values are unwelcome.
> + 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;
*current_group. Likewise below.
> +
> +/*-------------------------------------------------------.
> +| 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;
If you return a local variable, name it "res".
> +}
> +
> +/*-------------------------------------.
> +| 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,
Errors in Bison start in lower case (that's from GNU coding standards).
Don't use \ and multiline string literals, rather do this:
"first part"
"second part"
> + 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);
Using a common message with a %s for = or > would make translators lives
easier. Introduce a function to issue the error.
> + 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,
Why not Wprec?
> + _("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)
That fits in 80 cols?
> +{
> + 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);
> + }
Why the braces?
> + 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);
Code duplication in the error message, you really should factor.
> + 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) {
Wrong style of brace.
> + case prec_superior_strict:
> + transitive = false;
Make it clear that you want to fall through.
> + 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)
This is C99, but that's ok.
> + (*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;
Shouldn't you introduce a prec_node_new function?
> +
> 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;
Use ?:.
> }
> }
>
> @@ -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. |
> +`-------------------------------------*/
This is getting so complex that it might make sense to move all this
into a dedicated set of files.
> +
> +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);
Should be a separated patch. This patch is doing way too many
things at the same time.
>
> 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));
Now that's what I call a leakā¦ Why don't you use a char buf[20]?
> + sprintf (buff, "__anon%i__", anon_group_counter++);
Don't use dangerous functions, use snprintf. I'm not sure %i
is portable.
> + 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 {
Brace.
> + /** 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 {
Braces, several times.
> + 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
Tests are needed!