Pushing on lr1 stack is now public
[cascardo/grammar.git] / first.c
diff --git a/first.c b/first.c
index 034e15a..040a04c 100644 (file)
--- a/first.c
+++ b/first.c
@@ -457,7 +457,7 @@ void first_check (gpointer key, gpointer val, gpointer data)
  * We should iterate through the rules for each nonterminal until only
  * terminals are known to be in the first set of it.
  */
-GHashTable* grammar_first (Grammar* grammar)
+GHashTable* grammar_first (grammar_t* grammar)
 {
   GHashTable* first;
   gboolean stop;
@@ -474,7 +474,7 @@ GHashTable* grammar_first (Grammar* grammar)
   return first;
 }
 
-void put_key_on_list (gpointer key, gpointer val, gpointer data)
+static void put_key_on_list (gpointer key, gpointer val, gpointer data)
 {
   GList** l;
   l = (GList**) data;
@@ -490,8 +490,55 @@ GList* first_get (GHashTable* first, symbol_t* symbol)
   if (g_hash_table_lookup_extended (first, symbol, NULL,
                                    (gpointer*) &first_set))
     {
-      g_hash_table_foreach (first->terminals, put_key_on_list, &l);
+      if (first_set->has_empty)
+       l = g_list_prepend (l, symbol_new (TRUE, 0));
+      g_hash_table_foreach (first_set->terminals, put_key_on_list, &l);
     }
   return l;
 
 }
+
+GList* first_rule (GHashTable* first, rule_t* rule)
+{
+
+  GHashTable* terminals;
+  GList* symbols;
+  GList* l;
+
+  l = NULL;
+
+  symbols = grammar_get_rule (rule);
+
+  terminals = g_hash_table_new_full (symbol_hash, symbol_equal, g_free, NULL);
+
+  while (symbols != NULL)
+    {
+      first_set_t* first_set;
+      symbol_t* symbol;
+      symbol = (symbol_t*) symbols->data;
+      if (symbol->terminal)
+       {
+         g_hash_table_insert (terminals, symbol_copy (symbol), NULL);
+         break;
+       }
+      if (!g_hash_table_lookup_extended (first, symbol, NULL,
+                                        (gpointer*) &first_set))
+       {
+         g_hash_table_destroy (terminals);
+         return NULL;
+       }
+      first_set_union (terminals, first_set->terminals);
+      if (first_set->has_empty == FALSE)
+       break;
+      symbols = g_list_next (symbols);
+    }
+
+  if (symbols == NULL)
+    l = g_list_prepend (l, symbol_new (TRUE, 0));
+  g_hash_table_foreach (terminals, put_key_on_list, &l);
+
+  g_hash_table_destroy (terminals);
+
+  return l;
+  
+}