+
+
+/*--------------------------------------------------.
+| Put THIS in TOKEN_TRANSLATIONS if it is a token. |
+`--------------------------------------------------*/
+
+static inline bool
+symbol_translation (symbol *this)
+{
+ /* Non-terminal? */
+ if (this->class == token_sym
+ && this->user_token_number != USER_NUMBER_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);
+
+ token_translations[this->user_token_number] = this->number;
+ }
+
+ return true;
+}
+
+static bool
+symbol_translation_processor (void *this, void *null ATTRIBUTE_UNUSED)
+{
+ return symbol_translation (this);
+}
+
+
+/*----------------------.
+| A symbol hash table. |
+`----------------------*/
+
+/* Initial capacity of symbols hash table. */
+#define HT_INITIAL_CAPACITY 257
+
+static struct hash_table *symbol_table = NULL;
+
+static inline bool
+hash_compare_symbol (const symbol *m1, const symbol *m2)
+{
+ /* Since tags are unique, we can compare the pointers themselves. */
+ return UNIQSTR_EQ (m1->tag, m2->tag);
+}
+
+static bool
+hash_symbol_comparator (void const *m1, void const *m2)
+{
+ return hash_compare_symbol (m1, m2);
+}
+
+static inline unsigned int
+hash_symbol (const symbol *m, unsigned int tablesize)
+{
+ /* Since tags are unique, we can hash the pointer itself. */
+ return ((uintptr_t) m->tag) % tablesize;
+}
+
+static unsigned int
+hash_symbol_hasher (void const *m, unsigned int tablesize)
+{
+ return hash_symbol (m, tablesize);
+}
+
+
+/*-------------------------------.
+| Create the symbol hash table. |
+`-------------------------------*/
+
+void
+symbols_new (void)
+{
+ symbol_table = hash_initialize (HT_INITIAL_CAPACITY,
+ NULL,
+ hash_symbol_hasher,
+ hash_symbol_comparator,
+ free);
+}
+
+
+/*----------------------------------------------------------------.
+| Find the symbol named KEY, and return it. If it does not exist |
+| yet, create it. |
+`----------------------------------------------------------------*/
+
+symbol *
+symbol_get (const char *key, location loc)
+{
+ symbol probe;
+ symbol *entry;
+
+ /* Keep the symbol in a printable form. */
+ key = uniqstr_new (quotearg_style (escape_quoting_style, key));
+ probe.tag = key;
+ entry = hash_lookup (symbol_table, &probe);
+
+ if (!entry)
+ {
+ /* First insertion in the hash. */
+ entry = symbol_new (key, loc);
+ hash_insert (symbol_table, entry);
+ }
+ return entry;
+}
+
+
+/*------------------------------------------------------------------.
+| Generate a dummy nonterminal, whose name cannot conflict with the |
+| user's names. |
+`------------------------------------------------------------------*/
+
+symbol *
+dummy_symbol_get (location loc)
+{
+ /* Incremented for each generated symbol. */
+ static int dummy_count = 0;
+ static char buf[256];
+
+ symbol *sym;
+
+ sprintf (buf, "@%d", ++dummy_count);
+ sym = symbol_get (buf, loc);
+ sym->class = nterm_sym;
+ sym->number = nvars++;
+ return sym;
+}
+
+
+/*-------------------.
+| Free the symbols. |
+`-------------------*/
+
+void
+symbols_free (void)
+{
+ hash_free (symbol_table);
+ free (symbols);
+}
+
+
+/*---------------------------------------------------------------.
+| Look for undefined symbols, report an error, and consider them |
+| terminals. |
+`---------------------------------------------------------------*/
+
+static void
+symbols_do (Hash_processor processor, void *processor_data)
+{
+ hash_do_for_each (symbol_table, processor, processor_data);
+}
+
+
+/*--------------------------------------------------------------.
+| Check that all the symbols are defined. Report any undefined |
+| symbols and consider them nonterminals. |
+`--------------------------------------------------------------*/
+