+rule_t* rule_copy (rule_t* rule)
+{
+ rule_t* new_rule;
+ GList* r;
+ new_rule = rule_new ();
+ r = rule->right;
+ while (r != NULL)
+ {
+ rule_append (new_rule, symbol_copy (r->data));
+ r = g_list_next (r);
+ }
+ return new_rule;
+}
+
+gint rule_cmp (rule_t* a, rule_t* b)
+{
+ GList* la;
+ GList* lb;
+ la = grammar_get_rule (a);
+ lb = grammar_get_rule (b);
+ while (la != NULL && lb != NULL)
+ {
+ int c;
+ if ((c = symbol_cmp (la->data, lb->data)) != 0)
+ return c;
+ la = g_list_next (la);
+ lb = g_list_next (lb);
+ }
+ if (la == lb)
+ return 0;
+ else if (la == NULL)
+ return -1;
+ return 1;
+}
+
+gboolean rule_equal (gconstpointer data1, gconstpointer data2)
+{
+ return (rule_cmp (data1, data2) == 0);
+}
+
+guint rule_hash (gconstpointer data)
+{
+ GList* l;
+ guint hash;
+ l = grammar_get_rule (data);
+ hash = 0;
+ while (l != NULL)
+ {
+ hash = 37 * hash + symbol_hash (l->data);
+ l = g_list_next (l);
+ }
+ return hash;
+}
+
+symbol_t* rule_pop (rule_t* rule)
+{
+ GList* r;
+ if ((r = g_list_first (rule->right)) == NULL)
+ return NULL;
+ rule->right = g_list_remove_link (r, r);
+ g_free (r->data);
+ g_list_free (r);
+ if (rule->right == NULL)
+ return NULL;
+ return rule->right->data;
+}
+