bison-patches
[Top][All Lists]
Advanced

[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




reply via email to

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