blob: 9221aea7130b04c2d53cc4f20e7cbedb0929edf4 [file] [log] [blame]
# include "ldefs.h"
void
cfoll(int v)
{
int i,j,k;
uchar *p;
i = name[v];
if(i < NCH) i = 1; /* character */
switch(i){
case 1: case RSTR: case RCCL: case RNCCL: case RNULLS:
for(j=0;j<tptr;j++)
tmpstat[j] = FALSE;
count = 0;
follow(v);
# ifdef PP
padd(foll,v); /* packing version */
# endif
# ifndef PP
add(foll,v); /* no packing version */
# endif
if(i == RSTR) cfoll(left[v]);
else if(i == RCCL || i == RNCCL){ /* compress ccl list */
for(j=1; j<NCH;j++)
symbol[j] = (i==RNCCL);
p = ptr[v];
while(*p)
symbol[*p++] = (i == RCCL);
p = pcptr;
for(j=1;j<NCH;j++)
if(symbol[j]){
for(k=0;p+k < pcptr; k++)
if(cindex[j] == *(p+k))
break;
if(p+k >= pcptr)*pcptr++ = cindex[j];
}
*pcptr++ = 0;
if(pcptr > pchar + pchlen)
error("Too many packed character classes");
ptr[v] = p;
name[v] = RCCL; /* RNCCL eliminated */
# ifdef DEBUG
if(debug && *p){
print("ccl %d: %d",v,*p++);
while(*p)
print(", %d",*p++);
print("\n");
}
# endif
}
break;
case CARAT:
cfoll(left[v]);
break;
case STAR: case PLUS: case QUEST: case RSCON:
cfoll(left[v]);
break;
case BAR: case RCAT: case DIV: case RNEWE:
cfoll(left[v]);
cfoll(right[v]);
break;
# ifdef DEBUG
case FINAL:
case S1FINAL:
case S2FINAL:
break;
default:
warning("bad switch cfoll %d",v);
# endif
}
}
# ifdef DEBUG
void
pfoll(void)
{
int i,k,*p;
int j;
/* print sets of chars which may follow positions */
print("pos\tchars\n");
for(i=0;i<tptr;i++)
if(p=foll[i]){
j = *p++;
if(j >= 1){
print("%d:\t%d",i,*p++);
for(k=2;k<=j;k++)
print(", %d",*p++);
print("\n");
}
}
}
# endif
void
add(int **array, int n)
{
int i, *temp;
uchar *ctemp;
temp = nxtpos;
ctemp = tmpstat;
array[n] = nxtpos; /* note no packing is done in positions */
*temp++ = count;
for(i=0;i<tptr;i++)
if(ctemp[i] == TRUE)
*temp++ = i;
nxtpos = temp;
if(nxtpos >= positions+maxpos)
error("Too many positions %s",(maxpos== MAXPOS?"\nTry using %p num":""));
return;
}
void
follow(int v)
{
int p;
if(v >= tptr-1)return;
p = parent[v];
if(p == 0) return;
switch(name[p]){
/* will not be CHAR RNULLS FINAL S1FINAL S2FINAL RCCL RNCCL */
case RSTR:
if(tmpstat[p] == FALSE){
count++;
tmpstat[p] = TRUE;
}
break;
case STAR: case PLUS:
first(v);
follow(p);
break;
case BAR: case QUEST: case RNEWE:
follow(p);
break;
case RCAT: case DIV:
if(v == left[p]){
if(nullstr[right[p]])
follow(p);
first(right[p]);
}
else follow(p);
break;
case RSCON: case CARAT:
follow(p);
break;
# ifdef DEBUG
default:
warning("bad switch follow %d",p);
# endif
}
}
void
first(int v) /* calculate set of positions with v as root which can be active initially */
{
int i;
uchar *p;
i = name[v];
if(i < NCH)i = 1;
switch(i){
case 1: case RCCL: case RNCCL: case RNULLS: case FINAL: case S1FINAL: case S2FINAL:
if(tmpstat[v] == FALSE){
count++;
tmpstat[v] = TRUE;
}
break;
case BAR: case RNEWE:
first(left[v]);
first(right[v]);
break;
case CARAT:
if(stnum % 2 == 1)
first(left[v]);
break;
case RSCON:
i = stnum/2 +1;
p = (uchar*)right[v];
while(*p)
if(*p++ == i){
first(left[v]);
break;
}
break;
case STAR: case QUEST: case PLUS: case RSTR:
first(left[v]);
break;
case RCAT: case DIV:
first(left[v]);
if(nullstr[left[v]])
first(right[v]);
break;
# ifdef DEBUG
default:
warning("bad switch first %d",v);
# endif
}
}
void
cgoto(void)
{
int i, j, s;
int npos, curpos, n;
int tryit;
uchar tch[NCH];
int tst[NCH];
uchar *q;
/* generate initial state, for each start condition */
Bprint(&fout,"int yyvstop[] = {\n0,\n");
while(stnum < 2 || stnum/2 < sptr){
for(i = 0; i<tptr; i++) tmpstat[i] = 0;
count = 0;
if(tptr > 0)first(tptr-1);
add(state,stnum);
# ifdef DEBUG
if(debug){
if(stnum > 1)
print("%s:\n",sname[stnum/2]);
pstate(stnum);
}
# endif
stnum++;
}
stnum--;
/* even stnum = might not be at line begin */
/* odd stnum = must be at line begin */
/* even states can occur anywhere, odd states only at line begin */
for(s = 0; s <= stnum; s++){
tryit = FALSE;
cpackflg[s] = FALSE;
sfall[s] = -1;
acompute(s);
for(i=0;i<NCH;i++) symbol[i] = 0;
npos = *state[s];
for(i = 1; i<=npos; i++){
curpos = *(state[s]+i);
if(name[curpos] < NCH) symbol[name[curpos]] = TRUE;
else switch(name[curpos]){
case RCCL:
tryit = TRUE;
q = ptr[curpos];
while(*q){
for(j=1;j<NCH;j++)
if(cindex[j] == *q)
symbol[j] = TRUE;
q++;
}
break;
case RSTR:
symbol[right[curpos]] = TRUE;
break;
# ifdef DEBUG
case RNULLS:
case FINAL:
case S1FINAL:
case S2FINAL:
break;
default:
warning("bad switch cgoto %d state %d",curpos,s);
break;
# endif
}
}
# ifdef DEBUG
if(debug){
print("State %d transitions on:\n\t",s);
charc = 0;
for(i = 1; i<NCH; i++){
if(symbol[i]) allprint(i);
if(charc > LINESIZE){
charc = 0;
print("\n\t");
}
}
print("\n");
}
# endif
/* for each char, calculate next state */
n = 0;
for(i = 1; i<NCH; i++){
if(symbol[i]){
nextstate(s,i); /* executed for each state, transition pair */
xstate = notin(stnum);
if(xstate == -2) warning("bad state %d %o",s,i);
else if(xstate == -1){
if(stnum >= nstates)
error("Too many states %s",(nstates == NSTATES ? "\nTry using %n num":""));
add(state,++stnum);
# ifdef DEBUG
if(debug)pstate(stnum);
# endif
tch[n] = i;
tst[n++] = stnum;
} else { /* xstate >= 0 ==> state exists */
tch[n] = i;
tst[n++] = xstate;
}
}
}
tch[n] = 0;
tst[n] = -1;
/* pack transitions into permanent array */
if(n > 0) packtrans(s,tch,tst,n,tryit);
else gotof[s] = -1;
}
Bprint(&fout,"0};\n");
}
/* Beware -- 70% of total CPU time is spent in this subroutine -
if you don't believe me - try it yourself ! */
void
nextstate(int s, int c)
{
int j, *newpos;
uchar *temp, *tz;
int *pos, i, *f, num, curpos, number;
/* state to goto from state s on char c */
num = *state[s];
temp = tmpstat;
pos = state[s] + 1;
for(i = 0; i<num; i++){
curpos = *pos++;
j = name[curpos];
if(j < NCH && j == c
|| j == RSTR && c == right[curpos]
|| j == RCCL && member(c, ptr[curpos])){
f = foll[curpos];
number = *f;
newpos = f+1;
for(j=0;j<number;j++)
temp[*newpos++] = 2;
}
}
j = 0;
tz = temp + tptr;
while(temp < tz){
if(*temp == 2){
j++;
*temp++ = 1;
}
else *temp++ = 0;
}
count = j;
}
int
notin(int n)
{ /* see if tmpstat occurs previously */
int *j,k;
uchar *temp;
int i;
if(count == 0)
return(-2);
temp = tmpstat;
for(i=n;i>=0;i--){ /* for each state */
j = state[i];
if(count == *j++){
for(k=0;k<count;k++)
if(!temp[*j++])break;
if(k >= count)
return(i);
}
}
return(-1);
}
void
packtrans(int st, uchar *tch, int *tst, int cnt, int tryit)
{
/* pack transitions into nchar, nexts */
/* nchar is terminated by '\0', nexts uses cnt, followed by elements */
/* gotof[st] = index into nchr, nexts for state st */
/* sfall[st] = t implies t is fall back state for st */
/* == -1 implies no fall back */
int i,j,k;
int cmin, cval, tcnt, diff, p, *ast;
uchar *ach;
int go[NCH], temp[NCH], c;
int swork[NCH];
uchar cwork[NCH];
int upper;
rcount += cnt;
cmin = -1;
cval = NCH;
ast = tst;
ach = tch;
/* try to pack transitions using ccl's */
if(tryit){ /* ccl's used */
for(i=1;i<NCH;i++){
go[i] = temp[i] = -1;
symbol[i] = 1;
}
for(i=0;i<cnt;i++){
go[tch[i]] = tst[i];
symbol[tch[i]] = 0;
}
for(i=0; i<cnt;i++){
c = match[tch[i]];
if(go[c] != tst[i] || c == tch[i])
temp[tch[i]] = tst[i];
}
/* fill in error entries */
for(i=1;i<NCH;i++)
if(symbol[i]) temp[i] = -2; /* error trans */
/* count them */
k = 0;
for(i=1;i<NCH;i++)
if(temp[i] != -1)k++;
if(k <cnt){ /* compress by char */
# ifdef DEBUG
if(debug) print("use compression %d, %d vs %d\n",st,k,cnt);
# endif
k = 0;
for(i=1;i<NCH;i++)
if(temp[i] != -1){
cwork[k] = i;
swork[k++] = (temp[i] == -2 ? -1 : temp[i]);
}
cwork[k] = 0;
# ifdef PC
ach = cwork;
ast = swork;
cnt = k;
cpackflg[st] = TRUE;
# endif
}
}
for(i=0; i<st; i++){ /* get most similar state */
/* reject state with more transitions, state already represented by a third state,
and state which is compressed by char if ours is not to be */
if(sfall[i] != -1) continue;
if(cpackflg[st] == 1) if(!(cpackflg[i] == 1)) continue;
p = gotof[i];
if(p == -1) /* no transitions */ continue;
tcnt = nexts[p];
if(tcnt > cnt) continue;
diff = 0;
j = 0;
upper = p + tcnt;
while(ach[j] && p < upper){
while(ach[j] < nchar[p] && ach[j]){diff++; j++; }
if(ach[j] == 0)break;
if(ach[j] > nchar[p]){diff=NCH;break;}
/* ach[j] == nchar[p] */
if(ast[j] != nexts[++p] || ast[j] == -1 || (cpackflg[st] && ach[j] != match[ach[j]]))diff++;
j++;
}
while(ach[j]){
diff++;
j++;
}
if(p < upper)diff = NCH;
if(diff < cval && diff < tcnt){
cval = diff;
cmin = i;
if(cval == 0)break;
}
}
/* cmin = state "most like" state st */
# ifdef DEBUG
if(debug)print("select st %d for st %d diff %d\n",cmin,st,cval);
# endif
# ifdef PS
if(cmin != -1){ /* if we can use st cmin */
gotof[st] = nptr;
k = 0;
sfall[st] = cmin;
p = gotof[cmin]+1;
j = 0;
while(ach[j]){
/* if cmin has a transition on c, then so will st */
/* st may be "larger" than cmin, however */
while(ach[j] < nchar[p-1] && ach[j]){
k++;
nchar[nptr] = ach[j];
nexts[++nptr] = ast[j];
j++;
}
if(nchar[p-1] == 0)break;
if(ach[j] > nchar[p-1]){
warning("bad transition %d %d",st,cmin);
goto nopack;
}
/* ach[j] == nchar[p-1] */
if(ast[j] != nexts[p] || ast[j] == -1 || (cpackflg[st] && ach[j] != match[ach[j]])){
k++;
nchar[nptr] = ach[j];
nexts[++nptr] = ast[j];
}
p++;
j++;
}
while(ach[j]){
nchar[nptr] = ach[j];
nexts[++nptr] = ast[j++];
k++;
}
nexts[gotof[st]] = cnt = k;
nchar[nptr++] = 0;
} else {
# endif
nopack:
/* stick it in */
gotof[st] = nptr;
nexts[nptr] = cnt;
for(i=0;i<cnt;i++){
nchar[nptr] = ach[i];
nexts[++nptr] = ast[i];
}
nchar[nptr++] = 0;
# ifdef PS
}
# endif
if(cnt < 1){
gotof[st] = -1;
nptr--;
} else
if(nptr > ntrans)
error("Too many transitions %s",(ntrans==NTRANS?"\nTry using %a num":""));
}
# ifdef DEBUG
void
pstate(int s)
{
int *p,i,j;
print("State %d:\n",s);
p = state[s];
i = *p++;
if(i == 0) return;
print("%4d",*p++);
for(j = 1; j<i; j++){
print(", %4d",*p++);
if(j%30 == 0)print("\n");
}
print("\n");
return;
}
# endif
int
member(int d, uchar *t)
{
int c;
uchar *s;
c = d;
s = t;
c = cindex[c];
while(*s)
if(*s++ == c) return(1);
return(0);
}
# ifdef DEBUG
void
stprt(int i)
{
int p, t;
print("State %d:",i);
/* print actions, if any */
t = atable[i];
if(t != -1)print(" final");
print("\n");
if(cpackflg[i] == TRUE)print("backup char in use\n");
if(sfall[i] != -1)print("fall back state %d\n",sfall[i]);
p = gotof[i];
if(p == -1) return;
print("(%d transitions)\n",nexts[p]);
while(nchar[p]){
charc = 0;
if(nexts[p+1] >= 0)
print("%d\t",nexts[p+1]);
else print("err\t");
allprint(nchar[p++]);
while(nexts[p] == nexts[p+1] && nchar[p]){
if(charc > LINESIZE){
charc = 0;
print("\n\t");
}
allprint(nchar[p++]);
}
print("\n");
}
print("\n");
}
# endif
void
acompute(int s) /* compute action list = set of poss. actions */
{
int *p, i, j;
int cnt, m;
int temp[300], k, neg[300], n;
k = 0;
n = 0;
p = state[s];
cnt = *p++;
if(cnt > 300)
error("Too many positions for one state - acompute");
for(i=0;i<cnt;i++){
if(name[*p] == FINAL)temp[k++] = left[*p];
else if(name[*p] == S1FINAL){temp[k++] = left[*p];
if (left[*p] >= NACTIONS) error("Too many right contexts");
extra[left[*p]] = 1;
} else if(name[*p] == S2FINAL)neg[n++] = left[*p];
p++;
}
atable[s] = -1;
if(k < 1 && n < 1) return;
# ifdef DEBUG
if(debug) print("final %d actions:",s);
# endif
/* sort action list */
for(i=0; i<k; i++)
for(j=i+1;j<k;j++)
if(temp[j] < temp[i]){
m = temp[j];
temp[j] = temp[i];
temp[i] = m;
}
/* remove dups */
for(i=0;i<k-1;i++)
if(temp[i] == temp[i+1]) temp[i] = 0;
/* copy to permanent quarters */
atable[s] = aptr;
# ifdef DEBUG
Bprint(&fout,"/* actions for state %d */",s);
# endif
Bputc(&fout, '\n');
for(i=0;i<k;i++)
if(temp[i] != 0){
Bprint(&fout,"%d,\n",temp[i]);
# ifdef DEBUG
if(debug)
print("%d ",temp[i]);
# endif
aptr++;
}
for(i=0;i<n;i++){ /* copy fall back actions - all neg */
Bprint(&fout,"%d,\n",neg[i]);
aptr++;
# ifdef DEBUG
if(debug)print("%d ",neg[i]);
# endif
}
# ifdef DEBUG
if(debug)print("\n");
# endif
Bprint(&fout,"0,\n");
aptr++;
return;
}
# ifdef DEBUG
void
pccl(void) {
/* print character class sets */
int i, j;
print("char class intersection\n");
for(i=0; i< ccount; i++){
charc = 0;
print("class %d:\n\t",i);
for(j=1;j<NCH;j++)
if(cindex[j] == i){
allprint(j);
if(charc > LINESIZE){
print("\n\t");
charc = 0;
}
}
print("\n");
}
charc = 0;
print("match:\n");
for(i=0;i<NCH;i++){
allprint(match[i]);
if(charc > LINESIZE){
print("\n");
charc = 0;
}
}
print("\n");
return;
}
# endif
void
mkmatch(void)
{
int i;
uchar tab[NCH];
for(i=0; i<ccount; i++)
tab[i] = 0;
for(i=1;i<NCH;i++)
if(tab[cindex[i]] == 0)
tab[cindex[i]] = i;
/* tab[i] = principal char for new ccl i */
for(i = 1; i<NCH; i++)
match[i] = tab[cindex[i]];
return;
}
void
layout(void)
{
/* format and output final program's tables */
int i, j, k;
int top, bot, startup, omin;
for(i=0; i<outsize;i++)
verify[i] = advance[i] = 0;
omin = 0;
yytop = 0;
for(i=0; i<= stnum; i++){ /* for each state */
j = gotof[i];
if(j == -1){
stoff[i] = 0;
continue;
}
bot = j;
while(nchar[j])j++;
top = j - 1;
# ifdef DEBUG
if (debug) {
print("State %d: (layout)\n", i);
for(j=bot; j<=top;j++) {
print(" %o", nchar[j]);
if (j%10==0) print("\n");
}
print("\n");
}
# endif
while(verify[omin+NCH]) omin++;
startup = omin;
# ifdef DEBUG
if (debug) print("bot,top %d, %d startup begins %d\n",bot,top,startup);
# endif
do {
startup += 1;
if(startup > outsize - NCH)
error("output table overflow");
for(j = bot; j<= top; j++){
k = startup + nchar[j];
if(verify[k])break;
}
} while (j <= top);
/* have found place */
# ifdef DEBUG
if (debug) print(" startup going to be %d\n", startup);
# endif
for(j = bot; j<= top; j++){
k = startup + nchar[j];
verify[k] = i+1; /* state number + 1*/
advance[k] = nexts[j+1]+1; /* state number + 1*/
if(yytop < k) yytop = k;
}
stoff[i] = startup;
}
/* stoff[i] = offset into verify, advance for trans for state i */
/* put out yywork */
Bprint(&fout,"# define YYTYPE %s\n",stnum+1 >= NCH ? "int" : "Uchar");
Bprint(&fout,"struct yywork { YYTYPE verify, advance; } yycrank[] = {\n");
for(i=0;i<=yytop;i+=4){
for(j=0;j<4;j++){
k = i+j;
if(verify[k])
Bprint(&fout,"%d,%d,\t",verify[k],advance[k]);
else
Bprint(&fout,"0,0,\t");
}
Bputc(&fout, '\n');
}
Bprint(&fout,"0,0};\n");
/* put out yysvec */
Bprint(&fout,"struct yysvf yysvec[] = {\n");
Bprint(&fout,"0,\t0,\t0,\n");
for(i=0;i<=stnum;i++){ /* for each state */
if(cpackflg[i])stoff[i] = -stoff[i];
Bprint(&fout,"yycrank+%d,\t",stoff[i]);
if(sfall[i] != -1)
Bprint(&fout,"yysvec+%d,\t", sfall[i]+1); /* state + 1 */
else Bprint(&fout,"0,\t\t");
if(atable[i] != -1)
Bprint(&fout,"yyvstop+%d,",atable[i]);
else Bprint(&fout,"0,\t");
# ifdef DEBUG
Bprint(&fout,"\t\t/* state %d */",i);
# endif
Bputc(&fout, '\n');
}
Bprint(&fout,"0,\t0,\t0};\n");
/* put out yymatch */
Bprint(&fout,"struct yywork *yytop = yycrank+%d;\n",yytop);
Bprint(&fout,"struct yysvf *yybgin = yysvec+1;\n");
Bprint(&fout,"Uchar yymatch[] = {\n");
for(i=0; i<NCH; i+=8){
for(j=0; j<8; j++){
int fbch;
fbch = match[i+j];
if(isprint(fbch) && fbch != '\'' && fbch != '\\')
Bprint(&fout,"'%c' ,",fbch);
else Bprint(&fout,"0%-3o,",fbch);
}
Bputc(&fout, '\n');
}
Bprint(&fout,"0};\n");
/* put out yyextra */
Bprint(&fout,"Uchar yyextra[] = {\n");
for(i=0;i<casecount;i+=8){
for(j=0;j<8;j++)
Bprint(&fout, "%d,", i+j<NACTIONS ?
extra[i+j] : 0);
Bputc(&fout, '\n');
}
Bprint(&fout,"0};\n");
}
# ifdef PP
void
padd(int **array, int n)
{
int i, *j, k;
array[n] = nxtpos;
if(count == 0){
*nxtpos++ = 0;
return;
}
for(i=tptr-1;i>=0;i--){
j = array[i];
if(j && *j++ == count){
for(k=0;k<count;k++)
if(!tmpstat[*j++])break;
if(k >= count){
array[n] = array[i];
return;
}
}
}
add(array,n);
}
# endif