/* Symbol table manager for Bison.
- Copyright (C) 1984, 1989, 2000, 2001, 2002, 2004, 2005, 2006, 2007,
- 2008, 2009
- Free Software Foundation, Inc.
+ Copyright (C) 1984, 1989, 2000-2002, 2004-2012 Free Software
+ Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
#include "system.h"
#include <hash.h>
-#include <quotearg.h>
#include "complain.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. |
`------------------------*/
/* 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, '-'))
+ if (tag[0] != '\"' && tag[0] != '\'' && mbschr (tag, '-'))
yacc_at (loc, _("POSIX Yacc forbids dashes in symbol names: %s"),
tag);
}
}
-/*-----------------------------------.
-| 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. |
`-----------------------------------------*/
if (user_token_number == 0)
{
endtoken = sym;
- endtoken->number = 0;
/* It is always mapped to 0, so it was already counted in
NTOKENS. */
- --ntokens;
+ if (endtoken->number != NUMBER_UNDEFINED)
+ --ntokens;
+ endtoken->number = 0;
}
}
symbol_make_alias (symbol *sym, symbol *str, location loc)
{
if (str->alias)
- warn_at (loc, _("symbol `%s' used more than once as a literal string"),
- str->tag);
+ warn_at (loc, _("symbol %s used more than once as a literal string"),
+ str->tag);
else if (sym->alias)
- warn_at (loc, _("symbol `%s' given more than one literal string"),
- sym->tag);
+ warn_at (loc, _("symbol %s given more than one literal string"),
+ sym->tag);
else
{
str->class = token_sym;
symbol_check_alias_consistency (symbol *this)
{
symbol *sym = this;
- symbol *str = this->alias;
+ symbol *str = this->alias;
/* Check only the symbol in the symbol-string pair. */
if (!(this->alias
static inline bool
symbol_pack (symbol *this)
{
+ aver (this->number != NUMBER_UNDEFINED);
if (this->class == nterm_sym)
- {
- this->number += ntokens;
- }
- else if (this->alias)
- {
- /* This symbol and its alias are a single token defn.
- Allocate a tokno, and assign to both check agreement of
- prec and assoc fields and make both the same */
- if (this->number == NUMBER_UNDEFINED)
- {
- if (this == endtoken || this->alias == endtoken)
- this->number = this->alias->number = 0;
- else
- {
- aver (this->alias->number != NUMBER_UNDEFINED);
- this->number = this->alias->number;
- }
- }
- /* 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 */
- aver (this->number != NUMBER_UNDEFINED);
+ this->number += ntokens;
+ else if (this->user_token_number == USER_NUMBER_HAS_STRING_ALIAS)
+ return true;
symbols[this->number] = this;
return true;
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 (nondeterministic) traversal of the symbol
- hash table.
+ second step, via a traversal of the symbol table sorted on tag.
- Make errors deterministic: keep the first declaration first. */
+ However, error messages make more sense if we keep the first
+ declaration first. */
if (location_cmp (first->location, second->location) > 0)
{
symbol* tmp = first;
if (!entry)
{
/* First insertion in the hash. */
+ aver (!symbols_sorted);
entry = symbol_new (key, loc);
if (!hash_insert (symbol_table, entry))
xalloc_die ();
hash_free (symbol_table);
hash_free (semantic_type_table);
free (symbols);
+ free (symbols_sorted);
}
| 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. |