2006-06-08 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / monoburg / monoburg.c
index 61752b9b38ff2318b6992317de22355d3077918c..32c75012610b52ebc39f79b5b4c9522bd0afb961 100644 (file)
@@ -8,7 +8,8 @@
  */
 
 #include <stdio.h>
-
+#include <string.h>
+#include <stdlib.h>
 #include "monoburg.h"
 
 extern void yyparse (void);
@@ -18,10 +19,17 @@ static GList *term_list;
 static GHashTable *nonterm_hash;
 static GList *nonterm_list;
 static GList *rule_list;
+static GList *prefix_list;
 
 FILE *inputfd;
 FILE *outputfd;
+GHashTable *definedvars;
 static FILE *deffd;
+static FILE *cfd;
+
+static int dag_mode = 0;
+static int predefined_terms = 0;
+static int default_cost = 0;
 
 static void output (char *fmt, ...) 
 {
@@ -32,16 +40,22 @@ static void output (char *fmt, ...)
        va_end (ap);
 }
 
-void     
-create_rule (char *id, Tree *tree, char *code, char *cost, char *cfunc)
+Rule*
+make_rule (char *id, Tree *tree)
 {
        Rule *rule = g_new0 (Rule, 1);
+       rule->lhs = nonterm (id);
+       rule->tree = tree;
+
+       return rule;
+}
 
+void
+rule_add (Rule *rule, char *code, char *cost, char *cfunc)
+{
        if (!cfunc && !cost)
-               cost = "0";
+               cost = g_strdup_printf ("%d", default_cost);
 
-       rule->lhs = nonterm (id);
-       rule->tree = tree;
        rule_list = g_list_append (rule_list, rule);
        rule->cost = g_strdup (cost);
        rule->cfunc = g_strdup (cfunc);
@@ -50,26 +64,55 @@ create_rule (char *id, Tree *tree, char *code, char *cost, char *cfunc)
        if (cfunc) {
                if (cost)
                        yyerror ("duplicated costs (constant costs and cost function)");
-               else 
-                       rule->cost = g_strdup_printf ("mono_burg_cost_%d (tree)",
-                                                     g_list_length (rule_list));
+               else {
+                       if (dag_mode)
+                               rule->cost = g_strdup_printf ("mono_burg_cost_%d (p, data)",
+                                                             g_list_length (rule_list));
+                       else
+                               rule->cost = g_strdup_printf ("mono_burg_cost_%d (tree, data)",
+                                                             g_list_length (rule_list));
+               }
        }
 
        rule->lhs->rules = g_list_append (rule->lhs->rules, rule);
 
-       if (tree->op)
-               tree->op->rules = g_list_append (tree->op->rules, rule);
+       if (rule->tree->op)
+               rule->tree->op->rules = g_list_append (rule->tree->op->rules, rule);
        else 
-               tree->nonterm->chain = g_list_append (tree->nonterm->chain, rule);
+               rule->tree->nonterm->chain = g_list_append (rule->tree->nonterm->chain, rule);
+}
+
+void     
+create_rule (char *id, Tree *tree, char *code, char *cost, char *cfunc)
+{
+       Rule *rule = make_rule (id, tree);
+
+       rule_add (rule, code, cost, cfunc);
 }
 
 Tree *
 create_tree (char *id, Tree *left, Tree *right)
 {
        int arity = (left != NULL) + (right != NULL);
-       Term *term = g_hash_table_lookup (term_hash, id);
+       Term *term = NULL; 
        Tree *tree = g_new0 (Tree, 1);
-       
+
+       if (term_hash)
+               term = g_hash_table_lookup (term_hash, id);
+
+       /* try if id has termprefix */
+       if (!term) {
+               GList *pl;
+               for (pl = prefix_list; pl; pl = pl->next) {
+                       char *pfx = (char *)pl->data;
+                       if (!strncmp (pfx, id, strlen (pfx))) {
+                               term = create_term (id, -1);
+                               break;
+                       }
+               }
+
+       }
+
        if (term) {
                if (term->arity == -1)
                        term->arity = arity;
@@ -96,11 +139,20 @@ check_term_num (char *key, Term *value, int num)
 }
  
 void  
+create_term_prefix (char *id)
+{
+       if (!predefined_terms)
+               yyerror ("%termprefix is only available with -p option");
+
+       prefix_list = g_list_prepend (prefix_list, g_strdup (id));
+}
+
+Term *
 create_term (char *id, int num)
 {
        Term *term;
 
-       if (nonterm_list)
+       if (!predefined_terms && nonterm_list)
                yyerror ("terminal definition after nonterminal definition");
 
        if (num < -1)
@@ -109,7 +161,7 @@ create_term (char *id, int num)
        if (!term_hash) 
                term_hash = g_hash_table_new (g_str_hash , g_str_equal);
 
-       g_hash_table_foreach (term_hash, (GHFunc) check_term_num, (gpointer) num);
+       g_hash_table_foreach (term_hash, (GHFunc) check_term_num, GINT_TO_POINTER (num));
 
        term = g_new0 (Term, 1);
 
@@ -120,6 +172,8 @@ create_term (char *id, int num)
        term_list = g_list_append (term_list, term);
 
        g_hash_table_insert (term_hash, term->name, term);
+
+       return term;
 }
 
 NonTerm *
@@ -223,7 +277,8 @@ emit_header ()
        output ("#ifndef MBTREE_RIGHT\n#define MBTREE_RIGHT(t) ((t)->right)\n#endif\n");
        output ("#ifndef MBTREE_STATE\n#define MBTREE_STATE(t) ((t)->state)\n#endif\n");
        output ("#ifndef MBCGEN_TYPE\n#define MBCGEN_TYPE int\n#endif\n");
-
+       output ("#ifndef MBALLOC_STATE\n#define MBALLOC_STATE g_new (MBState, 1)\n#endif\n");
+       output ("#ifndef MBCOST_DATA\n#define MBCOST_DATA gpointer\n#endif\n");
        output ("\n");
        output ("#define MBMAXCOST 32768\n");
 
@@ -243,8 +298,11 @@ emit_header ()
                Term *t = (Term *)l->data;
                if (t->number == -1)
                        t->number = next_term_num ();
-               
-               output ("#define MB_TERM_%s\t %d\n", t->name, t->number);
+
+               if (predefined_terms)
+                       output ("#define MB_TERM_%s\t %s\n", t->name, t->name);
+               else
+                       output ("#define MB_TERM_%s\t %d\n", t->name, t->number);
 
        }
        output ("\n");
@@ -273,6 +331,12 @@ emit_state ()
        output ("typedef struct _MBState MBState;\n");
        output ("struct _MBState {\n");
        output ("\tint\t\t op;\n");
+
+       if (dag_mode) {
+               output ("\tMBTREE_TYPE\t *tree;\n");
+               output ("\tgint32 reg1, reg2;\n");
+       }
+       
        output ("\tMBState\t\t*left, *right;\n");
        output ("\tguint16\t\tcost[%d];\n", g_list_length (nonterm_list) + 1);
 
@@ -296,7 +360,7 @@ emit_decoders ()
 
        for (l = nonterm_list; l; l = l->next) {
                NonTerm *n = (NonTerm *)l->data;
-               output ("int mono_burg_decode_%s[] = {\n", n->name);
+               output ("const short mono_burg_decode_%s[] = {\n", n->name);
                output ("\t0,\n");
                for (rl = n->rules; rl; rl = rl->next) {
                        Rule *rule = (Rule *)rl->data;
@@ -311,19 +375,29 @@ static void
 emit_tree_match (char *st, Tree *t)
 {
        char *tn;
+       int not_first = strcmp (st, "p->");
+
+       /* we can omit this check at the top level */
+       if (not_first) {
+               if (predefined_terms)
+                       output ("\t\t\t%sop == %s /* %s */", st, t->op->name, t->op->name);
+               else
+                       output ("\t\t\t%sop == %d /* %s */", st, t->op->number, t->op->name);
+       }
 
-       output ("\t\t\t%sop == %d /* %s */", st, t->op->number, t->op->name);
-       
        if (t->left && t->left->op) {
                tn = g_strconcat (st, "left->", NULL);
-               output (" &&\n");
+               if (not_first)
+                       output (" &&\n");
+               not_first = 1;
                emit_tree_match (tn, t->left);
                g_free (tn);
        }
 
        if (t->right && t->right->op) {
                tn = g_strconcat (st, "right->", NULL);
-               output (" &&\n");
+               if (not_first)
+                       output (" &&\n");
                emit_tree_match (tn, t->right);
                g_free (tn);
        }
@@ -396,34 +470,57 @@ emit_label_func ()
        GList *l;
        int i;
 
-       output ("static MBState *\n");
-       output ("mono_burg_label_priv (MBTREE_TYPE *tree) {\n");
+       if (dag_mode) {
+               output ("static void\n");
+               output ("mono_burg_label_priv (MBTREE_TYPE *tree, MBCOST_DATA *data, MBState *p) {\n");
+       } else {
+               output ("static MBState *\n");
+               output ("mono_burg_label_priv (MBTREE_TYPE *tree, MBCOST_DATA *data) {\n");
+       }
 
        output ("\tint arity;\n");
        output ("\tint c;\n");
-       output ("\tMBState *p, *left, *right;\n\n");
+       if (!dag_mode) 
+               output ("\tMBState *p;\n");
+       output ("\tMBState *left = NULL, *right = NULL;\n\n");
 
        output ("\tswitch (mono_burg_arity [MBTREE_OP(tree)]) {\n");
        output ("\tcase 0:\n");
-       output ("\t\tleft = NULL;\n");
-       output ("\t\tright = NULL;\n");
        output ("\t\tbreak;\n");
        output ("\tcase 1:\n");
-       output ("\t\tleft = mono_burg_label_priv (MBTREE_LEFT(tree));\n");
-       output ("\t\tright = NULL;\n");
+       if (dag_mode) {
+               output ("\t\tleft = MBALLOC_STATE;\n");
+               output ("\t\tmono_burg_label_priv (MBTREE_LEFT(tree), data, left);\n");         
+       } else {
+               output ("\t\tleft = mono_burg_label_priv (MBTREE_LEFT(tree), data);\n");
+               output ("\t\tright = NULL;\n");
+       }
        output ("\t\tbreak;\n");
        output ("\tcase 2:\n");
-       output ("\t\tleft = mono_burg_label_priv (MBTREE_LEFT(tree));\n");
-       output ("\t\tright = mono_burg_label_priv (MBTREE_RIGHT(tree));\n");
+       if (dag_mode) {
+               output ("\t\tleft = MBALLOC_STATE;\n");
+               output ("\t\tmono_burg_label_priv (MBTREE_LEFT(tree), data, left);\n");         
+               output ("\t\tright = MBALLOC_STATE;\n");
+               output ("\t\tmono_burg_label_priv (MBTREE_RIGHT(tree), data, right);\n");               
+       } else {
+               output ("\t\tleft = mono_burg_label_priv (MBTREE_LEFT(tree), data);\n");
+               output ("\t\tright = mono_burg_label_priv (MBTREE_RIGHT(tree), data);\n");
+       }
        output ("\t}\n\n");
 
        output ("\tarity = (left != NULL) + (right != NULL);\n");
        output ("\tg_assert (arity == mono_burg_arity [MBTREE_OP(tree)]);\n\n");
 
-       output ("\tp = g_new0 (MBState, 1);\n");
+       if (!dag_mode)
+               output ("\tp = MBALLOC_STATE;\n");
+
+       output ("\tmemset (p, 0, sizeof (MBState));\n");
        output ("\tp->op = MBTREE_OP(tree);\n");
        output ("\tp->left = left;\n");
        output ("\tp->right = right;\n");
+
+       if (dag_mode)
+               output ("\tp->tree = tree;\n"); 
        
        for (l = nonterm_list, i = 0; l; l = l->next) {
                output ("\tp->cost [%d] = 32767;\n", ++i);
@@ -434,7 +531,11 @@ emit_label_func ()
        for (l = term_list; l; l = l->next) {
                Term *t = (Term *)l->data;
                GList *rl;
-               output ("\tcase %d: /* %s */\n", t->number, t->name);
+               
+               if (predefined_terms)
+                       output ("\tcase %s: /* %s */\n", t->name, t->name);
+               else
+                       output ("\tcase %d: /* %s */\n", t->number, t->name);
 
                for (rl = t->rules; rl; rl = rl->next) {
                        Rule *rule = (Rule *)rl->data; 
@@ -461,18 +562,28 @@ emit_label_func ()
        }
        
        output ("\tdefault:\n");
-       output ("\t\tg_error (\"unknown operator\");\n");
+       output ("#ifdef MBGET_OP_NAME\n");
+       output ("\t\tg_error (\"unknown operator: %%s\", MBGET_OP_NAME(MBTREE_OP(tree)));\n");
+       output ("#else\n");
+       output ("\t\tg_error (\"unknown operator: 0x%%04x\", MBTREE_OP(tree));\n");
+       output ("#endif\n");
        output ("\t}\n\n");
 
-       output ("\tMBTREE_STATE(tree) = p;\n");
-
-       output ("\treturn p;\n");
+       if (!dag_mode) {
+               output ("\tMBTREE_STATE(tree) = p;\n");
+               output ("\treturn p;\n");
+       }
 
        output ("}\n\n");
 
        output ("MBState *\n");
-       output ("mono_burg_label (MBTREE_TYPE *tree)\n{\n");
-       output ("\tMBState *p = mono_burg_label_priv (tree);\n");
+       output ("mono_burg_label (MBTREE_TYPE *tree, MBCOST_DATA *data)\n{\n");
+       if (dag_mode) {
+               output ("\tMBState *p = MBALLOC_STATE;\n");
+               output ("\tmono_burg_label_priv (tree, data, p);\n");           
+       } else {
+               output ("\tMBState *p = mono_burg_label_priv (tree, data);\n");
+       }
        output ("\treturn p->rule_%s ? p : NULL;\n", ((NonTerm *)nonterm_list->data)->name);
        output ("}\n\n");
 }
@@ -487,11 +598,20 @@ compute_kids (char *ts, Tree *tree, int *n)
        } else if (tree->op && tree->op->arity) {
                char *res2 = NULL;
 
-               res = compute_kids (g_strdup_printf ("MBTREE_LEFT(%s)", ts), 
-                                   tree->left, n);
-               if (tree->op->arity == 2)
-                       res2 = compute_kids (g_strdup_printf ("MBTREE_RIGHT(%s)", ts), 
-                                            tree->right, n);
+               if (dag_mode) {
+                       res = compute_kids (g_strdup_printf ("%s->left", ts), 
+                                           tree->left, n);
+                       if (tree->op->arity == 2)
+                               res2 = compute_kids (g_strdup_printf ("%s->right", ts), 
+                                                    tree->right, n);
+               } else {
+                       res = compute_kids (g_strdup_printf ("MBTREE_LEFT(%s)", ts), 
+                                           tree->left, n);
+                       if (tree->op->arity == 2)
+                               res2 = compute_kids (g_strdup_printf ("MBTREE_RIGHT(%s)", ts), 
+                                                    tree->right, n);
+               }
+
                return g_strconcat (res, res2, NULL);
        }
        return "";
@@ -525,11 +645,18 @@ emit_kids ()
        output ("}\n\n");
 
 
-       output ("MBTREE_TYPE **\n");
-       output ("mono_burg_kids (MBTREE_TYPE *tree, int rulenr, MBTREE_TYPE *kids [])\n{\n");
-       output ("\tg_return_val_if_fail (tree != NULL, NULL);\n");
-       output ("\tg_return_val_if_fail (MBTREE_STATE(tree) != NULL, NULL);\n");
-       output ("\tg_return_val_if_fail (kids != NULL, NULL);\n\n");
+       if (dag_mode) {
+               output ("MBState **\n");
+               output ("mono_burg_kids (MBState *state, int rulenr, MBState *kids [])\n{\n");
+               output ("\tg_return_val_if_fail (state != NULL, NULL);\n");
+               output ("\tg_return_val_if_fail (kids != NULL, NULL);\n\n");
+
+       } else {
+               output ("MBTREE_TYPE **\n");
+               output ("mono_burg_kids (MBTREE_TYPE *tree, int rulenr, MBTREE_TYPE *kids [])\n{\n");
+               output ("\tg_return_val_if_fail (tree != NULL, NULL);\n");
+               output ("\tg_return_val_if_fail (kids != NULL, NULL);\n\n");
+       }
 
        output ("\tswitch (rulenr) {\n");
 
@@ -543,7 +670,11 @@ emit_kids ()
                int kn = 0;
                char *k;
 
-               k = compute_kids ("tree", rule->tree, &kn);
+               if (dag_mode)
+                       k = compute_kids ("state", rule->tree, &kn);
+               else
+                       k = compute_kids ("tree", rule->tree, &kn);
+
                for (j = 0; j < c; j++)
                        if (!strcmp (sa [j], k))
                                break;
@@ -572,25 +703,38 @@ static void
 emit_emitter_func ()
 {
        GList *l;
-       int i;
+       int i, rulen;
+       GHashTable *cache = g_hash_table_new (g_str_hash, g_str_equal);
 
        for (l =  rule_list, i = 0; l; l = l->next) {
                Rule *rule = (Rule *)l->data;
                
                if (rule->code) {
+                       if ((rulen = GPOINTER_TO_INT (g_hash_table_lookup (cache, rule->code)))) {
+                               emit_rule_string (rule, "");
+                               output ("#define mono_burg_emit_%d mono_burg_emit_%d\n\n", i, rulen);
+                               i++;
+                               continue;
+                       }
                        output ("static void ");
 
                        emit_rule_string (rule, "");
 
-                       output ("mono_burg_emit_%d (MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n", i);
+                       if (dag_mode)
+                               output ("mono_burg_emit_%d (MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n", i);
+                       else
+                               output ("mono_burg_emit_%d (MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n", i);
                        output ("{\n");
                        output ("%s\n", rule->code);
                        output ("}\n\n");
+                       g_hash_table_insert (cache, rule->code, GINT_TO_POINTER (i));
                }
                i++;
        }
 
-       output ("MBEmitFunc mono_burg_func [] = {\n");
+       g_hash_table_destroy (cache);
+
+       output ("MBEmitFunc const mono_burg_func [] = {\n");
        output ("\tNULL,\n");
        for (l =  rule_list, i = 0; l; l = l->next) {
                Rule *rule = (Rule *)l->data;
@@ -613,11 +757,14 @@ emit_cost_func ()
                Rule *rule = (Rule *)l->data;
                
                if (rule->cfunc) {
-                       output ("static guint16\n");
+                       output ("inline static guint16\n");
 
                        emit_rule_string (rule, "");
-
-                       output ("mono_burg_cost_%d (MBTREE_TYPE *tree)\n", i + 1);
+                       
+                       if (dag_mode)
+                               output ("mono_burg_cost_%d (MBState *state, MBCOST_DATA *data)\n", i + 1);
+                       else
+                               output ("mono_burg_cost_%d (MBTREE_TYPE *tree, MBCOST_DATA *data)\n", i + 1);
                        output ("{\n");
                        output ("%s\n", rule->cfunc);
                        output ("}\n\n");
@@ -671,37 +818,77 @@ compute_nonterms (Tree *tree)
        } 
 }
 
+static int
+count_nonterms (Tree *tree)
+{
+       if (!tree)
+               return 0;
+
+       if (tree->nonterm) {
+               return 1;
+       } else {
+               return count_nonterms (tree->left) + count_nonterms (tree->right);
+       } 
+}
+
 static void
 emit_vardefs ()
 {
        GList *l;
        int i, j, c, n, *si;
        char **sa;
+       int *nts_offsets;
+       int current_offset;
+
+       if (predefined_terms) {
+               output ("#if HAVE_ARRAY_ELEM_INIT\n");
+               output ("const guint8 mono_burg_arity [MBMAX_OPCODES] = {\n"); 
+               for (l = term_list, i = 0; l; l = l->next) {
+                       Term *t = (Term *)l->data;
+                       output ("\t [%s] = %d, /* %s */\n", t->name, t->arity, t->name);
+               }
+               output ("};\n\n");
+               output ("void\nmono_burg_init (void) {\n");
+               output ("}\n\n");
+               output ("#else\n");
+               output ("guint8 mono_burg_arity [MBMAX_OPCODES];\n"); 
 
-       output ("guint8 mono_burg_arity [] = {\n"); 
-       for (l = term_list, i = 0; l; l = l->next) {
-               Term *t = (Term *)l->data;
+               output ("void\nmono_burg_init (void)\n{\n");
 
-               while (i < t->number) {
-                       output ("\t0,\n");
-                       i++;
+               for (l = term_list, i = 0; l; l = l->next) {
+                       Term *t = (Term *)l->data;
+                       output ("\tmono_burg_arity [%s] = %d; /* %s */\n", t->name, t->arity, t->name);
                }
+               output ("}\n\n");
+               output ("#endif /* HAVE_ARRAY_ELEM_INIT */\n");
+
+       } else {
+               output ("const guint8 mono_burg_arity [] = {\n"); 
+               for (l = term_list, i = 0; l; l = l->next) {
+                       Term *t = (Term *)l->data;
+
+                       while (i < t->number) {
+                               output ("\t0,\n");
+                               i++;
+                       }
                
-               output ("\t%d, /* %s */\n", t->arity, t->name);
+                       output ("\t%d, /* %s */\n", t->arity, t->name);
 
-               i++;
-       }
-       output ("};\n\n");
+                       i++;
+               }
+               output ("};\n\n");
 
-       output ("char *mono_burg_term_string [] = {\n");
-       output ("\tNULL,\n");
-       for (l = term_list, i = 0; l; l = l->next) {
-               Term *t = (Term *)l->data;
-               output ("\t\"%s\",\n", t->name);
+               output ("const char *const mono_burg_term_string [] = {\n");
+               output ("\tNULL,\n");
+               for (l = term_list, i = 0; l; l = l->next) {
+                       Term *t = (Term *)l->data;
+                       output ("\t\"%s\",\n", t->name);
+               }
+               output ("};\n\n");
        }
-       output ("};\n\n");
 
-       output ("char *mono_burg_rule_string [] = {\n");
+       output ("#if MONOBURG_LOG\n");
+       output ("const char * const mono_burg_rule_string [] = {\n");
        output ("\tNULL,\n");
        for (l = rule_list, i = 0; l; l = l->next) {
                Rule *rule = (Rule *)l->data;
@@ -709,12 +896,17 @@ emit_vardefs ()
                emit_tree_string (rule->tree);
                output ("\",\n");
        }
-       output ("};\n\n");
+       output ("};\n");
+       output ("#endif /* MONOBURG_LOG */\n\n");
 
        n = g_list_length (rule_list);
        sa = g_new0 (char *, n);
        si = g_new0 (int, n);
+       nts_offsets = g_new0 (int, n);
 
+       /* at offset 0 we store 0 to mean end of list */
+       current_offset = 1;
+       output ("const guint16 mono_burg_nts_data [] = {\n\t0,\n");
        /* compress the _nts array */
        for (l = rule_list, i = 0, c = 0; l; l = l->next) {
                Rule *rule = (Rule *)l->data;
@@ -726,17 +918,20 @@ emit_vardefs ()
 
                si [i++] = j;
                if (j == c) {
-                       output ("static guint16 mono_burg_nts_%d [] = { %s0 };\n", c, s);
+                       output ("\t%s0,\n", s);
+                       nts_offsets [c] = current_offset;
                        sa [c++] = s;
+                       current_offset += count_nonterms (rule->tree) + 1;
                }
        }       
-       output ("\n");
+       output ("\t0\n};\n\n");
 
-       output ("guint16 *mono_burg_nts [] = {\n");
+       output ("const guint8 mono_burg_nts [] = {\n");
        output ("\t0,\n");
        for (l = rule_list, i = 0; l; l = l->next) {
                Rule *rule = (Rule *)l->data;
-               output ("\tmono_burg_nts_%d, ", si [i++]);
+               output ("\t%d, /* %s */ ", nts_offsets [si [i]], sa [si [i]]);
+               ++i;
                emit_rule_string (rule, "");
        }
        output ("};\n\n");
@@ -745,17 +940,28 @@ emit_vardefs ()
 static void
 emit_prototypes ()
 {
-       output ("typedef void (*MBEmitFunc) (MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
-
-       output ("extern char *mono_burg_term_string [];\n");
-       output ("extern char *mono_burg_rule_string [];\n");
-       output ("extern guint16 *mono_burg_nts [];\n");
-       output ("extern MBEmitFunc mono_burg_func [];\n");
-
-       output ("MBState *mono_burg_label (MBTREE_TYPE *tree);\n");
+       if (dag_mode)
+               output ("typedef void (*MBEmitFunc) (MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
+       else
+               output ("typedef void (*MBEmitFunc) (MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
+       
+       output ("extern const char * const mono_burg_term_string [];\n");
+       output ("#if MONOBURG_LOG\n");
+       output ("extern const char * const mono_burg_rule_string [];\n");
+       output ("#endif /* MONOBURG_LOG */\n");
+       output ("extern const guint16 mono_burg_nts_data [];\n");
+       output ("extern const guint8 mono_burg_nts [];\n");
+       output ("extern MBEmitFunc const mono_burg_func [];\n");
+
+       output ("MBState *mono_burg_label (MBTREE_TYPE *tree, MBCOST_DATA *data);\n");
        output ("int mono_burg_rule (MBState *state, int goal);\n");
-       output ("MBTREE_TYPE **mono_burg_kids (MBTREE_TYPE *tree, int rulenr, MBTREE_TYPE *kids []);\n");
 
+       if (dag_mode)
+               output ("MBState **mono_burg_kids (MBState *state, int rulenr, MBState *kids []);\n");
+       else
+               output ("MBTREE_TYPE **mono_burg_kids (MBTREE_TYPE *tree, int rulenr, MBTREE_TYPE *kids []);\n");
+
+       output ("extern void mono_burg_init (void);\n");
        output ("\n");
 }
 
@@ -800,7 +1006,7 @@ check_result ()
        for (l = nonterm_list; l; l = l->next) {
                NonTerm *n = (NonTerm *)l->data;
                if (!n->reached)
-                       g_error ("unreachable nonterm \"%s\"", n->name);
+                       g_warning ("unreachable nonterm \"%s\"", n->name);
        }
 }
 
@@ -808,31 +1014,52 @@ static void
 usage ()
 {
        fprintf (stderr,
-                "Usage is: monoburg [-d file] [file] \n");
+                "Usage is: monoburg -d file.h -s file.c [inputfile] \n");
        exit (1);
 }
 
+static void
+warning_handler (const gchar *log_domain,
+                GLogLevelFlags log_level,
+                const gchar *message,
+                gpointer user_data)
+{
+       (void) fprintf ((FILE *) user_data, "** WARNING **: %s\n", message);
+}
+
 int
 main (int argc, char *argv [])
 {
+       char *cfile = NULL;
        char *deffile = NULL;
-       char *infile = NULL;
+       GList *infiles = NULL;
        int i;
 
+        definedvars = g_hash_table_new (g_str_hash, g_str_equal);
+       g_log_set_handler (NULL, G_LOG_LEVEL_WARNING, warning_handler, stderr);
+
        for (i = 1; i < argc; i++){
                if (argv [i][0] == '-'){
                        if (argv [i][1] == 'h') {
                                usage ();
+                       } else if (argv [i][1] == 'e') {
+                               dag_mode = 1;
+                       } else if (argv [i][1] == 'p') {
+                               predefined_terms = 1;
                        } else if (argv [i][1] == 'd') {
                                deffile = argv [++i];
+                       } else if (argv [i][1] == 's') {
+                               cfile = argv [++i];
+                       } else if (argv [i][1] == 'c') {
+                               default_cost = atoi (argv [++i]);
+                       } else if (argv [i][1] == 'D') {
+                                g_hash_table_insert (definedvars, &argv [i][2],
+                                                     GUINT_TO_POINTER (1));
                        } else {
                                usage ();
                        }
                } else {
-                       if (infile)
-                               usage ();
-                       else
-                               infile = argv [i];
+                       infiles = g_list_append (infiles, argv [i]);
                }
        }
 
@@ -848,17 +1075,27 @@ main (int argc, char *argv [])
                outputfd = stdout;
 
 
-       if (infile) {
-               if (!(inputfd = fopen (infile, "r"))) {
-                       perror ("cant open input file");
-                       exit (-1);
+       if (infiles) {
+               GList *l = infiles;
+               while (l) {
+                       char *infile = (char *)l->data;
+                       if (!(inputfd = fopen (infile, "r"))) {
+                               perror ("cant open input file");
+                               exit (-1);
+                       }
+
+                       yyparse ();
+
+                       reset_parser ();
+
+                       l->data = inputfd;
+                       l = l->next;
                }
        } else {
                inputfd = stdin;
+               yyparse ();
        }
 
-       yyparse ();
-
        check_result ();
 
        if (!nonterm_list)
@@ -872,7 +1109,18 @@ main (int argc, char *argv [])
        if (deffd) {
                output ("#endif /* _MONO_BURG_DEFS_ */\n");
                fclose (deffd);
-               outputfd = stdout;
+
+               if (cfile == NULL)
+                       outputfd = stdout;
+               else {
+                       if (!(cfd = fopen (cfile, "w"))) {
+                               perror ("cant open c output file");
+                               (void) remove (deffile);
+                               exit (-1);
+                       }
+
+                       outputfd = cfd;
+               }
 
                output ("#include \"%s\"\n\n", deffile);
        }
@@ -887,11 +1135,20 @@ main (int argc, char *argv [])
 
        emit_kids ();
 
-       yyparsetail ();
-
-       if (infile)
-               fclose (inputfd);
+       if (infiles) {
+               GList *l = infiles;
+               while (l) {
+                       inputfd = l->data;
+                       yyparsetail ();
+                       fclose (inputfd);
+                       l = l->next;
+               }
+       } else {
+               yyparsetail ();
+       }
 
+       if (cfile)
+               fclose (cfd);
 
        return 0;
 }