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