* tiny
[mascara-docs.git] / compilers / q3 / lcc / lburg / .svn / text-base / lburg.c.svn-base
blobc43c96acbcd9872b9e1bfc501d29eb97f392eac4
1 #include <assert.h>
2 #include <ctype.h>
3 #include <stdarg.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <time.h>
8 #include "lburg.h"
10 static char rcsid[] = "lburg.c - faked rcsid";
12 static char *prefix = "";
13 static int Tflag = 0;
14 static int ntnumber = 0;
15 static Nonterm start = 0;
16 static Term terms;
17 static Nonterm nts;
18 static Rule rules;
19 static int nrules;
20 static struct block {
21         struct block *link;
22 } *memlist;                     /* list of allocated blocks */
24 static char *stringf(char *fmt, ...);
25 static void print(char *fmt, ...);
26 static void ckreach(Nonterm p);
27 static void emitclosure(Nonterm nts);
28 static void emitcost(Tree t, char *v);
29 static void emitdefs(Nonterm nts, int ntnumber);
30 static void emitheader(void);
31 static void emitkids(Rule rules, int nrules);
32 static void emitnts(Rule rules, int nrules);
33 static void emitrecalc(char *pre, Term root, Term kid);
34 static void emitrecord(char *pre, Rule r, char *c, int cost);
35 static void emitrule(Nonterm nts);
36 static void emitlabel(Term terms, Nonterm start, int ntnumber);
37 static void emitstring(Rule rules);
38 static void emitstruct(Nonterm nts, int ntnumber);
39 static void emittest(Tree t, char *v, char *suffix);
41 int main(int argc, char *argv[]) {
42         int c, i;
43         Nonterm p;
44         
45         for (i = 1; i < argc; i++)
46                 if (strcmp(argv[i], "-T") == 0)
47                         Tflag = 1;
48                 else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2])
49                         prefix = &argv[i][2];
50                 else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc)
51                         prefix = argv[++i];
52                 else if (*argv[i] == '-' && argv[i][1]) {
53                         yyerror("usage: %s [-T | -p prefix]... [ [ input ] output ] \n",
54                                 argv[0]);
55                         exit(1);
56                 } else if (infp == NULL) {
57                         if (strcmp(argv[i], "-") == 0)
58                                 infp = stdin;
59                         else if ((infp = fopen(argv[i], "r")) == NULL) {
60                                 yyerror("%s: can't read `%s'\n", argv[0], argv[i]);
61                                 exit(1);
62                         }
63                 } else if (outfp == NULL) {
64                         if (strcmp(argv[i], "-") == 0)
65                                 outfp = stdout;
66                         if ((outfp = fopen(argv[i], "w")) == NULL) {
67                                 yyerror("%s: can't write `%s'\n", argv[0], argv[i]);
68                                 exit(1);
69                         }
70                 }
71         if (infp == NULL)
72                 infp = stdin;
73         if (outfp == NULL)
74                 outfp = stdout;
75         yyparse();
76         if (start)
77                 ckreach(start);
78         for (p = nts; p; p = p->link) {
79                 if (p->rules == NULL)
80                         yyerror("undefined nonterminal `%s'\n", p->name);
81                 if (!p->reached)
82                         yyerror("can't reach nonterminal `%s'\n", p->name);
83         }
84         emitheader();
85         emitdefs(nts, ntnumber);
86         emitstruct(nts, ntnumber);
87         emitnts(rules, nrules);
88         emitstring(rules);
89         emitrule(nts);
90         emitclosure(nts);
91         if (start)
92                 emitlabel(terms, start, ntnumber);
93         emitkids(rules, nrules);
94         if (!feof(infp))
95                 while ((c = getc(infp)) != EOF)
96                         putc(c, outfp);
97         while (memlist) {       /* for purify */
98                 struct block *q = memlist->link;
99                 free(memlist);
100                 memlist = q;
101         }
102         return errcnt > 0;
105 /* alloc - allocate nbytes or issue fatal error */
106 void *alloc(int nbytes) {
107         struct block *p = calloc(1, sizeof *p + nbytes);
109         if (p == NULL) {
110                 yyerror("out of memory\n");
111                 exit(1);
112         }
113         p->link = memlist;
114         memlist = p;
115         return p + 1;
118 /* stringf - format and save a string */
119 static char *stringf(char *fmt, ...) {
120         va_list ap;
121         char buf[512];
123         va_start(ap, fmt);
124         vsprintf(buf, fmt, ap);
125         va_end(ap);
126         return strcpy(alloc(strlen(buf) + 1), buf);
127 }       
129 struct entry {
130         union {
131                 char *name;
132                 struct term t;
133                 struct nonterm nt;
134         } sym;
135         struct entry *link;
136 } *table[211];
137 #define HASHSIZE (sizeof table/sizeof table[0])
139 /* hash - return hash number for str */
140 static unsigned hash(char *str) {
141         unsigned h = 0;
143         while (*str)
144                 h = (h<<1) + *str++;
145         return h;
148 /* lookup - lookup symbol name */
149 static void *lookup(char *name) {
150         struct entry *p = table[hash(name)%HASHSIZE];
152         for ( ; p; p = p->link)
153                 if (strcmp(name, p->sym.name) == 0)
154                         return &p->sym;
155         return 0;
158 /* install - install symbol name */
159 static void *install(char *name) {
160         struct entry *p = alloc(sizeof *p);
161         int i = hash(name)%HASHSIZE;
163         p->sym.name = name;
164         p->link = table[i];
165         table[i] = p;
166         return &p->sym;
169 /* nonterm - create a new terminal id, if necessary */
170 Nonterm nonterm(char *id) {
171         Nonterm p = lookup(id), *q = &nts;
173         if (p && p->kind == NONTERM)
174                 return p;
175         if (p && p->kind == TERM)
176                 yyerror("`%s' is a terminal\n", id);
177         p = install(id);
178         p->kind = NONTERM;
179         p->number = ++ntnumber;
180         if (p->number == 1)
181                 start = p;
182         while (*q && (*q)->number < p->number)
183                 q = &(*q)->link;
184         assert(*q == 0 || (*q)->number != p->number);
185         p->link = *q;
186         *q = p;
187         return p;
190 /* term - create a new terminal id with external symbol number esn */
191 Term term(char *id, int esn) {
192         Term p = lookup(id), *q = &terms;
194         if (p)
195                 yyerror("redefinition of terminal `%s'\n", id);
196         else
197                 p = install(id);
198         p->kind = TERM;
199         p->esn = esn;
200         p->arity = -1;
201         while (*q && (*q)->esn < p->esn)
202                 q = &(*q)->link;
203         if (*q && (*q)->esn == p->esn)
204                 yyerror("duplicate external symbol number `%s=%d'\n",
205                         p->name, p->esn);
206         p->link = *q;
207         *q = p;
208         return p;
211 /* tree - create & initialize a tree node with the given fields */
212 Tree tree(char *id, Tree left, Tree right) {
213         Tree t = alloc(sizeof *t);
214         Term p = lookup(id);
215         int arity = 0;
217         if (left && right)
218                 arity = 2;
219         else if (left)
220                 arity = 1;
221         if (p == NULL && arity > 0) {
222                 yyerror("undefined terminal `%s'\n", id);
223                 p = term(id, -1);
224         } else if (p == NULL && arity == 0)
225                 p = (Term)nonterm(id);
226         else if (p && p->kind == NONTERM && arity > 0) {
227                 yyerror("`%s' is a nonterminal\n", id);
228                 p = term(id, -1);
229         }
230         if (p->kind == TERM && p->arity == -1)
231                 p->arity = arity;
232         if (p->kind == TERM && arity != p->arity)
233                 yyerror("inconsistent arity for terminal `%s'\n", id);
234         t->op = p;
235         t->nterms = p->kind == TERM;
236         if ((t->left = left) != NULL)
237                 t->nterms += left->nterms;
238         if ((t->right = right) != NULL)
239                 t->nterms += right->nterms;
240         return t;
243 /* rule - create & initialize a rule with the given fields */
244 Rule rule(char *id, Tree pattern, char *template, char *code) {
245         Rule r = alloc(sizeof *r), *q;
246         Term p = pattern->op;
247         char *end;
249         r->lhs = nonterm(id);
250         r->packed = ++r->lhs->lhscount;
251         for (q = &r->lhs->rules; *q; q = &(*q)->decode)
252                 ;
253         *q = r;
254         r->pattern = pattern;
255         r->ern = ++nrules;
256         r->template = template;
257         r->code = code;
258         r->cost = strtol(code, &end, 10);
259         if (*end) {
260                 r->cost = -1;
261                 r->code = stringf("(%s)", code);
262         }
263         if (p->kind == TERM) {
264                 for (q = &p->rules; *q; q = &(*q)->next)
265                         ;
266                 *q = r;
267         } else if (pattern->left == NULL && pattern->right == NULL) {
268                 Nonterm p = pattern->op;
269                 r->chain = p->chain;
270                 p->chain = r;
271                 if (r->cost == -1)
272                         yyerror("illegal nonconstant cost `%s'\n", code);
273         }
274         for (q = &rules; *q; q = &(*q)->link)
275                 ;
276         r->link = *q;
277         *q = r;
278         return r;
281 /* print - formatted output */
282 static void print(char *fmt, ...) {
283         va_list ap;
285         va_start(ap, fmt);
286         for ( ; *fmt; fmt++)
287                 if (*fmt == '%')
288                         switch (*++fmt) {
289                         case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break;
290                         case 's': fputs(va_arg(ap, char *), outfp); break;
291                         case 'P': fprintf(outfp, "%s_", prefix); break;
292                         case 'T': {
293                                 Tree t = va_arg(ap, Tree);
294                                 print("%S", t->op);
295                                 if (t->left && t->right)
296                                         print("(%T,%T)", t->left, t->right);
297                                 else if (t->left)
298                                         print("(%T)", t->left);
299                                 break;
300                                 }
301                         case 'R': {
302                                 Rule r = va_arg(ap, Rule);
303                                 print("%S: %T", r->lhs, r->pattern);
304                                 break;
305                                 }
306                         case 'S': fputs(va_arg(ap, Term)->name, outfp); break;
307                         case '1': case '2': case '3': case '4': case '5': {
308                                 int n = *fmt - '0';
309                                 while (n-- > 0)
310                                         putc('\t', outfp);
311                                 break;
312                                 }
313                         default: putc(*fmt, outfp); break;                      
314                         }
315                 else
316                         putc(*fmt, outfp);
317         va_end(ap);
320 /* reach - mark all nonterminals in tree t as reachable */
321 static void reach(Tree t) {
322         Nonterm p = t->op;
324         if (p->kind == NONTERM)
325                 if (!p->reached)
326                         ckreach(p);
327         if (t->left)
328                 reach(t->left);
329         if (t->right)
330                 reach(t->right);
333 /* ckreach - mark all nonterminals reachable from p */
334 static void ckreach(Nonterm p) {
335         Rule r;
337         p->reached = 1;
338         for (r = p->rules; r; r = r->decode)
339                 reach(r->pattern);
342 /* emitcase - emit one case in function state */
343 static void emitcase(Term p, int ntnumber) {
344         Rule r;
346         print("%1case %d: /* %S */\n", p->esn, p);
347         switch (p->arity) {
348         case 0: case -1:
349                 break;
350         case 1:
351                 print("%2%Plabel(LEFT_CHILD(a));\n");
352                 break;
353         case 2:
354                 print("%2%Plabel(LEFT_CHILD(a));\n");
355                 print("%2%Plabel(RIGHT_CHILD(a));\n");
356                 break;
357         default: assert(0);
358         }
359         for (r = p->rules; r; r = r->next) {
360                 char *indent = "\t\t\0";
361                 switch (p->arity) {
362                 case 0: case -1:
363                         print("%2/* %R */\n", r);
364                         if (r->cost == -1) {
365                                 print("%2c = %s;\n", r->code);
366                                 emitrecord("\t\t", r, "c", 0);
367                         } else
368                                 emitrecord("\t\t", r, r->code, 0);
369                         break;
370                 case 1:
371                         if (r->pattern->nterms > 1) {
372                                 print("%2if (%1/* %R */\n", r);
373                                 emittest(r->pattern->left, "LEFT_CHILD(a)", " ");
374                                 print("%2) {\n");
375                                 indent = "\t\t\t";
376                         } else
377                                 print("%2/* %R */\n", r);
378                         if (r->pattern->nterms == 2 && r->pattern->left
379                         &&  r->pattern->right == NULL)
380                                 emitrecalc(indent, r->pattern->op, r->pattern->left->op);
381                         print("%sc = ", indent);
382                         emitcost(r->pattern->left, "LEFT_CHILD(a)");
383                         print("%s;\n", r->code);
384                         emitrecord(indent, r, "c", 0);
385                         if (indent[2])
386                                 print("%2}\n");
387                         break;
388                 case 2:
389                         if (r->pattern->nterms > 1) {
390                                 print("%2if (%1/* %R */\n", r);
391                                 emittest(r->pattern->left,  "LEFT_CHILD(a)",
392                                         r->pattern->right->nterms ? " && " : " ");
393                                 emittest(r->pattern->right, "RIGHT_CHILD(a)", " ");
394                                 print("%2) {\n");
395                                 indent = "\t\t\t";
396                         } else
397                                 print("%2/* %R */\n", r);
398                         print("%sc = ", indent);
399                         emitcost(r->pattern->left,  "LEFT_CHILD(a)");
400                         emitcost(r->pattern->right, "RIGHT_CHILD(a)");
401                         print("%s;\n", r->code);
402                         emitrecord(indent, r, "c", 0);
403                         if (indent[2])
404                                 print("%2}\n");
405                         break;
406                 default: assert(0);
407                 }
408         }
409         print("%2break;\n");
412 /* emitclosure - emit the closure functions */
413 static void emitclosure(Nonterm nts) {
414         Nonterm p;
416         for (p = nts; p; p = p->link)
417                 if (p->chain)
418                         print("static void %Pclosure_%S(NODEPTR_TYPE, int);\n", p);
419         print("\n");
420         for (p = nts; p; p = p->link)
421                 if (p->chain) {
422                         Rule r;
423                         print("static void %Pclosure_%S(NODEPTR_TYPE a, int c) {\n"
424 "%1struct %Pstate *p = STATE_LABEL(a);\n", p);
425                         for (r = p->chain; r; r = r->chain)
426                                 emitrecord("\t", r, "c", r->cost);
427                         print("}\n\n");
428                 }
431 /* emitcost - emit cost computation for tree t */
432 static void emitcost(Tree t, char *v) {
433         Nonterm p = t->op;
435         if (p->kind == TERM) {
436                 if (t->left)
437                         emitcost(t->left,  stringf("LEFT_CHILD(%s)",  v));
438                 if (t->right)
439                         emitcost(t->right, stringf("RIGHT_CHILD(%s)", v));
440         } else
441                 print("((struct %Pstate *)(%s->x.state))->cost[%P%S_NT] + ", v, p);
444 /* emitdefs - emit nonterminal defines and data structures */
445 static void emitdefs(Nonterm nts, int ntnumber) {
446         Nonterm p;
448         for (p = nts; p; p = p->link)
449                 print("#define %P%S_NT %d\n", p, p->number);
450         print("\n");
451         print("static char *%Pntname[] = {\n%10,\n");
452         for (p = nts; p; p = p->link)
453                 print("%1\"%S\",\n", p);
454         print("%10\n};\n\n");
457 /* emitheader - emit initial definitions */
458 static void emitheader(void) {
459         time_t timer = time(NULL);
461         print("/*\ngenerated at %sby %s\n*/\n", ctime(&timer), rcsid);
462         print("static void %Pkids(NODEPTR_TYPE, int, NODEPTR_TYPE[]);\n");
463         print("static void %Plabel(NODEPTR_TYPE);\n");
464         print("static int %Prule(void*, int);\n\n");
467 /* computekids - compute paths to kids in tree t */
468 static char *computekids(Tree t, char *v, char *bp, int *ip) {
469         Term p = t->op;
471         if (p->kind == NONTERM) {
472                 sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v);
473                 bp += strlen(bp);
474         } else if (p->arity > 0) {
475                 bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip);
476                 if (p->arity == 2)
477                         bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip);
478         }
479         return bp;
482 /* emitkids - emit _kids */
483 static void emitkids(Rule rules, int nrules) {
484         int i;
485         Rule r, *rc = alloc((nrules + 1 + 1)*sizeof *rc);
486         char **str  = alloc((nrules + 1 + 1)*sizeof *str);
488         for (i = 0, r = rules; r; r = r->link) {
489                 int j = 0;
490                 char buf[1024], *bp = buf;
491                 *computekids(r->pattern, "p", bp, &j) = 0;
492                 for (j = 0; str[j] && strcmp(str[j], buf); j++)
493                         ;
494                 if (str[j] == NULL)
495                         str[j] = strcpy(alloc(strlen(buf) + 1), buf);
496                 r->kids = rc[j];
497                 rc[j] = r;
498         }
499         print("static void %Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n"
500 "%1if (!p)\n%2fatal(\"%Pkids\", \"Null tree\\n\", 0);\n"
501 "%1if (!kids)\n%2fatal(\"%Pkids\", \"Null kids\\n\", 0);\n"
502 "%1switch (eruleno) {\n");
503         for (i = 0; (r = rc[i]) != NULL; i++) {
504                 for ( ; r; r = r->kids)
505                         print("%1case %d: /* %R */\n", r->ern, r);
506                 print("%s%2break;\n", str[i]);
507         }
508         print("%1default:\n%2fatal(\"%Pkids\", \"Bad rule number %%d\\n\", eruleno);\n%1}\n}\n\n");
511 /* emitlabel - emit label function */
512 static void emitlabel(Term terms, Nonterm start, int ntnumber) {
513         int i;
514         Term p;
516         print("static void %Plabel(NODEPTR_TYPE a) {\n%1int c;\n"
517 "%1struct %Pstate *p;\n\n"
518 "%1if (!a)\n%2fatal(\"%Plabel\", \"Null tree\\n\", 0);\n");
519         print("%1STATE_LABEL(a) = p = allocate(sizeof *p, FUNC);\n"
520 "%1p->rule._stmt = 0;\n");
521         for (i = 1; i <= ntnumber; i++)
522                 print("%1p->cost[%d] =\n", i);
523         print("%20x7fff;\n%1switch (OP_LABEL(a)) {\n");
524         for (p = terms; p; p = p->link)
525                 emitcase(p, ntnumber);
526         print("%1default:\n"
527 "%2fatal(\"%Plabel\", \"Bad terminal %%d\\n\", OP_LABEL(a));\n%1}\n}\n\n");
530 /* computents - fill in bp with _nts vector for tree t */
531 static char *computents(Tree t, char *bp) {
532         if (t) {
533                 Nonterm p = t->op;
534                 if (p->kind == NONTERM) {
535                         sprintf(bp, "%s_%s_NT, ", prefix, p->name);
536                         bp += strlen(bp);
537                 } else
538                         bp = computents(t->right, computents(t->left,  bp));
539         }
540         return bp;
543 /* emitnts - emit _nts ragged array */
544 static void emitnts(Rule rules, int nrules) {
545         Rule r;
546         int i, j, *nts = alloc((nrules + 1)*sizeof *nts);
547         char **str = alloc((nrules + 1)*sizeof *str);
549         for (i = 0, r = rules; r; r = r->link) {
550                 char buf[1024];
551                 *computents(r->pattern, buf) = 0;
552                 for (j = 0; str[j] && strcmp(str[j], buf); j++)
553                         ;
554                 if (str[j] == NULL) {
555                         print("static short %Pnts_%d[] = { %s0 };\n", j, buf);
556                         str[j] = strcpy(alloc(strlen(buf) + 1), buf);
557                 }
558                 nts[i++] = j;
559         }
560         print("\nstatic short *%Pnts[] = {\n");
561         for (i = j = 0, r = rules; r; r = r->link) {
562                 for ( ; j < r->ern; j++)
563                         print("%10,%1/* %d */\n", j);
564                 print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++);
565         }
566         print("};\n\n");
569 /* emitrecalc - emit code that tests for recalculation of INDIR?(VREGP) */
570 static void emitrecalc(char *pre, Term root, Term kid) {
571         if (root->kind == TERM && strncmp(root->name, "INDIR", 5) == 0
572         &&   kid->kind == TERM &&  strcmp(kid->name,  "VREGP"   ) == 0) {
573                 Nonterm p;
574                 print("%sif (mayrecalc(a)) {\n", pre);
575                 print("%s%1struct %Pstate *q = a->syms[RX]->u.t.cse->x.state;\n", pre);
576                 for (p = nts; p; p = p->link) {
577                         print("%s%1if (q->cost[%P%S_NT] == 0) {\n", pre, p);
578                         print("%s%2p->cost[%P%S_NT] = 0;\n", pre, p);
579                         print("%s%2p->rule.%P%S = q->rule.%P%S;\n", pre, p, p);
580                         print("%s%1}\n", pre);
581                 }
582                 print("%s}\n", pre);
583         }
586 /* emitrecord - emit code that tests for a winning match of rule r */
587 static void emitrecord(char *pre, Rule r, char *c, int cost) {
588         if (Tflag)
589                 print("%s%Ptrace(a, %d, %s + %d, p->cost[%P%S_NT]);\n",
590                         pre, r->ern, c, cost, r->lhs);
591         print("%sif (", pre);
592         print("%s + %d < p->cost[%P%S_NT]) {\n"
593 "%s%1p->cost[%P%S_NT] = %s + %d;\n%s%1p->rule.%P%S = %d;\n",
594                 c, cost, r->lhs, pre, r->lhs, c, cost, pre, r->lhs,
595                 r->packed);
596         if (r->lhs->chain)
597                 print("%s%1%Pclosure_%S(a, %s + %d);\n", pre, r->lhs, c, cost);
598         print("%s}\n", pre);
601 /* emitrule - emit decoding vectors and _rule */
602 static void emitrule(Nonterm nts) {
603         Nonterm p;
605         for (p = nts; p; p = p->link) {
606                 Rule r;
607                 print("static short %Pdecode_%S[] = {\n%10,\n", p);
608                 for (r = p->rules; r; r = r->decode)
609                         print("%1%d,\n", r->ern);
610                 print("};\n\n");
611         }
612         print("static int %Prule(void *state, int goalnt) {\n"
613 "%1if (goalnt < 1 || goalnt > %d)\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n"
614 "%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber);
615         for (p = nts; p; p = p->link)
616                 print("%1case %P%S_NT:"
617 "%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p, p, p);
618         print("%1default:\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n%2return 0;\n%1}\n}\n\n");
621 /* emitstring - emit arrays of templates, instruction flags, and rules */
622 static void emitstring(Rule rules) {
623         Rule r;
625         print("static char *%Ptemplates[] = {\n");
626         print("/* 0 */%10,\n");
627         for (r = rules; r; r = r->link)
628                 print("/* %d */%1\"%s\",%1/* %R */\n", r->ern, r->template, r);
629         print("};\n");
630         print("\nstatic char %Pisinstruction[] = {\n");
631         print("/* 0 */%10,\n");
632         for (r = rules; r; r = r->link) {
633                 int len = strlen(r->template);
634                 print("/* %d */%1%d,%1/* %s */\n", r->ern,
635                         len >= 2 && r->template[len-2] == '\\' && r->template[len-1] == 'n',
636                         r->template);
637         }
638         print("};\n");
639         print("\nstatic char *%Pstring[] = {\n");
640         print("/* 0 */%10,\n");
641         for (r = rules; r; r = r->link)
642                 print("/* %d */%1\"%R\",\n", r->ern, r);
643         print("};\n\n");
646 /* emitstruct - emit the definition of the state structure */
647 static void emitstruct(Nonterm nts, int ntnumber) {
648         print("struct %Pstate {\n%1short cost[%d];\n%1struct {\n", ntnumber + 1);
649         for ( ; nts; nts = nts->link) {
650                 int n = 1, m = nts->lhscount;
651                 while ((m >>= 1) != 0)
652                         n++;            
653                 print("%2unsigned int %P%S:%d;\n", nts, n);
654         }
655         print("%1} rule;\n};\n\n");
658 /* emittest - emit clause for testing a match */
659 static void emittest(Tree t, char *v, char *suffix) {
660         Term p = t->op;
662         if (p->kind == TERM) {
663                 print("%3%s->op == %d%s/* %S */\n", v, p->esn,
664                         t->nterms > 1 ? " && " : suffix, p);
665                 if (t->left)
666                         emittest(t->left, stringf("LEFT_CHILD(%s)",  v),
667                                 t->right && t->right->nterms ? " && " : suffix);
668                 if (t->right)
669                         emittest(t->right, stringf("RIGHT_CHILD(%s)", v), suffix);
670         }