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