bison-patches
[Top][All Lists]
Advanced

[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!




reply via email to

[Prev in Thread] Current Thread [Next in Thread]