Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

lburg.c (17885B)


      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"
      9 
     10 static char rcsid[] = "lburg.c - faked rcsid";
     11 
     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 */
     23 
     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);
     40 
     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;
    103 }
    104 
    105 /* alloc - allocate nbytes or issue fatal error */
    106 void *alloc(int nbytes) {
    107 	struct block *p = calloc(1, sizeof *p + nbytes);
    108 
    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;
    116 }
    117 
    118 /* stringf - format and save a string */
    119 static char *stringf(char *fmt, ...) {
    120 	va_list ap;
    121 	char buf[512];
    122 
    123 	va_start(ap, fmt);
    124 	vsprintf(buf, fmt, ap);
    125 	va_end(ap);
    126 	return strcpy(alloc(strlen(buf) + 1), buf);
    127 }	
    128 
    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])
    138 
    139 /* hash - return hash number for str */
    140 static unsigned hash(char *str) {
    141 	unsigned h = 0;
    142 
    143 	while (*str)
    144 		h = (h<<1) + *str++;
    145 	return h;
    146 }
    147 
    148 /* lookup - lookup symbol name */
    149 static void *lookup(char *name) {
    150 	struct entry *p = table[hash(name)%HASHSIZE];
    151 
    152 	for ( ; p; p = p->link)
    153 		if (strcmp(name, p->sym.name) == 0)
    154 			return &p->sym;
    155 	return 0;
    156 }
    157 
    158 /* install - install symbol name */
    159 static void *install(char *name) {
    160 	struct entry *p = alloc(sizeof *p);
    161 	int i = hash(name)%HASHSIZE;
    162 
    163 	p->sym.name = name;
    164 	p->link = table[i];
    165 	table[i] = p;
    166 	return &p->sym;
    167 }
    168 
    169 /* nonterm - create a new terminal id, if necessary */
    170 Nonterm nonterm(char *id) {
    171 	Nonterm p = lookup(id), *q = &nts;
    172 
    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;
    188 }
    189 
    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;
    193 
    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;
    209 }
    210 
    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;
    216 
    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;
    241 }
    242 
    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;
    248 
    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;
    279 }
    280 
    281 /* print - formatted output */
    282 static void print(char *fmt, ...) {
    283 	va_list ap;
    284 
    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);
    318 }
    319 
    320 /* reach - mark all nonterminals in tree t as reachable */
    321 static void reach(Tree t) {
    322 	Nonterm p = t->op;
    323 
    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);
    331 }
    332 
    333 /* ckreach - mark all nonterminals reachable from p */
    334 static void ckreach(Nonterm p) {
    335 	Rule r;
    336 
    337         p->reached = 1;
    338 	for (r = p->rules; r; r = r->decode)
    339 		reach(r->pattern);
    340 }
    341 
    342 /* emitcase - emit one case in function state */
    343 static void emitcase(Term p, int ntnumber) {
    344 	Rule r;
    345 
    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");
    410 }
    411 
    412 /* emitclosure - emit the closure functions */
    413 static void emitclosure(Nonterm nts) {
    414 	Nonterm p;
    415 
    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 		}
    429 }
    430 
    431 /* emitcost - emit cost computation for tree t */
    432 static void emitcost(Tree t, char *v) {
    433 	Nonterm p = t->op;
    434 
    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);
    442 }
    443 
    444 /* emitdefs - emit nonterminal defines and data structures */
    445 static void emitdefs(Nonterm nts, int ntnumber) {
    446 	Nonterm p;
    447 
    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");
    455 }
    456 
    457 /* emitheader - emit initial definitions */
    458 static void emitheader(void) {
    459 	time_t timer = time(NULL);
    460 
    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");
    465 }
    466 
    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;
    470 
    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;
    480 }
    481 
    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);
    487 
    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");
    509 }
    510 
    511 /* emitlabel - emit label function */
    512 static void emitlabel(Term terms, Nonterm start, int ntnumber) {
    513 	int i;
    514 	Term p;
    515 
    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");
    528 }
    529 
    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;
    541 }
    542 
    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);
    548 
    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");
    567 }
    568 
    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 	}
    584 }
    585 
    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);
    599 }
    600 
    601 /* emitrule - emit decoding vectors and _rule */
    602 static void emitrule(Nonterm nts) {
    603 	Nonterm p;
    604 
    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");
    619 }
    620 
    621 /* emitstring - emit arrays of templates, instruction flags, and rules */
    622 static void emitstring(Rule rules) {
    623 	Rule r;
    624 
    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");
    644 }
    645 
    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");
    656 }
    657 
    658 /* emittest - emit clause for testing a match */
    659 static void emittest(Tree t, char *v, char *suffix) {
    660 	Term p = t->op;
    661 
    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 	}
    671 }