upper-case, just in case
[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;
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                         GList *cases;
714                         if ((cases = g_hash_table_lookup (cache, rule->code))) {
715                                 cases = g_list_append (cases, GINT_TO_POINTER (i));
716                         } else {
717                                 cases = g_list_append (NULL, GINT_TO_POINTER (i));
718                         }
719                         g_hash_table_insert (cache, rule->code, cases);
720                 }
721                 i++;
722         }
723
724         output ("void mono_burg_emit (int ern, MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s)\n {\n");
725         output ("\tswitch (ern) {");
726         for (l =  rule_list, i = 0; l; l = l->next) {
727                 Rule *rule = (Rule *)l->data;
728
729                 if (rule->code) {
730                         GList *cases, *tmp;
731                         cases = g_hash_table_lookup (cache, rule->code);
732                         if (cases && i != GPOINTER_TO_INT (cases->data)) {
733                                 i++;
734                                 continue;
735                         }
736                         emit_rule_string (rule, "");
737                         for (tmp = cases; tmp; tmp = tmp->next) {
738                                 output ("\tcase %d:\n", GPOINTER_TO_INT (tmp->data) + 1);
739                         }
740                         output ("\t{\n");
741                         output ("%s\n", rule->code);
742                         output ("\t}\n\treturn;\n");
743                 }
744                 i++;
745         }
746         output ("\t}\n}\n\n");
747         g_hash_table_destroy (cache);
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         output ("\n");
844         if (predefined_terms) {
845                 output ("#if HAVE_ARRAY_ELEM_INIT\n");
846                 output ("const guint8 mono_burg_arity [MBMAX_OPCODES] = {\n"); 
847                 for (l = term_list, i = 0; l; l = l->next) {
848                         Term *t = (Term *)l->data;
849                         output ("\t [%s] = %d, /* %s */\n", t->name, t->arity, t->name);
850                 }
851                 output ("};\n\n");
852                 output ("void\nmono_burg_init (void) {\n");
853                 output ("}\n\n");
854                 output ("#else\n");
855                 output ("guint8 mono_burg_arity [MBMAX_OPCODES];\n"); 
856
857                 output ("void\nmono_burg_init (void)\n{\n");
858
859                 for (l = term_list, i = 0; l; l = l->next) {
860                         Term *t = (Term *)l->data;
861                         output ("\tmono_burg_arity [%s] = %d; /* %s */\n", t->name, t->arity, t->name);
862                 }
863                 output ("}\n\n");
864                 output ("#endif /* HAVE_ARRAY_ELEM_INIT */\n");
865
866         } else {
867                 output ("const guint8 mono_burg_arity [] = {\n"); 
868                 for (l = term_list, i = 0; l; l = l->next) {
869                         Term *t = (Term *)l->data;
870
871                         while (i < t->number) {
872                                 output ("\t0,\n");
873                                 i++;
874                         }
875                 
876                         output ("\t%d, /* %s */\n", t->arity, t->name);
877
878                         i++;
879                 }
880                 output ("};\n\n");
881
882                 output ("const char *const mono_burg_term_string [] = {\n");
883                 output ("\tNULL,\n");
884                 for (l = term_list, i = 0; l; l = l->next) {
885                         Term *t = (Term *)l->data;
886                         output ("\t\"%s\",\n", t->name);
887                 }
888                 output ("};\n\n");
889         }
890
891         output ("#if MONOBURG_LOG\n");
892         output ("const char * const mono_burg_rule_string [] = {\n");
893         output ("\tNULL,\n");
894         for (l = rule_list, i = 0; l; l = l->next) {
895                 Rule *rule = (Rule *)l->data;
896                 output ("\t\"%s: ", rule->lhs->name);
897                 emit_tree_string (rule->tree);
898                 output ("\",\n");
899         }
900         output ("};\n");
901         output ("#endif /* MONOBURG_LOG */\n\n");
902
903         n = g_list_length (rule_list);
904         sa = g_new0 (char *, n);
905         si = g_new0 (int, n);
906         nts_offsets = g_new0 (int, n);
907
908         /* at offset 0 we store 0 to mean end of list */
909         current_offset = 1;
910         output ("const guint16 mono_burg_nts_data [] = {\n\t0,\n");
911         /* compress the _nts array */
912         for (l = rule_list, i = 0, c = 0; l; l = l->next) {
913                 Rule *rule = (Rule *)l->data;
914                 char *s = compute_nonterms (rule->tree);
915
916                 for (j = 0; j < c; j++)
917                         if (!strcmp (sa [j], s))
918                                 break;
919
920                 si [i++] = j;
921                 if (j == c) {
922                         output ("\t%s0,\n", s);
923                         nts_offsets [c] = current_offset;
924                         sa [c++] = s;
925                         current_offset += count_nonterms (rule->tree) + 1;
926                 }
927         }       
928         output ("\t0\n};\n\n");
929
930         output ("const guint8 mono_burg_nts [] = {\n");
931         output ("\t0,\n");
932         for (l = rule_list, i = 0; l; l = l->next) {
933                 Rule *rule = (Rule *)l->data;
934                 output ("\t%d, /* %s */ ", nts_offsets [si [i]], sa [si [i]]);
935                 ++i;
936                 emit_rule_string (rule, "");
937         }
938         output ("};\n\n");
939 }
940
941 static void
942 emit_prototypes ()
943 {
944         output ("extern const char * const mono_burg_term_string [];\n");
945         output ("#if MONOBURG_LOG\n");
946         output ("extern const char * const mono_burg_rule_string [];\n");
947         output ("#endif /* MONOBURG_LOG */\n");
948         output ("extern const guint16 mono_burg_nts_data [];\n");
949         output ("extern const guint8 mono_burg_nts [];\n");
950         output ("extern void mono_burg_emit (int ern, MBState *state, MBTREE_TYPE *tree, MBCGEN_TYPE *s);\n\n");
951
952         output ("MBState *mono_burg_label (MBTREE_TYPE *tree, MBCOST_DATA *data);\n");
953         output ("int mono_burg_rule (MBState *state, int goal);\n");
954
955         if (dag_mode)
956                 output ("MBState **mono_burg_kids (MBState *state, int rulenr, MBState *kids []);\n");
957         else
958                 output ("MBTREE_TYPE **mono_burg_kids (MBTREE_TYPE *tree, int rulenr, MBTREE_TYPE *kids []);\n");
959
960         output ("extern void mono_burg_init (void);\n");
961         output ("\n");
962 }
963
964 static void check_reach (NonTerm *n);
965
966 static void
967 mark_reached (Tree *tree)
968 {
969         if (tree->nonterm && !tree->nonterm->reached)
970                 check_reach (tree->nonterm);
971         if (tree->left)
972                 mark_reached (tree->left);
973         if (tree->right)
974                 mark_reached (tree->right);
975 }
976
977 static void
978 check_reach (NonTerm *n)
979 {
980         GList *l;
981
982         n->reached = 1;
983         for (l = n->rules; l; l = l->next) {
984                 Rule *rule = (Rule *)l->data;
985                 mark_reached (rule->tree);
986         }
987 }
988
989 static void
990 check_result ()
991 {
992         GList *l;
993
994         for (l = term_list; l; l = l->next) {
995                 Term *term = (Term *)l->data;
996                 if (term->arity == -1)
997                         g_warning ("unused terminal \"%s\"",term->name);
998         } 
999
1000         check_reach (((NonTerm *)nonterm_list->data));
1001
1002         for (l = nonterm_list; l; l = l->next) {
1003                 NonTerm *n = (NonTerm *)l->data;
1004                 if (!n->reached)
1005                         g_warning ("unreachable nonterm \"%s\"", n->name);
1006         }
1007 }
1008
1009 static void
1010 usage ()
1011 {
1012         fprintf (stderr,
1013                  "Usage is: monoburg -d file.h -s file.c [inputfile] \n");
1014         exit (1);
1015 }
1016
1017 static void
1018 warning_handler (const gchar *log_domain,
1019                  GLogLevelFlags log_level,
1020                  const gchar *message,
1021                  gpointer user_data)
1022 {
1023         (void) fprintf ((FILE *) user_data, "** WARNING **: %s\n", message);
1024 }
1025
1026 int
1027 main (int argc, char *argv [])
1028 {
1029         char *cfile = NULL;
1030         char *deffile = NULL;
1031         GList *infiles = NULL;
1032         int i;
1033
1034         definedvars = g_hash_table_new (g_str_hash, g_str_equal);
1035         g_log_set_handler (NULL, G_LOG_LEVEL_WARNING, warning_handler, stderr);
1036
1037         for (i = 1; i < argc; i++){
1038                 if (argv [i][0] == '-'){
1039                         if (argv [i][1] == 'h') {
1040                                 usage ();
1041                         } else if (argv [i][1] == 'e') {
1042                                 dag_mode = 1;
1043                         } else if (argv [i][1] == 'p') {
1044                                 predefined_terms = 1;
1045                         } else if (argv [i][1] == 'd') {
1046                                 deffile = argv [++i];
1047                         } else if (argv [i][1] == 's') {
1048                                 cfile = argv [++i];
1049                         } else if (argv [i][1] == 'c') {
1050                                 default_cost = atoi (argv [++i]);
1051                         } else if (argv [i][1] == 'D') {
1052                                 g_hash_table_insert (definedvars, &argv [i][2],
1053                                                      GUINT_TO_POINTER (1));
1054                         } else {
1055                                 usage ();
1056                         }
1057                 } else {
1058                         infiles = g_list_append (infiles, argv [i]);
1059                 }
1060         }
1061
1062         if (deffile) {
1063                 if (!(deffd = fopen (deffile, "w"))) {
1064                         perror ("cant open header output file");
1065                         exit (-1);
1066                 }
1067                 outputfd = deffd;
1068                 output ("#ifndef _MONO_BURG_DEFS_\n");
1069                 output ("#define _MONO_BURG_DEFS_\n\n");
1070         } else 
1071                 outputfd = stdout;
1072
1073
1074         if (infiles) {
1075                 GList *l = infiles;
1076                 while (l) {
1077                         char *infile = (char *)l->data;
1078                         if (!(inputfd = fopen (infile, "r"))) {
1079                                 perror ("cant open input file");
1080                                 exit (-1);
1081                         }
1082
1083                         yyparse ();
1084
1085                         reset_parser ();
1086
1087                         l->data = inputfd;
1088                         l = l->next;
1089                 }
1090         } else {
1091                 inputfd = stdin;
1092                 yyparse ();
1093         }
1094
1095         check_result ();
1096
1097         if (!nonterm_list)
1098                 g_error ("no start symbol found");
1099
1100         emit_header ();
1101         emit_nonterm ();
1102         emit_state ();
1103         emit_prototypes ();
1104
1105         if (deffd) {
1106                 output ("#endif /* _MONO_BURG_DEFS_ */\n");
1107                 fclose (deffd);
1108
1109                 if (cfile == NULL)
1110                         outputfd = stdout;
1111                 else {
1112                         if (!(cfd = fopen (cfile, "w"))) {
1113                                 perror ("cant open c output file");
1114                                 (void) remove (deffile);
1115                                 exit (-1);
1116                         }
1117
1118                         outputfd = cfd;
1119                 }
1120
1121                 output ("#include \"%s\"\n\n", deffile);
1122         }
1123         
1124         if (infiles) {
1125                 GList *l = infiles;
1126                 while (l) {
1127                         inputfd = l->data;
1128                         yyparsetail ();
1129                         fclose (inputfd);
1130                         l = l->next;
1131                 }
1132         } else {
1133                 yyparsetail ();
1134         }
1135
1136         emit_vardefs ();
1137         emit_cost_func ();
1138         emit_emitter_func ();
1139         emit_decoders ();
1140
1141         emit_closure ();
1142         emit_label_func ();
1143
1144         emit_kids ();
1145
1146         if (cfile)
1147                 fclose (cfd);
1148
1149         return 0;
1150 }