Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

lburg.c File Reference

#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "lburg.h"

Include dependency graph for lburg.c:

Include dependency graph

Go to the source code of this file.

Data Structures

struct  block
struct  entry

Defines

#define HASHSIZE   (sizeof table/sizeof table[0])

Functions

void * alloc (int nbytes)
void ckreach (Nonterm p)
char * computekids (Tree t, char *v, char *bp, int *ip)
char * computents (Tree t, char *bp)
void emitcase (Term p, int ntnumber)
void emitclosure (Nonterm nts)
void emitcost (Tree t, char *v)
void emitdefs (Nonterm nts, int ntnumber)
void emitheader (void)
void emitkids (Rule rules, int nrules)
void emitlabel (Term terms, Nonterm start, int ntnumber)
void emitnts (Rule rules, int nrules)
void emitrecalc (char *pre, Term root, Term kid)
void emitrecord (char *pre, Rule r, char *c, int cost)
void emitrule (Nonterm nts)
void emitstring (Rule rules)
void emitstruct (Nonterm nts, int ntnumber)
void emittest (Tree t, char *v, char *suffix)
unsigned hash (char *str)
void * install (char *name)
void * lookup (char *name)
int main (int argc, char *argv[])
Nonterm nonterm (char *id)
void print (char *fmt,...)
void reach (Tree t)
Rule rule (char *id, Tree pattern, char *template, char *code)
char * stringf (char *fmt,...)
Term term (char *id, int esn)
Tree tree (char *id, Tree left, Tree right)

Variables

blockmemlist
int nrules
int ntnumber = 0
Nonterm nts
char * prefix = ""
char rcsid [] = "lburg.c - faked rcsid"
Rule rules
Nonterm start = 0
entrytable [211]
Term terms
int Tflag = 0


Define Documentation

#define HASHSIZE   (sizeof table/sizeof table[0])
 

Definition at line 137 of file lburg.c.

Referenced by constant(), findlabel(), install(), lookup(), and relocate().


Function Documentation

void* alloc int  nbytes  ) 
 

Definition at line 106 of file lburg.c.

References calloc(), exit(), block::link, memlist, p, and yyerror().

Referenced by append(), compose(), concat(), emitkids(), emitnts(), install(), rule(), string(), stringf(), strsave(), tree(), and yylex().

00106                         {
00107     struct block *p = calloc(1, sizeof *p + nbytes);
00108 
00109     if (p == NULL) {
00110         yyerror("out of memory\n");
00111         exit(1);
00112     }
00113     p->link = memlist;
00114     memlist = p;
00115     return p + 1;
00116 }

Here is the call graph for this function:

void ckreach Nonterm  p  )  [static]
 

Definition at line 334 of file lburg.c.

References rule::decode, Nonterm, p, rule::pattern, r, reach(), nonterm::reached, Rule, and nonterm::rules.

Referenced by main(), and reach().

00334                                {
00335     Rule r;
00336 
00337         p->reached = 1;
00338     for (r = p->rules; r; r = r->decode)
00339         reach(r->pattern);
00340 }

Here is the call graph for this function:

char* computekids Tree  t,
char *  v,
char *  bp,
int *  ip
[static]
 

Definition at line 468 of file lburg.c.

References term::arity, term::kind, tree::left, tree::op, p, tree::right, sprintf(), stringf(), strlen(), t, Term, Tree, and v.

Referenced by emitkids().

00468                                                              {
00469     Term p = t->op;
00470 
00471     if (p->kind == NONTERM) {
00472         sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v);
00473         bp += strlen(bp);
00474     } else if (p->arity > 0) {
00475         bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip);
00476         if (p->arity == 2)
00477             bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip);
00478     }
00479     return bp;
00480 }

Here is the call graph for this function:

char* computents Tree  t,
char *  bp
[static]
 

Definition at line 531 of file lburg.c.

References computents(), nonterm::kind, tree::left, nonterm::name, Nonterm, tree::op, p, prefix, tree::right, sprintf(), strlen(), t, and Tree.

Referenced by computents(), and emitnts().

00531                                           {
00532     if (t) {
00533         Nonterm p = t->op;
00534         if (p->kind == NONTERM) {
00535             sprintf(bp, "%s_%s_NT, ", prefix, p->name);
00536             bp += strlen(bp);
00537         } else
00538             bp = computents(t->right, computents(t->left,  bp));
00539     }
00540     return bp;
00541 }

Here is the call graph for this function:

void emitcase Term  p,
int  ntnumber
[static]
 

Definition at line 343 of file lburg.c.

References term::arity, assert, rule::code, rule::cost, emitcost(), emitrecalc(), emitrecord(), emittest(), term::esn, tree::left, rule::next, tree::nterms, tree::op, p, rule::pattern, print(), r, tree::right, Rule, term::rules, and Term.

Referenced by emitlabel().

00343                                            {
00344     Rule r;
00345 
00346     print("%1case %d: /* %S */\n", p->esn, p);
00347     switch (p->arity) {
00348     case 0: case -1:
00349         break;
00350     case 1:
00351         print("%2%Plabel(LEFT_CHILD(a));\n");
00352         break;
00353     case 2:
00354         print("%2%Plabel(LEFT_CHILD(a));\n");
00355         print("%2%Plabel(RIGHT_CHILD(a));\n");
00356         break;
00357     default: assert(0);
00358     }
00359     for (r = p->rules; r; r = r->next) {
00360         char *indent = "\t\t\0";
00361         switch (p->arity) {
00362         case 0: case -1:
00363             print("%2/* %R */\n", r);
00364             if (r->cost == -1) {
00365                 print("%2c = %s;\n", r->code);
00366                 emitrecord("\t\t", r, "c", 0);
00367             } else
00368                 emitrecord("\t\t", r, r->code, 0);
00369             break;
00370         case 1:
00371             if (r->pattern->nterms > 1) {
00372                 print("%2if (%1/* %R */\n", r);
00373                 emittest(r->pattern->left, "LEFT_CHILD(a)", " ");
00374                 print("%2) {\n");
00375                 indent = "\t\t\t";
00376             } else
00377                 print("%2/* %R */\n", r);
00378             if (r->pattern->nterms == 2 && r->pattern->left
00379             &&  r->pattern->right == NULL)
00380                 emitrecalc(indent, r->pattern->op, r->pattern->left->op);
00381             print("%sc = ", indent);
00382             emitcost(r->pattern->left, "LEFT_CHILD(a)");
00383             print("%s;\n", r->code);
00384             emitrecord(indent, r, "c", 0);
00385             if (indent[2])
00386                 print("%2}\n");
00387             break;
00388         case 2:
00389             if (r->pattern->nterms > 1) {
00390                 print("%2if (%1/* %R */\n", r);
00391                 emittest(r->pattern->left,  "LEFT_CHILD(a)",
00392                     r->pattern->right->nterms ? " && " : " ");
00393                 emittest(r->pattern->right, "RIGHT_CHILD(a)", " ");
00394                 print("%2) {\n");
00395                 indent = "\t\t\t";
00396             } else
00397                 print("%2/* %R */\n", r);
00398             print("%sc = ", indent);
00399             emitcost(r->pattern->left,  "LEFT_CHILD(a)");
00400             emitcost(r->pattern->right, "RIGHT_CHILD(a)");
00401             print("%s;\n", r->code);
00402             emitrecord(indent, r, "c", 0);
00403             if (indent[2])
00404                 print("%2}\n");
00405             break;
00406         default: assert(0);
00407         }
00408     }
00409     print("%2break;\n");
00410 }

Here is the call graph for this function:

void emitclosure Nonterm  nts  )  [static]
 

Definition at line 413 of file lburg.c.

References rule::chain, nonterm::chain, rule::cost, emitrecord(), nonterm::link, Nonterm, p, print(), r, and Rule.

Referenced by main().

00413                                      {
00414     Nonterm p;
00415 
00416     for (p = nts; p; p = p->link)
00417         if (p->chain)
00418             print("static void %Pclosure_%S(NODEPTR_TYPE, int);\n", p);
00419     print("\n");
00420     for (p = nts; p; p = p->link)
00421         if (p->chain) {
00422             Rule r;
00423             print("static void %Pclosure_%S(NODEPTR_TYPE a, int c) {\n"
00424 "%1struct %Pstate *p = STATE_LABEL(a);\n", p);
00425             for (r = p->chain; r; r = r->chain)
00426                 emitrecord("\t", r, "c", r->cost);
00427             print("}\n\n");
00428         }
00429 }

Here is the call graph for this function:

void emitcost Tree  t,
char *  v
[static]
 

Definition at line 432 of file lburg.c.

References nonterm::kind, tree::left, Nonterm, tree::op, p, print(), tree::right, stringf(), t, Tree, and v.

Referenced by emitcase().

00432                                       {
00433     Nonterm p = t->op;
00434 
00435     if (p->kind == TERM) {
00436         if (t->left)
00437             emitcost(t->left,  stringf("LEFT_CHILD(%s)",  v));
00438         if (t->right)
00439             emitcost(t->right, stringf("RIGHT_CHILD(%s)", v));
00440     } else
00441         print("((struct %Pstate *)(%s->x.state))->cost[%P%S_NT] + ", v, p);
00442 }

Here is the call graph for this function:

void emitdefs Nonterm  nts,
int  ntnumber
[static]
 

Definition at line 445 of file lburg.c.

References nonterm::link, Nonterm, nonterm::number, p, and print().

Referenced by main().

00445                                                 {
00446     Nonterm p;
00447 
00448     for (p = nts; p; p = p->link)
00449         print("#define %P%S_NT %d\n", p, p->number);
00450     print("\n");
00451     print("static char *%Pntname[] = {\n%10,\n");
00452     for (p = nts; p; p = p->link)
00453         print("%1\"%S\",\n", p);
00454     print("%10\n};\n\n");
00455 }

Here is the call graph for this function:

void emitheader void   )  [static]
 

Definition at line 458 of file lburg.c.

References ctime(), NULL, print(), rcsid, time(), and time_t.

Referenced by main().

00458                              {
00459     time_t timer = time(NULL);
00460 
00461     print("/*\ngenerated at %sby %s\n*/\n", ctime(&timer), rcsid);
00462     print("static void %Pkids(NODEPTR_TYPE, int, NODEPTR_TYPE[]);\n");
00463     print("static void %Plabel(NODEPTR_TYPE);\n");
00464     print("static int %Prule(void*, int);\n\n");
00465 }

Here is the call graph for this function:

void emitkids Rule  rules,
int  nrules
[static]
 

Definition at line 483 of file lburg.c.

References alloc(), computekids(), rule::ern, i, j, rule::kids, rule::link, nrules, rule::pattern, print(), r, Rule, strcmp(), strcpy(), and strlen().

Referenced by main().

00483                                              {
00484     int i;
00485     Rule r, *rc = alloc((nrules + 1 + 1)*sizeof *rc);
00486     char **str  = alloc((nrules + 1 + 1)*sizeof *str);
00487 
00488     for (i = 0, r = rules; r; r = r->link) {
00489         int j = 0;
00490         char buf[1024], *bp = buf;
00491         *computekids(r->pattern, "p", bp, &j) = 0;
00492         for (j = 0; str[j] && strcmp(str[j], buf); j++)
00493             ;
00494         if (str[j] == NULL)
00495             str[j] = strcpy(alloc(strlen(buf) + 1), buf);
00496         r->kids = rc[j];
00497         rc[j] = r;
00498     }
00499     print("static void %Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n"
00500 "%1if (!p)\n%2fatal(\"%Pkids\", \"Null tree\\n\", 0);\n"
00501 "%1if (!kids)\n%2fatal(\"%Pkids\", \"Null kids\\n\", 0);\n"
00502 "%1switch (eruleno) {\n");
00503     for (i = 0; (r = rc[i]) != NULL; i++) {
00504         for ( ; r; r = r->kids)
00505             print("%1case %d: /* %R */\n", r->ern, r);
00506         print("%s%2break;\n", str[i]);
00507     }
00508     print("%1default:\n%2fatal(\"%Pkids\", \"Bad rule number %%d\\n\", eruleno);\n%1}\n}\n\n");
00509 }

Here is the call graph for this function:

void emitlabel Term  terms,
Nonterm  start,
int  ntnumber
[static]
 

Definition at line 512 of file lburg.c.

References emitcase(), i, term::link, Nonterm, ntnumber, p, print(), and Term.

Referenced by main().

00512                                                                {
00513     int i;
00514     Term p;
00515 
00516     print("static void %Plabel(NODEPTR_TYPE a) {\n%1int c;\n"
00517 "%1struct %Pstate *p;\n\n"
00518 "%1if (!a)\n%2fatal(\"%Plabel\", \"Null tree\\n\", 0);\n");
00519     print("%1STATE_LABEL(a) = p = allocate(sizeof *p, FUNC);\n"
00520 "%1p->rule._stmt = 0;\n");
00521     for (i = 1; i <= ntnumber; i++)
00522         print("%1p->cost[%d] =\n", i);
00523     print("%20x7fff;\n%1switch (OP_LABEL(a)) {\n");
00524     for (p = terms; p; p = p->link)
00525         emitcase(p, ntnumber);
00526     print("%1default:\n"
00527 "%2fatal(\"%Plabel\", \"Bad terminal %%d\\n\", OP_LABEL(a));\n%1}\n}\n\n");
00528 }

Here is the call graph for this function:

void emitnts Rule  rules,
int  nrules
[static]
 

Definition at line 544 of file lburg.c.

References alloc(), computents(), rule::ern, i, j, rule::link, nrules, nts, rule::pattern, print(), r, Rule, strcmp(), strcpy(), and strlen().

Referenced by main().

00544                                             {
00545     Rule r;
00546     int i, j, *nts = alloc((nrules + 1)*sizeof *nts);
00547     char **str = alloc((nrules + 1)*sizeof *str);
00548 
00549     for (i = 0, r = rules; r; r = r->link) {
00550         char buf[1024];
00551         *computents(r->pattern, buf) = 0;
00552         for (j = 0; str[j] && strcmp(str[j], buf); j++)
00553             ;
00554         if (str[j] == NULL) {
00555             print("static short %Pnts_%d[] = { %s0 };\n", j, buf);
00556             str[j] = strcpy(alloc(strlen(buf) + 1), buf);
00557         }
00558         nts[i++] = j;
00559     }
00560     print("\nstatic short *%Pnts[] = {\n");
00561     for (i = j = 0, r = rules; r; r = r->link) {
00562         for ( ; j < r->ern; j++)
00563             print("%10,%1/* %d */\n", j);
00564         print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++);
00565     }
00566     print("};\n\n");
00567 }

Here is the call graph for this function:

void emitrecalc char *  pre,
Term  root,
Term  kid
[static]
 

Definition at line 570 of file lburg.c.

References term::kind, nonterm::link, term::name, Nonterm, p, print(), root(), strcmp(), strncmp(), TERM, and Term.

Referenced by emitcase().

00570                                                        {
00571     if (root->kind == TERM && strncmp(root->name, "INDIR", 5) == 0
00572     &&   kid->kind == TERM &&  strcmp(kid->name,  "VREGP"   ) == 0) {
00573         Nonterm p;
00574         print("%sif (mayrecalc(a)) {\n", pre);
00575         print("%s%1struct %Pstate *q = a->syms[RX]->u.t.cse->x.state;\n", pre);
00576         for (p = nts; p; p = p->link) {
00577             print("%s%1if (q->cost[%P%S_NT] == 0) {\n", pre, p);
00578             print("%s%2p->cost[%P%S_NT] = 0;\n", pre, p);
00579             print("%s%2p->rule.%P%S = q->rule.%P%S;\n", pre, p, p);
00580             print("%s%1}\n", pre);
00581         }
00582         print("%s}\n", pre);
00583     }
00584 }

Here is the call graph for this function:

void emitrecord char *  pre,
Rule  r,
char *  c,
int  cost
[static]
 

Definition at line 587 of file lburg.c.

References c, nonterm::chain, rule::ern, rule::lhs, rule::packed, print(), r, and Rule.

Referenced by emitcase(), and emitclosure().

00587                                                              {
00588     if (Tflag)
00589         print("%s%Ptrace(a, %d, %s + %d, p->cost[%P%S_NT]);\n",
00590             pre, r->ern, c, cost, r->lhs);
00591     print("%sif (", pre);
00592     print("%s + %d < p->cost[%P%S_NT]) {\n"
00593 "%s%1p->cost[%P%S_NT] = %s + %d;\n%s%1p->rule.%P%S = %d;\n",
00594         c, cost, r->lhs, pre, r->lhs, c, cost, pre, r->lhs,
00595         r->packed);
00596     if (r->lhs->chain)
00597         print("%s%1%Pclosure_%S(a, %s + %d);\n", pre, r->lhs, c, cost);
00598     print("%s}\n", pre);
00599 }

Here is the call graph for this function:

void emitrule Nonterm  nts  )  [static]
 

Definition at line 602 of file lburg.c.

References rule::decode, rule::ern, nonterm::link, Nonterm, ntnumber, p, print(), r, Rule, and nonterm::rules.

Referenced by main().

00602                                   {
00603     Nonterm p;
00604 
00605     for (p = nts; p; p = p->link) {
00606         Rule r;
00607         print("static short %Pdecode_%S[] = {\n%10,\n", p);
00608         for (r = p->rules; r; r = r->decode)
00609             print("%1%d,\n", r->ern);
00610         print("};\n\n");
00611     }
00612     print("static int %Prule(void *state, int goalnt) {\n"
00613 "%1if (goalnt < 1 || goalnt > %d)\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n"
00614 "%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber);
00615     for (p = nts; p; p = p->link)
00616         print("%1case %P%S_NT:"
00617 "%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p, p, p);
00618     print("%1default:\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n%2return 0;\n%1}\n}\n\n");
00619 }

Here is the call graph for this function:

void emitstring Rule  rules  )  [static]
 

Definition at line 622 of file lburg.c.

References rule::ern, rule::link, print(), r, Rule, strlen(), and rule::template.

Referenced by main().

00622                                    {
00623     Rule r;
00624 
00625     print("static char *%Ptemplates[] = {\n");
00626     print("/* 0 */%10,\n");
00627     for (r = rules; r; r = r->link)
00628         print("/* %d */%1\"%s\",%1/* %R */\n", r->ern, r->template, r);
00629     print("};\n");
00630     print("\nstatic char %Pisinstruction[] = {\n");
00631     print("/* 0 */%10,\n");
00632     for (r = rules; r; r = r->link) {
00633         int len = strlen(r->template);
00634         print("/* %d */%1%d,%1/* %s */\n", r->ern,
00635             len >= 2 && r->template[len-2] == '\\' && r->template[len-1] == 'n',
00636             r->template);
00637     }
00638     print("};\n");
00639     print("\nstatic char *%Pstring[] = {\n");
00640     print("/* 0 */%10,\n");
00641     for (r = rules; r; r = r->link)
00642         print("/* %d */%1\"%R\",\n", r->ern, r);
00643     print("};\n\n");
00644 }

Here is the call graph for this function:

void emitstruct Nonterm  nts,
int  ntnumber
[static]
 

Definition at line 647 of file lburg.c.

References nonterm::lhscount, nonterm::link, m, n, Nonterm, ntnumber, nts, and print().

Referenced by main().

00647                                                   {
00648     print("struct %Pstate {\n%1short cost[%d];\n%1struct {\n", ntnumber + 1);
00649     for ( ; nts; nts = nts->link) {
00650         int n = 1, m = nts->lhscount;
00651         while ((m >>= 1) != 0)
00652             n++;        
00653         print("%2unsigned int %P%S:%d;\n", nts, n);
00654     }
00655     print("%1} rule;\n};\n\n");
00656 }

Here is the call graph for this function:

void emittest Tree  t,
char *  v,
char *  suffix
[static]
 

Definition at line 659 of file lburg.c.

References term::esn, term::kind, tree::left, tree::nterms, tree::op, p, print(), tree::right, stringf(), suffix(), t, Term, Tree, and v.

Referenced by emitcase().

00659                                                     {
00660     Term p = t->op;
00661 
00662     if (p->kind == TERM) {
00663         print("%3%s->op == %d%s/* %S */\n", v, p->esn,
00664             t->nterms > 1 ? " && " : suffix, p);
00665         if (t->left)
00666             emittest(t->left, stringf("LEFT_CHILD(%s)",  v),
00667                 t->right && t->right->nterms ? " && " : suffix);
00668         if (t->right)
00669             emittest(t->right, stringf("RIGHT_CHILD(%s)", v), suffix);
00670     }
00671 }

Here is the call graph for this function:

unsigned hash char *  str  )  [static]
 

Definition at line 140 of file lburg.c.

References h().

Referenced by install(), and lookup().

00140                                 {
00141     unsigned h = 0;
00142 
00143     while (*str)
00144         h = (h<<1) + *str++;
00145     return h;
00146 }

Here is the call graph for this function:

void* install char *  name  )  [static]
 

Definition at line 159 of file lburg.c.

References alloc(), hash(), i, symbol::name, name, and p.

00159                                  {
00160     struct entry *p = alloc(sizeof *p);
00161     int i = hash(name)%HASHSIZE;
00162 
00163     p->sym.name = name;
00164     p->link = table[i];
00165     table[i] = p;
00166     return &p->sym;
00167 }

Here is the call graph for this function:

void* lookup char *  name  )  [static]
 

Definition at line 149 of file lburg.c.

References hash(), entry::link, entry::name, name, p, strcmp(), and entry::sym.

00149                                 {
00150     struct entry *p = table[hash(name)%HASHSIZE];
00151 
00152     for ( ; p; p = p->link)
00153         if (strcmp(name, p->sym.name) == 0)
00154             return &p->sym;
00155     return 0;
00156 }

Here is the call graph for this function:

int main int  argc,
char *  argv[]
 

Definition at line 41 of file lburg.c.

References argv, c, ckreach(), emitclosure(), emitdefs(), emitheader(), emitkids(), emitlabel(), emitnts(), emitrule(), emitstring(), emitstruct(), errcnt, exit(), feof, fopen(), free(), getc, i, infp, block::link, nonterm::link, memlist, nonterm::name, Nonterm, nrules, ntnumber, nts, outfp, p, prefix, putc, q, nonterm::reached, rules, nonterm::rules, start, strcmp(), strncmp(), terms, Tflag, yyerror(), and yyparse().

00041                                  {
00042     int c, i;
00043     Nonterm p;
00044     
00045     for (i = 1; i < argc; i++)
00046         if (strcmp(argv[i], "-T") == 0)
00047             Tflag = 1;
00048         else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2])
00049             prefix = &argv[i][2];
00050         else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc)
00051             prefix = argv[++i];
00052         else if (*argv[i] == '-' && argv[i][1]) {
00053             yyerror("usage: %s [-T | -p prefix]... [ [ input ] output ] \n",
00054                 argv[0]);
00055             exit(1);
00056         } else if (infp == NULL) {
00057             if (strcmp(argv[i], "-") == 0)
00058                 infp = stdin;
00059             else if ((infp = fopen(argv[i], "r")) == NULL) {
00060                 yyerror("%s: can't read `%s'\n", argv[0], argv[i]);
00061                 exit(1);
00062             }
00063         } else if (outfp == NULL) {
00064             if (strcmp(argv[i], "-") == 0)
00065                 outfp = stdout;
00066             if ((outfp = fopen(argv[i], "w")) == NULL) {
00067                 yyerror("%s: can't write `%s'\n", argv[0], argv[i]);
00068                 exit(1);
00069             }
00070         }
00071     if (infp == NULL)
00072         infp = stdin;
00073     if (outfp == NULL)
00074         outfp = stdout;
00075     yyparse();
00076     if (start)
00077         ckreach(start);
00078     for (p = nts; p; p = p->link) {
00079         if (p->rules == NULL)
00080             yyerror("undefined nonterminal `%s'\n", p->name);
00081         if (!p->reached)
00082             yyerror("can't reach nonterminal `%s'\n", p->name);
00083     }
00084     emitheader();
00085     emitdefs(nts, ntnumber);
00086     emitstruct(nts, ntnumber);
00087     emitnts(rules, nrules);
00088     emitstring(rules);
00089     emitrule(nts);
00090     emitclosure(nts);
00091     if (start)
00092         emitlabel(terms, start, ntnumber);
00093     emitkids(rules, nrules);
00094     if (!feof(infp))
00095         while ((c = getc(infp)) != EOF)
00096             putc(c, outfp);
00097     while (memlist) {   /* for purify */
00098         struct block *q = memlist->link;
00099         free(memlist);
00100         memlist = q;
00101     }
00102     return