Add a FIXME comment.
[oota-llvm.git] / utils / Burg / plank.c
1 char rcsid_plank[] = "$Id$";
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include "b.h"
7 #include "fe.h"
8
9 #define ERROR_VAL 0
10
11 int speedflag = 0;
12
13 Item_Set *sortedStates;
14 static struct stateMapTable smt;
15 int exceptionTolerance = 0;
16 static int plankSize = 32;
17
18 static Plank newPlank ARGS((void));
19 static PlankMap newPlankMap ARGS((int));
20 static StateMap newStateMap ARGS((void));
21 static Exception newException ARGS((int, int));
22 static void enterStateMap ARGS((PlankMap, short *, int, int *));
23 static List assemblePlanks ARGS((void));
24 static void assignRules ARGS((RuleAST));
25 static int stateCompare ARGS((Item_Set *, Item_Set *));
26 static int ruleCompare ARGS((RuleAST *, RuleAST *));
27 static void renumber ARGS((void));
28 static short * newVector ARGS((void));
29 static int width ARGS((int));
30 static PlankMap mapToPmap ARGS((Dimension));
31 static void doDimPmaps ARGS((Operator));
32 static void doNonTermPmaps ARGS((NonTerminal));
33 static void makePmaps ARGS((void));
34 static void outPlank ARGS((Plank));
35 static void purgePlanks ARGS((List));
36 static void inToEx ARGS((void));
37 static void makePlankRuleMacros ARGS((void));
38 static void makePlankRule ARGS((void));
39 static void exceptionSwitch ARGS((List, const char *, const char *, const char *, int, const char *));
40 static void doPlankLabel ARGS((Operator));
41 static void doPlankLabelSafely ARGS((Operator));
42 static void doPlankLabelMacrosSafely ARGS((Operator));
43 static void makePlankState ARGS((void));
44
45 static Plank
46 newPlank()
47 {
48   Plank p;
49   char buf[50];
50   static int num = 0;
51
52   p = (Plank) zalloc(sizeof(struct plank));
53   sprintf(buf, "%s_plank_%d", prefix, num++);
54   p->name = (char *) zalloc(strlen(buf)+1);
55   strcpy(p->name, buf);
56   return p;
57 }
58
59 static PlankMap
60 newPlankMap(offset) int offset;
61 {
62   PlankMap im;
63
64   im = (PlankMap) zalloc(sizeof(struct plankMap));
65   im->offset = offset;
66   return im;
67 }
68
69 static StateMap
70 newStateMap()
71 {
72   char buf[50];
73   static int num = 0;
74
75   StateMap sm;
76
77   sm = (StateMap) zalloc(sizeof(struct stateMap));
78   sprintf(buf, "f%d", num++);
79   sm->fieldname = (char *) zalloc(strlen(buf)+1);
80   strcpy(sm->fieldname, buf);
81   return sm;
82 }
83
84 static Exception
85 newException(index, value) int index; int value;
86 {
87   Exception e;
88
89   e = (Exception) zalloc(sizeof(struct except));
90   e->index = index;
91   e->value = value;
92   return e;
93 }
94
95 static void
96 enterStateMap(im, v, width, new) PlankMap im; short * v; int width; int *new;
97 {
98   int i;
99   StateMap sm;
100   List l;
101   int size;
102
103   assert(im);
104   assert(v);
105   assert(width > 0);
106   size = globalMap->count;
107
108   for (l = smt.maps; l; l = l->next) {
109     int ecount;
110
111     sm = (StateMap) l->x;
112     ecount = 0;
113     for (i = 0; i < size; i++) {
114       if (v[i] != -1 && sm->value[i] != -1 && v[i] != sm->value[i]) {
115         if (++ecount > exceptionTolerance) {
116           goto again;
117         }
118       }
119     }
120     for (i = 0; i < size; i++) {
121       assert(v[i] >= 0);
122       assert(sm->value[i] >= 0);
123       if (v[i] == -1) {
124         continue;
125       }
126       if (sm->value[i] == -1) {
127         sm->value[i] = v[i];
128       } else if (v[i] != sm->value[i]) {
129         im->exceptions = newList(newException(i,v[i]), im->exceptions);
130       }
131     }
132     im->values = sm;
133     if (width > sm->width) {
134       sm->width = width;
135     }
136     *new = 0;
137     return;
138   again: ;
139   }
140   sm = newStateMap();
141   im->values = sm;
142   sm->value = v;
143   sm->width = width;
144   *new = 1;
145   smt.maps = newList(sm, smt.maps);
146 }
147
148 static List
149 assemblePlanks()
150 {
151   List planks = 0;
152   Plank pl;
153   List p;
154   List s;
155
156   for (s = smt.maps; s; s = s->next) {
157     StateMap sm = (StateMap) s->x;
158     for (p = planks; p; p = p->next) {
159       pl = (Plank) p->x;
160       if (sm->width <= plankSize - pl->width) {
161         pl->width += sm->width;
162         pl->fields = newList(sm, pl->fields);
163         sm->plank = pl;
164         goto next;
165       }
166     }
167     pl = newPlank();
168     pl->width = sm->width;
169     pl->fields = newList(sm, 0);
170     sm->plank = pl;
171     planks = appendList(pl, planks);
172   next: ;
173   }
174   return planks;
175 }
176
177 RuleAST *sortedRules;
178
179 static int count;
180
181 static void
182 assignRules(ast) RuleAST ast;
183 {
184   sortedRules[count++] = ast;
185 }
186
187 static int
188 stateCompare(s, t) Item_Set *s; Item_Set *t;
189 {
190   return strcmp((*s)->op->name, (*t)->op->name);
191 }
192
193 static int
194 ruleCompare(s, t) RuleAST *s; RuleAST *t;
195 {
196   return strcmp((*s)->lhs, (*t)->lhs);
197 }
198
199 void
200 dumpSortedStates()
201 {
202   int i;
203
204   printf("dump Sorted States: ");
205   for (i = 0; i < globalMap->count; i++) {
206     printf("%d ", sortedStates[i]->num);
207   }
208   printf("\n");
209 }
210
211 void
212 dumpSortedRules()
213 {
214   int i;
215
216   printf("dump Sorted Rules: ");
217   for (i = 0; i < max_ruleAST; i++) {
218     printf("%d ", sortedRules[i]->rule->erulenum);
219   }
220   printf("\n");
221 }
222
223 static void
224 renumber()
225 {
226   int i;
227   Operator previousOp;
228   NonTerminal previousLHS;
229   int base_counter;
230
231   sortedStates = (Item_Set*) zalloc(globalMap->count * sizeof(Item_Set));
232   for (i = 1; i < globalMap->count; i++) {
233     sortedStates[i-1] = globalMap->set[i];
234   }
235   qsort(sortedStates, globalMap->count-1, sizeof(Item_Set), (int(*)(const void *, const void *))stateCompare);
236   previousOp = 0;
237   for (i = 0; i < globalMap->count-1; i++) {
238     sortedStates[i]->newNum = i;
239     sortedStates[i]->op->stateCount++;
240     if (previousOp != sortedStates[i]->op) {
241       sortedStates[i]->op->baseNum = i;
242       previousOp = sortedStates[i]->op;
243     }
244   }
245
246   sortedRules = (RuleAST*) zalloc(max_ruleAST * sizeof(RuleAST));
247   count = 0;
248   foreachList((ListFn) assignRules, ruleASTs);
249   qsort(sortedRules, max_ruleAST, sizeof(RuleAST), (int(*)(const void *, const void *))ruleCompare);
250   previousLHS = 0;
251   base_counter = 0;
252   for (i = 0; i < max_ruleAST; i++) {
253     if (previousLHS != sortedRules[i]->rule->lhs) {
254       sortedRules[i]->rule->lhs->baseNum = base_counter;
255       previousLHS = sortedRules[i]->rule->lhs;
256       base_counter++; /* make space for 0 */
257     }
258     sortedRules[i]->rule->newNum = base_counter;
259     sortedRules[i]->rule->lhs->ruleCount++;
260     sortedRules[i]->rule->lhs->sampleRule = sortedRules[i]->rule; /* kludge for diagnostics */
261     base_counter++;
262   }
263 }
264
265 static short *
266 newVector()
267 {
268   short *p;
269   p = (short *) zalloc(globalMap->count* sizeof(short));
270   return p;
271 }
272
273 static int
274 width(v) int v;
275 {
276   int c;
277
278   for (c = 0; v; v >>= 1) {
279     c++;
280   }
281   return c;
282
283 }
284
285 static PlankMap
286 mapToPmap(d) Dimension d;
287 {
288   PlankMap im;
289   short *v;
290   int i;
291   int new;
292
293   if (d->map->count == 1) {
294     return 0;
295   }
296   assert(d->map->count > 1);
297   im = newPlankMap(0);
298   v = newVector();
299   for (i = 0; i < globalMap->count-1; i++) {
300     int index = d->map->set[d->index_map.class[sortedStates[i]->num]->num]->num;
301     assert(index >= 0);
302     v[i+1] = index;
303   }
304   v[0] = 0;
305   enterStateMap(im, v, width(d->map->count), &new);
306   if (!new) {
307     zfree(v);
308   }
309   return im;
310 }
311
312 static void
313 doDimPmaps(op) Operator op;
314 {
315   int i, j;
316   Dimension d;
317   short *v;
318   PlankMap im;
319   int new;
320
321   if (!op->table->rules) {
322     return;
323   }
324   switch (op->arity) {
325   case 0:
326     break;
327   case 1:
328     d = op->table->dimen[0];
329     if (d->map->count > 1) {
330       v = newVector();
331       im = newPlankMap(op->baseNum);
332       for (i = 0; i < globalMap->count-1; i++) {
333         int index = d->map->set[d->index_map.class[sortedStates[i]->num]->num]->num;
334         if (index) {
335           Item_Set *ts = transLval(op->table, index, 0);
336           v[i+1] = (*ts)->newNum - op->baseNum+1;
337           assert(v[i+1] >= 0);
338         }
339       }
340       enterStateMap(im, v, width(d->map->count-1), &new);
341       if (!new) {
342         zfree(v);
343       }
344       d->pmap = im;
345     }
346     break;
347   case 2:
348     if (op->table->dimen[0]->map->count == 1 && op->table->dimen[1]->map->count == 1) {
349       op->table->dimen[0]->pmap = 0;
350       op->table->dimen[1]->pmap = 0;
351     } else if (op->table->dimen[0]->map->count == 1) {
352       v = newVector();
353       im = newPlankMap(op->baseNum);
354       d = op->table->dimen[1];
355       for (i = 0; i < globalMap->count-1; i++) {
356         int index = d->map->set[d->index_map.class[sortedStates[i]->num]->num]->num;
357         if (index) {
358           Item_Set *ts = transLval(op->table, 1, index);
359           v[i+1] = (*ts)->newNum - op->baseNum+1;
360           assert(v[i+1] >= 0);
361         }
362       }
363       enterStateMap(im, v, width(d->map->count-1), &new);
364       if (!new) {
365         zfree(v);
366       }
367       d->pmap = im;
368     } else if (op->table->dimen[1]->map->count == 1) {
369       v = newVector();
370       im = newPlankMap(op->baseNum);
371       d = op->table->dimen[0];
372       for (i = 0; i < globalMap->count-1; i++) {
373         int index = d->map->set[d->index_map.class[sortedStates[i]->num]->num]->num;
374         if (index) {
375           Item_Set *ts = transLval(op->table, index, 1);
376           v[i +1] = (*ts)->newNum - op->baseNum +1;
377           assert(v[i +1] >= 0);
378         }
379       }
380       enterStateMap(im, v, width(d->map->count-1), &new);
381       if (!new) {
382         zfree(v);
383       }
384       d->pmap = im;
385     } else {
386       op->table->dimen[0]->pmap = mapToPmap(op->table->dimen[0]);
387       op->table->dimen[1]->pmap = mapToPmap(op->table->dimen[1]);
388       /* output table */
389       fprintf(outfile, "static unsigned %s %s_%s_transition[%d][%d] = {",
390         op->stateCount <= 255 ? "char" : "short",
391         prefix,
392         op->name,
393         op->table->dimen[0]->map->count,
394         op->table->dimen[1]->map->count);
395       for (i = 0; i < op->table->dimen[0]->map->count; i++) {
396         if (i > 0) {
397           fprintf(outfile, ",");
398         }
399         fprintf(outfile, "\n{");
400         for (j = 0; j < op->table->dimen[1]->map->count; j++) {
401           Item_Set *ts = transLval(op->table, i, j);
402           short diff;
403           if (j > 0) {
404             fprintf(outfile, ",");
405             if (j % 10 == 0) {
406               fprintf(outfile, "\t/* row %d, cols %d-%d*/\n",
407                 i,
408                 j-10,
409                 j-1);
410             }
411           }
412           if ((*ts)->num > 0) {
413             diff = (*ts)->newNum - op->baseNum +1;
414           } else {
415             diff = 0;
416           }
417           fprintf(outfile, "%5d", diff);
418         }
419         fprintf(outfile, "}\t/* row %d */", i);
420       }
421       fprintf(outfile, "\n};\n");
422     }
423     break;
424   default:
425     assert(0);
426   }
427 }
428
429 static NonTerminal *ntVector;
430
431 static void
432 doNonTermPmaps(n) NonTerminal n;
433 {
434   short *v;
435   PlankMap im;
436   int new;
437   int i;
438
439   ntVector[n->num] = n;
440   if (n->num >= last_user_nonterminal) {
441     return;
442   }
443   if (n->ruleCount <= 0) {
444     return;
445   }
446   im = newPlankMap(n->baseNum);
447   v = newVector();
448   for (i = 0; i < globalMap->count-1; i++) {
449     Rule r = globalMap->set[sortedStates[i]->num]->closed[n->num].rule;
450     if (r) {
451       r->used = 1;
452       v[i+1] = r->newNum - n->baseNum /*safely*/;
453       assert(v[i+1] >= 0);
454     }
455   }
456   enterStateMap(im, v, width(n->ruleCount+1), &new);
457   if (!new) {
458     zfree(v);
459   }
460   n->pmap = im;
461 }
462
463 static void
464 makePmaps()
465 {
466   foreachList((ListFn) doDimPmaps, operators);
467   ntVector = (NonTerminal*) zalloc((max_nonterminal) * sizeof(NonTerminal));
468   foreachList((ListFn) doNonTermPmaps, nonterminals);
469 }
470
471 static void
472 outPlank(p) Plank p;
473 {
474   List f;
475   int i;
476
477   fprintf(outfile, "static struct {\n");
478
479   for (f = p->fields; f; f = f->next) {
480     StateMap sm = (StateMap) f->x;
481     fprintf(outfile, "\tunsigned int %s:%d;\n", sm->fieldname, sm->width);
482   }
483
484   fprintf(outfile, "} %s[] = {\n", p->name);
485
486   for (i = 0; i < globalMap->count; i++) {
487     fprintf(outfile, "\t{");
488     for (f = p->fields; f; f = f->next) {
489       StateMap sm = (StateMap) f->x;
490       fprintf(outfile, "%4d,", sm->value[i] == -1 ? ERROR_VAL : sm->value[i]);
491     }
492     fprintf(outfile, "},\t/* row %d */\n", i);
493   }
494
495   fprintf(outfile, "};\n");
496 }
497
498 static void
499 purgePlanks(planks) List planks;
500 {
501   List p;
502
503   for (p = planks; p; p = p->next) {
504     Plank x = (Plank) p->x;
505     outPlank(x);
506   }
507 }
508
509 static void
510 inToEx()
511 {
512   int i;
513   int counter;
514
515   fprintf(outfile, "static short %s_eruleMap[] = {\n", prefix);
516   counter = 0;
517   for (i = 0; i < max_ruleAST; i++) {
518     if (counter > 0) {
519       fprintf(outfile, ",");
520       if (counter % 10 == 0) {
521         fprintf(outfile, "\t/* %d-%d */\n", counter-10, counter-1);
522       }
523     }
524     if (counter < sortedRules[i]->rule->newNum) {
525       assert(counter == sortedRules[i]->rule->newNum-1);
526       fprintf(outfile, "%5d", 0);
527       counter++;
528       if (counter > 0) {
529         fprintf(outfile, ",");
530         if (counter % 10 == 0) {
531           fprintf(outfile, "\t/* %d-%d */\n", counter-10, counter-1);
532         }
533       }
534     }
535     fprintf(outfile, "%5d", sortedRules[i]->rule->erulenum);
536     counter++;
537   }
538   fprintf(outfile, "\n};\n");
539 }
540
541 static void
542 makePlankRuleMacros()
543 {
544   int i;
545
546   for (i = 1; i < last_user_nonterminal; i++) {
547     List es;
548     PlankMap im = ntVector[i]->pmap;
549     fprintf(outfile, "#define %s_%s_rule(state)\t", prefix, ntVector[i]->name);
550     if (im) {
551       fprintf(outfile, "%s_eruleMap[", prefix);
552       for (es = im->exceptions; es; es = es->next) {
553         Exception e = (Exception) es->x;
554         fprintf(outfile, "((state) == %d ? %d :",
555             e->index, e->value);
556       }
557       fprintf(outfile, "%s[state].%s",
558         im->values->plank->name,
559         im->values->fieldname);
560       for (es = im->exceptions; es; es = es->next) {
561         fprintf(outfile, ")");
562       }
563       fprintf(outfile, " +%d]", im->offset);
564
565     } else {
566       /* nonterminal never appears on LHS. */
567       assert(ntVector[i] ==  start);
568       fprintf(outfile, "0");
569     }
570     fprintf(outfile, "\n");
571   }
572   fprintf(outfile, "\n");
573 }
574
575 static void
576 makePlankRule()
577 {
578   int i;
579
580   makePlankRuleMacros();
581
582   fprintf(outfile, "#ifdef __STDC__\n");
583   fprintf(outfile, "int %s_rule(int state, int goalnt) {\n", prefix);
584   fprintf(outfile, "#else\n");
585   fprintf(outfile, "int %s_rule(state, goalnt) int state; int goalnt; {\n", prefix);
586   fprintf(outfile, "#endif\n");
587
588   fprintf(outfile,
589   "\t%s_assert(state >= 0 && state < %d, %s_PANIC(\"Bad state %%d passed to %s_rule\\n\", state));\n",
590         prefix, globalMap->count, prefix, prefix);
591   fprintf(outfile, "\tswitch(goalnt) {\n");
592
593   for (i = 1; i < last_user_nonterminal; i++) {
594     fprintf(outfile, "\tcase %d:\n", i);
595     fprintf(outfile, "\t\treturn %s_%s_rule(state);\n", prefix, ntVector[i]->name);
596   }
597   fprintf(outfile, "\tdefault:\n");
598   fprintf(outfile, "\t\t%s_PANIC(\"Unknown nonterminal %%d in %s_rule;\\n\", goalnt);\n", prefix, prefix);
599   fprintf(outfile, "\t\tabort();\n");
600   fprintf(outfile, "\t\treturn 0;\n");
601   fprintf(outfile, "\t}\n");
602   fprintf(outfile, "}\n");
603 }
604
605 static void
606 exceptionSwitch(es, sw, pre, post, offset, def) List es; const char *sw; const char *pre; const char *post; int offset; const char *def;
607 {
608   if (es) {
609     fprintf(outfile, "\t\tswitch (%s) {\n", sw);
610     for (; es; es = es->next) {
611       Exception e = (Exception) es->x;
612       fprintf(outfile, "\t\tcase %d: %s %d; %s\n", e->index, pre, e->value+offset, post);
613     }
614     if (def) {
615       fprintf(outfile, "\t\tdefault: %s;\n", def);
616     }
617     fprintf(outfile, "\t\t}\n");
618   } else {
619     if (def) {
620       fprintf(outfile, "\t\t%s;\n", def);
621     }
622   }
623 }
624
625 static void
626 doPlankLabel(op) Operator op;
627 {
628   PlankMap im0;
629   PlankMap im1;
630   char buf[100];
631
632   fprintf(outfile, "\tcase %d:\n", op->num);
633   switch (op->arity) {
634   case 0:
635     fprintf(outfile, "\t\treturn %d;\n", op->table->transition[0]->newNum);
636     break;
637   case 1:
638     im0 = op->table->dimen[0]->pmap;
639     if (im0) {
640       exceptionSwitch(im0->exceptions, "l", "return ", "", im0->offset, 0);
641       fprintf(outfile, "\t\treturn %s[l].%s + %d;\n",
642         im0->values->plank->name, im0->values->fieldname, im0->offset);
643     } else {
644       Item_Set *ts = transLval(op->table, 1, 0);
645       if (*ts) {
646         fprintf(outfile, "\t\treturn %d;\n", (*ts)->newNum);
647       } else {
648         fprintf(outfile, "\t\treturn %d;\n", ERROR_VAL);
649       }
650     }
651     break;
652   case 2:
653     im0 = op->table->dimen[0]->pmap;
654     im1 = op->table->dimen[1]->pmap;
655     if (!im0 && !im1) {
656       Item_Set *ts = transLval(op->table, 1, 1);
657       if (*ts) {
658         fprintf(outfile, "\t\treturn %d;\n", (*ts)->newNum);
659       } else {
660         fprintf(outfile, "\t\treturn %d;\n", ERROR_VAL);
661       }
662     } else if (!im0) {
663       exceptionSwitch(im1->exceptions, "r", "return ", "", im1->offset, 0);
664       fprintf(outfile, "\t\treturn %s[r].%s + %d;\n",
665         im1->values->plank->name, im1->values->fieldname, im1->offset);
666     } else if (!im1) {
667       exceptionSwitch(im0->exceptions, "l", "return ", "", im0->offset, 0);
668       fprintf(outfile, "\t\treturn %s[l].%s + %d;\n",
669         im0->values->plank->name, im0->values->fieldname, im0->offset);
670     } else {
671       assert(im0->offset == 0);
672       assert(im1->offset == 0);
673       sprintf(buf, "l = %s[l].%s",
674         im0->values->plank->name, im0->values->fieldname);
675       exceptionSwitch(im0->exceptions, "l", "l =", "break;", 0, buf);
676       sprintf(buf, "r = %s[r].%s",
677         im1->values->plank->name, im1->values->fieldname);
678       exceptionSwitch(im1->exceptions, "r", "r =", "break;", 0, buf);
679
680       fprintf(outfile, "\t\treturn %s_%s_transition[l][r] + %d;\n",
681         prefix,
682         op->name,
683         op->baseNum);
684     }
685     break;
686   default:
687     assert(0);
688   }
689 }
690
691 static void
692 doPlankLabelMacrosSafely(op) Operator op;
693 {
694   PlankMap im0;
695   PlankMap im1;
696
697   switch (op->arity) {
698   case -1:
699     fprintf(outfile, "#define %s_%s_state\t0\n", prefix, op->name);
700     break;
701   case 0:
702     fprintf(outfile, "#define %s_%s_state", prefix, op->name);
703     fprintf(outfile, "\t%d\n", op->table->transition[0]->newNum+1);
704     break;
705   case 1:
706     fprintf(outfile, "#define %s_%s_state(l)", prefix, op->name);
707     im0 = op->table->dimen[0]->pmap;
708     if (im0) {
709       if (im0->exceptions) {
710         List es = im0->exceptions;
711         assert(0);
712         fprintf(outfile, "\t\tswitch (l) {\n");
713         for (; es; es = es->next) {
714           Exception e = (Exception) es->x;
715           fprintf(outfile, "\t\tcase %d: return %d;\n", e->index, e->value ? e->value+im0->offset : 0);
716         }
717         fprintf(outfile, "\t\t}\n");
718       }
719       if (speedflag) {
720         fprintf(outfile, "\t( %s[l].%s + %d )\n",
721           im0->values->plank->name, im0->values->fieldname,
722           im0->offset);
723       } else {
724         fprintf(outfile, "\t( (%s_TEMP = %s[l].%s) ? %s_TEMP + %d : 0 )\n",
725           prefix,
726           im0->values->plank->name, im0->values->fieldname,
727           prefix,
728           im0->offset);
729       }
730     } else {
731       Item_Set *ts = transLval(op->table, 1, 0);
732       if (*ts) {
733         fprintf(outfile, "\t%d\n", (*ts)->newNum+1);
734       } else {
735         fprintf(outfile, "\t%d\n", 0);
736       }
737     }
738     break;
739   case 2:
740     fprintf(outfile, "#define %s_%s_state(l,r)", prefix, op->name);
741
742     im0 = op->table->dimen[0]->pmap;
743     im1 = op->table->dimen[1]->pmap;
744     if (!im0 && !im1) {
745       Item_Set *ts = transLval(op->table, 1, 1);
746       assert(0);
747       if (*ts) {
748         fprintf(outfile, "\t\treturn %d;\n", (*ts)->newNum+1);
749       } else {
750         fprintf(outfile, "\t\treturn %d;\n", 0);
751       }
752     } else if (!im0) {
753       assert(0);
754       if (im1->exceptions) {
755         List es = im1->exceptions;
756         fprintf(outfile, "\t\tswitch (r) {\n");
757         for (; es; es = es->next) {
758           Exception e = (Exception) es->x;
759           fprintf(outfile, "\t\tcase %d: return %d;\n", e->index, e->value ? e->value+im1->offset : 0);
760         }
761         fprintf(outfile, "\t\t}\n");
762       }
763       fprintf(outfile, "\t\tstate = %s[r].%s; offset = %d;\n",
764         im1->values->plank->name, im1->values->fieldname, im1->offset);
765       fprintf(outfile, "\t\tbreak;\n");
766     } else if (!im1) {
767       assert(0);
768       if (im0->exceptions) {
769         List es = im0->exceptions;
770         fprintf(outfile, "\t\tswitch (l) {\n");
771         for (; es; es = es->next) {
772           Exception e = (Exception) es->x;
773           fprintf(outfile, "\t\tcase %d: return %d;\n", e->index, e->value ? e->value+im0->offset : 0);
774         }
775         fprintf(outfile, "\t\t}\n");
776       }
777       fprintf(outfile, "\t\tstate = %s[l].%s; offset = %d;\n",
778         im0->values->plank->name, im0->values->fieldname, im0->offset);
779       fprintf(outfile, "\t\tbreak;\n");
780     } else {
781       assert(im0->offset == 0);
782       assert(im1->offset == 0);
783       /*
784       sprintf(buf, "l = %s[l].%s",
785         im0->values->plank->name, im0->values->fieldname);
786       exceptionSwitch(im0->exceptions, "l", "l =", "break;", 0, buf);
787       sprintf(buf, "r = %s[r].%s",
788         im1->values->plank->name, im1->values->fieldname);
789       exceptionSwitch(im1->exceptions, "r", "r =", "break;", 0, buf);
790
791       fprintf(outfile, "\t\tstate = %s_%s_transition[l][r]; offset = %d;\n",
792         prefix,
793         op->name,
794         op->baseNum);
795       fprintf(outfile, "\t\tbreak;\n");
796       */
797
798       if (speedflag) {
799         fprintf(outfile, "\t( %s_%s_transition[%s[l].%s][%s[r].%s] + %d)\n",
800           prefix,
801           op->name,
802           im0->values->plank->name, im0->values->fieldname,
803           im1->values->plank->name, im1->values->fieldname,
804           op->baseNum);
805       } else {
806         fprintf(outfile, "\t( (%s_TEMP = %s_%s_transition[%s[l].%s][%s[r].%s]) ? ",
807           prefix,
808           prefix,
809           op->name,
810           im0->values->plank->name, im0->values->fieldname,
811           im1->values->plank->name, im1->values->fieldname);
812         fprintf(outfile, "%s_TEMP + %d : 0 )\n",
813           prefix,
814           op->baseNum);
815       }
816     }
817     break;
818   default:
819     assert(0);
820   }
821 }
822 static void
823 doPlankLabelSafely(op) Operator op;
824 {
825   fprintf(outfile, "\tcase %d:\n", op->num);
826   switch (op->arity) {
827   case -1:
828     fprintf(outfile, "\t\treturn 0;\n");
829     break;
830   case 0:
831     fprintf(outfile, "\t\treturn %s_%s_state;\n", prefix, op->name);
832     break;
833   case 1:
834     fprintf(outfile, "\t\treturn %s_%s_state(l);\n", prefix, op->name);
835     break;
836   case 2:
837     fprintf(outfile, "\t\treturn %s_%s_state(l,r);\n", prefix, op->name);
838     break;
839   default:
840     assert(0);
841   }
842 }
843
844 static void
845 makePlankState()
846 {
847   fprintf(outfile, "\n");
848   fprintf(outfile, "int %s_TEMP;\n", prefix);
849   foreachList((ListFn) doPlankLabelMacrosSafely, operators);
850   fprintf(outfile, "\n");
851
852   fprintf(outfile, "#ifdef __STDC__\n");
853   switch (max_arity) {
854   case -1:
855     fprintf(stderr, "ERROR: no terminals in grammar.\n");
856     exit(1);
857   case 0:
858     fprintf(outfile, "int %s_state(int op) {\n", prefix);
859     fprintf(outfile, "#else\n");
860     fprintf(outfile, "int %s_state(op) int op; {\n", prefix);
861     break;
862   case 1:
863     fprintf(outfile, "int %s_state(int op, int l) {\n", prefix);
864     fprintf(outfile, "#else\n");
865     fprintf(outfile, "int %s_state(op, l) int op; int l; {\n", prefix);
866     break;
867   case 2:
868     fprintf(outfile, "int %s_state(int op, int l, int r) {\n", prefix);
869     fprintf(outfile, "#else\n");
870     fprintf(outfile, "int %s_state(op, l, r) int op; int l; int r; {\n", prefix);
871     break;
872   default:
873     assert(0);
874   }
875   fprintf(outfile, "#endif\n");
876
877   fprintf(outfile, "\tregister int %s_TEMP;\n", prefix);
878
879   fprintf(outfile, "#ifndef NDEBUG\n");
880
881   fprintf(outfile, "\tswitch (op) {\n");
882   opsOfArity(2);
883   if (max_arity >= 2) {
884     fprintf(outfile,
885     "\t\t%s_assert(r >= 0 && r < %d, %s_PANIC(\"Bad state %%d passed to %s_state\\n\", r));\n",
886         prefix, globalMap->count, prefix, prefix);
887     fprintf(outfile, "\t\t/*FALLTHROUGH*/\n");
888   }
889   opsOfArity(1);
890   if (max_arity > 1) {
891     fprintf(outfile,
892     "\t\t%s_assert(l >= 0 && l < %d, %s_PANIC(\"Bad state %%d passed to %s_state\\n\", l));\n",
893         prefix, globalMap->count, prefix, prefix);
894     fprintf(outfile, "\t\t/*FALLTHROUGH*/\n");
895   }
896   opsOfArity(0);
897   fprintf(outfile, "\t\tbreak;\n");
898   fprintf(outfile, "\t}\n");
899   fprintf(outfile, "#endif\n");
900
901   fprintf(outfile, "\tswitch (op) {\n");
902   fprintf(outfile,"\tdefault: %s_PANIC(\"Unknown op %%d in %s_state\\n\", op); abort(); return 0;\n",
903     prefix, prefix);
904   foreachList((ListFn) doPlankLabelSafely, operators);
905   fprintf(outfile, "\t}\n");
906
907   fprintf(outfile, "}\n");
908 }
909
910 void
911 makePlanks()
912 {
913   List planks;
914   renumber();
915   makePmaps();
916   planks = assemblePlanks();
917   purgePlanks(planks);
918   inToEx();
919   makePlankRule();
920   makePlankState();
921 }