+
+void
+state_rule_lookahead_tokens_print_xml (state *s, rule *r,
+ FILE *out, int level)
+{
+ /* Find the reduction we are handling. */
+ reductions *reds = s->reductions;
+ int red = state_reduction_find (s, r);
+
+ /* Print them if there are. */
+ if (reds->lookahead_tokens && red != -1)
+ {
+ bitset_iterator biter;
+ int k;
+ xml_puts (out, level, "<lookaheads>");
+ BITSET_FOR_EACH (biter, reds->lookahead_tokens[red], k, 0)
+ {
+ xml_printf (out, level + 1, "<symbol class=\"%s\">%s</symbol>",
+ symbol_class_get_string (symbols[k]),
+ xml_escape (symbols[k]->tag));
+ }
+ xml_puts (out, level, "</lookaheads>");
+ }
+}
+
+
+/*---------------------.
+| A state hash table. |
+`---------------------*/
+
+/* Initial capacity of states hash table. */
+#define HT_INITIAL_CAPACITY 257
+
+static struct hash_table *state_table = NULL;
+
+/* Two states are equal if they have the same core items. */
+static inline bool
+state_compare (state const *s1, state const *s2)
+{
+ size_t i;
+
+ if (s1->nitems != s2->nitems)
+ return false;
+
+ for (i = 0; i < s1->nitems; ++i)
+ if (s1->items[i] != s2->items[i])
+ return false;
+
+ return true;
+}
+
+static bool
+state_comparator (void const *s1, void const *s2)
+{
+ return state_compare (s1, s2);
+}
+
+static inline size_t
+state_hash (state const *s, size_t tablesize)
+{
+ /* Add up the state's item numbers to get a hash key. */
+ size_t key = 0;
+ size_t i;
+ for (i = 0; i < s->nitems; ++i)
+ key += s->items[i];
+ return key % tablesize;
+}
+
+static size_t
+state_hasher (void const *s, size_t tablesize)
+{
+ return state_hash (s, tablesize);
+}
+
+
+/*-------------------------------.
+| Create the states hash table. |
+`-------------------------------*/
+
+void
+state_hash_new (void)
+{
+ state_table = hash_initialize (HT_INITIAL_CAPACITY,
+ NULL,
+ state_hasher,
+ state_comparator,
+ NULL);
+}
+
+
+/*---------------------------------------------.
+| Free the states hash table, not the states. |
+`---------------------------------------------*/
+
+void
+state_hash_free (void)
+{
+ hash_free (state_table);
+}
+
+
+/*-----------------------------------.
+| Insert S in the state hash table. |
+`-----------------------------------*/
+
+void
+state_hash_insert (state *s)
+{
+ hash_insert (state_table, s);
+}
+
+
+/*------------------------------------------------------------------.
+| Find the state associated to the CORE, and return it. If it does |
+| not exist yet, return NULL. |
+`------------------------------------------------------------------*/
+
+state *
+state_hash_lookup (size_t nitems, item_number *core)
+{
+ size_t items_size = nitems * sizeof *core;
+ state *probe = xmalloc (offsetof (state, items) + items_size);
+ state *entry;
+
+ probe->nitems = nitems;
+ memcpy (probe->items, core, items_size);
+ entry = hash_lookup (state_table, probe);
+ free (probe);
+ return entry;
+}
+
+
+/*--------------------------------------------------------.
+| Record S and all states reachable from S in REACHABLE. |
+`--------------------------------------------------------*/
+
+static void
+state_record_reachable_states (state *s, bitset reachable)
+{
+ if (bitset_test (reachable, s->number))
+ return;
+ bitset_set (reachable, s->number);
+ {
+ int i;
+ for (i = 0; i < s->transitions->num; ++i)
+ if (!TRANSITION_IS_DISABLED (s->transitions, i))
+ state_record_reachable_states (s->transitions->states[i], reachable);
+ }
+}
+
+void
+state_remove_unreachable_states (state_number old_to_new[])
+{
+ state_number nstates_reachable = 0;
+ bitset reachable = bitset_create (nstates, BITSET_FIXED);
+ state_record_reachable_states (states[0], reachable);
+ {
+ state_number i;
+ for (i = 0; i < nstates; ++i)
+ {
+ if (bitset_test (reachable, states[i]->number))
+ {
+ states[nstates_reachable] = states[i];
+ states[nstates_reachable]->number = nstates_reachable;
+ old_to_new[i] = nstates_reachable++;
+ }
+ else
+ {
+ state_free (states[i]);
+ old_to_new[i] = nstates;
+ }
+ }
+ }
+ nstates = nstates_reachable;
+ bitset_free (reachable);
+}
+
+/* All the decorated states, indexed by the state number. */
+state **states = NULL;
+
+
+/*----------------------.
+| Free all the states. |
+`----------------------*/
+
+void
+states_free (void)
+{
+ state_number i;
+ for (i = 0; i < nstates; ++i)
+ state_free (states[i]);
+ free (states);
+}