Added code to generate dense switches
This commit is contained in:
parent
c146e278fc
commit
4934f830fc
|
@ -73,3 +73,6 @@ extern string LLgenid; /* LLgen identification string */
|
|||
extern t_token lextoken; /* the current token */
|
||||
extern int nerrors;
|
||||
extern string rec_file, incl_file;
|
||||
extern int low_percentage, high_percentage;
|
||||
extern int min_cases_for_jmptable;
|
||||
extern int jmptable_option;
|
||||
|
|
|
@ -45,6 +45,7 @@ static string c_read = "LLread();\n";
|
|||
|
||||
static int nlabel; /* count for the generation of labels */
|
||||
static int firsts; /* are there any? */
|
||||
static int listcount;
|
||||
|
||||
/* In this file the following routines are defined: */
|
||||
extern gencode();
|
||||
|
@ -60,6 +61,7 @@ STATIC getparams();
|
|||
STATIC gettok();
|
||||
STATIC rulecode();
|
||||
STATIC int * dopush();
|
||||
STATIC int * mk_tokenlist();
|
||||
STATIC getaction();
|
||||
STATIC alternation();
|
||||
STATIC codeforterm();
|
||||
|
@ -68,6 +70,9 @@ STATIC gencases();
|
|||
STATIC genpush();
|
||||
STATIC genpop();
|
||||
STATIC genincrdecr();
|
||||
STATIC add_cases();
|
||||
STATIC int analyze_switch();
|
||||
STATIC out_list();
|
||||
|
||||
# define NOPOP -20000
|
||||
|
||||
|
@ -82,6 +87,17 @@ doclose(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) {
|
||||
register p_file p = files;
|
||||
|
||||
|
@ -222,6 +238,7 @@ generate(f) p_file f; {
|
|||
register p_first ff;
|
||||
int mustpop;
|
||||
|
||||
listcount = 0;
|
||||
/* Generate first sets */
|
||||
for (ff = f->f_firsts; ff; ff = ff->ff_next) {
|
||||
macro(ff->ff_name,&nonterms[ff->ff_nont]);
|
||||
|
@ -502,23 +519,28 @@ rulecode(p,safety,mustscan,mustpop) register p_gram p; {
|
|||
}
|
||||
|
||||
STATIC
|
||||
alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
|
||||
alternation(pp, safety, mustscan, mustpop, lb)
|
||||
p_gram pp;
|
||||
{
|
||||
register p_gram p = pp;
|
||||
register FILE *f = fpars;
|
||||
register p_link l;
|
||||
int hulp, hulp1,hulp2;
|
||||
int haddefault = 0;
|
||||
int unsafe = 1;
|
||||
int nsafe;
|
||||
p_set set;
|
||||
p_set setalloc();
|
||||
int *tokenlist = mk_tokenlist();
|
||||
int casecnt = 0;
|
||||
int compacted;
|
||||
int unsafe;
|
||||
|
||||
assert(safety < NOSCANDONE);
|
||||
l = g_getlink(p);
|
||||
hulp = nlabel++;
|
||||
hulp1 = nlabel++;
|
||||
hulp2 = nlabel++;
|
||||
if (!lb) lb = hulp1;
|
||||
if (!onerror && safety <= SAFESCANDONE) unsafe = 0;
|
||||
unsafe = onerror || safety > SAFESCANDONE;
|
||||
if (!unsafe) {
|
||||
genpop(mustpop);
|
||||
mustpop = NOPOP;
|
||||
|
@ -526,33 +548,76 @@ alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
|
|||
if (unsafe && hulp1 == lb) {
|
||||
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) {
|
||||
l = g_getlink(p);
|
||||
if (l->l_flag & COND) {
|
||||
if (l->l_flag & NOCONF) {
|
||||
fputs("#ifdef ___NOCONFLICT___\n", f);
|
||||
}
|
||||
set = setalloc();
|
||||
setunion(set, l->l_others);
|
||||
setintersect(set, l->l_symbs);
|
||||
setminus(l->l_symbs, set);
|
||||
setminus(l->l_others, set);
|
||||
gencases(set);
|
||||
else gencases(tokenlist, casecnt++, compacted);
|
||||
controlline();
|
||||
fputs("if (!",f);
|
||||
getaction(0);
|
||||
fprintf(f,") goto L_%d;\n", hulp);
|
||||
if (l->l_flag & NOCONF) {
|
||||
fputs("#endif\n", f);
|
||||
free((p_mem) set);
|
||||
}
|
||||
}
|
||||
if (!unsafe && (l->l_flag & DEF)) {
|
||||
haddefault = 1;
|
||||
fputs("default:\n", f);
|
||||
}
|
||||
else gencases(l->l_symbs);
|
||||
else gencases(tokenlist, casecnt++, compacted);
|
||||
nsafe = SAFE;
|
||||
if (l->l_flag & DEF) {
|
||||
if (unsafe) {
|
||||
|
@ -572,16 +637,13 @@ alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
|
|||
p++;
|
||||
fprintf(f,"L_%d : ;\n",hulp);
|
||||
if (g_gettype(p+1) == EORULE) {
|
||||
setminus(g_getlink(p)->l_symbs, set);
|
||||
free((p_mem) set);
|
||||
continue;
|
||||
}
|
||||
free((p_mem) set);
|
||||
if (!haddefault) {
|
||||
fputs("default:\n", f);
|
||||
}
|
||||
else {
|
||||
gencases(l->l_others);
|
||||
gencases(tokenlist, casecnt++, compacted);
|
||||
safety = SAFE;
|
||||
unsafe = 0;
|
||||
}
|
||||
|
@ -594,7 +656,9 @@ alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
|
|||
}
|
||||
p++;
|
||||
}
|
||||
if (compacted) fputs(c_close, f);
|
||||
fputs(c_close, f);
|
||||
free((p_mem) tokenlist);
|
||||
}
|
||||
|
||||
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 != FIXED) {
|
||||
fputs(c_close, f); /* Close switch */
|
||||
fputs(c_close, f);
|
||||
if (rep_kind != OPT) {
|
||||
genpop(ispushed);
|
||||
fputs(c_break, f);
|
||||
|
@ -826,18 +891,18 @@ genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
|
|||
int hulp1, hulp2;
|
||||
int safeterm;
|
||||
int termissafe = 0;
|
||||
int casecnt = 0;
|
||||
int *tokenlist = mk_tokenlist();
|
||||
int compacted;
|
||||
|
||||
if (rep_kind == PLUS) safeterm = gettout(q);
|
||||
else if (rep_kind == OPT) safeterm = safety;
|
||||
else /* if (rep_kind == STAR) */ safeterm = max(safety, gettout(q));
|
||||
hulp2 = nlabel++;
|
||||
fprintf(f, "L_%d : ", hulp2);
|
||||
fputs("switch(LLcsymb) {\n", f);
|
||||
if (q->t_flags & RESOLVER) {
|
||||
if (q->t_flags & NOCONF) {
|
||||
fputs("#ifdef ___NOCONFLICT___\n", f);
|
||||
}
|
||||
hulp1 = nlabel++;
|
||||
if (! (q->t_flags & NOCONF)) {
|
||||
p1 = setalloc();
|
||||
setunion(p1,q->t_first);
|
||||
setintersect(p1,q->t_follow);
|
||||
|
@ -848,8 +913,31 @@ genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
|
|||
setminus(q->t_first, p1);
|
||||
setminus(q->t_follow, p1);
|
||||
setminus(q->t_contains, p1);
|
||||
gencases(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 & NOCONF) {
|
||||
fputs("#ifdef ___NOCONFLICT___\n", f);
|
||||
}
|
||||
else gencases(tokenlist, casecnt++, compacted);
|
||||
controlline();
|
||||
fputs("if (", f);
|
||||
getaction(0);
|
||||
|
@ -860,9 +948,8 @@ genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
|
|||
}
|
||||
if (safeterm == 0 || (!onerror && safeterm <= SAFESCANDONE)) {
|
||||
fputs("default:\n", f);
|
||||
termissafe = 1;
|
||||
}
|
||||
else gencases(q->t_follow);
|
||||
else gencases(tokenlist, casecnt++, compacted);
|
||||
if (rep_kind == OPT) genpop(ispushed);
|
||||
fputs(c_break, f);
|
||||
if (! termissafe) {
|
||||
|
@ -880,10 +967,7 @@ genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
|
|||
fputs(c_close, f);
|
||||
fprintf(f,"else if (LL_%d & 1) goto L_%d;}\n",nvar, hulp2);
|
||||
}
|
||||
if (!onerror && (q->t_flags & PERSISTENT) && safeterm != SAFE) {
|
||||
gencases(q->t_contains);
|
||||
}
|
||||
else gencases(q->t_first);
|
||||
gencases(tokenlist, casecnt, compacted);
|
||||
if (q->t_flags & RESOLVER) {
|
||||
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);
|
||||
genpop(ispushed);
|
||||
}
|
||||
free((p_mem) tokenlist);
|
||||
return safeterm;
|
||||
}
|
||||
|
||||
STATIC
|
||||
gencases(setp) register p_set setp; {
|
||||
gencases(tokenlist, caseno, compacted)
|
||||
int *tokenlist;
|
||||
{
|
||||
/*
|
||||
* setp points to a bitset indicating which cases must
|
||||
* be generated.
|
||||
|
@ -916,9 +1003,13 @@ gencases(setp) register p_set setp; {
|
|||
register p_token p;
|
||||
register int i;
|
||||
|
||||
if (compacted) fprintf(fpars, "case %d :\n", caseno);
|
||||
for (i = 0, p = tokens; i < ntokens; i++, p++) {
|
||||
if (IN(setp,i)) {
|
||||
if (tokenlist[i] == caseno) {
|
||||
fprintf(fpars,
|
||||
compacted ?
|
||||
(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);
|
||||
|
@ -975,3 +1066,58 @@ STATIC
|
|||
genpop(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);
|
||||
}
|
||||
|
|
|
@ -62,3 +62,6 @@ string LLgenid = "/* LLgen generated code from source %s */\n";
|
|||
t_token lextoken;
|
||||
int nerrors;
|
||||
string rec_file, incl_file;
|
||||
int low_percentage = 10, high_percentage = 30;
|
||||
int min_cases_for_jmptable = 8;
|
||||
int jmptable_option;
|
||||
|
|
|
@ -52,6 +52,10 @@ main(argc,argv) register string argv[]; {
|
|||
while (argc >= 2 && (arg = argv[1], *arg == '-')) {
|
||||
while (*++arg) {
|
||||
switch(*arg) {
|
||||
case 'j':
|
||||
case 'J':
|
||||
jmptable_option = 1;
|
||||
continue;
|
||||
case 'w':
|
||||
case 'W':
|
||||
wflag = 1;
|
||||
|
@ -60,6 +64,18 @@ main(argc,argv) register string argv[]; {
|
|||
case 'V':
|
||||
verbose++;
|
||||
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
|
||||
case 'd':
|
||||
case 'D':
|
||||
|
@ -91,9 +107,7 @@ main(argc,argv) register string argv[]; {
|
|||
fprintf(stderr,"illegal option : %c\n",*arg);
|
||||
exit(1);
|
||||
}
|
||||
# ifndef NDEBUG
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
argv++;
|
||||
argc--;
|
||||
|
|
Loading…
Reference in a new issue