]> git.saurik.com Git - bison.git/blobdiff - src/symtab.c
Make it easier to write deterministic tests.
[bison.git] / src / symtab.c
index 8910f09c4ee0e4744f848b1aad4ec655c24e5dfe..7d18f92d4da0a12b180a7964c4f0dc3ed8f7034f 100644 (file)
@@ -1,24 +1,23 @@
 /* Symbol table manager for Bison.
 
-   Copyright (C) 1984, 1989, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free
-   Software Foundation, Inc.
+   Copyright (C) 1984, 1989, 2000, 2001, 2002, 2004, 2005, 2006, 2007,
+   2008, 2009
+   Free Software Foundation, Inc.
 
    This file is part of Bison, the GNU Compiler Compiler.
 
-   Bison is free software; you can redistribute it and/or modify
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
 
-   Bison is distributed in the hope that it will be useful,
+   This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with Bison; see the file COPYING.  If not, write to
-   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 #include "system.h"
 #include "gram.h"
 #include "symtab.h"
 
+/*-------------------------------------------------------------------.
+| Symbols sorted by tag.  Allocated by the first invocation of       |
+| symbols_do, after which no more symbols should be created.         |
+`-------------------------------------------------------------------*/
+
+static symbol **symbols_sorted = NULL;
+
 /*------------------------.
 | Distinguished symbols.  |
 `------------------------*/
@@ -60,6 +66,13 @@ symbol_new (uniqstr tag, location loc)
   symbol *res = xmalloc (sizeof *res);
 
   uniqstr_assert (tag);
+
+  /* If the tag is not a string (starts with a double quote), check
+     that it is valid for Yacc. */
+  if (tag[0] != '\"' && tag[0] != '\'' && strchr (tag, '-'))
+    yacc_at (loc, _("POSIX Yacc forbids dashes in symbol names: %s"),
+             tag);
+
   res->tag = tag;
   res->location = loc;
 
@@ -152,6 +165,7 @@ semantic_type_redeclaration (semantic_type *s, const char *what, location first,
 }
 
 
+
 /*-----------------------------------------------------------------.
 | Set the TYPE_NAME associated with SYM.  Does nothing if passed 0 |
 | as TYPE_NAME.                                                    |
@@ -170,6 +184,23 @@ symbol_type_set (symbol *sym, uniqstr type_name, location loc)
     }
 }
 
+/*-----------------------------------.
+| Get the CLASS associated with SYM. |
+`-----------------------------------*/
+
+const char *
+symbol_class_get_string (symbol *sym)
+{
+  if (sym->class)
+    {
+      if (sym->class == token_sym)
+       return "terminal";
+      else if (sym->class == nterm_sym)
+       return "nonterminal";
+    }
+  return "unknown";
+}
+
 
 /*-----------------------------------------.
 | Set the DESTRUCTOR associated with SYM.  |
@@ -343,9 +374,7 @@ symbol_user_token_number_set (symbol *sym, int user_token_number, location loc)
 {
   int *user_token_numberp;
 
-  aver (sym->class == token_sym);
-
-  if (sym->user_token_number != USER_NUMBER_ALIAS)
+  if (sym->user_token_number != USER_NUMBER_HAS_STRING_ALIAS)
     user_token_numberp = &sym->user_token_number;
   else
     user_token_numberp = &sym->alias->user_token_number;
@@ -394,29 +423,24 @@ symbol_check_defined_processor (void *sym, void *null ATTRIBUTE_UNUSED)
 }
 
 
-/*------------------------------------------------------------------.
-| Declare the new symbol SYM.  Make it an alias of SYMVAL, and type |
-| SYMVAL with SYM's type.                                           |
-`------------------------------------------------------------------*/
-
 void
-symbol_make_alias (symbol *sym, symbol *symval, location loc)
+symbol_make_alias (symbol *sym, symbol *str, location loc)
 {
-  if (symval->alias)
+  if (str->alias)
     warn_at (loc, _("symbol `%s' used more than once as a literal string"),
-            symval->tag);
+            str->tag);
   else if (sym->alias)
     warn_at (loc, _("symbol `%s' given more than one literal string"),
             sym->tag);
   else
     {
-      symval->class = token_sym;
-      symval->user_token_number = sym->user_token_number;
-      sym->user_token_number = USER_NUMBER_ALIAS;
-      symval->alias = sym;
-      sym->alias = symval;
-      symval->number = sym->number;
-      symbol_type_set (symval, sym->type_name, loc);
+      str->class = token_sym;
+      str->user_token_number = sym->user_token_number;
+      sym->user_token_number = USER_NUMBER_HAS_STRING_ALIAS;
+      str->alias = sym;
+      sym->alias = str;
+      str->number = sym->number;
+      symbol_type_set (str, sym->type_name, loc);
     }
 }
 
@@ -429,46 +453,47 @@ symbol_make_alias (symbol *sym, symbol *symval, location loc)
 static inline void
 symbol_check_alias_consistency (symbol *this)
 {
-  symbol *alias = this;
-  symbol *orig  = this->alias;
+  symbol *sym = this;
+  symbol *str  = this->alias;
 
-  /* Check only those that _are_ the aliases.  */
-  if (!(this->alias && this->user_token_number == USER_NUMBER_ALIAS))
+  /* Check only the symbol in the symbol-string pair.  */
+  if (!(this->alias
+        && this->user_token_number == USER_NUMBER_HAS_STRING_ALIAS))
     return;
 
-  if (orig->type_name != alias->type_name)
+  if (str->type_name != sym->type_name)
     {
-      if (orig->type_name)
-       symbol_type_set (alias, orig->type_name, orig->type_location);
+      if (str->type_name)
+       symbol_type_set (sym, str->type_name, str->type_location);
       else
-       symbol_type_set (orig, alias->type_name, alias->type_location);
+       symbol_type_set (str, sym->type_name, sym->type_location);
     }
 
 
-  if (orig->destructor.code || alias->destructor.code)
+  if (str->destructor.code || sym->destructor.code)
     {
-      if (orig->destructor.code)
-       symbol_destructor_set (alias, &orig->destructor);
+      if (str->destructor.code)
+       symbol_destructor_set (sym, &str->destructor);
       else
-       symbol_destructor_set (orig, &alias->destructor);
+       symbol_destructor_set (str, &sym->destructor);
     }
 
-  if (orig->printer.code || alias->printer.code)
+  if (str->printer.code || sym->printer.code)
     {
-      if (orig->printer.code)
-       symbol_printer_set (alias, &orig->printer);
+      if (str->printer.code)
+       symbol_printer_set (sym, &str->printer);
       else
-       symbol_printer_set (orig, &alias->printer);
+       symbol_printer_set (str, &sym->printer);
     }
 
-  if (alias->prec || orig->prec)
+  if (sym->prec || str->prec)
     {
-      if (orig->prec)
-       symbol_precedence_set (alias, orig->prec, orig->assoc,
-                              orig->prec_location);
+      if (str->prec)
+       symbol_precedence_set (sym, str->prec, str->assoc,
+                              str->prec_location);
       else
-       symbol_precedence_set (orig, alias->prec, alias->assoc,
-                              alias->prec_location);
+       symbol_precedence_set (str, sym->prec, sym->assoc,
+                              sym->prec_location);
     }
 }
 
@@ -508,8 +533,8 @@ symbol_pack (symbol *this)
              this->number = this->alias->number;
            }
        }
-      /* Do not do processing below for USER_NUMBER_ALIASes.  */
-      if (this->user_token_number == USER_NUMBER_ALIAS)
+      /* Do not do processing below for USER_NUMBER_HAS_STRING_ALIASes.  */
+      if (this->user_token_number == USER_NUMBER_HAS_STRING_ALIAS)
        return true;
     }
   else /* this->class == token_sym */
@@ -526,7 +551,26 @@ symbol_pack_processor (void *this, void *null ATTRIBUTE_UNUSED)
 }
 
 
+static void
+user_token_number_redeclaration (int num, symbol *first, symbol *second)
+{
+  /* User token numbers are not assigned during the parsing, but in a
+     second step, via a traversal of the symbol table sorted on tag.
 
+     However, error messages make more sense if we keep the first
+     declaration first.  */
+  if (location_cmp (first->location, second->location) > 0)
+    {
+      symbol* tmp = first;
+      first = second;
+      second = tmp;
+    }
+  complain_at (second->location,
+               _("user token number %d redeclaration for %s"),
+               num, second->tag);
+  complain_at (first->location, _("previous declaration for %s"),
+               first->tag);
+}
 
 /*--------------------------------------------------.
 | Put THIS in TOKEN_TRANSLATIONS if it is a token.  |
@@ -537,14 +581,14 @@ symbol_translation (symbol *this)
 {
   /* Non-terminal? */
   if (this->class == token_sym
-      && this->user_token_number != USER_NUMBER_ALIAS)
+      && this->user_token_number != USER_NUMBER_HAS_STRING_ALIAS)
     {
       /* A token which translation has already been set? */
       if (token_translations[this->user_token_number] != undeftoken->number)
-       complain_at (this->location,
-                    _("tokens %s and %s both assigned number %d"),
-                    symbols[token_translations[this->user_token_number]]->tag,
-                    this->tag, this->user_token_number);
+       user_token_number_redeclaration
+          (this->user_token_number,
+           symbols[token_translations[this->user_token_number]],
+           this);
 
       token_translations[this->user_token_number] = this->number;
     }
@@ -658,8 +702,10 @@ symbol_from_uniqstr (const uniqstr key, location loc)
   if (!entry)
     {
       /* First insertion in the hash. */
+      aver (!symbols_sorted);
       entry = symbol_new (key, loc);
-      hash_insert (symbol_table, entry);
+      if (!hash_insert (symbol_table, entry))
+        xalloc_die ();
     }
   return entry;
 }
@@ -683,7 +729,8 @@ semantic_type_from_uniqstr (const uniqstr key)
     {
       /* First insertion in the hash. */
       entry = semantic_type_new (key);
-      hash_insert (semantic_type_table, entry);
+      if (!hash_insert (semantic_type_table, entry))
+        xalloc_die ();
     }
   return entry;
 }
@@ -750,6 +797,7 @@ symbols_free (void)
   hash_free (symbol_table);
   hash_free (semantic_type_table);
   free (symbols);
+  free (symbols_sorted);
 }
 
 
@@ -758,13 +806,36 @@ symbols_free (void)
 | terminals.                                                     |
 `---------------------------------------------------------------*/
 
+static int
+symbols_cmp (symbol const *a, symbol const *b)
+{
+  return strcmp (a->tag, b->tag);
+}
+
+static int
+symbols_cmp_qsort (void const *a, void const *b)
+{
+  return symbols_cmp (*(symbol * const *)a, *(symbol * const *)b);
+}
+
 static void
 symbols_do (Hash_processor processor, void *processor_data)
 {
-  hash_do_for_each (symbol_table, processor, processor_data);
+  size_t count = hash_get_n_entries (symbol_table);
+  if (!symbols_sorted)
+    {
+      symbols_sorted = xnmalloc (count, sizeof *symbols_sorted);
+      hash_get_entries (symbol_table, (void**)symbols_sorted, count);
+      qsort (symbols_sorted, count, sizeof *symbols_sorted,
+             symbols_cmp_qsort);
+    }
+  {
+    size_t i;
+    for (i = 0; i < count; ++i)
+      processor (symbols_sorted[i], processor_data);
+  }
 }
 
-
 /*--------------------------------------------------------------.
 | Check that all the symbols are defined.  Report any undefined |
 | symbols and consider them nonterminals.                       |
@@ -937,4 +1008,3 @@ default_tagless_printer_set (code_props const *printer)
     }
   default_tagless_printer = *printer;
 }
-