| # 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 |