2006-06-08 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / monoburg / monoburg.c
1 /*
2  * monoburg.c: an iburg like code generator generator
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include "monoburg.h"
14
15 extern void yyparse (void);
16
17 static GHashTable *term_hash;
18 static GList *term_list;
19 static GHashTable *nonterm_hash;
20 static GList *nonterm_list;
21 static GList *rule_list;
22 static GList *prefix_list;
23
24 FILE *inputfd;
25 FILE *outputfd;
26 GHashTable *definedvars;
27 static FILE *deffd;
28 static FILE *cfd;
29
30 static int dag_mode = 0;
31 static int predefined_terms = 0;
32 static int default_cost = 0;
33
34 static void output (char *fmt, ...) 
35 {
36         va_list ap;
37
38         va_start(ap, fmt);
39         vfprintf (outputfd, fmt, ap);
40         va_end (ap);
41 }
42
43 Rule*
44 make_rule (char *id, Tree *tree)
45 {
46         Rule *rule = g_new0 (Rule, 1);
47         rule->lhs = nonterm (id);
48         rule->tree = tree;
49
50         return rule;
51 }
52
53 void
54 rule_add (Rule *rule, char *code, char *cost, char *cfunc)
55 {
56         if (!cfunc && !cost)
57                 cost = g_strdup_printf ("%d", default_cost);
58
59         rule_list = g_list_append (rule_list, rule);
60         rule->cost = g_strdup (cost);
61         rule->cfunc = g_strdup (cfunc);
62         rule->code = g_strdup (code);
63
64         if (cfunc) {
65                 if (cost)
66                         yyerror ("duplicated costs (constant costs and cost function)");
67                 else {
68                         if (dag_mode)
69                                 rule->cost = g_strdup_printf ("mono_burg_cost_%d (p, data)",
70                                                               g_list_length (rule_list));
71                         else
72                                 rule->cost = g_strdup_printf ("mono_burg_cost_%d (tree, data)",
73                                                               g_list_length (rule_list));
74                 }
75         }
76
77         rule->lhs->rules = g_list_append (rule->lhs->rules, rule);
78
79         if (rule->tree->op)
80                 rule->tree->op->rules = g_list_append (rule->tree->op->rules, rule);
81         else 
82                 rule->tree->nonterm->chain = g_list_append (rule->tree->nonterm->chain, rule);
83 }
84
85 void     
86 create_rule (char *id, Tree *tree, char *code, char *cost, char *cfunc)
87 {
88         Rule *rule = make_rule (id, tree);
89
90         rule_add (rule, code, cost, cfunc);
91 }
92
93 Tree *
94 create_tree (char *id, Tree *left, Tree *right)
95 {
96         int arity = (left != NULL) + (right != NULL);
97         Term *term = NULL; 
98         Tree *tree = g_new0 (Tree, 1);
99
100         if (term_hash)
101                 term = g_hash_table_lookup (term_hash, id);
102
103         /* try if id has termprefix */
104         if (!term) {
105                 GList *pl;
106                 for (pl = prefix_list; pl; pl = pl->next) {
107                         char *pfx = (char *)pl->data;
108                         if (!strncmp (pfx, id, strlen (pfx))) {
109                                 term = create_term (id, -1);
110                                 break;
111                         }
112                 }
113
114         }
115
116         if (term) {
117                 if (term->arity == -1)
118                         term->arity = arity;
119
120                 if (term->arity != arity)
121                         yyerror ("changed arity of terminal %s from %d to %d",
122                                  id, term->arity, arity);
123
124                 tree->op = term;
125                 tree->left = left;
126                 tree->right = right;
127         } else {
128                 tree->nonterm = nonterm (id);
129         }
130
131         return tree;
132 }
133
134 static void
135 check_term_num (char *key, Term *value, int num)
136 {
137         if (num != -1 && value->number == num)
138                 yyerror ("duplicate terminal id \"%s\"", key);
139 }
140  
141 void  
142 create_term_prefix (char *id)
143 {
144         if (!predefined_terms)
145                 yyerror ("%termprefix is only available with -p option");
146
147         prefix_list = g_list_prepend (prefix_list, g_strdup (id));
148 }
149
150 Term *
151 create_term (char *id, int num)
152 {
153         Term *term;
154
155         if (!predefined_terms && nonterm_list)
156                 yyerror ("terminal definition after nonterminal definition");
157
158         if (num < -1)
159                 yyerror ("invalid terminal number %d", num);
160
161         if (!term_hash) 
162                 term_hash = g_hash_table_new (g_str_hash , g_str_equal);
163
164         g_hash_table_foreach (term_hash, (GHFunc) check_term_num, GINT_TO_POINTER (num));
165
166         term = g_new0 (Term, 1);
167
168         term->name = g_strdup (id);
169         term->number = num;
170         term->arity = -1;
171
172         term_list = g_list_append (term_list, term);
173
174         g_hash_table_insert (term_hash, term->name, term);
175
176         return term;
177 }
178
179 NonTerm *
180 nonterm (char *id)
181 {
182         NonTerm *nterm;
183
184         if (!nonterm_hash) 
185                 nonterm_hash = g_hash_table_new (g_str_hash , g_str_equal);
186
187         if ((nterm = g_hash_table_lookup (nonterm_hash, id)))
188                 return nterm;
189
190         nterm = g_new0 (NonTerm, 1);
191
192         nterm->name = g_strdup (id);
193         nonterm_list = g_list_append (nonterm_list, nterm);
194         nterm->number = g_list_length (nonterm_list);
195         
196         g_hash_table_insert (nonterm_hash, nterm->name, nterm);
197
198         return nterm;
199 }
200
201 void
202 start_nonterm (char *id)
203 {
204         static gboolean start_def;
205         
206         if (start_def)
207                 yyerror ("start symbol redeclared");
208         
209         start_def = TRUE;
210         nonterm (id); 
211 }
212
213 static void
214 emit_tree_string (Tree *tree)
215 {
216         if (tree->op) {
217                 output ("%s", tree->op->name);
218                 if (tree->op->arity) {
219                         output ("(");
220                         emit_tree_string (tree->left);
221                         if (tree->right) {
222                                 output (", ");
223                                 emit_tree_string (tree->right);
224                         }
225                         output (")");
226                 }
227         } else 
228                 output ("%s", tree->nonterm->name);
229 }
230
231 static void
232 emit_rule_string (Rule *rule, char *fill)
233 {
234         output ("%s/* ", fill);
235         
236         output ("%s: ", rule->lhs->name);
237
238         emit_tree_string (rule->tree);
239
240         output (" */\n");
241 }
242
243 static int
244 next_term_num ()
245 {
246         GList *l = term_list;
247         int i = 1;
248
249         while (l) {
250                 Term *t = (Term *)l->data;
251                 if (t->number == i) {
252                         l = term_list;
253                         i++;
254                 } else
255                         l = l->next;
256         }
257         return i;
258 }
259
260 static int
261 term_compare_func (Term *t1, Term *t2)
262 {
263         return t1->number - t2->number;
264 }
265
266 static void
267 emit_header ()
268 {
269         GList *l;
270
271         output ("#include <glib.h>\n");
272         output ("\n");
273
274         output ("#ifndef MBTREE_TYPE\n#error MBTREE_TYPE undefined\n#endif\n");
275         output ("#ifndef MBTREE_OP\n#define MBTREE_OP(t) ((t)->op)\n#endif\n");
276         output ("#ifndef MBTREE_LEFT\n#define MBTREE_LEFT(t) ((t)->left)\n#endif\n");
277         output ("#ifndef MBTREE_RIGHT\n#define MBTREE_RIGHT(t) ((t)->right)\n#endif\n");
278         output ("#ifndef MBTREE_STATE\n#define MBTREE_STATE(t) ((t)->state)\n#endif\n");
279         output ("#ifndef MBCGEN_TYPE\n#define MBCGEN_TYPE int\n#endif\n");
280         output ("#ifndef MBALLOC_STATE\n#define MBALLOC_STATE g_new (MBState, 1)\n#endif\n");
281         output ("#ifndef MBCOST_DATA\n#define MBCOST_DATA gpointer\n#endif\n");
282         output ("\n");
283         output ("#define MBMAXCOST 32768\n");
284
285         output ("\n");
286         output ("#define MBCOND(x) if (!(x)) return MBMAXCOST;\n");
287
288         output ("\n");
289
290         for (l = term_list; l; l = l->next) {
291                 Term *t = (Term *)l->data;
292                 if (t->number == -1)
293                         t->number = next_term_num ();
294         }
295         term_list = g_list_sort (term_list, (GCompareFunc)term_compare_func);
296
297         for (l = term_list; l; l = l->next) {
298                 Term *t = (Term *)l->data;
299                 if (t->number == -1)
300                         t->number = next_term_num ();
301
302                 if (predefined_terms)
303                         output ("#define MB_TERM_%s\t %s\n", t->name, t->name);
304                 else
305                         output ("#define MB_TERM_%s\t %d\n", t->name, t->number);
306
307         }
308         output ("\n");
309
310 }
311
312 static void
313 emit_nonterm ()
314 {
315         GList *l;
316
317         for (l = nonterm_list; l; l = l->next) {
318                 NonTerm *n = (NonTerm *)l->data;
319                 output ("#define MB_NTERM_%s\t%d\n", n->name, n->number);
320         }
321         output ("#define MB_MAX_NTERMS\t%d\n", g_list_length (nonterm_list));
322         output ("\n");
323 }
324
325 static void
326 emit_state ()
327 {
328         GList *l;
329         int i, j;
330
331         output ("typedef struct _MBState MBState;\n");
332         output ("struct _MBState {\n");
333         output ("\tint\t\t op;\n");
334
335         if (dag_mode) {
336                 output ("\tMBTREE_TYPE\t *tree;\n");
337                 output ("\tgint32 reg1, reg2;\n");
338         }
339         
340         output ("\tMBState\t\t*left, *right;\n");
341         output ("\tguint16\t\tcost[%d];\n", g_list_length (nonterm_list) + 1);
342
343         for (l = nonterm_list; l; l = l->next) {
344                 NonTerm *n = (NonTerm *)l->data;
345                 g_assert (g_list_length (n->rules) < 256);
346                 i = g_list_length (n->rules);
347                 j = 1;
348                 while (i >>= 1)
349                         j++;
350                 output ("\tunsigned int\t rule_%s:%d;\n",  n->name, j); 
351         }
352         output ("};\n\n");
353 }
354
355 static void
356 emit_decoders ()
357 {
358         GList *l;
359         GList *rl;
360
361         for (l = nonterm_list; l; l = l->next) {
362                 NonTerm *n = (NonTerm *)l->data;
363                 output ("const short mono_burg_decode_%s[] = {\n", n->name);
364                 output ("\t0,\n");
365                 for (rl = n->rules; rl; rl = rl->next) {
366                         Rule *rule = (Rule *)rl->data;
367                         output ("\t%d,\n", g_list_index (rule_list, rule) + 1);
368                 }
369                 
370                 output ("};\n\n");
371         }
372 }
373
374 static void
375 emit_tree_match (char *st, Tree *t)
376 {
377         char *tn;
378         int not_first = strcmp (st, "p->");
379
380         /* we can omit this check at the top level */
381         if (not_first) {
382                 if (predefined_terms)
383                         output ("\t\t\t%sop == %s /* %s */", st, t->op->name, t->op->name);
384                 else
385                         output ("\t\t\t%sop == %d /* %s */", st, t->op->number, t->op->name);
386         }
387
388         if (t->left && t->left->op) {
389                 tn = g_strconcat (st, "left->", NULL);
390                 if (not_first)
391                         output (" &&\n");
392                 not_first = 1;
393                 emit_tree_match (tn, t->left);
394                 g_free (tn);
395         }
396
397         if (t->right && t->right->op) {
398                 tn = g_strconcat (st, "right->", NULL);
399                 if (not_first)
400                         output (" &&\n");
401                 emit_tree_match (tn, t->right);
402                 g_free (tn);
403         }
404 }
405
406 static void
407 emit_rule_match (Rule *rule)
408 {
409         Tree *t = rule->tree; 
410
411         if ((t->left && t->left->op) || 
412             (t->right && t->right->op)) {       
413                 output ("\t\tif (\n");
414                 emit_tree_match ("p->", t);
415                 output ("\n\t\t)\n");
416         }
417 }
418
419 static void
420 emit_costs (char *st, Tree *t)
421 {
422         char *tn;
423
424         if (t->op) {
425
426                 if (t->left) {
427                         tn = g_strconcat (st, "left->", NULL);
428                         emit_costs (tn, t->left);
429                         g_free (tn);
430                 }
431
432                 if (t->right) {
433                         tn = g_strconcat (st, "right->", NULL);
434                         emit_costs (tn, t->right);
435                 }
436         } else
437                 output ("%scost[MB_NTERM_%s] + ", st, t->nonterm->name);
438 }
439
440 static void
441 emit_cond_assign (Rule *rule, char *cost, char *fill)
442 {
443         char *rc;
444
445         if (cost)
446                 rc = g_strconcat ("c + ", cost, NULL);
447         else
448                 rc = g_strdup ("c");
449
450
451         output ("%sif (%s < p->cost[MB_NTERM_%s]) {\n", fill, rc, rule->lhs->name);
452
453         output ("%s\tp->cost[MB_NTERM_%s] = %s;\n", fill, rule->lhs->name, rc);
454
455         output ("%s\tp->rule_%s = %d;\n", fill, rule->lhs->name, 
456                 g_list_index (rule->lhs->rules, rule) + 1);
457
458         if (rule->lhs->chain)
459                 output ("%s\tclosure_%s (p, %s);\n", fill, rule->lhs->name, rc); 
460
461         output ("%s}\n", fill);
462
463         g_free (rc);
464         
465 }
466
467 static void
468 emit_label_func ()
469 {
470         GList *l;
471         int i;
472
473         if (dag_mode) {
474                 output ("static void\n");
475                 output ("mono_burg_label_priv (MBTREE_TYPE *tree, MBCOST_DATA *data, MBState *p) {\n");
476         } else {
477                 output ("static MBState *\n");
478                 output ("mono_burg_label_priv (MBTREE_TYPE *tree, MBCOST_DATA *data) {\n");
479         }
480
481         output ("\tint arity;\n");
482         output ("\tint c;\n");
483         if (!dag_mode) 
484                 output ("\tMBState *p;\n");
485         output ("\tMBState *left = NULL, *right = NULL;\n\n");
486
487         output ("\tswitch (mono_burg_arity [MBTREE_OP(tree)]) {\n");
488         output ("\tcase 0:\n");
489         output ("\t\tbreak;\n");
490         output ("\tcase 1:\n");
491         if (dag_mode) {
492                 output ("\t\tleft = MBALLOC_STATE;\n");
493                 output ("\t\tmono_burg_label_priv (MBTREE_LEFT(tree), data, left);\n");         
494         } else {
495                 output ("\t\tleft = mono_burg_label_priv (MBTREE_LEFT(tree), data);\n");
496                 output ("\t\tright = NULL;\n");
497         }
498         output ("\t\tbreak;\n");
499         output ("\tcase 2:\n");
500         if (dag_mode) {
501                 output ("\t\tleft = MBALLOC_STATE;\n");
502                 output ("\t\tmono_burg_label_priv (MBTREE_LEFT(tree), data, left);\n");         
503                 output ("\t\tright = MBALLOC_STATE;\n");
504                 output ("\t\tmono_burg_label_priv (MBTREE_RIGHT(tree), data, right);\n");               
505         } else {
506                 output ("\t\tleft = mono_burg_label_priv (MBTREE_LEFT(tree), data);\n");
507                 output ("\t\tright = mono_burg_label_priv (MBTREE_RIGHT(tree), data);\n");
508         }
509         output ("\t}\n\n");
510
511         output ("\tarity = (left != NULL) + (right != NULL);\n");
512         output ("\tg_assert (arity == mono_burg_arity [MBTREE_OP(tree)]);\n\n");
513
514         if (!dag_mode)
515                 output ("\tp = MBALLOC_STATE;\n");
516
517         output ("\tmemset (p, 0, sizeof (MBState));\n");
518         output ("\tp->op = MBTREE_OP(tree);\n");
519         output ("\tp->left = left;\n");
520         output ("\tp->right = right;\n");
521
522         if (dag_mode)
523                 output ("\tp->tree = tree;\n"); 
524         
525         for (l = nonterm_list, i = 0; l; l = l->next) {
526                 output ("\tp->cost [%d] = 32767;\n", ++i);
527         }
528         output ("\n");
529
530         output ("\tswitch (MBTREE_OP(tree)) {\n");
531         for (l = term_list; l; l = l->next) {
532                 Term *t = (Term *)l->data;
533                 GList *rl;
534                 
535                 if (predefined_terms)
536                         output ("\tcase %s: /* %s */\n", t->name, t->name);
537                 else
538                         output ("\tcase %d: /* %s */\n", t->number, t->name);
539
540                 for (rl = t->rules; rl; rl = rl->next) {
541                         Rule *rule = (Rule *)rl->data; 
542                         Tree *t = rule->tree;
543
544                         emit_rule_string (rule, "\t\t");
545
546                         emit_rule_match (rule);
547                         
548                         output ("\t\t{\n");
549
550                         output ("\t\t\tc = ");
551                         
552                         emit_costs ("", t);
553         
554                         output ("%s;\n", rule->cost);
555
556                         emit_cond_assign (rule, NULL, "\t\t\t");
557
558                         output ("\t\t}\n");
559                 }
560
561                 output ("\t\tbreak;\n");
562         }
563         
564         output ("\tdefault:\n");
565         output ("#ifdef MBGET_OP_NAME\n");
566         output ("\t\tg_error (\"unknown operator: %%s\", MBGET_OP_NAME(MBTREE_OP(tree)));\n");
567         output ("#else\n");
568         output ("\t\tg_error (\"unknown operator: 0x%%04x\", MBTREE_OP(tree));\n");
569         output ("#endif\n");
570         output ("\t}\n\n");
571
572         if (!dag_mode) {
573                 output ("\tMBTREE_STATE(tree) = p;\n");
574                 output ("\treturn p;\n");
575         }
576
577         output ("}\n\n");
578
579         output ("MBState *\n");
580         output ("mono_burg_label (MBTREE_TYPE *tree, MBCOST_DATA *data)\n{\n");
581         if (dag_mode) {
582                 output ("\tMBState *p = MBALLOC_STATE;\n");
583                 output ("\tmono_burg_label_priv (tree, data, p);\n");           
584         } else {
585                 output ("\tMBState *p = mono_burg_label_priv (tree, data);\n");
586         }
587         output ("\treturn p->rule_%s ? p : NULL;\n", ((NonTerm *)nonterm_list->data)->name);
588         output ("}\n\n");
589 }
590
591 static char *
592 compute_kids (char *ts, Tree *tree, int *n)
593 {
594         char *res;
595
596         if (tree->nonterm) {
597                 return g_strdup_printf ("\t\tkids[%d] = %s;\n", (*n)++, ts);
598         } else if (tree->op && tree->op->arity) {
599                 char *res2 = NULL;
600
601                 if (dag_mode) {
602                         res = compute_kids (g_strdup_printf ("%s->left", ts), 
603                                             tree->left, n);
604                         if (tree->op->arity == 2)
605                                 res2 = compute_kids (g_strdup_printf ("%s->right", ts), 
606                                                      tree->right, n);
607                 } else {
608                         res = compute_kids (g_strdup_printf ("MBTREE_LEFT(%s)", ts), 
609                                             tree->left, n);
610                         if (tree->op->arity == 2)
611                                 res2 = compute_kids (g_strdup_printf ("MBTREE_RIGHT(%s)", ts), 
612                                                      tree->right, n);
613                 }
614
615                 return g_strconcat (res, res2, NULL);
616         }
617         return "";
618 }
619
620 static void
621 emit_kids ()
622 {
623         GList *l, *nl;
624         int i, j, c, n, *si;
625         char **sa;
626
627         output ("int\n");
628         output ("mono_burg_rule (MBState *state, int goal)\n{\n");
629
630         output ("\tg_return_val_if_fail (state != NULL, 0);\n"); 
631         output ("\tg_return_val_if_fail (goal > 0, 0);\n\n");
632
633         output ("\tswitch (goal) {\n");
634
635         for (nl = nonterm_list; nl; nl = nl->next) {
636                 NonTerm *n = (NonTerm *)nl->data;
637                 output ("\tcase MB_NTERM_%s:\n", n->name);
638                 output ("\t\treturn mono_burg_decode_%s [state->rule_%s];\n",
639                         n->name, n->name);
640         }
641
642         output ("\tdefault: g_assert_not_reached ();\n");
643         output ("\t}\n");
644         output ("\treturn 0;\n");
645         output ("}\n\n");
646
647
648         if (dag_mode) {
649                 output ("MBState **\n");
650                 output ("mono_burg_kids (MBState *state, int rulenr, MBState *kids [])\n{\n");
651                 output ("\tg_return_val_if_fail (state != NULL, NULL);\n");
652                 output ("\tg_return_val_if_fail (kids != NULL, NULL);\n\n");
653
654         } else {
655                 output ("MBTREE_TYPE **\n");
656                 output ("mono_burg_kids (MBTREE_TYPE *tree, int rulenr, MBTREE_TYPE *kids [])\n{\n");
657                 output ("\tg_return_val_if_fail (tree != NULL, NULL);\n");
658                 output ("\tg_return_val_if_fail (kids != NULL, NULL);\n\n");
659         }
660
661         output ("\tswitch (rulenr) {\n");
662
663         n = g_list_length (rule_list);
664         sa = g_new0 (char *, n);
665         si = g_new0 (int, n);
666
667         /* compress the case statement */
668         for (l = rule_list, i = 0, c = 0; l; l = l->next) {
669                 Rule *rule = (Rule *)l->data;
670                 int kn = 0;
671                 char *k;
672
673                 if (dag_mode)
674                         k = compute_kids ("state", rule->tree, &kn);
675                 else
676                         k = compute_kids ("tree", rule->tree, &kn);
677
678                 for (j = 0; j < c; j++)
679                         if (!strcmp (sa [j], k))
680                                 break;
681
682                 si [i++] = j;
683                 if (j == c)
684                         sa [c++] = k;
685         }
686
687         for (i = 0; i < c; i++) {
688                 for (l = rule_list, j = 0; l; l = l->next, j++)
689                         if (i == si [j])
690                                 output ("\tcase %d:\n", j + 1);
691                 output ("%s", sa [i]);
692                 output ("\t\tbreak;\n");
693         }
694
695         output ("\tdefault:\n\t\tg_assert_not_reached ();\n");
696         output ("\t}\n");
697         output ("\treturn kids;\n");
698         output ("}\n\n");
699
700 }
701
702 static void
703 emit_emitter_func ()
704 {
705         GList *l;
706         int i, rulen;
707         GHashTable *cache = g_hash_table_new (g_str_hash, g_str_equal);
708
709         for (l =  rule_list, i = 0; l; l = l->next) {
710                 Rule *rule = (Rule *)l->data;
711                 
712                 if (rule->code) {
713                         if ((rulen = GPOINTER_TO_INT (g_hash_table_lookup (cache, rule->code)))) {
714                                 emit_rule_string (rule, "");
715                                 output ("#define mono_burg_emit_%d mono_burg_emit_%d\n\n", i, rulen);
716                                 i++;
717                                 continue;
718                         }
719                         output ("static void ");
720
721                         emit_rule_string (rule, "");
722
723                         if (dag_mode)
724                                 output ("mono_burg_emit_%d (MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n", i);
725                         else
726                                 output ("mono_burg_emit_%d (MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n", i);
727                         output ("{\n");
728                         output ("%s\n", rule->code);
729                         output ("}\n\n");
730                         g_hash_table_insert (cache, rule->code, GINT_TO_POINTER (i));
731                 }
732                 i++;
733         }
734
735         g_hash_table_destroy (cache);
736
737         output ("MBEmitFunc const mono_burg_func [] = {\n");
738         output ("\tNULL,\n");
739         for (l =  rule_list, i = 0; l; l = l->next) {
740                 Rule *rule = (Rule *)l->data;
741                 if (rule->code)
742                         output ("\tmono_burg_emit_%d,\n", i);
743                 else
744                         output ("\tNULL,\n");
745                 i++;
746         }
747         output ("};\n\n");
748 }
749
750 static void
751 emit_cost_func ()
752 {
753         GList *l;
754         int i;
755
756         for (l =  rule_list, i = 0; l; l = l->next) {
757                 Rule *rule = (Rule *)l->data;
758                 
759                 if (rule->cfunc) {
760                         output ("inline static guint16\n");
761
762                         emit_rule_string (rule, "");
763                         
764                         if (dag_mode)
765                                 output ("mono_burg_cost_%d (MBState *state, MBCOST_DATA *data)\n", i + 1);
766                         else
767                                 output ("mono_burg_cost_%d (MBTREE_TYPE *tree, MBCOST_DATA *data)\n", i + 1);
768                         output ("{\n");
769                         output ("%s\n", rule->cfunc);
770                         output ("}\n\n");
771                 }
772                 i++;
773         }
774 }
775
776 static void
777 emit_closure ()
778 {
779         GList *l, *rl;
780
781         for (l = nonterm_list; l; l = l->next) {
782                 NonTerm *n = (NonTerm *)l->data;
783                 
784                 if (n->chain)
785                         output ("static void closure_%s (MBState *p, int c);\n", n->name);
786         }
787
788         output ("\n");
789
790         for (l = nonterm_list; l; l = l->next) {
791                 NonTerm *n = (NonTerm *)l->data;
792                 
793                 if (n->chain) {
794                         output ("static void\n");
795                         output ("closure_%s (MBState *p, int c)\n{\n", n->name);
796                         for (rl = n->chain; rl; rl = rl->next) {
797                                 Rule *rule = (Rule *)rl->data;
798                                 
799                                 emit_rule_string (rule, "\t");
800                                 emit_cond_assign (rule, rule->cost, "\t");
801                         }
802                         output ("}\n\n");
803                 }
804         }
805 }
806
807 static char *
808 compute_nonterms (Tree *tree)
809 {
810         if (!tree)
811                 return "";
812
813         if (tree->nonterm) {
814                 return g_strdup_printf ("MB_NTERM_%s, ", tree->nonterm->name);
815         } else {
816                 return g_strconcat (compute_nonterms (tree->left),
817                                     compute_nonterms (tree->right), NULL);
818         } 
819 }
820
821 static int
822 count_nonterms (Tree *tree)
823 {
824         if (!tree)
825                 return 0;
826
827         if (tree->nonterm) {
828                 return 1;
829         } else {
830                 return count_nonterms (tree->left) + count_nonterms (tree->right);
831         } 
832 }
833
834 static void
835 emit_vardefs ()
836 {
837         GList *l;
838         int i, j, c, n, *si;
839         char **sa;
840         int *nts_offsets;
841         int current_offset;
842
843         if (predefined_terms) {
844                 output ("#if HAVE_ARRAY_ELEM_INIT\n");
845                 output ("const guint8 mono_burg_arity [MBMAX_OPCODES] = {\n"); 
846                 for (l = term_list, i = 0; l; l = l->next) {
847                         Term *t = (Term *)l->data;
848                         output ("\t [%s] = %d, /* %s */\n", t->name, t->arity, t->name);
849                 }
850                 output ("};\n\n");
851                 output ("void\nmono_burg_init (void) {\n");
852                 output ("}\n\n");
853                 output ("#else\n");
854                 output ("guint8 mono_burg_arity [MBMAX_OPCODES];\n"); 
855
856                 output ("void\nmono_burg_init (void)\n{\n");
857
858                 for (l = term_list, i = 0; l; l = l->next) {
859                         Term *t = (Term *)l->data;
860                         output ("\tmono_burg_arity [%s] = %d; /* %s */\n", t->name, t->arity, t->name);
861                 }
862                 output ("}\n\n");
863                 output ("#endif /* HAVE_ARRAY_ELEM_INIT */\n");
864
865         } else {
866                 output ("const guint8 mono_burg_arity [] = {\n"); 
867                 for (l = term_list, i = 0; l; l = l->next) {
868                         Term *t = (Term *)l->data;
869
870                         while (i < t->number) {
871                                 output ("\t0,\n");
872                                 i++;
873                         }
874                 
875                         output ("\t%d, /* %s */\n", t->arity, t->name);
876
877                         i++;
878                 }
879                 output ("};\n\n");
880
881                 output ("const char *const mono_burg_term_string [] = {\n");
882                 output ("\tNULL,\n");
883                 for (l = term_list, i = 0; l; l = l->next) {
884                         Term *t = (Term *)l->data;
885                         output ("\t\"%s\",\n", t->name);
886                 }
887                 output ("};\n\n");
888         }
889
890         output ("#if MONOBURG_LOG\n");
891         output ("const char * const mono_burg_rule_string [] = {\n");
892         output ("\tNULL,\n");
893         for (l = rule_list, i = 0; l; l = l->next) {
894                 Rule *rule = (Rule *)l->data;
895                 output ("\t\"%s: ", rule->lhs->name);
896                 emit_tree_string (rule->tree);
897                 output ("\",\n");
898         }
899         output ("};\n");
900         output ("#endif /* MONOBURG_LOG */\n\n");
901
902         n = g_list_length (rule_list);
903         sa = g_new0 (char *, n);
904         si = g_new0 (int, n);
905         nts_offsets = g_new0 (int, n);
906
907         /* at offset 0 we store 0 to mean end of list */
908         current_offset = 1;
909         output ("const guint16 mono_burg_nts_data [] = {\n\t0,\n");
910         /* compress the _nts array */
911         for (l = rule_list, i = 0, c = 0; l; l = l->next) {
912                 Rule *rule = (Rule *)l->data;
913                 char *s = compute_nonterms (rule->tree);
914
915                 for (j = 0; j < c; j++)
916                         if (!strcmp (sa [j], s))
917                                 break;
918
919                 si [i++] = j;
920                 if (j == c) {
921                         output ("\t%s0,\n", s);
922                         nts_offsets [c] = current_offset;
923                         sa [c++] = s;
924                         current_offset += count_nonterms (rule->tree) + 1;
925                 }
926         }       
927         output ("\t0\n};\n\n");
928
929         output ("const guint8 mono_burg_nts [] = {\n");
930         output ("\t0,\n");
931         for (l = rule_list, i = 0; l; l = l->next) {
932                 Rule *rule = (Rule *)l->data;
933                 output ("\t%d, /* %s */ ", nts_offsets [si [i]], sa [si [i]]);
934                 ++i;
935                 emit_rule_string (rule, "");
936         }
937         output ("};\n\n");
938 }
939
940 static void
941 emit_prototypes ()
942 {
943         if (dag_mode)
944                 output ("typedef void (*MBEmitFunc) (MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
945         else
946                 output ("typedef void (*MBEmitFunc) (MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
947         
948         output ("extern const char * const mono_burg_term_string [];\n");
949         output ("#if MONOBURG_LOG\n");
950         output ("extern const char * const mono_burg_rule_string [];\n");
951         output ("#endif /* MONOBURG_LOG */\n");
952         output ("extern const guint16 mono_burg_nts_data [];\n");
953         output ("extern const guint8 mono_burg_nts [];\n");
954         output ("extern MBEmitFunc const mono_burg_func [];\n");
955
956         output ("MBState *mono_burg_label (MBTREE_TYPE *tree, MBCOST_DATA *data);\n");
957         output ("int mono_burg_rule (MBState *state, int goal);\n");
958
959         if (dag_mode)
960                 output ("MBState **mono_burg_kids (MBState *state, int rulenr, MBState *kids []);\n");
961         else
962                 output ("MBTREE_TYPE **mono_burg_kids (MBTREE_TYPE *tree, int rulenr, MBTREE_TYPE *kids []);\n");
963
964         output ("extern void mono_burg_init (void);\n");
965         output ("\n");
966 }
967
968 static void check_reach (NonTerm *n);
969
970 static void
971 mark_reached (Tree *tree)
972 {
973         if (tree->nonterm && !tree->nonterm->reached)
974                 check_reach (tree->nonterm);
975         if (tree->left)
976                 mark_reached (tree->left);
977         if (tree->right)
978                 mark_reached (tree->right);
979 }
980
981 static void
982 check_reach (NonTerm *n)
983 {
984         GList *l;
985
986         n->reached = 1;
987         for (l = n->rules; l; l = l->next) {
988                 Rule *rule = (Rule *)l->data;
989                 mark_reached (rule->tree);
990         }
991 }
992
993 static void
994 check_result ()
995 {
996         GList *l;
997
998         for (l = term_list; l; l = l->next) {
999                 Term *term = (Term *)l->data;
1000                 if (term->arity == -1)
1001                         g_warning ("unused terminal \"%s\"",term->name);
1002         } 
1003
1004         check_reach (((NonTerm *)nonterm_list->data));
1005
1006         for (l = nonterm_list; l; l = l->next) {
1007                 NonTerm *n = (NonTerm *)l->data;
1008                 if (!n->reached)
1009                         g_warning ("unreachable nonterm \"%s\"", n->name);
1010         }
1011 }
1012
1013 static void
1014 usage ()
1015 {
1016         fprintf (stderr,
1017                  "Usage is: monoburg -d file.h -s file.c [inputfile] \n");
1018         exit (1);
1019 }
1020
1021 static void
1022 warning_handler (const gchar *log_domain,
1023                  GLogLevelFlags log_level,
1024                  const gchar *message,
1025                  gpointer user_data)
1026 {
1027         (void) fprintf ((FILE *) user_data, "** WARNING **: %s\n", message);
1028 }
1029
1030 int
1031 main (int argc, char *argv [])
1032 {
1033         char *cfile = NULL;
1034         char *deffile = NULL;
1035         GList *infiles = NULL;
1036         int i;
1037
1038         definedvars = g_hash_table_new (g_str_hash, g_str_equal);
1039         g_log_set_handler (NULL, G_LOG_LEVEL_WARNING, warning_handler, stderr);
1040
1041         for (i = 1; i < argc; i++){
1042                 if (argv [i][0] == '-'){
1043                         if (argv [i][1] == 'h') {
1044                                 usage ();
1045                         } else if (argv [i][1] == 'e') {
1046                                 dag_mode = 1;
1047                         } else if (argv [i][1] == 'p') {
1048                                 predefined_terms = 1;
1049                         } else if (argv [i][1] == 'd') {
1050                                 deffile = argv [++i];
1051                         } else if (argv [i][1] == 's') {
1052                                 cfile = argv [++i];
1053                         } else if (argv [i][1] == 'c') {
1054                                 default_cost = atoi (argv [++i]);
1055                         } else if (argv [i][1] == 'D') {
1056                                 g_hash_table_insert (definedvars, &argv [i][2],
1057                                                      GUINT_TO_POINTER (1));
1058                         } else {
1059                                 usage ();
1060                         }
1061                 } else {
1062                         infiles = g_list_append (infiles, argv [i]);
1063                 }
1064         }
1065
1066         if (deffile) {
1067                 if (!(deffd = fopen (deffile, "w"))) {
1068                         perror ("cant open header output file");
1069                         exit (-1);
1070                 }
1071                 outputfd = deffd;
1072                 output ("#ifndef _MONO_BURG_DEFS_\n");
1073                 output ("#define _MONO_BURG_DEFS_\n\n");
1074         } else 
1075                 outputfd = stdout;
1076
1077
1078         if (infiles) {
1079                 GList *l = infiles;
1080                 while (l) {
1081                         char *infile = (char *)l->data;
1082                         if (!(inputfd = fopen (infile, "r"))) {
1083                                 perror ("cant open input file");
1084                                 exit (-1);
1085                         }
1086
1087                         yyparse ();
1088
1089                         reset_parser ();
1090
1091                         l->data = inputfd;
1092                         l = l->next;
1093                 }
1094         } else {
1095                 inputfd = stdin;
1096                 yyparse ();
1097         }
1098
1099         check_result ();
1100
1101         if (!nonterm_list)
1102                 g_error ("no start symbol found");
1103
1104         emit_header ();
1105         emit_nonterm ();
1106         emit_state ();
1107         emit_prototypes ();
1108
1109         if (deffd) {
1110                 output ("#endif /* _MONO_BURG_DEFS_ */\n");
1111                 fclose (deffd);
1112
1113                 if (cfile == NULL)
1114                         outputfd = stdout;
1115                 else {
1116                         if (!(cfd = fopen (cfile, "w"))) {
1117                                 perror ("cant open c output file");
1118                                 (void) remove (deffile);
1119                                 exit (-1);
1120                         }
1121
1122                         outputfd = cfd;
1123                 }
1124
1125                 output ("#include \"%s\"\n\n", deffile);
1126         }
1127         
1128         emit_vardefs ();
1129         emit_cost_func ();
1130         emit_emitter_func ();
1131         emit_decoders ();
1132
1133         emit_closure ();
1134         emit_label_func ();
1135
1136         emit_kids ();
1137
1138         if (infiles) {
1139                 GList *l = infiles;
1140                 while (l) {
1141                         inputfd = l->data;
1142                         yyparsetail ();
1143                         fclose (inputfd);
1144                         l = l->next;
1145                 }
1146         } else {
1147                 yyparsetail ();
1148         }
1149
1150         if (cfile)
1151                 fclose (cfd);
1152
1153         return 0;
1154 }