Added code to generate dense switches

This commit is contained in:
ceriel 1988-06-22 16:23:36 +00:00
parent c146e278fc
commit 4934f830fc
4 changed files with 210 additions and 44 deletions

View file

@ -73,3 +73,6 @@ extern string LLgenid; /* LLgen identification string */
extern t_token lextoken; /* the current token */ extern t_token lextoken; /* the current token */
extern int nerrors; extern int nerrors;
extern string rec_file, incl_file; extern string rec_file, incl_file;
extern int low_percentage, high_percentage;
extern int min_cases_for_jmptable;
extern int jmptable_option;

View file

@ -45,6 +45,7 @@ static string c_read = "LLread();\n";
static int nlabel; /* count for the generation of labels */ static int nlabel; /* count for the generation of labels */
static int firsts; /* are there any? */ static int firsts; /* are there any? */
static int listcount;
/* In this file the following routines are defined: */ /* In this file the following routines are defined: */
extern gencode(); extern gencode();
@ -60,6 +61,7 @@ STATIC getparams();
STATIC gettok(); STATIC gettok();
STATIC rulecode(); STATIC rulecode();
STATIC int * dopush(); STATIC int * dopush();
STATIC int * mk_tokenlist();
STATIC getaction(); STATIC getaction();
STATIC alternation(); STATIC alternation();
STATIC codeforterm(); STATIC codeforterm();
@ -68,6 +70,9 @@ STATIC gencases();
STATIC genpush(); STATIC genpush();
STATIC genpop(); STATIC genpop();
STATIC genincrdecr(); STATIC genincrdecr();
STATIC add_cases();
STATIC int analyze_switch();
STATIC out_list();
# define NOPOP -20000 # define NOPOP -20000
@ -82,6 +87,17 @@ doclose(f)
fclose(f); fclose(f);
} }
STATIC int *
mk_tokenlist()
{
register int *p = (int *)alloc(ntokens * sizeof(int)) + ntokens;
register int i = ntokens;
while (i--) *--p = -1;
return p;
}
gencode(argc) { gencode(argc) {
register p_file p = files; register p_file p = files;
@ -222,6 +238,7 @@ generate(f) p_file f; {
register p_first ff; register p_first ff;
int mustpop; int mustpop;
listcount = 0;
/* Generate first sets */ /* Generate first sets */
for (ff = f->f_firsts; ff; ff = ff->ff_next) { for (ff = f->f_firsts; ff; ff = ff->ff_next) {
macro(ff->ff_name,&nonterms[ff->ff_nont]); macro(ff->ff_name,&nonterms[ff->ff_nont]);
@ -502,23 +519,28 @@ rulecode(p,safety,mustscan,mustpop) register p_gram p; {
} }
STATIC STATIC
alternation(p, safety, mustscan, mustpop, lb) register p_gram p; { alternation(pp, safety, mustscan, mustpop, lb)
register FILE *f = fpars; p_gram pp;
{
register p_gram p = pp;
register FILE *f = fpars;
register p_link l; register p_link l;
int hulp, hulp1,hulp2; int hulp, hulp1,hulp2;
int haddefault = 0; int haddefault = 0;
int unsafe = 1;
int nsafe; int nsafe;
p_set set; p_set set;
p_set setalloc(); p_set setalloc();
int *tokenlist = mk_tokenlist();
int casecnt = 0;
int compacted;
int unsafe;
assert(safety < NOSCANDONE); assert(safety < NOSCANDONE);
l = g_getlink(p);
hulp = nlabel++; hulp = nlabel++;
hulp1 = nlabel++; hulp1 = nlabel++;
hulp2 = nlabel++; hulp2 = nlabel++;
if (!lb) lb = hulp1; if (!lb) lb = hulp1;
if (!onerror && safety <= SAFESCANDONE) unsafe = 0; unsafe = onerror || safety > SAFESCANDONE;
if (!unsafe) { if (!unsafe) {
genpop(mustpop); genpop(mustpop);
mustpop = NOPOP; mustpop = NOPOP;
@ -526,33 +548,76 @@ alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
if (unsafe && hulp1 == lb) { if (unsafe && hulp1 == lb) {
fprintf(f,"L_%d: \n", hulp1); fprintf(f,"L_%d: \n", hulp1);
} }
fputs("switch(LLcsymb) {\n", f); while (g_gettype(p) != EORULE) {
l = g_getlink(p);
if (l->l_flag & COND) {
if (!(l->l_flag & NOCONF)) {
set = setalloc();
setunion(set, l->l_others);
setintersect(set, l->l_symbs);
setminus(l->l_symbs, set);
setminus(l->l_others, set);
add_cases(set, tokenlist, casecnt++);
}
}
if (!unsafe && (l->l_flag & DEF)) {
haddefault = 1;
}
else add_cases(l->l_symbs, tokenlist, casecnt++);
if (l->l_flag & DEF) {
haddefault = 1;
}
if ((l->l_flag & COND) && !(l->l_flag & NOCONF)) {
p++;
if (g_gettype(p+1) == EORULE) {
setminus(g_getlink(p)->l_symbs, set);
free((p_mem) set);
continue;
}
free((p_mem) set);
if (!haddefault) {
}
else {
add_cases(l->l_others, tokenlist, casecnt++);
unsafe = 0;
}
break;
}
p++;
}
unsafe = onerror || safety > SAFESCANDONE;
p = pp;
haddefault = 0;
compacted = analyze_switch(tokenlist);
if (compacted) {
fputs("{", f);
out_list(tokenlist, listcount, casecnt);
fprintf(f, "switch(LL%d_tklist[LLcsymb]) {\n", listcount++);
}
else fputs("switch(LLcsymb) {\n", f);
casecnt = 0;
while (g_gettype(p) != EORULE) { while (g_gettype(p) != EORULE) {
l = g_getlink(p); l = g_getlink(p);
if (l->l_flag & COND) { if (l->l_flag & COND) {
if (l->l_flag & NOCONF) { if (l->l_flag & NOCONF) {
fputs("#ifdef ___NOCONFLICT___\n", f); fputs("#ifdef ___NOCONFLICT___\n", f);
} }
set = setalloc(); else gencases(tokenlist, casecnt++, compacted);
setunion(set, l->l_others);
setintersect(set, l->l_symbs);
setminus(l->l_symbs, set);
setminus(l->l_others, set);
gencases(set);
controlline(); controlline();
fputs("if (!",f); fputs("if (!",f);
getaction(0); getaction(0);
fprintf(f,") goto L_%d;\n", hulp); fprintf(f,") goto L_%d;\n", hulp);
if (l->l_flag & NOCONF) { if (l->l_flag & NOCONF) {
fputs("#endif\n", f); fputs("#endif\n", f);
free((p_mem) set);
} }
} }
if (!unsafe && (l->l_flag & DEF)) { if (!unsafe && (l->l_flag & DEF)) {
haddefault = 1; haddefault = 1;
fputs("default:\n", f); fputs("default:\n", f);
} }
else gencases(l->l_symbs); else gencases(tokenlist, casecnt++, compacted);
nsafe = SAFE; nsafe = SAFE;
if (l->l_flag & DEF) { if (l->l_flag & DEF) {
if (unsafe) { if (unsafe) {
@ -572,16 +637,13 @@ alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
p++; p++;
fprintf(f,"L_%d : ;\n",hulp); fprintf(f,"L_%d : ;\n",hulp);
if (g_gettype(p+1) == EORULE) { if (g_gettype(p+1) == EORULE) {
setminus(g_getlink(p)->l_symbs, set);
free((p_mem) set);
continue; continue;
} }
free((p_mem) set);
if (!haddefault) { if (!haddefault) {
fputs("default:\n", f); fputs("default:\n", f);
} }
else { else {
gencases(l->l_others); gencases(tokenlist, casecnt++, compacted);
safety = SAFE; safety = SAFE;
unsafe = 0; unsafe = 0;
} }
@ -594,7 +656,9 @@ alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
} }
p++; p++;
} }
if (compacted) fputs(c_close, f);
fputs(c_close, f); fputs(c_close, f);
free((p_mem) tokenlist);
} }
STATIC int * STATIC int *
@ -801,6 +865,7 @@ codeforterm(q,safety,toplevel) register p_term q; {
if (rep_kind != OPT && rep_kind != FIXED) fputs("continue;\n", f); if (rep_kind != OPT && rep_kind != FIXED) fputs("continue;\n", f);
if (rep_kind != FIXED) { if (rep_kind != FIXED) {
fputs(c_close, f); /* Close switch */ fputs(c_close, f); /* Close switch */
fputs(c_close, f);
if (rep_kind != OPT) { if (rep_kind != OPT) {
genpop(ispushed); genpop(ispushed);
fputs(c_break, f); fputs(c_break, f);
@ -826,30 +891,53 @@ genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
int hulp1, hulp2; int hulp1, hulp2;
int safeterm; int safeterm;
int termissafe = 0; int termissafe = 0;
int casecnt = 0;
int *tokenlist = mk_tokenlist();
int compacted;
if (rep_kind == PLUS) safeterm = gettout(q); if (rep_kind == PLUS) safeterm = gettout(q);
else if (rep_kind == OPT) safeterm = safety; else if (rep_kind == OPT) safeterm = safety;
else /* if (rep_kind == STAR) */ safeterm = max(safety, gettout(q)); else /* if (rep_kind == STAR) */ safeterm = max(safety, gettout(q));
hulp2 = nlabel++; hulp2 = nlabel++;
fprintf(f, "L_%d : ", hulp2); fprintf(f, "L_%d : ", hulp2);
fputs("switch(LLcsymb) {\n", f); if (q->t_flags & RESOLVER) {
hulp1 = nlabel++;
if (! (q->t_flags & NOCONF)) {
p1 = setalloc();
setunion(p1,q->t_first);
setintersect(p1,q->t_follow);
/*
* p1 now points to a set containing the conflicting
* symbols
*/
setminus(q->t_first, p1);
setminus(q->t_follow, p1);
setminus(q->t_contains, p1);
add_cases(p1, tokenlist, casecnt++);
free((p_mem) p1);
}
}
if (safeterm == 0 || (!onerror && safeterm <= SAFESCANDONE)) {
termissafe = 1;
}
else add_cases(q->t_follow, tokenlist, casecnt++);
if (!onerror && (q->t_flags & PERSISTENT) && safeterm != SAFE) {
add_cases(q->t_contains, tokenlist, casecnt);
}
else add_cases(q->t_first, tokenlist, casecnt);
compacted = analyze_switch(tokenlist);
fputs("{", f);
if (compacted) {
out_list(tokenlist, listcount, casecnt);
fprintf(f, "switch(LL%d_tklist[LLcsymb]) {\n", listcount++);
}
else fputs("switch(LLcsymb) {\n", f);
casecnt = 0;
if (q->t_flags & RESOLVER) { if (q->t_flags & RESOLVER) {
if (q->t_flags & NOCONF) { if (q->t_flags & NOCONF) {
fputs("#ifdef ___NOCONFLICT___\n", f); fputs("#ifdef ___NOCONFLICT___\n", f);
} }
hulp1 = nlabel++; else gencases(tokenlist, casecnt++, compacted);
p1 = setalloc();
setunion(p1,q->t_first);
setintersect(p1,q->t_follow);
/*
* p1 now points to a set containing the conflicting
* symbols
*/
setminus(q->t_first, p1);
setminus(q->t_follow, p1);
setminus(q->t_contains, p1);
gencases(p1);
free((p_mem) p1);
controlline(); controlline();
fputs("if (", f); fputs("if (", f);
getaction(0); getaction(0);
@ -860,9 +948,8 @@ genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
} }
if (safeterm == 0 || (!onerror && safeterm <= SAFESCANDONE)) { if (safeterm == 0 || (!onerror && safeterm <= SAFESCANDONE)) {
fputs("default:\n", f); fputs("default:\n", f);
termissafe = 1;
} }
else gencases(q->t_follow); else gencases(tokenlist, casecnt++, compacted);
if (rep_kind == OPT) genpop(ispushed); if (rep_kind == OPT) genpop(ispushed);
fputs(c_break, f); fputs(c_break, f);
if (! termissafe) { if (! termissafe) {
@ -880,10 +967,7 @@ genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
fputs(c_close, f); fputs(c_close, f);
fprintf(f,"else if (LL_%d & 1) goto L_%d;}\n",nvar, hulp2); fprintf(f,"else if (LL_%d & 1) goto L_%d;}\n",nvar, hulp2);
} }
if (!onerror && (q->t_flags & PERSISTENT) && safeterm != SAFE) { gencases(tokenlist, casecnt, compacted);
gencases(q->t_contains);
}
else gencases(q->t_first);
if (q->t_flags & RESOLVER) { if (q->t_flags & RESOLVER) {
fprintf(f, "L_%d : ;\n", hulp1); fprintf(f, "L_%d : ;\n", hulp1);
} }
@ -893,11 +977,14 @@ genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
fputs(rep_kind == STAR ? "if (!LL_i) " : "if (LL_i == 1) ", f); fputs(rep_kind == STAR ? "if (!LL_i) " : "if (LL_i == 1) ", f);
genpop(ispushed); genpop(ispushed);
} }
free((p_mem) tokenlist);
return safeterm; return safeterm;
} }
STATIC STATIC
gencases(setp) register p_set setp; { gencases(tokenlist, caseno, compacted)
int *tokenlist;
{
/* /*
* setp points to a bitset indicating which cases must * setp points to a bitset indicating which cases must
* be generated. * be generated.
@ -916,11 +1003,15 @@ gencases(setp) register p_set setp; {
register p_token p; register p_token p;
register int i; register int i;
if (compacted) fprintf(fpars, "case %d :\n", caseno);
for (i = 0, p = tokens; i < ntokens; i++, p++) { for (i = 0, p = tokens; i < ntokens; i++, p++) {
if (IN(setp,i)) { if (tokenlist[i] == caseno) {
fprintf(fpars, fprintf(fpars,
p->t_tokno<0400 ? "case /* '%s' */ %d : ;\n" compacted ?
: "case /* %s */ %d : ;\n", (p->t_tokno < 0400 ? "/* case '%s' */\n" :
"/* case %s */\n") :
p->t_tokno<0400 ? "case /* '%s' */ %d : ;\n"
: "case /* %s */ %d : ;\n",
p->t_string, i); p->t_string, i);
} }
} }
@ -975,3 +1066,58 @@ STATIC
genpop(d) { genpop(d) {
genincrdecr("decr", d); genincrdecr("decr", d);
} }
STATIC int
analyze_switch(tokenlist)
int *tokenlist;
{
register int i;
int ncases = 0;
int percentage;
int maxcase = 0, mincase = 0;
if (! jmptable_option) return 0;
for (i = 0; i < ntokens; i++) {
if (tokenlist[i] >= 0) {
ncases++;
if (! mincase) mincase = i + 1;
maxcase = i + 1;
}
}
if (ncases < min_cases_for_jmptable) return 0;
percentage = ncases * 100 / (maxcase - mincase);
fprintf(fpars, "/* percentage is %d */\n", percentage);
return percentage >= low_percentage && percentage <= high_percentage;
}
STATIC
add_cases(s, tokenlist, caseno)
p_set s;
int *tokenlist;
{
register int i;
for (i = 0; i < ntokens; i++) {
if (IN(s, i)) {
tokenlist[i] = caseno;
}
}
}
STATIC
out_list(tokenlist, listno, casecnt)
int *tokenlist;
{
register int i;
register FILE *f = fpars;
fprintf(f, "static %s LL%d_tklist[] = {",
casecnt <= 127 ? "char" : "short",
listno);
for (i = 0; i < ntokens; i++) {
fprintf(f, "%c%d,", i % 10 == 0 ? '\n': ' ', tokenlist[i]);
}
fputs(c_arrend, f);
}

View file

@ -62,3 +62,6 @@ string LLgenid = "/* LLgen generated code from source %s */\n";
t_token lextoken; t_token lextoken;
int nerrors; int nerrors;
string rec_file, incl_file; string rec_file, incl_file;
int low_percentage = 10, high_percentage = 30;
int min_cases_for_jmptable = 8;
int jmptable_option;

View file

@ -52,6 +52,10 @@ main(argc,argv) register string argv[]; {
while (argc >= 2 && (arg = argv[1], *arg == '-')) { while (argc >= 2 && (arg = argv[1], *arg == '-')) {
while (*++arg) { while (*++arg) {
switch(*arg) { switch(*arg) {
case 'j':
case 'J':
jmptable_option = 1;
continue;
case 'w': case 'w':
case 'W': case 'W':
wflag = 1; wflag = 1;
@ -60,6 +64,18 @@ main(argc,argv) register string argv[]; {
case 'V': case 'V':
verbose++; verbose++;
continue; continue;
case 'l':
case 'L':
low_percentage = atoi(++arg);
break;
case 'h':
case 'H':
high_percentage = atoi(++arg);
break;
case 'm':
case 'M':
min_cases_for_jmptable = atoi(++arg);
break;
# ifndef NDEBUG # ifndef NDEBUG
case 'd': case 'd':
case 'D': case 'D':
@ -91,9 +107,7 @@ main(argc,argv) register string argv[]; {
fprintf(stderr,"illegal option : %c\n",*arg); fprintf(stderr,"illegal option : %c\n",*arg);
exit(1); exit(1);
} }
# ifndef NDEBUG
break; break;
# endif
} }
argv++; argv++;
argc--; argc--;