|  | # include "ldefs.h" | 
|  | uchar * | 
|  | getl(uchar *p)	/* return next line of input, throw away trailing '\n' */ | 
|  | /* returns 0 if eof is had immediately */ | 
|  | { | 
|  | int c; | 
|  | uchar *s, *t; | 
|  |  | 
|  | t = s = p; | 
|  | while(((c = gch()) != 0) && c != '\n') | 
|  | *t++ = c; | 
|  | *t = 0; | 
|  | if(c == 0 && s == t) return((uchar *)0); | 
|  | prev = '\n'; | 
|  | pres = '\n'; | 
|  | return(s); | 
|  | } | 
|  |  | 
|  | void | 
|  | printerr(char *type, char *fmt, va_list argl) | 
|  | { | 
|  | char buf[1024]; | 
|  |  | 
|  | if(!eof)fprint(errorf,"%d: ",yyline); | 
|  | fprint(errorf,"(%s) ", type); | 
|  | vseprint(buf, buf+sizeof(buf), fmt, argl); | 
|  | fprint(errorf, "%s\n", buf); | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | error(char *s,...) | 
|  | { | 
|  | va_list argl; | 
|  |  | 
|  | va_start(argl, s); | 
|  | printerr("Error", s, argl); | 
|  | va_end(argl); | 
|  | # ifdef DEBUG | 
|  | if(debug && sect != ENDSECTION) { | 
|  | sect1dump(); | 
|  | sect2dump(); | 
|  | } | 
|  | # endif | 
|  | if( | 
|  | # ifdef DEBUG | 
|  | debug || | 
|  | # endif | 
|  | report == 1) statistics(); | 
|  | exits("error");	/* error return code */ | 
|  | } | 
|  |  | 
|  | void | 
|  | warning(char *s,...) | 
|  | { | 
|  | va_list argl; | 
|  |  | 
|  | va_start(argl, s); | 
|  | printerr("Warning", s, argl); | 
|  | va_end(argl); | 
|  | Bflush(&fout); | 
|  | } | 
|  |  | 
|  | void | 
|  | lgate(void) | 
|  | { | 
|  | int fd; | 
|  |  | 
|  | if (lgatflg) return; | 
|  | lgatflg=1; | 
|  | if(foutopen == 0){ | 
|  | fd = create("lex.yy.c", OWRITE, 0666); | 
|  | if(fd < 0) | 
|  | error("Can't open lex.yy.c"); | 
|  | Binit(&fout, fd, OWRITE); | 
|  | foutopen = 1; | 
|  | } | 
|  | phead1(); | 
|  | } | 
|  |  | 
|  | void | 
|  | cclinter(int sw) | 
|  | { | 
|  | /* sw = 1 ==> ccl */ | 
|  | int i, j, k; | 
|  | int m; | 
|  | if(!sw){		/* is NCCL */ | 
|  | for(i=1;i<NCH;i++) | 
|  | symbol[i] ^= 1;			/* reverse value */ | 
|  | } | 
|  | for(i=1;i<NCH;i++) | 
|  | if(symbol[i]) break; | 
|  | if(i >= NCH) return; | 
|  | i = cindex[i]; | 
|  | /* see if ccl is already in our table */ | 
|  | j = 0; | 
|  | if(i){ | 
|  | for(j=1;j<NCH;j++){ | 
|  | if((symbol[j] && cindex[j] != i) || | 
|  | (!symbol[j] && cindex[j] == i)) break; | 
|  | } | 
|  | } | 
|  | if(j >= NCH) return;		/* already in */ | 
|  | m = 0; | 
|  | k = 0; | 
|  | for(i=1;i<NCH;i++) | 
|  | if(symbol[i]){ | 
|  | if(!cindex[i]){ | 
|  | cindex[i] = ccount; | 
|  | symbol[i] = 0; | 
|  | m = 1; | 
|  | } else k = 1; | 
|  | } | 
|  | /* m == 1 implies last value of ccount has been used */ | 
|  | if(m)ccount++; | 
|  | if(k == 0) return;	/* is now in as ccount wholly */ | 
|  | /* intersection must be computed */ | 
|  | for(i=1;i<NCH;i++){ | 
|  | if(symbol[i]){ | 
|  | m = 0; | 
|  | j = cindex[i];	/* will be non-zero */ | 
|  | for(k=1;k<NCH;k++){ | 
|  | if(cindex[k] == j){ | 
|  | if(symbol[k]) symbol[k] = 0; | 
|  | else { | 
|  | cindex[k] = ccount; | 
|  | m = 1; | 
|  | } | 
|  | } | 
|  | } | 
|  | if(m)ccount++; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | int | 
|  | usescape(int c) | 
|  | { | 
|  | int d; | 
|  | switch(c){ | 
|  | case 'n': c = '\n'; break; | 
|  | case 'r': c = '\r'; break; | 
|  | case 't': c = '\t'; break; | 
|  | case 'b': c = '\b'; break; | 
|  | case 'f': c = 014; break;		/* form feed for ascii */ | 
|  | case '0': case '1': case '2': case '3': | 
|  | case '4': case '5': case '6': case '7': | 
|  | c -= '0'; | 
|  | while('0' <= (d=gch()) && d <= '7'){ | 
|  | c = c * 8 + (d-'0'); | 
|  | if(!('0' <= peek && peek <= '7')) break; | 
|  | } | 
|  | break; | 
|  | } | 
|  | return(c); | 
|  | } | 
|  |  | 
|  | int | 
|  | lookup(uchar *s, uchar **t) | 
|  | { | 
|  | int i; | 
|  | i = 0; | 
|  | while(*t){ | 
|  | if(strcmp((char *)s, *(char **)t) == 0) | 
|  | return(i); | 
|  | i++; | 
|  | t++; | 
|  | } | 
|  | return(-1); | 
|  | } | 
|  |  | 
|  | int | 
|  | cpyact(void) | 
|  | { /* copy C action to the next ; or closing } */ | 
|  | int brac, c, mth; | 
|  | int savline, sw; | 
|  |  | 
|  | brac = 0; | 
|  | sw = TRUE; | 
|  | savline = 0; | 
|  |  | 
|  | while(!eof){ | 
|  | c = gch(); | 
|  | swt: | 
|  | switch( c ){ | 
|  |  | 
|  | case '|':	if(brac == 0 && sw == TRUE){ | 
|  | if(peek == '|')gch();		/* eat up an extra '|' */ | 
|  | return(0); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ';': | 
|  | if( brac == 0 ){ | 
|  | Bputc(&fout, c); | 
|  | Bputc(&fout, '\n'); | 
|  | return(1); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case '{': | 
|  | brac++; | 
|  | savline=yyline; | 
|  | break; | 
|  |  | 
|  | case '}': | 
|  | brac--; | 
|  | if( brac == 0 ){ | 
|  | Bputc(&fout, c); | 
|  | Bputc(&fout, '\n'); | 
|  | return(1); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case '/':	/* look for comments */ | 
|  | Bputc(&fout, c); | 
|  | c = gch(); | 
|  | if( c != '*' ) goto swt; | 
|  |  | 
|  | /* it really is a comment */ | 
|  |  | 
|  | Bputc(&fout, c); | 
|  | savline=yyline; | 
|  | while( c=gch() ){ | 
|  | if( c=='*' ){ | 
|  | Bputc(&fout, c); | 
|  | if( (c=gch()) == '/' ) goto loop; | 
|  | } | 
|  | Bputc(&fout, c); | 
|  | } | 
|  | yyline=savline; | 
|  | error( "EOF inside comment" ); | 
|  |  | 
|  | case '\'':	/* character constant */ | 
|  | mth = '\''; | 
|  | goto string; | 
|  |  | 
|  | case '"':	/* character string */ | 
|  | mth = '"'; | 
|  |  | 
|  | string: | 
|  |  | 
|  | Bputc(&fout, c); | 
|  | while( c=gch() ){ | 
|  | if( c=='\\' ){ | 
|  | Bputc(&fout, c); | 
|  | c=gch(); | 
|  | } | 
|  | else if( c==mth ) goto loop; | 
|  | Bputc(&fout, c); | 
|  | if (c == '\n') { | 
|  | yyline--; | 
|  | error( "Non-terminated string or character constant"); | 
|  | } | 
|  | } | 
|  | error( "EOF in string or character constant" ); | 
|  |  | 
|  | case '\0': | 
|  | yyline = savline; | 
|  | error("Action does not terminate"); | 
|  | default: | 
|  | break;		/* usual character */ | 
|  | } | 
|  | loop: | 
|  | if(c != ' ' && c != '\t' && c != '\n') sw = FALSE; | 
|  | Bputc(&fout, c); | 
|  | } | 
|  | error("Premature EOF"); | 
|  | return(0); | 
|  | } | 
|  |  | 
|  | int | 
|  | gch(void){ | 
|  | int c; | 
|  | prev = pres; | 
|  | c = pres = peek; | 
|  | peek = pushptr > pushc ? *--pushptr : Bgetc(fin); | 
|  | if(peek == Beof && sargc > 1){ | 
|  | Bterm(fin); | 
|  | fin = Bopen(sargv[fptr++],OREAD); | 
|  | if(fin == 0) | 
|  | error("Cannot open file %s",sargv[fptr-1]); | 
|  | peek = Bgetc(fin); | 
|  | sargc--; | 
|  | sargv++; | 
|  | } | 
|  | if(c == Beof) { | 
|  | eof = TRUE; | 
|  | Bterm(fin); | 
|  | fin = 0; | 
|  | return(0); | 
|  | } | 
|  | if(c == '\n')yyline++; | 
|  | return(c); | 
|  | } | 
|  |  | 
|  | int | 
|  | mn2(int a, int d, uintptr c) | 
|  | { | 
|  | name[tptr] = a; | 
|  | left[tptr] = d; | 
|  | right[tptr] = c; | 
|  | parent[tptr] = 0; | 
|  | nullstr[tptr] = 0; | 
|  | switch(a){ | 
|  | case RSTR: | 
|  | parent[d] = tptr; | 
|  | break; | 
|  | case BAR: | 
|  | case RNEWE: | 
|  | if(nullstr[d] || nullstr[c]) nullstr[tptr] = TRUE; | 
|  | parent[d] = parent[c] = tptr; | 
|  | break; | 
|  | case RCAT: | 
|  | case DIV: | 
|  | if(nullstr[d] && nullstr[c])nullstr[tptr] = TRUE; | 
|  | parent[d] = parent[c] = tptr; | 
|  | break; | 
|  | case RSCON: | 
|  | parent[d] = tptr; | 
|  | nullstr[tptr] = nullstr[d]; | 
|  | break; | 
|  | # ifdef DEBUG | 
|  | default: | 
|  | warning("bad switch mn2 %d %d",a,d); | 
|  | break; | 
|  | # endif | 
|  | } | 
|  | if(tptr > treesize) | 
|  | error("Parse tree too big %s",(treesize == TREESIZE?"\nTry using %e num":"")); | 
|  | return(tptr++); | 
|  | } | 
|  |  | 
|  | int | 
|  | mnp(int a, void *p) | 
|  | { | 
|  | name[tptr] = a; | 
|  | left[tptr] = 0; | 
|  | parent[tptr] = 0; | 
|  | nullstr[tptr] = 0; | 
|  | ptr[tptr] = p; | 
|  | switch(a){ | 
|  | case RCCL: | 
|  | case RNCCL: | 
|  | if(strlen(p) == 0) nullstr[tptr] = TRUE; | 
|  | break; | 
|  | default: | 
|  | error("bad switch mnp %d %P", a, p); | 
|  | break; | 
|  | } | 
|  | if(tptr > treesize) | 
|  | error("Parse tree too big %s",(treesize == TREESIZE?"\nTry using %e num":"")); | 
|  | return(tptr++); | 
|  | } | 
|  |  | 
|  | int | 
|  | mn1(int a, int d) | 
|  | { | 
|  | name[tptr] = a; | 
|  | left[tptr] = d; | 
|  | parent[tptr] = 0; | 
|  | nullstr[tptr] = 0; | 
|  | switch(a){ | 
|  | case STAR: | 
|  | case QUEST: | 
|  | nullstr[tptr] = TRUE; | 
|  | parent[d] = tptr; | 
|  | break; | 
|  | case PLUS: | 
|  | case CARAT: | 
|  | nullstr[tptr] = nullstr[d]; | 
|  | parent[d] = tptr; | 
|  | break; | 
|  | case S2FINAL: | 
|  | nullstr[tptr] = TRUE; | 
|  | break; | 
|  | # ifdef DEBUG | 
|  | case FINAL: | 
|  | case S1FINAL: | 
|  | break; | 
|  | default: | 
|  | warning("bad switch mn1 %d %d",a,d); | 
|  | break; | 
|  | # endif | 
|  | } | 
|  | if(tptr > treesize) | 
|  | error("Parse tree too big %s",(treesize == TREESIZE?"\nTry using %e num":"")); | 
|  | return(tptr++); | 
|  | } | 
|  |  | 
|  | int | 
|  | mn0(int a) | 
|  | { | 
|  | name[tptr] = a; | 
|  | parent[tptr] = 0; | 
|  | nullstr[tptr] = 0; | 
|  | if(a >= NCH) switch(a){ | 
|  | case RNULLS: nullstr[tptr] = TRUE; break; | 
|  | # ifdef DEBUG | 
|  | default: | 
|  | warning("bad switch mn0 %d",a); | 
|  | break; | 
|  | # endif | 
|  | } | 
|  | if(tptr > treesize) | 
|  | error("Parse tree too big %s",(treesize == TREESIZE?"\nTry using %e num":"")); | 
|  | return(tptr++); | 
|  | } | 
|  |  | 
|  | void | 
|  | munputc(int p) | 
|  | { | 
|  | *pushptr++ = peek;		/* watch out for this */ | 
|  | peek = p; | 
|  | if(pushptr >= pushc+TOKENSIZE) | 
|  | error("Too many characters pushed"); | 
|  | } | 
|  |  | 
|  | void | 
|  | munputs(uchar *p) | 
|  | { | 
|  | int i,j; | 
|  | *pushptr++ = peek; | 
|  | peek = p[0]; | 
|  | i = strlen((char*)p); | 
|  | for(j = i-1; j>=1; j--) | 
|  | *pushptr++ = p[j]; | 
|  | if(pushptr >= pushc+TOKENSIZE) | 
|  | error("Too many characters pushed"); | 
|  | } | 
|  |  | 
|  | int | 
|  | dupl(int n) | 
|  | { | 
|  | /* duplicate the subtree whose root is n, return ptr to it */ | 
|  | int i; | 
|  |  | 
|  | i = name[n]; | 
|  | if(i < NCH) return(mn0(i)); | 
|  | switch(i){ | 
|  | case RNULLS: | 
|  | return(mn0(i)); | 
|  | case RCCL: case RNCCL: | 
|  | return(mnp(i,ptr[n])); | 
|  | case FINAL: case S1FINAL: case S2FINAL: | 
|  | return(mn1(i,left[n])); | 
|  | case STAR: case QUEST: case PLUS: case CARAT: | 
|  | return(mn1(i,dupl(left[n]))); | 
|  | case RSTR: case RSCON: | 
|  | return(mn2(i,dupl(left[n]),right[n])); | 
|  | case BAR: case RNEWE: case RCAT: case DIV: | 
|  | return(mn2(i,dupl(left[n]),dupl(right[n]))); | 
|  | # ifdef DEBUG | 
|  | default: | 
|  | warning("bad switch dupl %d",n); | 
|  | # endif | 
|  | } | 
|  | return(0); | 
|  | } | 
|  |  | 
|  | # ifdef DEBUG | 
|  | void | 
|  | allprint(int c) | 
|  | { | 
|  | if(c < 0) | 
|  | c += 256;	/* signed char */ | 
|  | switch(c){ | 
|  | case 014: | 
|  | print("\\f"); | 
|  | charc++; | 
|  | break; | 
|  | case '\n': | 
|  | print("\\n"); | 
|  | charc++; | 
|  | break; | 
|  | case '\t': | 
|  | print("\\t"); | 
|  | charc++; | 
|  | break; | 
|  | case '\b': | 
|  | print("\\b"); | 
|  | charc++; | 
|  | break; | 
|  | case ' ': | 
|  | print("\\\bb"); | 
|  | break; | 
|  | default: | 
|  | if(!isprint(c)){ | 
|  | print("\\%-3o",c); | 
|  | charc += 3; | 
|  | } else | 
|  | print("%c", c); | 
|  | break; | 
|  | } | 
|  | charc++; | 
|  | } | 
|  |  | 
|  | void | 
|  | strpt(uchar *s) | 
|  | { | 
|  | charc = 0; | 
|  | while(*s){ | 
|  | allprint(*s++); | 
|  | if(charc > LINESIZE){ | 
|  | charc = 0; | 
|  | print("\n\t"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | sect1dump(void) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | print("Sect 1:\n"); | 
|  | if(def[0]){ | 
|  | print("str	trans\n"); | 
|  | i = -1; | 
|  | while(def[++i]) | 
|  | print("%s\t%s\n",def[i],subs[i]); | 
|  | } | 
|  | if(sname[0]){ | 
|  | print("start names\n"); | 
|  | i = -1; | 
|  | while(sname[++i]) | 
|  | print("%s\n",sname[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | sect2dump(void) | 
|  | { | 
|  | print("Sect 2:\n"); | 
|  | treedump(); | 
|  | } | 
|  |  | 
|  | void | 
|  | treedump(void) | 
|  | { | 
|  | int t; | 
|  | uchar *p; | 
|  | print("treedump %d nodes:\n",tptr); | 
|  | for(t=0;t<tptr;t++){ | 
|  | print("%4d ",t); | 
|  | parent[t] ? print("p=%4d",parent[t]) : print("      "); | 
|  | print("  "); | 
|  | if(name[t] < NCH) | 
|  | allprint(name[t]); | 
|  | else switch(name[t]){ | 
|  | case RSTR: | 
|  | print("%d ",left[t]); | 
|  | allprint(right[t]); | 
|  | break; | 
|  | case RCCL: | 
|  | print("ccl "); | 
|  | allprint(ptr[t]); | 
|  | break; | 
|  | case RNCCL: | 
|  | print("nccl "); | 
|  | allprint(ptr[t]); | 
|  | break; | 
|  | case DIV: | 
|  | print("/ %d %d",left[t],right[t]); | 
|  | break; | 
|  | case BAR: | 
|  | print("| %d %d",left[t],right[t]); | 
|  | break; | 
|  | case RCAT: | 
|  | print("cat %d %d",left[t],right[t]); | 
|  | break; | 
|  | case PLUS: | 
|  | print("+ %d",left[t]); | 
|  | break; | 
|  | case STAR: | 
|  | print("* %d",left[t]); | 
|  | break; | 
|  | case CARAT: | 
|  | print("^ %d",left[t]); | 
|  | break; | 
|  | case QUEST: | 
|  | print("? %d",left[t]); | 
|  | break; | 
|  | case RNULLS: | 
|  | print("nullstring"); | 
|  | break; | 
|  | case FINAL: | 
|  | print("final %d",left[t]); | 
|  | break; | 
|  | case S1FINAL: | 
|  | print("s1final %d",left[t]); | 
|  | break; | 
|  | case S2FINAL: | 
|  | print("s2final %d",left[t]); | 
|  | break; | 
|  | case RNEWE: | 
|  | print("new %d %d",left[t],right[t]); | 
|  | break; | 
|  | case RSCON: | 
|  | p = (uchar *)right[t]; | 
|  | print("start %s",sname[*p++-1]); | 
|  | while(*p) | 
|  | print(", %s",sname[*p++-1]); | 
|  | print(" %d",left[t]); | 
|  | break; | 
|  | default: | 
|  | print("unknown %d %d %d",name[t],left[t],right[t]); | 
|  | break; | 
|  | } | 
|  | if(nullstr[t])print("\t(null poss.)"); | 
|  | print("\n"); | 
|  | } | 
|  | } | 
|  | # endif |