10 static char rcsid
[] = "$Id$";
11 static char *prefix
= "";
13 static int ntnumber
= 0;
14 static Nonterm start
= 0;
21 } *memlist
; /* list of allocated blocks */
23 static char *stringf(char *fmt
, ...);
24 static void print(char *fmt
, ...);
25 static void ckreach(Nonterm p
);
26 static void emitclosure(Nonterm nts
);
27 static void emitcost(Tree t
, char *v
);
28 static void emitdefs(Nonterm nts
, int ntnumber
);
29 static void emitheader(void);
30 static void emitkids(Rule rules
, int nrules
);
31 static void emitnts(Rule rules
, int nrules
);
32 static void emitrecalc(char *pre
, Term root
, Term kid
);
33 static void emitrecord(char *pre
, Rule r
, char *c
, int cost
);
34 static void emitrule(Nonterm nts
);
35 static void emitlabel(Term terms
, Nonterm start
, int ntnumber
);
36 static void emitstring(Rule rules
);
37 static void emitstruct(Nonterm nts
, int ntnumber
);
38 static void emittest(Tree t
, char *v
, char *suffix
);
40 int main(int argc
, char *argv
[]) {
44 for (i
= 1; i
< argc
; i
++)
45 if (strcmp(argv
[i
], "-T") == 0)
47 else if (strncmp(argv
[i
], "-p", 2) == 0 && argv
[i
][2])
49 else if (strncmp(argv
[i
], "-p", 2) == 0 && i
+ 1 < argc
)
51 else if (*argv
[i
] == '-' && argv
[i
][1]) {
52 yyerror("usage: %s [-T | -p prefix]... [ [ input ] output ] \n",
55 } else if (infp
== NULL
) {
56 if (strcmp(argv
[i
], "-") == 0)
58 else if ((infp
= fopen(argv
[i
], "r")) == NULL
) {
59 yyerror("%s: can't read `%s'\n", argv
[0], argv
[i
]);
62 } else if (outfp
== NULL
) {
63 if (strcmp(argv
[i
], "-") == 0)
65 if ((outfp
= fopen(argv
[i
], "w")) == NULL
) {
66 yyerror("%s: can't write `%s'\n", argv
[0], argv
[i
]);
77 for (p
= nts
; p
; p
= p
->link
) {
79 yyerror("undefined nonterminal `%s'\n", p
->name
);
81 yyerror("can't reach nonterminal `%s'\n", p
->name
);
84 emitdefs(nts
, ntnumber
);
85 emitstruct(nts
, ntnumber
);
86 emitnts(rules
, nrules
);
91 emitlabel(terms
, start
, ntnumber
);
92 emitkids(rules
, nrules
);
94 while ((c
= getc(infp
)) != EOF
)
96 while (memlist
) { /* for purify */
97 struct block
*q
= memlist
->link
;
104 /* alloc - allocate nbytes or issue fatal error */
105 void *alloc(int nbytes
) {
106 struct block
*p
= calloc(1, sizeof *p
+ nbytes
);
109 yyerror("out of memory\n");
117 /* stringf - format and save a string */
118 static char *stringf(char *fmt
, ...) {
123 vsprintf(buf
, fmt
, ap
);
125 return strcpy(alloc(strlen(buf
) + 1), buf
);
136 #define HASHSIZE (sizeof table/sizeof table[0])
138 /* hash - return hash number for str */
139 static unsigned hash(char *str
) {
147 /* lookup - lookup symbol name */
148 static void *lookup(char *name
) {
149 struct entry
*p
= table
[hash(name
)%HASHSIZE
];
151 for ( ; p
; p
= p
->link
)
152 if (strcmp(name
, p
->sym
.name
) == 0)
157 /* install - install symbol name */
158 static void *install(char *name
) {
159 struct entry
*p
= alloc(sizeof *p
);
160 int i
= hash(name
)%HASHSIZE
;
168 /* nonterm - create a new terminal id, if necessary */
169 Nonterm
nonterm(char *id
) {
170 Nonterm p
= lookup(id
), *q
= &nts
;
172 if (p
&& p
->kind
== NONTERM
)
174 if (p
&& p
->kind
== TERM
)
175 yyerror("`%s' is a terminal\n", id
);
178 p
->number
= ++ntnumber
;
181 while (*q
&& (*q
)->number
< p
->number
)
183 assert(*q
== 0 || (*q
)->number
!= p
->number
);
189 /* term - create a new terminal id with external symbol number esn */
190 Term
term(char *id
, int esn
) {
191 Term p
= lookup(id
), *q
= &terms
;
194 yyerror("redefinition of terminal `%s'\n", id
);
200 while (*q
&& (*q
)->esn
< p
->esn
)
202 if (*q
&& (*q
)->esn
== p
->esn
)
203 yyerror("duplicate external symbol number `%s=%d'\n",
210 /* tree - create & initialize a tree node with the given fields */
211 Tree
tree(char *id
, Tree left
, Tree right
) {
212 Tree t
= alloc(sizeof *t
);
220 if (p
== NULL
&& arity
> 0) {
221 yyerror("undefined terminal `%s'\n", id
);
223 } else if (p
== NULL
&& arity
== 0)
224 p
= (Term
)nonterm(id
);
225 else if (p
&& p
->kind
== NONTERM
&& arity
> 0) {
226 yyerror("`%s' is a nonterminal\n", id
);
229 if (p
->kind
== TERM
&& p
->arity
== -1)
231 if (p
->kind
== TERM
&& arity
!= p
->arity
)
232 yyerror("inconsistent arity for terminal `%s'\n", id
);
234 t
->nterms
= p
->kind
== TERM
;
235 if ((t
->left
= left
) != NULL
)
236 t
->nterms
+= left
->nterms
;
237 if ((t
->right
= right
) != NULL
)
238 t
->nterms
+= right
->nterms
;
242 /* rule - create & initialize a rule with the given fields */
243 Rule
rule(char *id
, Tree pattern
, char *template, char *code
) {
244 Rule r
= alloc(sizeof *r
), *q
;
245 Term p
= pattern
->op
;
248 r
->lhs
= nonterm(id
);
249 r
->packed
= ++r
->lhs
->lhscount
;
250 for (q
= &r
->lhs
->rules
; *q
; q
= &(*q
)->decode
)
253 r
->pattern
= pattern
;
255 r
->template = template;
257 r
->cost
= strtol(code
, &end
, 10);
260 r
->code
= stringf("(%s)", code
);
262 if (p
->kind
== TERM
) {
263 for (q
= &p
->rules
; *q
; q
= &(*q
)->next
)
266 } else if (pattern
->left
== NULL
&& pattern
->right
== NULL
) {
267 Nonterm p
= pattern
->op
;
271 yyerror("illegal nonconstant cost `%s'\n", code
);
273 for (q
= &rules
; *q
; q
= &(*q
)->link
)
280 /* print - formatted output */
281 static void print(char *fmt
, ...) {
288 case 'd': fprintf(outfp
, "%d", va_arg(ap
, int)); break;
289 case 's': fputs(va_arg(ap
, char *), outfp
); break;
290 case 'P': fprintf(outfp
, "%s_", prefix
); break;
292 Tree t
= va_arg(ap
, Tree
);
294 if (t
->left
&& t
->right
)
295 print("(%T,%T)", t
->left
, t
->right
);
297 print("(%T)", t
->left
);
301 Rule r
= va_arg(ap
, Rule
);
302 print("%S: %T", r
->lhs
, r
->pattern
);
306 Term t
= va_arg(ap
, Term
);
307 fputs(t
->name
, outfp
);
310 case '1': case '2': case '3': case '4': case '5': {
316 default: putc(*fmt
, outfp
); break;
323 /* reach - mark all nonterminals in tree t as reachable */
324 static void reach(Tree t
) {
327 if (p
->kind
== NONTERM
)
336 /* ckreach - mark all nonterminals reachable from p */
337 static void ckreach(Nonterm p
) {
341 for (r
= p
->rules
; r
; r
= r
->decode
)
345 /* emitcase - emit one case in function state */
346 static void emitcase(Term p
, int ntnumber
) {
349 print("%1case %d: /* %S */\n", p
->esn
, p
);
354 print("%2%Plabel(LEFT_CHILD(a));\n");
357 print("%2%Plabel(LEFT_CHILD(a));\n");
358 print("%2%Plabel(RIGHT_CHILD(a));\n");
362 for (r
= p
->rules
; r
; r
= r
->next
) {
363 char *indent
= "\t\t\0";
366 print("%2/* %R */\n", r
);
368 print("%2c = %s;\n", r
->code
);
369 emitrecord("\t\t", r
, "c", 0);
371 emitrecord("\t\t", r
, r
->code
, 0);
374 if (r
->pattern
->nterms
> 1) {
375 print("%2if (%1/* %R */\n", r
);
376 emittest(r
->pattern
->left
, "LEFT_CHILD(a)", " ");
380 print("%2/* %R */\n", r
);
381 if (r
->pattern
->nterms
== 2 && r
->pattern
->left
382 && r
->pattern
->right
== NULL
)
383 emitrecalc(indent
, r
->pattern
->op
, r
->pattern
->left
->op
);
384 print("%sc = ", indent
);
385 emitcost(r
->pattern
->left
, "LEFT_CHILD(a)");
386 print("%s;\n", r
->code
);
387 emitrecord(indent
, r
, "c", 0);
392 if (r
->pattern
->nterms
> 1) {
393 print("%2if (%1/* %R */\n", r
);
394 emittest(r
->pattern
->left
, "LEFT_CHILD(a)",
395 r
->pattern
->right
->nterms
? " && " : " ");
396 emittest(r
->pattern
->right
, "RIGHT_CHILD(a)", " ");
400 print("%2/* %R */\n", r
);
401 print("%sc = ", indent
);
402 emitcost(r
->pattern
->left
, "LEFT_CHILD(a)");
403 emitcost(r
->pattern
->right
, "RIGHT_CHILD(a)");
404 print("%s;\n", r
->code
);
405 emitrecord(indent
, r
, "c", 0);
415 /* emitclosure - emit the closure functions */
416 static void emitclosure(Nonterm nts
) {
419 for (p
= nts
; p
; p
= p
->link
)
421 print("static void %Pclosure_%S(NODEPTR_TYPE, int);\n", p
);
423 for (p
= nts
; p
; p
= p
->link
)
426 print("static void %Pclosure_%S(NODEPTR_TYPE a, int c) {\n"
427 "%1struct %Pstate *p = STATE_LABEL(a);\n", p
);
428 for (r
= p
->chain
; r
; r
= r
->chain
)
429 emitrecord("\t", r
, "c", r
->cost
);
434 /* emitcost - emit cost computation for tree t */
435 static void emitcost(Tree t
, char *v
) {
438 if (p
->kind
== TERM
) {
440 emitcost(t
->left
, stringf("LEFT_CHILD(%s)", v
));
442 emitcost(t
->right
, stringf("RIGHT_CHILD(%s)", v
));
444 print("((struct %Pstate *)(%s->x.state))->cost[%P%S_NT] + ", v
, p
);
447 /* emitdefs - emit nonterminal defines and data structures */
448 static void emitdefs(Nonterm nts
, int ntnumber
) {
451 for (p
= nts
; p
; p
= p
->link
)
452 print("#define %P%S_NT %d\n", p
, p
->number
);
454 print("static char *%Pntname[] = {\n%10,\n");
455 for (p
= nts
; p
; p
= p
->link
)
456 print("%1\"%S\",\n", p
);
457 print("%10\n};\n\n");
460 /* emitheader - emit initial definitions */
461 static void emitheader(void) {
462 time_t timer
= time(NULL
);
464 print("/*\ngenerated at %sby %s\n*/\n", ctime(&timer
), rcsid
);
465 print("static void %Pkids(NODEPTR_TYPE, int, NODEPTR_TYPE[]);\n");
466 print("static void %Plabel(NODEPTR_TYPE);\n");
467 print("static int %Prule(void*, int);\n\n");
470 /* computekids - compute paths to kids in tree t */
471 static char *computekids(Tree t
, char *v
, char *bp
, int *ip
) {
474 if (p
->kind
== NONTERM
) {
475 sprintf(bp
, "\t\tkids[%d] = %s;\n", (*ip
)++, v
);
477 } else if (p
->arity
> 0) {
478 bp
= computekids(t
->left
, stringf("LEFT_CHILD(%s)", v
), bp
, ip
);
480 bp
= computekids(t
->right
, stringf("RIGHT_CHILD(%s)", v
), bp
, ip
);
485 /* emitkids - emit _kids */
486 static void emitkids(Rule rules
, int nrules
) {
488 Rule r
, *rc
= alloc((nrules
+ 1 + 1)*sizeof *rc
);
489 char **str
= alloc((nrules
+ 1 + 1)*sizeof *str
);
491 for (i
= 0, r
= rules
; r
; r
= r
->link
) {
493 char buf
[1024], *bp
= buf
;
494 *computekids(r
->pattern
, "p", bp
, &j
) = 0;
495 for (j
= 0; str
[j
] && strcmp(str
[j
], buf
); j
++)
498 str
[j
] = strcpy(alloc(strlen(buf
) + 1), buf
);
502 print("static void %Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n"
503 "%1if (!p)\n%2fatal(\"%Pkids\", \"Null tree\\n\", 0);\n"
504 "%1if (!kids)\n%2fatal(\"%Pkids\", \"Null kids\\n\", 0);\n"
505 "%1switch (eruleno) {\n");
506 for (i
= 0; (r
= rc
[i
]) != NULL
; i
++) {
507 for ( ; r
; r
= r
->kids
)
508 print("%1case %d: /* %R */\n", r
->ern
, r
);
509 print("%s%2break;\n", str
[i
]);
511 print("%1default:\n%2fatal(\"%Pkids\", \"Bad rule number %%d\\n\", eruleno);\n%1}\n}\n\n");
514 /* emitlabel - emit label function */
515 static void emitlabel(Term terms
, Nonterm start
, int ntnumber
) {
519 print("static void %Plabel(NODEPTR_TYPE a) {\n%1int c;\n"
520 "%1struct %Pstate *p;\n\n"
521 "%1if (!a)\n%2fatal(\"%Plabel\", \"Null tree\\n\", 0);\n");
522 print("%1STATE_LABEL(a) = p = allocate(sizeof *p, FUNC);\n"
523 "%1p->rule._stmt = 0;\n");
524 for (i
= 1; i
<= ntnumber
; i
++)
525 print("%1p->cost[%d] =\n", i
);
526 print("%20x7fff;\n%1switch (OP_LABEL(a)) {\n");
527 for (p
= terms
; p
; p
= p
->link
)
528 emitcase(p
, ntnumber
);
530 "%2fatal(\"%Plabel\", \"Bad terminal %%d\\n\", OP_LABEL(a));\n%1}\n}\n\n");
533 /* computents - fill in bp with _nts vector for tree t */
534 static char *computents(Tree t
, char *bp
) {
537 if (p
->kind
== NONTERM
) {
538 sprintf(bp
, "%s_%s_NT, ", prefix
, p
->name
);
541 bp
= computents(t
->right
, computents(t
->left
, bp
));
546 /* emitnts - emit _nts ragged array */
547 static void emitnts(Rule rules
, int nrules
) {
549 int i
, j
, *nts
= alloc((nrules
+ 1)*sizeof *nts
);
550 char **str
= alloc((nrules
+ 1)*sizeof *str
);
552 for (i
= 0, r
= rules
; r
; r
= r
->link
) {
554 *computents(r
->pattern
, buf
) = 0;
555 for (j
= 0; str
[j
] && strcmp(str
[j
], buf
); j
++)
557 if (str
[j
] == NULL
) {
558 print("static short %Pnts_%d[] = { %s0 };\n", j
, buf
);
559 str
[j
] = strcpy(alloc(strlen(buf
) + 1), buf
);
563 print("\nstatic short *%Pnts[] = {\n");
564 for (i
= j
= 0, r
= rules
; r
; r
= r
->link
) {
565 for ( ; j
< r
->ern
; j
++)
566 print("%10,%1/* %d */\n", j
);
567 print("%1%Pnts_%d,%1/* %d */\n", nts
[i
++], j
++);
572 /* emitrecalc - emit code that tests for recalculation of INDIR?(VREGP) */
573 static void emitrecalc(char *pre
, Term root
, Term kid
) {
574 if (root
->kind
== TERM
&& strncmp(root
->name
, "INDIR", 5) == 0
575 && kid
->kind
== TERM
&& strcmp(kid
->name
, "VREGP" ) == 0) {
577 print("%sif (mayrecalc(a)) {\n", pre
);
578 print("%s%1struct %Pstate *q = a->syms[RX]->u.t.cse->x.state;\n", pre
);
579 for (p
= nts
; p
; p
= p
->link
) {
580 print("%s%1if (q->cost[%P%S_NT] == 0) {\n", pre
, p
);
581 print("%s%2p->cost[%P%S_NT] = 0;\n", pre
, p
);
582 print("%s%2p->rule.%P%S = q->rule.%P%S;\n", pre
, p
, p
);
583 print("%s%1}\n", pre
);
589 /* emitrecord - emit code that tests for a winning match of rule r */
590 static void emitrecord(char *pre
, Rule r
, char *c
, int cost
) {
592 print("%s%Ptrace(a, %d, %s + %d, p->cost[%P%S_NT]);\n",
593 pre
, r
->ern
, c
, cost
, r
->lhs
);
594 print("%sif (", pre
);
595 print("%s + %d < p->cost[%P%S_NT]) {\n"
596 "%s%1p->cost[%P%S_NT] = %s + %d;\n%s%1p->rule.%P%S = %d;\n",
597 c
, cost
, r
->lhs
, pre
, r
->lhs
, c
, cost
, pre
, r
->lhs
,
600 print("%s%1%Pclosure_%S(a, %s + %d);\n", pre
, r
->lhs
, c
, cost
);
604 /* emitrule - emit decoding vectors and _rule */
605 static void emitrule(Nonterm nts
) {
608 for (p
= nts
; p
; p
= p
->link
) {
610 print("static short %Pdecode_%S[] = {\n%10,\n", p
);
611 for (r
= p
->rules
; r
; r
= r
->decode
)
612 print("%1%d,\n", r
->ern
);
615 print("static int %Prule(void *state, int goalnt) {\n"
616 "%1if (goalnt < 1 || goalnt > %d)\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n"
617 "%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber
);
618 for (p
= nts
; p
; p
= p
->link
)
619 print("%1case %P%S_NT:"
620 "%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p
, p
, p
);
621 print("%1default:\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n%2return 0;\n%1}\n}\n\n");
624 /* emitstring - emit arrays of templates, instruction flags, and rules */
625 static void emitstring(Rule rules
) {
628 print("static char *%Ptemplates[] = {\n");
629 print("/* 0 */%10,\n");
630 for (r
= rules
; r
; r
= r
->link
)
631 print("/* %d */%1\"%s\",%1/* %R */\n", r
->ern
, r
->template, r
);
633 print("\nstatic char %Pisinstruction[] = {\n");
634 print("/* 0 */%10,\n");
635 for (r
= rules
; r
; r
= r
->link
) {
636 int len
= strlen(r
->template);
637 print("/* %d */%1%d,%1/* %s */\n", r
->ern
,
638 len
>= 2 && r
->template[len
-2] == '\\' && r
->template[len
-1] == 'n',
642 print("\nstatic char *%Pstring[] = {\n");
643 print("/* 0 */%10,\n");
644 for (r
= rules
; r
; r
= r
->link
)
645 print("/* %d */%1\"%R\",\n", r
->ern
, r
);
649 /* emitstruct - emit the definition of the state structure */
650 static void emitstruct(Nonterm nts
, int ntnumber
) {
651 print("struct %Pstate {\n%1short cost[%d];\n%1struct {\n", ntnumber
+ 1);
652 for ( ; nts
; nts
= nts
->link
) {
653 int n
= 1, m
= nts
->lhscount
;
654 while ((m
>>= 1) != 0)
656 print("%2unsigned int %P%S:%d;\n", nts
, n
);
658 print("%1} rule;\n};\n\n");
661 /* emittest - emit clause for testing a match */
662 static void emittest(Tree t
, char *v
, char *suffix
) {
665 if (p
->kind
== TERM
) {
666 print("%3%s->op == %d%s/* %S */\n", v
, p
->esn
,
667 t
->nterms
> 1 ? " && " : suffix
, p
);
669 emittest(t
->left
, stringf("LEFT_CHILD(%s)", v
),
670 t
->right
&& t
->right
->nterms
? " && " : suffix
);
672 emittest(t
->right
, stringf("RIGHT_CHILD(%s)", v
), suffix
);