1 /* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
2 * For full copyright and restrictions on use see the file COPYING in the top
3 * level of the LLgen tree.
9 * An Extended LL(1) Parser Generator
11 * Author : Ceriel J.H. Jacobs
16 * Defines the routine "gencode", which generates the parser
18 * This file is a mess, it should be cleaned up some time.
29 static string rcsid3 = "$Id: gencode.c,v 2.45 2002/04/04 12:33:15 ceriel Exp $";
33 * Some codestrings used more than once
36 static string c_arrend = "0 };\n";
37 static string c_close = "}\n";
38 static string c_break = "break;\n";
39 static string c_read = "LLread();\n";
41 /* Some constants used for reading from the action file */
45 static int nlabel; /* count for the generation of labels */
46 static int firsts; /* are there any? */
49 /* In this file the following routines are defined: */
55 STATIC genncrecovery();
57 STATIC string genname();
63 STATIC getansiparams();
64 STATIC genprototypes();
67 STATIC int * dopush();
68 STATIC int * mk_tokenlist();
78 STATIC int analyze_switch();
81 STATIC correct_prefix();
85 p_mem alloc(), ralloc();
91 fatal(0,"Write error on temporary");
99 register int i = ntokens;
100 register int *p = (int *)alloc((unsigned)(i * sizeof(int))) + i;
102 while (i--) *--p = -1;
110 if (!firsts) fputs("#define LLNOFIRSTS\n", fpars);
111 if (ansi_c) fputs("#define LL_ANSI_C 1\n", fpars);
113 fputs("#if __STDC__ || __cplusplus\n#define LL_ANSI_C 1\n#endif\n", fpars);
115 #ifdef NON_CORRECTING
116 if (non_corr) fputs("#define LL_NON_CORR 1\n", fpars);
118 fprintf(fpars, "#define LL_LEXI %s\n", lexical);
123 register p_file p = files;
125 /* Set up for code generation */
126 if ((fact = fopen(f_temp,"r")) == NULL) {
127 fatal(0,e_noopen,f_temp);
130 #ifdef NON_CORRECTING
131 /* The non-correcting error recovery must be generated BEFORE
132 parser code is generated!!!! In case of conflict resolvers,
133 the code-generation process will delete conflicting symbols
134 from first and followsets, making them UNUSABLE for the
135 non-correcting error recovery code.
140 /* For every source file .... */
146 /* generate code ... */
151 install(genname(p->f_name),p->f_name);
161 opentemp(str) string str; {
163 if ((fpars = fopen(f_pars,"w")) == NULL) {
164 fatal(0,e_noopen,f_pars);
167 fprintf(fpars,LLgenid,str);
175 opentemp((string) 0);
176 for (p = tokens; p < maxt; p++) {
177 if (p->t_tokno > maxno) maxno = p->t_tokno;
178 if (p->t_tokno >= 0400) {
179 fprintf(fpars,"#define %s %d\n",
184 fprintf(fpars, "#define %s_MAXTOKNO %d\n", prefix ? prefix : "LL",
186 #ifdef NON_CORRECTING
188 fprintf(fpars, "#define %sNONCORR\n", prefix ? prefix : "LL");
192 install(f_include, ".");
201 register p_set *psetl;
206 opentemp((string) 0);
210 for (st = start; st; st = st->ff_next) {
211 /* Make sure that every set the parser needs is in the list
212 * before generating a define of the number of them!
214 p = &nonterms[st->ff_nont];
215 if (g_gettype(p->n_rule) == ALTERNATION) {
216 findindex(p->n_contains);
221 "#define LL_SSIZE %d\n#define LL_NSETS %d\n#define LL_NTERMINALS %d\n",
225 if (onerror) fprintf(f,"#define LL_USERHOOK %s\n", onerror);
226 #ifdef NON_CORRECTING
228 fputs("static int nc_done = 0;\n", f);
229 fputs("static int err_seen = 0;\n", f);
232 /* Now generate the routines that call the startsymbols */
233 fputs("#if LL_ANSI_C\n", f);
234 for (st = start; st; st = st->ff_next) {
235 p = &nonterms[st->ff_nont];
237 genextname(st->ff_nont, p->n_name, f);
238 fputs("(void);\n", f);
240 fputs("#endif\n", f);
241 for (st = start; st; st = st->ff_next) {
242 fprintf(f, "#if LL_ANSI_C\nvoid %s(void)\n#else\n%s()\n#endif\n", st->ff_name, st->ff_name);
243 p = &nonterms[st->ff_nont];
244 fputs(" {\n\tunsigned int s[LL_NTERMINALS+LL_NSETS+2];", f);
245 #ifdef NON_CORRECTING
247 fputs(" \n\tint oldstartsymb;", f);
248 fputs(" \n\tint oldncflag;", f);
249 fputs(" \n\toldstartsymb = LLstartsymb;", f);
250 fputs(" \n\toldncflag = nc_done;", f);
251 fputs(" \n\tnc_done = 0;", f);
252 fprintf(f, "\n\tLLstartsymb = %d;", st->ff_nont + assval);
255 fputs("\n\tLLnewlevel(s);\n\tLLread();\n", f);
256 if (g_gettype(p->n_rule) == ALTERNATION) {
257 genpush(findindex(p->n_contains));
259 genextname(st->ff_nont, p->n_name, f);
261 if (getntout(p) == NOSCANDONE) {
262 fputs("\tLL_NOSCANDONE(EOFILE);\n",f);
264 else fputs("\tLL_SCANDONE(EOFILE);\n",f);
265 fputs("\tLLoldlevel(s);\n",f);
266 #ifdef NON_CORRECTING
268 fputs("\tLLstartsymb = oldstartsymb;\n", f);
269 fputs("\tif (nc_done == 1) { \n", f);
270 fputs("\t\terr_seen = 1;\n", f);
271 fputs("\tnc_done = oldncflag;\n", f);
278 /* Now generate the sets */
279 fputs("static char LLsets[] = {\n",f);
280 for (psetl = setptr; psetl < maxptr; psetl++) prset(*psetl);
282 index = (int *) alloc((unsigned) (assval * sizeof(int)));
283 for (q = index; q < &index[assval];) *q++ = -1;
284 for (t = tokens; t < maxt; t++) {
285 index[t->t_tokno] = t - tokens;
287 fputs("#define LLindex (LL_index+1)\nstatic short LL_index[] = {0,0,\n",f);
288 for (q = index+1; q < &index[assval]; q++) {
289 fprintf(f, "%d,\n", *q);
294 fputs("static short LLtok[] = {\n", f);
295 for (t = tokens; t < maxt; t++) {
296 fprintf(f, t->t_tokno<0400 ? "'%s',\n" : "%s,\n",t->t_string);
300 fputs("#define LL_NEWMESS\n", f);
306 #ifdef NON_CORRECTING
314 /* Generate the non-correcting error recovery file */
316 opentemp((string) 0);
323 fprintf(f, "#define LLFIRST_NT %d\n", assval);
324 fprintf(f, "#define LLSETSIZE %d\n", nbytes);
326 index = (int *) alloc((unsigned) (assval * sizeof(int)));
327 for (q = index; q < &index[assval];) *q++ = -1;
328 for (t = tokens; t < maxt; t++) {
329 index[t->t_tokno] = t - tokens;
331 fputs("#define LLindex (LL_index+1)\nstatic short LL_index[] = {0,0,\n",f);
332 for (q = index+1; q < &index[assval]; q++) {
333 fprintf(f, "%d,\n", *q);
338 copyfile(nc_incl_file);
339 copyfile(nc_rec_file);
347 generate(f) p_file f; {
349 * Generates a parsing routine for every nonterminal
358 fprintf(fpars, "#define LL_LEXI %s\n", lexical);
360 /* Generate first sets */
361 for (ff = f->f_firsts; ff; ff = ff->ff_next) {
362 macro(ff->ff_name,&nonterms[ff->ff_nont]);
367 /* For every nonterminal generate a function */
368 for (s = f->f_nonterminals; s != -1; s = p->n_next) {
370 /* Generate functions in the order in which the nonterminals
371 * were defined in the grammar. This is important, because
372 * of synchronisation with the action file
374 while (p->n_count--) getaction(1);
375 if (g_gettype(p->n_rule) == EORULE &&
376 getntparams(p) == 0) {
379 if (is_first) genprototypes(f);
381 if (p->n_flags & GENSTATIC) fputs("static\n", fpars);
382 fputs("#if LL_ANSI_C\nvoid\n#endif\n", fpars);
383 genextname(s, p->n_name, fpars);
384 if (p->n_flags & PARAMS) {
385 long off = ftell(fact);
386 fputs("(\n#if LL_ANSI_C\n", fpars);
390 fputs("#else\n", fpars);
393 fputs("#endif\n{\n", fpars);
395 else fputs("(\n#if LL_ANSI_C\nvoid\n#endif\n) {\n", fpars);
396 if (p->n_flags & LOCALS) getaction(1);
399 if (g_gettype(p->n_rule) == ALTERNATION &&
401 mustpop = findindex(p->n_contains);
402 if (i == NOSCANDONE) {
403 fputs(c_read, fpars);
410 getntout(p) != NOSCANDONE,
412 fputs(c_close, fpars);
425 for (k = 0; k < sizeof(int); k++) {
426 fprintf(fpars,"'\\%o',",(int)(i & 0377));
438 macro(s,n) string s; p_nont n; {
441 i = findindex(n->n_first);
443 fprintf(fpars, "#define %s(x) ((x) == %d)\n",
445 tokens[-(i+1)].t_tokno);
449 fprintf(fpars,"#define %s(x) LLfirst((x), %d)\n", s, i);
454 /* Copy a compiler control line */
456 register FILE *f1,*f2;
458 f1 = fact; f2 = fpars;
463 if (l == EOF) fatal(0, "temp file mangled");
465 } while ( l != '\n' ) ;
470 /* getparams is called if a nonterminal has parameters. The names
471 * of the parameters have to be found, and they should be declared
480 /* save offset in file to be able to copy the declaration later */
482 /* First pass through declaration, find the parameter names */
484 while ((l = gettok()) != ENDDECL) {
485 if ((l == ';' || l == ',') && ltext[0] != '\0') {
487 * The last identifier found before a ';' or a ','
488 * must be a parameter
490 fprintf(fpars,"%c%s", first, ltext);
495 if (ltext[0] != '\0') {
496 fprintf(fpars, "%c%s", first, ltext);
501 * Now copy the declarations
503 l = getc(fact); /* patch: some implementations of fseek
504 do not work properly after "ungetc"
508 fprintf(fpars, "%c\n",add_semi);
516 * Generate prototypes for all nonterminals
520 long off = ftell(fact);
522 fputs("#if LL_ANSI_C\n", fpars);
523 for (i = 0; i < nnonterms; i++) {
524 if (! IN(f->f_used, i)) continue;
526 if (g_gettype(p->n_rule) == EORULE &&
527 getntparams(p) == 0) {
530 if (p->n_flags & GENSTATIC) fputs("static ", fpars);
531 fputs("void ", fpars);
532 genextname(i, p->n_name, fpars);
533 if (p->n_flags & PARAMS) {
535 fseek(fact, p->n_off, 0);
539 else fputs("(void);\n", fpars);
542 fputs("#else\n", fpars);
543 for (i = 0; i < nnonterms; i++) {
544 if (! IN(f->f_used, i)) continue;
546 if (!(p->n_flags & GENSTATIC)) continue;
547 if (g_gettype(p->n_rule) == EORULE &&
548 getntparams(p) == 0) {
551 fputs("static ", fpars);
552 genextname(i, p->n_name, fpars);
553 fputs("();\n", fpars);
555 fputs("#endif\n", fpars);
559 getansiparams(mkdef) {
560 /* getansiparams is called if a nonterminal has parameters
561 * and an ANSI C function definition/declaration has to be produced.
562 * If a definition has to be produced, "mkdef" is set to 1.
568 while ((l = gettok()) != ENDDECL) {
569 if (l > 0177 || c_class[l] != ISSPA) {
575 if ((l == ';' || l == ',') && ltext[0] != '\0') {
577 * The last identifier found before a ';' or a ','
578 * must be a parameter
583 else if (l == IDENT) fprintf(fpars, "%s", ltext);
584 else fputc(l, fpars);
586 fprintf(fpars, ") %c\n", mkdef ? ' ' : ';');
591 /* Read from the action file. */
603 if (ch != '\0') return '\n';
612 if (c_class[ch] == ISLET) {
616 if (c-ltext >= LTEXTSZ) --c;
618 } while (c_class[ch] == ISLET || c_class[ch] == ISDIG);
619 if (ch != EOF) ungetc(ch,f);
628 rulecode(p,safety,mustscan,mustpop) register p_gram p; {
630 * Code for a production rule.
633 register int toplevel = 1;
640 * First generate code to push the contains sets of this rule
643 ppushlist = dopush(p,safety,1, &pushlist);
644 if (mustpop != NOPOP) for (ppu = pushlist; ppu < ppushlist; ppu++) {
645 if (*ppu == mustpop) {
646 *ppu = mustpop = NOPOP;
650 if (g_gettype(p) != ALTERNATION) {
654 for (ppu = pushlist; ppu < ppushlist; ppu++) genpush(*ppu);
655 free((p_mem) pushlist);
658 switch (g_gettype(p)) {
660 if (mustscan && safety == NOSCANDONE) {
669 t = &tokens[g_getcont(p)];
671 fprintf(f,"LLtdecr(%d);\n", g_getcont(p));
673 if (safety == SAFE) {
676 else if (safety == SAFESCANDONE) {
677 fputs("LL_SSCANDONE(",f);
679 else if (safety == SCANDONE) {
680 fputs("LL_SCANDONE(",f);
682 else /* if (safety == NOSCANDONE) */ {
683 fputs("LL_NOSCANDONE(", f);
685 if (t->t_tokno < 0400) s = "'%s');\n";
687 fprintf(f,s,t->t_string);
688 if (safety <= SAFESCANDONE && toplevel > 0) {
697 register p_nont n = &nonterms[g_getcont(p)];
699 if (safety == NOSCANDONE &&
700 getntsafe(n) < NOSCANDONE) {
701 safety = getntsafe(n);
705 (g_gettype(n->n_rule) != ALTERNATION ||
706 getntsafe(n) <= SAFESCANDONE)) {
707 genpop(findindex(n->n_contains));
709 genextname(g_getcont(p), n->n_name, f);
716 else fputs("();\n", f);
717 safety = getntout(n);
720 safety = codeforterm(g_getterm(p),
729 alternation(p, safety, mustscan, mustpop, 0);
738 alternation(pp, safety, mustscan, mustpop, lb)
741 register p_gram p = pp;
742 register FILE *f = fpars;
744 int hulp, hulp1,hulp2;
749 int *tokenlist = mk_tokenlist();
754 assert(safety < NOSCANDONE);
759 unsafe = onerror || safety > SAFESCANDONE;
764 if (unsafe && hulp1 == lb) {
765 fprintf(f,"goto L_%d; /* so that the label is used for certain */\nL_%d: ;\n", hulp1, hulp1);
767 if (safety == SAFE) {
768 /* check if we can avoid to generate the switch */
770 if (g_gettype(p) == EORULE) return;
772 if (l->l_flag & COND) break;
773 if ((g_gettype(l->l_rule) != TERMINAL &&
774 g_gettype(l->l_rule) != LITERAL) ||
775 g_gettype(l->l_rule+1) != EORULE) break;
780 while (g_gettype(p) != EORULE) {
783 if (l->l_flag & COND) {
784 if (!(l->l_flag & NOCONF)) {
786 setunion(set, l->l_others);
787 setintersect(set, l->l_symbs);
788 setminus(l->l_symbs, set);
789 setminus(l->l_others, set);
790 add_cases(set, tokenlist, casecnt++);
793 if (!unsafe && (l->l_flag & DEF)) {
796 else add_cases(l->l_symbs, tokenlist, casecnt++);
797 if (l->l_flag & DEF) {
800 if ((l->l_flag & COND) && !(l->l_flag & NOCONF)) {
802 if (g_gettype(p+1) == EORULE) {
803 setminus(g_getlink(p)->l_symbs, set);
811 add_cases(l->l_others, tokenlist, casecnt++);
819 unsafe = onerror || safety > SAFESCANDONE;
822 compacted = analyze_switch(tokenlist);
825 out_list(tokenlist, listcount++, casecnt);
827 else fputs("switch(LLcsymb) {\n", f);
830 while (g_gettype(p) != EORULE) {
832 if (l->l_flag & COND) {
833 if (l->l_flag & NOCONF) {
834 fputs("#ifdef ___NOCONFLICT___\n", f);
836 else gencases(tokenlist, casecnt++, compacted);
840 fprintf(f,") goto L_%d;\n", hulp);
841 if (l->l_flag & NOCONF) {
842 fputs("#endif\n", f);
845 if (!unsafe && (l->l_flag & DEF)) {
847 fputs("default:\n", f);
849 else gencases(tokenlist, casecnt++, compacted);
851 if (l->l_flag & DEF) {
853 fprintf(f,"goto L_%d;\nL_%d: ;\n", hulp2, hulp2);
855 if (safety != SAFE) nsafe = SAFESCANDONE;
857 rulecode(l->l_rule, nsafe, mustscan, mustpop);
859 if (unsafe && (l->l_flag & DEF)) {
862 "default: if (LLskip()) goto L_%d;\ngoto L_%d;\n",
865 if ((l->l_flag & COND) && !(l->l_flag & NOCONF)) {
867 fprintf(f,"goto L_%d;\nL_%d : ;\n", hulp, hulp);
868 if (g_gettype(p+1) == EORULE) {
872 fputs("default:\n", f);
875 gencases(tokenlist, casecnt++, compacted);
883 alternation(p,safety,mustscan,mustpop,lb);
888 if (compacted) fputs(c_close, f);
890 free((p_mem) tokenlist);
894 dopush(p,safety,toplevel,pp) register p_gram p; int **pp; {
896 * The safety only matters if toplevel != 0
898 unsigned int i = 100;
899 register int *ip = (int *) alloc(100 * sizeof(int));
906 ralloc((p_mem) (*pp), (i + 100) * sizeof(int));
910 switch(g_gettype(p)) {
916 int rep_kind, rep_count;
919 rep_kind = r_getkind(q);
920 rep_count = r_getnum(q);
921 if (!(toplevel > 0 && safety <= SAFESCANDONE &&
922 (rep_kind == OPT || (rep_kind == FIXED && rep_count == 0)))) {
923 *ip++ = findindex(q->t_contains);
928 if (toplevel > 0 && safety <= SAFESCANDONE) {
934 if (toplevel == 0) *ip++ = -(g_getcont(p)+1);
939 n = &nonterms[g_getcont(p)];
941 (g_gettype(n->n_rule) == ALTERNATION &&
942 getntsafe(n) > SAFESCANDONE)) {
943 *ip++ = findindex(n->n_contains);
956 # define max(a,b) ((a) < (b) ? (b) : (a))
960 /* Read an action from the action file.
961 * flag = 1 if it is an action,
962 * 0 when reading parameters
976 if (flag != 2) break;
988 if (ch == ENDDECL) break;
991 if (flag) fputs("\n",f);
995 codeforterm(q,safety,toplevel) register p_term q; {
997 * Generate code for a term
999 register FILE *f = fpars;
1000 register int rep_count = r_getnum(q);
1001 register int rep_kind = r_getkind(q);
1002 int term_is_persistent = (q->t_flags & PERSISTENT);
1003 int ispushed = NOPOP;
1005 if (!(toplevel > 0 &&
1006 (safety == 0 || (!onerror && safety <= SAFESCANDONE)) &&
1007 (rep_kind == OPT || (rep_kind == FIXED && rep_count == 0)))) {
1008 ispushed = findindex(q->t_contains);
1010 if (safety == NOSCANDONE && (rep_kind != FIXED || rep_count == 0 ||
1011 gettout(q) != NOSCANDONE)) {
1015 if (rep_kind == PLUS && !term_is_persistent) {
1018 temp = findindex(q->t_first);
1019 if (temp != ispushed) {
1026 /* N > 0, so generate fixed forloop */
1027 fputs("{\nregister LL_i;\n", f);
1028 assert(ispushed != NOPOP);
1029 fprintf(f, "for (LL_i = %d; LL_i >= 0; LL_i--) {\n", rep_count - 1);
1030 if (rep_kind == FIXED) {
1031 fputs("if (!LL_i) ", f);
1034 if (safety == NOSCANDONE) {
1035 assert(gettout(q) == NOSCANDONE);
1040 else if (rep_kind != OPT && rep_kind != FIXED) {
1041 /* '+' or '*', so generate infinite loop */
1042 fputs("for (;;) {\n",f);
1044 else if (rep_kind == OPT &&
1045 (safety == 0 || (!onerror && safety <= SAFESCANDONE))) {
1049 if (rep_kind == STAR || rep_kind == OPT) {
1050 genswhead(q, rep_kind, rep_count, safety, ispushed);
1053 t_safety(rep_kind,rep_count,term_is_persistent,safety),
1054 gettout(q) != NOSCANDONE,
1055 rep_kind == FIXED ? ispushed : NOPOP);
1056 if (gettout(q) == NOSCANDONE && rep_kind != FIXED) {
1059 /* in the case of '+', the if is after the code for the rule */
1060 if (rep_kind == PLUS) {
1062 fputs("if (!LL_i) break;\n", f);
1064 genswhead(q, rep_kind, rep_count, safety, ispushed);
1066 if (rep_kind != OPT && rep_kind != FIXED) fputs("continue;\n", f);
1067 if (rep_kind != FIXED) {
1068 fputs(c_close, f); /* Close switch */
1070 if (rep_kind != OPT) {
1075 if (rep_kind != OPT && (rep_kind != FIXED || rep_count > 0)) {
1076 fputs(c_close, f); /* Close for */
1077 if (rep_count > 0) {
1078 fputs(c_close, f);/* Close Register ... */
1081 return t_after(rep_kind, rep_count, gettout(q));
1085 genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
1087 * Generate switch statement for term q
1089 register FILE *f = fpars;
1092 int hulp1 = 0, hulp2;
1096 int *tokenlist = mk_tokenlist();
1099 if (rep_kind == PLUS) safeterm = gettout(q);
1100 else if (rep_kind == OPT) safeterm = safety;
1101 else /* if (rep_kind == STAR) */ safeterm = max(safety, gettout(q));
1103 fprintf(f, "goto L_%d;\nL_%d : ", hulp2, hulp2);
1104 if (q->t_flags & RESOLVER) {
1106 if (! (q->t_flags & NOCONF)) {
1108 setunion(p1,q->t_first);
1109 setintersect(p1,q->t_follow);
1111 * p1 now points to a set containing the conflicting
1114 setminus(q->t_first, p1);
1115 setminus(q->t_follow, p1);
1116 setminus(q->t_contains, p1);
1117 add_cases(p1, tokenlist, casecnt++);
1121 if (safeterm == 0 || (!onerror && safeterm <= SAFESCANDONE)) {
1124 else add_cases(q->t_follow, tokenlist, casecnt++);
1125 if (!onerror && (q->t_flags & PERSISTENT) && safeterm != SAFE) {
1126 add_cases(q->t_contains, tokenlist, casecnt);
1128 else add_cases(q->t_first, tokenlist, casecnt);
1129 compacted = analyze_switch(tokenlist);
1132 out_list(tokenlist, listcount++, casecnt);
1134 else fputs("switch(LLcsymb) {\n", f);
1136 if (q->t_flags & RESOLVER) {
1137 if (q->t_flags & NOCONF) {
1138 fputs("#ifdef ___NOCONFLICT___\n", f);
1140 else gencases(tokenlist, casecnt++, compacted);
1144 fprintf(f, ") goto L_%d;\n", hulp1);
1145 if (q->t_flags & NOCONF) {
1146 fputs("#endif /* ___NOCONFLICT___ */\n", f);
1149 if (safeterm == 0 || (!onerror && safeterm <= SAFESCANDONE)) {
1150 fputs("default:\n", f);
1152 else gencases(tokenlist, casecnt++, compacted);
1153 if (rep_kind == OPT) genpop(ispushed);
1159 assert(ispushed != NOPOP);
1160 if (ispushed >= 0) i = -ispushed;
1161 else i = tokens[-(ispushed+1)].t_tokno;
1163 fprintf(f,"default:{int LL_%d=LLnext(%d);\n;if (!LL_%d) {\n",
1165 if (rep_kind == OPT) genpop(ispushed);
1168 fprintf(f,"else if (LL_%d & 1) goto L_%d;}\n",nvar, hulp2);
1170 gencases(tokenlist, casecnt, compacted);
1171 if (q->t_flags & RESOLVER) {
1172 fprintf(f, "goto L_%d;\nL_%d : ;\n", hulp1, hulp1);
1174 if (rep_kind == OPT) genpop(ispushed);
1175 if (rep_count > 0) {
1176 assert(ispushed != NOPOP);
1177 fputs(rep_kind == STAR ? "if (!LL_i) " : "if (LL_i == 1) ", f);
1180 free((p_mem) tokenlist);
1184 gencases(tokenlist, caseno, compacted)
1188 * setp points to a bitset indicating which cases must
1190 * YECH, the PCC compiler does not accept many cases without
1191 * statements in between, so after every case label an empty
1192 * statement is generated.
1193 * The C-grammar used by PCC is really stupid on this point :
1194 * it contains the rule
1195 * statement : label statement
1196 * which is right-recursive, and as is well known, LALR parsers don't
1197 * handle these things very well.
1198 * The grammar should have been written :
1199 * labeledstatement : labels statement ;
1200 * labels : labels label | ;
1205 if (compacted) fprintf(fpars, "case %d :\n", caseno);
1206 for (i = 0, p = tokens; i < ntokens; i++, p++) {
1207 if (tokenlist[i] == caseno) {
1210 (p->t_tokno < 0400 ? "/* case '%s' */\n" :
1211 "/* case %s */\n") :
1212 p->t_tokno<0400 ? "case /* '%s' */ %d : ;\n"
1213 : "case /* %s */ %d : ;\n",
1219 static char namebuf[20];
1222 genname(s) string s; {
1224 * Generate a target file name from the
1225 * source file name s.
1227 register string c,d;
1232 while (*s == '/') s++;
1233 if (*s) c = namebuf;
1238 for (d = c; --d > namebuf;) if (*d == '.') break;
1239 if (d == namebuf) d = c;
1240 if (d >= &namebuf[12]) {
1241 fatal(0,"%s : filename too long",namebuf);
1251 genincrdecr("incr", d);
1255 genincrdecr(s, d) string s; {
1256 if (d == NOPOP) return;
1258 fprintf(fpars, "LLs%s(%d);\n", s, d / nbytes);
1261 fprintf(fpars, "LLt%s(%d);\n", s, -(d + 1));
1266 genincrdecr("decr", d);
1270 analyze_switch(tokenlist)
1276 int maxcase = 0, mincase = 0;
1278 if (! jmptable_option) return 0;
1279 for (i = 0; i < ntokens; i++) {
1280 if (tokenlist[i] >= 0) {
1282 if (! mincase) mincase = i + 1;
1287 if (ncases < min_cases_for_jmptable) return 0;
1288 percentage = ncases * 100 / (maxcase - mincase);
1289 fprintf(fpars, "/* percentage is %d */\n", percentage);
1290 return percentage >= low_percentage && percentage <= high_percentage;
1294 add_cases(s, tokenlist, caseno)
1300 for (i = 0; i < ntokens; i++) {
1302 tokenlist[i] = caseno;
1308 out_list(tokenlist, listno, casecnt)
1312 register FILE *f = fpars;
1314 fprintf(f, "static %s LL%d_tklist[] = {",
1315 casecnt <= 127 ? "char" : "short",
1318 for (i = 0; i < ntokens; i++) {
1319 fprintf(f, "%c%d,", i % 10 == 0 ? '\n': ' ', tokenlist[i]);
1322 fprintf(f, "switch(LL%d_tklist[LLcsymb]) {\n", listno);
1330 fprintf(f, "%s%d_%s", prefix ? prefix : "LL", d, s);
1336 register FILE *f = fpars;
1337 register char *s = prefix;
1340 fprintf(f, "#define LLsymb %ssymb\n", s);
1341 fprintf(f, "#define LLerror %serror\n", s);
1342 fprintf(f, "#define LLsafeerror %ssafeerror\n", s);
1343 fprintf(f, "#ifndef LL_FASTER\n#define LLscan %sscan\n#endif\n", s);
1344 fprintf(f, "#define LLscnt %sscnt\n", s);
1345 fprintf(f, "#define LLtcnt %stcnt\n", s);
1346 fprintf(f, "#define LLcsymb %scsymb\n", s);
1347 fprintf(f, "#define LLread %sread\n", s);
1348 fprintf(f, "#define LLskip %sskip\n", s);
1349 fprintf(f, "#define LLnext %snext\n", s);
1350 fprintf(f, "#define LLfirst %sfirst\n", s);
1351 fprintf(f, "#define LLnewlevel %snewlevel\n", s);
1352 fprintf(f, "#define LLoldlevel %soldlevel\n", s);
1353 fprintf(f, "#define LLmessage %smessage\n", s);
1354 #ifdef NON_CORRECTING
1355 fprintf(f, "#define LLnc_recovery %sncrecovery\n", s);
1356 fprintf(f, "#define LLstartsymb %sstartsymb\n", s);
1359 fprintf(f, "#include \"%s\"\n", f_include);