ref: 9ced712a2ad70557a8ceb89ff3b969b92c85f68c
dir: /sys/src/cmd/lex/sub2.c/
# 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":"")); } 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"); } # 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++; } # 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"); } # 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]]; } 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