+void
+rule_lhs_print (rule const *r, symbol const *previous_lhs, FILE *out)
+{
+ fprintf (out, " %3d ", r->number);
+ if (previous_lhs != r->lhs)
+ fprintf (out, "%s:", r->lhs->tag);
+ else
+ fprintf (out, "%*s|", (int) strlen (previous_lhs->tag), "");
+}
+
+void
+rule_lhs_print_xml (rule const *r, FILE *out, int level)
+{
+ xml_printf (out, level, "<lhs>%s</lhs>", r->lhs->tag);
+}
+
+size_t
+rule_rhs_length (rule const *r)
+{
+ size_t res = 0;
+ item_number *rhsp;
+ for (rhsp = r->rhs; *rhsp >= 0; ++rhsp)
+ ++res;
+ return res;
+}
+
+void
+rule_rhs_print (rule const *r, FILE *out)
+{
+ if (0 <= *r->rhs)
+ {
+ item_number *rp;
+ for (rp = r->rhs; *rp >= 0; rp++)
+ fprintf (out, " %s", symbols[*rp]->tag);
+ }
+ else
+ fputs (" %empty", out);
+}
+
+static void
+rule_rhs_print_xml (rule const *r, FILE *out, int level)
+{
+ if (*r->rhs >= 0)
+ {
+ item_number *rp;
+ xml_puts (out, level, "<rhs>");
+ for (rp = r->rhs; *rp >= 0; rp++)
+ xml_printf (out, level + 1, "<symbol>%s</symbol>",
+ xml_escape (symbols[*rp]->tag));
+ xml_puts (out, level, "</rhs>");
+ }
+ else
+ {
+ xml_puts (out, level, "<rhs>");
+ xml_puts (out, level + 1, "<empty/>");
+ xml_puts (out, level, "</rhs>");
+ }
+}