1: # 2: # include "stdio.h" 3: /* C command 4: /* written by John F. Reiser 5: /* July/August 1978 6: */ 7: 8: #define STATIC 9: 10: #define STDIN 0 11: #define STDOUT 1 12: #define STDERR 2 13: #define READ 0 14: #define WRITE 1 15: #define SALT '#' 16: #ifndef BUFSIZ 17: #define BUFSIZ 512 18: #endif 19: 20: char *pbeg,*pbuf,*pend; 21: char *outp,*inp; 22: char *newp; 23: char cinit; 24: 25: /* some code depends on whether characters are sign or zero extended */ 26: /* #if '\377' < 0 not used here, old cpp doesn't understand */ 27: #if pdp11 | vax 28: #define COFF 128 29: #else 30: #define COFF 0 31: #endif 32: 33: # if gcos 34: #define ALFSIZ 512 /* alphabet size */ 35: # else 36: #define ALFSIZ 256 /* alphabet size */ 37: # endif 38: char macbit[ALFSIZ+11]; 39: char toktyp[ALFSIZ]; 40: #define BLANK 1 41: #define IDENT 2 42: #define NUMBR 3 43: 44: /* a superimposed code is used to reduce the number of calls to the 45: /* symbol table lookup routine. (if the kth character of an identifier 46: /* is 'a' and there are no macro names whose kth character is 'a' 47: /* then the identifier cannot be a macro name, hence there is no need 48: /* to look in the symbol table.) 'scw1' enables the test based on 49: /* single characters and their position in the identifier. 'scw2' 50: /* enables the test based on adjacent pairs of characters and their 51: /* position in the identifier. scw1 typically costs 1 indexed fetch, 52: /* an AND, and a jump per character of identifier, until the identifier 53: /* is known as a non-macro name or until the end of the identifier. 54: /* scw1 is inexpensive. scw2 typically costs 4 indexed fetches, 55: /* an add, an AND, and a jump per character of identifier, but it is also 56: /* slightly more effective at reducing symbol table searches. 57: /* scw2 usually costs too much because the symbol table search is 58: /* usually short; but if symbol table search should become expensive, 59: /* the code is here. 60: /* using both scw1 and scw2 is of dubious value. 61: */ 62: #define scw1 1 63: #define scw2 0 64: 65: #if scw2 66: char t21[ALFSIZ],t22[ALFSIZ],t23[ALFSIZ+8]; 67: #endif 68: 69: #if scw1 70: #define b0 1 71: #define b1 2 72: #define b2 4 73: #define b3 8 74: #define b4 16 75: #define b5 32 76: #define b6 64 77: #define b7 128 78: #endif 79: 80: #define IB 1 81: #define SB 2 82: #define NB 4 83: #define CB 8 84: #define QB 16 85: #define WB 32 86: char fastab[ALFSIZ]; 87: char slotab[ALFSIZ]; 88: char *ptrtab; 89: #define isslo (ptrtab==(slotab+COFF)) 90: #define isid(a) ((fastab+COFF)[a]&IB) 91: #define isspc(a) (ptrtab[a]&SB) 92: #define isnum(a) ((fastab+COFF)[a]&NB) 93: #define iscom(a) ((fastab+COFF)[a]&CB) 94: #define isquo(a) ((fastab+COFF)[a]&QB) 95: #define iswarn(a) ((fastab+COFF)[a]&WB) 96: 97: #define eob(a) ((a)>=pend) 98: #define bob(a) (pbeg>=(a)) 99: 100: char buffer[8+BUFSIZ+BUFSIZ+8]; 101: 102: # define SBSIZE 12000 103: char sbf[SBSIZE]; 104: char *savch = sbf; 105: 106: # define DROP 0xFE /* special character not legal ASCII or EBCDIC */ 107: # define WARN DROP 108: # define SAME 0 109: # define MAXINC 10 110: # define MAXFRE 14 /* max buffers of macro pushback */ 111: # define MAXFRM 31 /* max number of formals/actuals to a macro */ 112: 113: static char warnc = WARN; 114: 115: int mactop,fretop; 116: char *instack[MAXFRE],*bufstack[MAXFRE],*endbuf[MAXFRE]; 117: 118: int plvl; /* parenthesis level during scan for macro actuals */ 119: int maclin; /* line number of macro call requiring actuals */ 120: char *macfil; /* file name of macro call requiring actuals */ 121: char *macnam; /* name of macro requiring actuals */ 122: int maclvl; /* # calls since last decrease in nesting level */ 123: char *macforw; /* pointer which must be exceeded to decrease nesting level */ 124: int macdam; /* offset to macforw due to buffer shifting */ 125: 126: #if tgp 127: int tgpscan; /* flag for dump(); */ 128: #endif 129: 130: STATIC int inctop[MAXINC]; 131: STATIC char *fnames[MAXINC]; 132: STATIC char *dirnams[MAXINC]; /* actual directory of #include files */ 133: STATIC int fins[MAXINC]; 134: STATIC int lineno[MAXINC]; 135: 136: STATIC char *dirs[10]; /* -I and <> directories */ 137: char *strdex(), *copy(), *subst(), *trmdir(); 138: struct symtab *stsym(); 139: STATIC int fin = STDIN; 140: STATIC FILE *fout = stdout; 141: STATIC int nd = 1; 142: STATIC int pflag; /* don't put out lines "# 12 foo.c" */ 143: STATIC int passcom; /* don't delete comments */ 144: STATIC int rflag; /* allow macro recursion */ 145: STATIC int ifno; 146: # define NPREDEF 20 147: STATIC char *prespc[NPREDEF]; 148: STATIC char **predef = prespc; 149: STATIC char *punspc[NPREDEF]; 150: STATIC char **prund = punspc; 151: STATIC int exfail; 152: struct symtab { 153: char *name; 154: char *value; 155: } *lastsym, *lookup(), *slookup(); 156: 157: # if gcos 158: #include <setjmp.h> 159: static jmp_buf env; 160: # define main mainpp 161: # undef exit 162: # define exit(S) longjmp(env, 1) 163: # define open(S,D) fileno(fopen(S, "r")) 164: # define close(F) fclose(_f[F]) 165: extern FILE *_f[]; 166: # define symsiz 500 167: # else 168: # define symsiz 400 169: # endif 170: STATIC struct symtab stab[symsiz]; 171: 172: STATIC struct symtab *defloc; 173: STATIC struct symtab *udfloc; 174: STATIC struct symtab *incloc; 175: STATIC struct symtab *ifloc; 176: STATIC struct symtab *elsloc; 177: STATIC struct symtab *eifloc; 178: STATIC struct symtab *ifdloc; 179: STATIC struct symtab *ifnloc; 180: STATIC struct symtab *ysysloc; 181: STATIC struct symtab *varloc; 182: STATIC struct symtab *lneloc; 183: STATIC struct symtab *ulnloc; 184: STATIC struct symtab *uflloc; 185: STATIC int trulvl; 186: STATIC int flslvl; 187: 188: sayline() { 189: if (pflag==0) fprintf(fout,"# %d \"%s\"\n", lineno[ifno], fnames[ifno]); 190: } 191: 192: /* data structure guide 193: /* 194: /* most of the scanning takes place in the buffer: 195: /* 196: /* (low address) (high address) 197: /* pbeg pbuf pend 198: /* | <-- BUFSIZ chars --> | <-- BUFSIZ chars --> | 199: /* _______________________________________________________________________ 200: /* |_______________________________________________________________________| 201: /* | | | 202: /* |<-- waiting -->| |<-- waiting --> 203: /* | to be |<-- current -->| to be 204: /* | written | token | scanned 205: /* | | | 206: /* outp inp p 207: /* 208: /* *outp first char not yet written to output file 209: /* *inp first char of current token 210: /* *p first char not yet scanned 211: /* 212: /* macro expansion: write from *outp to *inp (chars waiting to be written), 213: /* ignore from *inp to *p (chars of the macro call), place generated 214: /* characters in front of *p (in reverse order), update pointers, 215: /* resume scanning. 216: /* 217: /* symbol table pointers point to just beyond the end of macro definitions; 218: /* the first preceding character is the number of formal parameters. 219: /* the appearance of a formal in the body of a definition is marked by 220: /* 2 chars: the char WARN, and a char containing the parameter number. 221: /* the first char of a definition is preceded by a zero character. 222: /* 223: /* when macro expansion attempts to back up over the beginning of the 224: /* buffer, some characters preceding *pend are saved in a side buffer, 225: /* the address of the side buffer is put on 'instack', and the rest 226: /* of the main buffer is moved to the right. the end of the saved buffer 227: /* is kept in 'endbuf' since there may be nulls in the saved buffer. 228: /* 229: /* similar action is taken when an 'include' statement is processed, 230: /* except that the main buffer must be completely emptied. the array 231: /* element 'inctop[ifno]' records the last side buffer saved when 232: /* file 'ifno' was included. these buffers remain dormant while 233: /* the file is being read, and are reactivated at end-of-file. 234: /* 235: /* instack[0 : mactop] holds the addresses of all pending side buffers. 236: /* instack[inctop[ifno]+1 : mactop-1] holds the addresses of the side 237: /* buffers which are "live"; the side buffers instack[0 : inctop[ifno]] 238: /* are dormant, waiting for end-of-file on the current file. 239: /* 240: /* space for side buffers is obtained from 'savch' and is never returned. 241: /* bufstack[0:fretop-1] holds addresses of side buffers which 242: /* are available for use. 243: */ 244: 245: dump() { 246: /* write part of buffer which lies between outp and inp . 247: /* this should be a direct call to 'write', but the system slows to a crawl 248: /* if it has to do an unaligned copy. thus we buffer. this silly loop 249: /* is 15% of the total time, thus even the 'putc' macro is too slow. 250: */ 251: register char *p1,*p2; register FILE *f; 252: if ((p1=outp)==inp || flslvl!=0) return; 253: #if tgp 254: #define MAXOUT 80 255: if (!tgpscan) {/* scan again to insure <= MAXOUT chars between linefeeds */ 256: register char c,*pblank; char savc,stopc,brk; 257: tgpscan=1; brk=stopc=pblank=0; p2=inp; savc= *p2; *p2='\0'; 258: while (c= *p1++) { 259: if (c=='\\') c= *p1++; 260: if (stopc==c) stopc=0; 261: else if (c=='"' || c=='\'') stopc=c; 262: if (p1-outp>MAXOUT && pblank!=0) { 263: *pblank++='\n'; inp=pblank; dump(); brk=1; pblank=0; 264: } 265: if (c==' ' && stopc==0) pblank=p1-1; 266: } 267: if (brk) sayline(); 268: *p2=savc; inp=p2; p1=outp; tgpscan=0; 269: } 270: #endif 271: f=fout; 272: # if gcos 273: /* filter out "$ program c" card if first line of input */ 274: /* gmatch is a simple pattern matcher in the GCOS Standard Library */ 275: { static int gmfirst = 0; 276: if (!gmfirst) { 277: ++gmfirst; 278: if (gmatch(p1, "^$*program[ \t]*c*")) 279: p1 = strdex(p1, '\n'); 280: } 281: } 282: # endif 283: while (p1<inp) putc(*p1++,f); 284: outp=p1; 285: } 286: 287: char * 288: refill(p) register char *p; { 289: /* dump buffer. save chars from inp to p. read into buffer at pbuf, 290: /* contiguous with p. update pointers, return new p. 291: */ 292: register char *np,*op; register int ninbuf; 293: dump(); np=pbuf-(p-inp); op=inp; 294: if (bob(np+1)) {pperror("token too long"); np=pbeg; p=inp+BUFSIZ;} 295: macdam += np-inp; outp=inp=np; 296: while (op<p) *np++= *op++; 297: p=np; 298: for (;;) { 299: if (mactop>inctop[ifno]) {/* retrieve hunk of pushed-back macro text */ 300: op=instack[--mactop]; np=pbuf; 301: do {while (*np++= *op++);} while (op<endbuf[mactop]); pend=np-1; 302: /* make buffer space avail for 'include' processing */ 303: if (fretop<MAXFRE) bufstack[fretop++]=instack[mactop]; 304: return(p); 305: } else {/* get more text from file(s) */ 306: maclvl=0; 307: if (0<(ninbuf=read(fin,pbuf,BUFSIZ))) { 308: pend=pbuf+ninbuf; *pend='\0'; 309: return(p); 310: } 311: /* end of #include file */ 312: if (ifno==0) {/* end of input */ 313: if (plvl!=0) { 314: int n=plvl,tlin=lineno[ifno]; char *tfil=fnames[ifno]; 315: lineno[ifno]=maclin; fnames[ifno]=macfil; 316: pperror("%s: unterminated macro call",macnam); 317: lineno[ifno]=tlin; fnames[ifno]=tfil; 318: np=p; *np++='\n'; /* shut off unterminated quoted string */ 319: while (--n>=0) *np++=')'; /* supply missing parens */ 320: pend=np; *np='\0'; if (plvl<0) plvl=0; 321: return(p); 322: } 323: inp=p; dump(); exit(exfail); 324: } 325: close(fin); fin=fins[--ifno]; dirs[0]=dirnams[ifno]; sayline(); 326: } 327: } 328: } 329: 330: #define BEG 0 331: #define LF 1 332: 333: char * 334: cotoken(p) register char *p; { 335: register int c,i; char quoc; 336: static int state = BEG; 337: 338: if (state!=BEG) goto prevlf; 339: for (;;) { 340: again: 341: while (!isspc(*p++)); 342: switch (*(inp=p-1)) { 343: case 0: { 344: if (eob(--p)) {p=refill(p); goto again;} 345: else ++p; /* ignore null byte */ 346: } break; 347: case '|': case '&': for (;;) {/* sloscan only */ 348: if (*p++== *inp) break; 349: if (eob(--p)) p=refill(p); 350: else break; 351: } break; 352: case '=': case '!': for (;;) {/* sloscan only */ 353: if (*p++=='=') break; 354: if (eob(--p)) p=refill(p); 355: else break; 356: } break; 357: case '<': case '>': for (;;) {/* sloscan only */ 358: if (*p++=='=' || p[-2]==p[-1]) break; 359: if (eob(--p)) p=refill(p); 360: else break; 361: } break; 362: case '\\': for (;;) { 363: if (*p++=='\n') {++lineno[ifno]; break;} 364: if (eob(--p)) p=refill(p); 365: else {++p; break;} 366: } break; 367: case '/': for (;;) { 368: if (*p++=='*') {/* comment */ 369: if (!passcom) {inp=p-2; dump(); ++flslvl;} 370: for (;;) { 371: while (!iscom(*p++)); 372: if (p[-1]=='*') for (;;) { 373: if (*p++=='/') goto endcom; 374: if (eob(--p)) { 375: if (!passcom) {inp=p; p=refill(p);} 376: else if ((p-inp)>=BUFSIZ) {/* split long comment */ 377: inp=p; p=refill(p); /* last char written is '*' */ 378: putc('/',fout); /* terminate first part */ 379: /* and fake start of 2nd */ 380: outp=inp=p-=3; *p++='/'; *p++='*'; *p++='*'; 381: } else p=refill(p); 382: } else break; 383: } else if (p[-1]=='\n') { 384: ++lineno[ifno]; if (!passcom) putc('\n',fout); 385: } else if (eob(--p)) { 386: if (!passcom) {inp=p; p=refill(p);} 387: else if ((p-inp)>=BUFSIZ) {/* split long comment */ 388: inp=p; p=refill(p); 389: putc('*',fout); putc('/',fout); 390: outp=inp=p-=2; *p++='/'; *p++='*'; 391: } else p=refill(p); 392: } else ++p; /* ignore null byte */ 393: } 394: endcom: 395: if (!passcom) {outp=inp=p; --flslvl; goto again;} 396: break; 397: } 398: if (eob(--p)) p=refill(p); 399: else break; 400: } break; 401: # if gcos 402: case '`': 403: # endif 404: case '"': case '\'': { 405: quoc=p[-1]; 406: for (;;) { 407: while (!isquo(*p++)); 408: if (p[-1]==quoc) break; 409: if (p[-1]=='\n') {--p; break;} /* bare \n terminates quotation */ 410: if (p[-1]=='\\') for (;;) { 411: if (*p++=='\n') {++lineno[ifno]; break;} /* escaped \n ignored */ 412: if (eob(--p)) p=refill(p); 413: else {++p; break;} 414: } else if (eob(--p)) p=refill(p); 415: else ++p; /* it was a different quote character */ 416: } 417: } break; 418: case '\n': { 419: ++lineno[ifno]; if (isslo) {state=LF; return(p);} 420: prevlf: 421: state=BEG; 422: for (;;) { 423: if (*p++=='#') return(p); 424: if (eob(inp= --p)) p=refill(p); 425: else goto again; 426: } 427: } break; 428: case '0': case '1': case '2': case '3': case '4': 429: case '5': case '6': case '7': case '8': case '9': 430: for (;;) { 431: while (isnum(*p++)); 432: if (eob(--p)) p=refill(p); 433: else break; 434: } break; 435: case 'A': case 'B': case 'C': case 'D': case 'E': 436: case 'F': case 'G': case 'H': case 'I': case 'J': 437: case 'K': case 'L': case 'M': case 'N': case 'O': 438: case 'P': case 'Q': case 'R': case 'S': case 'T': 439: case 'U': case 'V': case 'W': case 'X': case 'Y': 440: case 'Z': case '_': 441: case 'a': case 'b': case 'c': case 'd': case 'e': 442: case 'f': case 'g': case 'h': case 'i': case 'j': 443: case 'k': case 'l': case 'm': case 'n': case 'o': 444: case 'p': case 'q': case 'r': case 's': case 't': 445: case 'u': case 'v': case 'w': case 'x': case 'y': 446: case 'z': 447: #if scw1 448: #define tmac1(c,bit) if (!xmac1(c,bit,&)) goto nomac 449: #define xmac1(c,bit,op) ((macbit+COFF)[c] op (bit)) 450: #else 451: #define tmac1(c,bit) 452: #define xmac1(c,bit,op) 453: #endif 454: 455: #if scw2 456: #define tmac2(c0,c1,cpos) if (!xmac2(c0,c1,cpos,&)) goto nomac 457: #define xmac2(c0,c1,cpos,op)\ 458: ((macbit+COFF)[(t21+COFF)[c0]+(t22+COFF)[c1]] op (t23+COFF+cpos)[c0]) 459: #else 460: #define tmac2(c0,c1,cpos) 461: #define xmac2(c0,c1,cpos,op) 462: #endif 463: 464: if (flslvl) goto nomac; 465: for (;;) { 466: c= p[-1]; tmac1(c,b0); 467: i= *p++; if (!isid(i)) goto endid; tmac1(i,b1); tmac2(c,i,0); 468: c= *p++; if (!isid(c)) goto endid; tmac1(c,b2); tmac2(i,c,1); 469: i= *p++; if (!isid(i)) goto endid; tmac1(i,b3); tmac2(c,i,2); 470: c= *p++; if (!isid(c)) goto endid; tmac1(c,b4); tmac2(i,c,3); 471: i= *p++; if (!isid(i)) goto endid; tmac1(i,b5); tmac2(c,i,4); 472: c= *p++; if (!isid(c)) goto endid; tmac1(c,b6); tmac2(i,c,5); 473: i= *p++; if (!isid(i)) goto endid; tmac1(i,b7); tmac2(c,i,6); 474: tmac2(i,0,7); 475: while (isid(*p++)); 476: if (eob(--p)) {refill(p); p=inp+1; continue;} 477: goto lokid; 478: endid: 479: if (eob(--p)) {refill(p); p=inp+1; continue;} 480: tmac2(p[-1],0,-1+(p-inp)); 481: lokid: 482: slookup(inp,p,0); if (newp) {p=newp; goto again;} 483: else break; 484: nomac: 485: while (isid(*p++)); 486: if (eob(--p)) {p=refill(p); goto nomac;} 487: else break; 488: } break; 489: } /* end of switch */ 490: 491: if (isslo) return(p); 492: } /* end of infinite loop */ 493: } 494: 495: char * 496: skipbl(p) register char *p; {/* get next non-blank token */ 497: do {outp=inp=p; p=cotoken(p);} while ((toktyp+COFF)[*inp]==BLANK); 498: return(p); 499: } 500: 501: char * 502: unfill(p) register char *p; { 503: /* take <= BUFSIZ chars from right end of buffer and put them on instack . 504: /* slide rest of buffer to the right, update pointers, return new p. 505: */ 506: register char *np,*op; register int d; 507: if (mactop>=MAXFRE) { 508: pperror("%s: too much pushback",macnam); 509: p=inp=pend; dump(); /* begin flushing pushback */ 510: while (mactop>inctop[ifno]) {p=refill(p); p=inp=pend; dump();} 511: } 512: if (fretop>0) np=bufstack[--fretop]; 513: else { 514: np=savch; savch+=BUFSIZ; 515: if (savch>=sbf+SBSIZE) {pperror("no space"); exit(exfail);} 516: *savch++='\0'; 517: } 518: instack[mactop]=np; op=pend-BUFSIZ; if (op<p) op=p; 519: for (;;) {while (*np++= *op++); if (eob(op)) break;} /* out with old */ 520: endbuf[mactop++]=np; /* mark end of saved text */ 521: np=pbuf+BUFSIZ; op=pend-BUFSIZ; pend=np; if (op<p) op=p; 522: while (outp<op) *--np= *--op; /* slide over new */ 523: if (bob(np)) pperror("token too long"); 524: d=np-outp; outp+=d; inp+=d; macdam+=d; return(p+d); 525: } 526: 527: char * 528: doincl(p) register char *p; { 529: int filok,inctype; 530: register char *cp; char **dirp,*nfil; char filname[BUFSIZ]; 531: 532: p=skipbl(p); cp=filname; 533: if (*inp++=='<') {/* special <> syntax */ 534: inctype=1; 535: for (;;) { 536: outp=inp=p; p=cotoken(p); 537: if (*inp=='\n') {--p; *cp='\0'; break;} 538: if (*inp=='>') { *cp='\0'; break;} 539: # ifdef gimpel 540: if (*inp=='.' && !intss()) *inp='#'; 541: # endif 542: while (inp<p) *cp++= *inp++; 543: } 544: } else if (inp[-1]=='"') {/* regular "" syntax */ 545: inctype=0; 546: # ifdef gimpel 547: while (inp<p) {if (*inp=='.' && !intss()) *inp='#'; *cp++= *inp++;} 548: # else 549: while (inp<p) *cp++= *inp++; 550: # endif 551: if (*--cp=='"') *cp='\0'; 552: } else {pperror("bad include syntax",0); inctype=2;} 553: /* flush current file to \n , then write \n */ 554: ++flslvl; do {outp=inp=p; p=cotoken(p);} while (*inp!='\n'); --flslvl; 555: inp=p; dump(); if (inctype==2) return(p); 556: /* look for included file */ 557: if (ifno+1 >=MAXINC) { 558: pperror("Unreasonable include nesting",0); return(p); 559: } 560: if((nfil=savch)>sbf+SBSIZE-BUFSIZ) {pperror("no space"); exit(exfail);} 561: filok=0; 562: for (dirp=dirs+inctype; *dirp; ++dirp) { 563: if ( 564: # if gcos 565: strdex(filname, '/') 566: # else 567: filname[0]=='/' 568: # endif 569: || **dirp=='\0') strcpy(nfil,filname); 570: else { 571: strcpy(nfil,*dirp); 572: # if unix || gcos 573: strcat(nfil,"/"); 574: # endif 575: #ifdef ibm 576: #ifndef gimpel 577: strcat(nfil,"."); 578: #endif 579: #endif 580: strcat(nfil,filname); 581: } 582: if (0<(fins[ifno+1]=open(nfil,READ))) { 583: filok=1; fin=fins[++ifno]; break; 584: } 585: } 586: if (filok==0) pperror("Can't find include file %s",filname); 587: else { 588: lineno[ifno]=1; fnames[ifno]=cp=nfil; while (*cp++); savch=cp; 589: dirnams[ifno]=dirs[0]=trmdir(copy(nfil)); 590: sayline(); 591: /* save current contents of buffer */ 592: while (!eob(p)) p=unfill(p); 593: inctop[ifno]=mactop; 594: } 595: return(p); 596: } 597: 598: equfrm(a,p1,p2) register char *a,*p1,*p2; { 599: register char c; int flag; 600: c= *p2; *p2='\0'; 601: flag=strcmp(a,p1); *p2=c; return(flag==SAME); 602: } 603: 604: char * 605: dodef(p) char *p; {/* process '#define' */ 606: register char *pin,*psav,*cf; 607: char **pf,**qf; int b,c,params; struct symtab *np; 608: char *oldval,*oldsavch; 609: char *formal[MAXFRM]; /* formal[n] is name of nth formal */ 610: char formtxt[BUFSIZ]; /* space for formal names */ 611: 612: if (savch>sbf+SBSIZE-BUFSIZ) {pperror("too much defining"); return(p);} 613: oldsavch=savch; /* to reclaim space if redefinition */ 614: ++flslvl; /* prevent macro expansion during 'define' */ 615: p=skipbl(p); pin=inp; 616: if ((toktyp+COFF)[*pin]!=IDENT) { 617: ppwarn("illegal macro name"); while (*inp!='\n') p=skipbl(p); return(p); 618: } 619: np=slookup(pin,p,1); 620: if (oldval=np->value) savch=oldsavch; /* was previously defined */ 621: b=1; cf=pin; 622: while (cf<p) {/* update macbit */ 623: c= *cf++; xmac1(c,b,|=); b=(b+b)&0xFF; 624: if (cf!=p) xmac2(c,*cf,-1+(cf-pin),|=); 625: else xmac2(c,0,-1+(cf-pin),|=); 626: } 627: params=0; outp=inp=p; p=cotoken(p); pin=inp; 628: if (*pin=='(') {/* with parameters; identify the formals */ 629: cf=formtxt; pf=formal; 630: for (;;) { 631: p=skipbl(p); pin=inp; 632: if (*pin=='\n') { 633: --lineno[ifno]; --p; pperror("%s: missing )",np->name); break; 634: } 635: if (*pin==')') break; 636: if (*pin==',') continue; 637: if ((toktyp+COFF)[*pin]!=IDENT) { 638: c= *p; *p='\0'; pperror("bad formal: %s",pin); *p=c; 639: } else if (pf>= &formal[MAXFRM]) { 640: c= *p; *p='\0'; pperror("too many formals: %s",pin); *p=c; 641: } else { 642: *pf++=cf; while (pin<p) *cf++= *pin++; *cf++='\0'; ++params; 643: } 644: } 645: if (params==0) --params; /* #define foo() ... */ 646: } else if (*pin=='\n') {--lineno[ifno]; --p;} 647: /* remember beginning of macro body, so that we can 648: /* warn if a redefinition is different from old value. 649: */ 650: oldsavch=psav=savch; 651: for (;;) {/* accumulate definition until linefeed */ 652: outp=inp=p; p=cotoken(p); pin=inp; 653: if (*pin=='\\' && pin[1]=='\n') continue; /* ignore escaped lf */ 654: if (*pin=='\n') break; 655: if (params) {/* mark the appearance of formals in the definiton */ 656: if ((toktyp+COFF)[*pin]==IDENT) { 657: for (qf=pf; --qf>=formal; ) { 658: if (equfrm(*qf,pin,p)) { 659: *psav++=qf-formal+1; *psav++=WARN; pin=p; break; 660: } 661: } 662: } else if (*pin=='"' || *pin=='\'' 663: # if gcos 664: || *pin=='`' 665: # endif 666: ) {/* inside quotation marks, too */ 667: char quoc= *pin; 668: for (*psav++= *pin++; pin<p && *pin!=quoc; ) { 669: while (pin<p && !isid(*pin)) *psav++= *pin++; 670: cf=pin; while (cf<p && isid(*cf)) ++cf; 671: for (qf=pf; --qf>=formal; ) { 672: if (equfrm(*qf,pin,cf)) { 673: *psav++=qf-formal+1; *psav++=WARN; pin=cf; break; 674: } 675: } 676: while (pin<cf) *psav++= *pin++; 677: } 678: } 679: } 680: while (pin<p) *psav++= *pin++; 681: } 682: *psav++=params; *psav++='\0'; 683: if ((cf=oldval)!=NULL) {/* redefinition */ 684: --cf; /* skip no. of params, which may be zero */ 685: while (*--cf); /* go back to the beginning */ 686: if (0!=strcmp(++cf,oldsavch)) {/* redefinition different from old */ 687: --lineno[ifno]; ppwarn("%s redefined",np->name); ++lineno[ifno]; 688: np->value=psav-1; 689: } else psav=oldsavch; /* identical redef.; reclaim space */ 690: } else np->value=psav-1; 691: --flslvl; inp=pin; savch=psav; return(p); 692: } 693: 694: #define fasscan() ptrtab=fastab+COFF 695: #define sloscan() ptrtab=slotab+COFF 696: 697: char * 698: control(p) register char *p; {/* find and handle preprocessor control lines */ 699: register struct symtab *np; 700: for (;;) { 701: fasscan(); p=cotoken(p); if (*inp=='\n') ++inp; dump(); 702: sloscan(); p=skipbl(p); 703: *--inp=SALT; outp=inp; ++flslvl; np=slookup(inp,p,0); --flslvl; 704: if (np==defloc) {/* define */ 705: if (flslvl==0) {p=dodef(p); continue;} 706: } else if (np==incloc) {/* include */ 707: if (flslvl==0) {p=doincl(p); continue;} 708: } else if (np==ifnloc) {/* ifndef */ 709: ++flslvl; p=skipbl(p); np=slookup(inp,p,0); --flslvl; 710: if (flslvl==0 && np->value==0) ++trulvl; 711: else ++flslvl; 712: } else if (np==ifdloc) {/* ifdef */ 713: ++flslvl; p=skipbl(p); np=slookup(inp,p,0); --flslvl; 714: if (flslvl==0 && np->value!=0) ++trulvl; 715: else ++flslvl; 716: } else if (np==eifloc) {/* endif */ 717: if (flslvl) {if (--flslvl==0) sayline();} 718: else if (trulvl) --trulvl; 719: else pperror("If-less endif",0); 720: } else if (np==elsloc) {/* else */ 721: if (flslvl) { 722: if (--flslvl!=0) ++flslvl; 723: else {++trulvl; sayline();} 724: } 725: else if (trulvl) {++flslvl; --trulvl;} 726: else pperror("If-less else",0); 727: } else if (np==udfloc) {/* undefine */ 728: if (flslvl==0) { 729: ++flslvl; p=skipbl(p); slookup(inp,p,DROP); --flslvl; 730: } 731: } else if (np==ifloc) {/* if */ 732: #if tgp 733: pperror(" IF not implemented, true assumed", 0); 734: if (flslvl==0) ++trulvl; else ++flslvl; 735: #else 736: newp=p; 737: if (flslvl==0 && yyparse()) ++trulvl; else ++flslvl; 738: p=newp; 739: #endif 740: } else if (np==lneloc) {/* line */ 741: if (flslvl==0 && pflag==0) { 742: outp=inp=p; *--outp='#'; while (*inp!='\n') p=cotoken(p); 743: continue; 744: } 745: } else if (*++inp=='\n') outp=inp; /* allows blank line after # */ 746: else pperror("undefined control",0); 747: /* flush to lf */ 748: ++flslvl; while (*inp!='\n') {outp=inp=p; p=cotoken(p);} --flslvl; 749: } 750: } 751: 752: struct symtab * 753: stsym(s) register char *s; { 754: char buf[BUFSIZ]; register char *p; 755: 756: /* make definition look exactly like end of #define line */ 757: /* copy to avoid running off end of world when param list is at end */ 758: p=buf; while (*p++= *s++); 759: p=buf; while (isid(*p++)); /* skip first identifier */ 760: if (*--p=='=') {*p++=' '; while (*p++);} 761: else {s=" 1"; while (*p++= *s++);} 762: pend=p; *--p='\n'; 763: sloscan(); dodef(buf); return(lastsym); 764: } 765: 766: struct symtab * 767: ppsym(s) char *s; {/* kluge */ 768: register struct symtab *sp; 769: cinit=SALT; *savch++=SALT; sp=stsym(s); --sp->name; cinit=0; return(sp); 770: } 771: 772: /* VARARGS1 */ 773: pperror(s,x,y) char *s; { 774: if (fnames[ifno][0]) fprintf(stderr, 775: # if gcos 776: "*%c* \"%s\", line ", exfail >= 0 ? 'F' : 'W', 777: # else 778: "%s: ", 779: # endif 780: fnames[ifno]); 781: fprintf(stderr, "%d: ",lineno[ifno]); 782: fprintf(stderr, s, x, y); 783: fprintf(stderr,"\n"); 784: ++exfail; 785: } 786: 787: yyerror(s,a,b) char *s; { 788: pperror(s,a,b); 789: } 790: 791: ppwarn(s,x) char *s; { 792: int fail = exfail; 793: exfail = -1; 794: pperror(s,x); 795: exfail = fail; 796: } 797: 798: struct symtab * 799: lookup(namep, enterf) 800: char *namep; 801: { 802: register char *np, *snp; 803: register int c, i; int around; 804: register struct symtab *sp; 805: 806: /* namep had better not be too long (currently, <=8 chars) */ 807: np=namep; around=0; i=cinit; 808: while (c= *np++) i += i+c; c=i; /* c=i for register usage on pdp11 */ 809: c %= symsiz; if (c<0) c += symsiz; 810: sp = &stab[c]; 811: while (snp=sp->name) { 812: np = namep; 813: while (*snp++ == *np) if (*np++ == '\0') { 814: if (enterf==DROP) {sp->name[0]= DROP; sp->value=0;} 815: return(lastsym=sp); 816: } 817: if (--sp < &stab[0]) 818: if (around) {pperror("too many defines", 0); exit(exfail);} 819: else {++around; sp = &stab[symsiz-1];} 820: } 821: if (enterf>0) sp->name=namep; 822: return(lastsym=sp); 823: } 824: 825: struct symtab * 826: slookup(p1,p2,enterf) register char *p1,*p2; int enterf;{ 827: register char *p3; char c2,c3; struct symtab *np; 828: c2= *p2; *p2='\0'; /* mark end of token */ 829: if ((p2-p1)>8) p3=p1+8; else p3=p2; 830: c3= *p3; *p3='\0'; /* truncate to 8 chars or less */ 831: if (enterf==1) p1=copy(p1); 832: np=lookup(p1,enterf); *p3=c3; *p2=c2; 833: if (np->value!=0 && flslvl==0) newp=subst(p2,np); 834: else newp=0; 835: return(np); 836: } 837: 838: char * 839: subst(p,sp) register char *p; struct symtab *sp; { 840: static char match[]="%s: argument mismatch"; 841: register char *ca,*vp; int params; 842: char *actual[MAXFRM]; /* actual[n] is text of nth actual */ 843: char acttxt[BUFSIZ]; /* space for actuals */ 844: 845: if (0==(vp=sp->value)) return(p); 846: if ((p-macforw)<=macdam) { 847: if (++maclvl>symsiz && !rflag) { 848: pperror("%s: macro recursion",sp->name); return(p); 849: } 850: } else maclvl=0; /* level decreased */ 851: macforw=p; macdam=0; /* new target for decrease in level */ 852: macnam=sp->name; 853: dump(); 854: if (sp==ulnloc) { 855: vp=acttxt; *vp++='\0'; 856: sprintf(vp,"%d",lineno[ifno]); while (*vp++); 857: } else if (sp==uflloc) { 858: vp=acttxt; *vp++='\0'; 859: sprintf(vp,"\"%s\"",fnames[ifno]); while (*vp++); 860: } 861: if (0!=(params= *--vp&0xFF)) {/* definition calls for params */ 862: register char **pa; 863: ca=acttxt; pa=actual; 864: if (params==0xFF) params=1; /* #define foo() ... */ 865: sloscan(); ++flslvl; /* no expansion during search for actuals */ 866: plvl= -1; 867: do p=skipbl(p); while (*inp=='\n'); /* skip \n too */ 868: if (*inp=='(') { 869: maclin=lineno[ifno]; macfil=fnames[ifno]; 870: for (plvl=1; plvl!=0; ) { 871: *ca++='\0'; 872: for (;;) { 873: outp=inp=p; p=cotoken(p); 874: if (*inp=='(') ++plvl; 875: if (*inp==')' && --plvl==0) {--params; break;} 876: if (plvl==1 && *inp==',') {--params; break;} 877: while (inp<p) *ca++= *inp++; 878: if (ca> &acttxt[BUFSIZ]) 879: pperror("%s: actuals too long",sp->name); 880: } 881: if (pa>= &actual[MAXFRM]) ppwarn(match,sp->name); 882: else *pa++=ca; 883: } 884: } 885: if (params!=0) ppwarn(match,sp->name); 886: while (--params>=0) *pa++=""+1; /* null string for missing actuals */ 887: --flslvl; fasscan(); 888: } 889: for (;;) {/* push definition onto front of input stack */ 890: while (!iswarn(*--vp)) { 891: if (bob(p)) {outp=inp=p; p=unfill(p);} 892: *--p= *vp; 893: } 894: if (*vp==warnc) {/* insert actual param */ 895: ca=actual[*--vp-1]; 896: while (*--ca) { 897: if (bob(p)) {outp=inp=p; p=unfill(p);} 898: *--p= *ca; 899: } 900: } else break; 901: } 902: outp=inp=p; 903: return(p); 904: } 905: 906: 907: 908: 909: char * 910: trmdir(s) register char *s; { 911: register char *p = s; 912: while (*p++); --p; while (p>s && *--p!='/'); 913: # if unix 914: if (p==s) *p++='.'; 915: # endif 916: *p='\0'; 917: return(s); 918: } 919: 920: STATIC char * 921: copy(s) register char *s; { 922: register char *old; 923: 924: old = savch; while (*savch++ = *s++); 925: return(old); 926: } 927: 928: char * 929: strdex(s,c) char *s,c; { 930: while (*s) if (*s++==c) return(--s); 931: return(0); 932: } 933: 934: yywrap(){ return(1); } 935: 936: main(argc,argv) 937: char *argv[]; 938: { 939: register int i,c; 940: register char *p; 941: char *tf,**cp2; 942: 943: # if gcos 944: if (setjmp(env)) return (exfail); 945: # endif 946: p="_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 947: i=0; 948: while (c= *p++) { 949: (fastab+COFF)[c] |= IB|NB|SB; (toktyp+COFF)[c]=IDENT; 950: #if scw2 951: /* 53 == 63-10; digits rarely appear in identifiers, 952: /* and can never be the first char of an identifier. 953: /* 11 == 53*53/sizeof(macbit) . 954: */ 955: ++i; (t21+COFF)[c]=(53*i)/11; (t22+COFF)[c]=i%11; 956: #endif 957: } 958: p="0123456789."; 959: while (c= *p++) {(fastab+COFF)[c] |= NB|SB; (toktyp+COFF)[c]=NUMBR;} 960: # if gcos 961: p="\n\"'`/\\"; 962: # else 963: p="\n\"'/\\"; 964: # endif 965: while (c= *p++) (fastab+COFF)[c] |= SB; 966: # if gcos 967: p="\n\"'`\\"; 968: # else 969: p="\n\"'\\"; 970: # endif 971: while (c= *p++) (fastab+COFF)[c] |= QB; 972: p="*\n"; while (c= *p++) (fastab+COFF)[c] |= CB; 973: (fastab+COFF)[warnc] |= WB; 974: (fastab+COFF)['\0'] |= CB|QB|SB|WB; 975: for (i=ALFSIZ; --i>=0; ) slotab[i]=fastab[i]|SB; 976: p=" \t\013\f\r"; /* note no \n; \v not legal for vertical tab? */ 977: while (c= *p++) (toktyp+COFF)[c]=BLANK; 978: #if scw2 979: for ((t23+COFF)[i=ALFSIZ+7-COFF]=1; --i>=-COFF; ) 980: if (((t23+COFF)[i]=(t23+COFF+1)[i]<<1)==0) (t23+COFF)[i]=1; 981: #endif 982: 983: # if unix 984: fnames[ifno=0] = ""; 985: # endif 986: # if ibm 987: fnames[ifno=0] = ""; 988: # endif 989: # if gcos 990: if (inquire(stdin, _TTY)) freopen("*src", "rt", stdin); 991: # endif 992: # if gimpel || gcos 993: fnames[ifno=0] = (char *)inquire(stdin, _FILENAME); 994: dirnams[0] = dirs[0] = trmdir(copy(fnames[0])); 995: # endif 996: for(i=1; i<argc; i++) 997: { 998: switch(argv[i][0]) 999: { 1000: case '-': 1001: # if gcos 1002: switch(toupper(argv[i][1])) { /* case-independent on GCOS */ 1003: # else 1004: switch(argv[i][1]) { 1005: # endif 1006: case 'P': pflag++; 1007: case 'E': continue; 1008: case 'R': ++rflag; continue; 1009: case 'C': passcom++; continue; 1010: case 'D': 1011: if (predef>prespc+NPREDEF) { 1012: pperror("too many -D options, ignoring %s",argv[i]); 1013: continue; 1014: } 1015: /* ignore plain "-D" (no argument) */ 1016: if (*(argv[i]+2)) *predef++ = argv[i]+2; 1017: continue; 1018: case 'U': 1019: if (prund>punspc+NPREDEF) { 1020: pperror("too many -U options, ignoring %s",argv[i]); 1021: continue; 1022: } 1023: *prund++ = argv[i]+2; 1024: continue; 1025: case 'I': 1026: if (nd>8) pperror("excessive -I file (%s) ignored",argv[i]); 1027: else dirs[nd++] = argv[i]+2; 1028: continue; 1029: case '\0': continue; 1030: default: 1031: pperror("unknown flag %s", argv[i]); 1032: continue; 1033: } 1034: default: 1035: if (fin==STDIN) { 1036: if (0>(fin=open(argv[i], READ))) { 1037: pperror("No source file %s",argv[i]); exit(8); 1038: } 1039: fnames[ifno]=copy(argv[i]); 1040: dirs[0]=dirnams[ifno]=trmdir(argv[i]); 1041: # ifndef gcos 1042: /* too dangerous to have file name in same syntactic position 1043: be input or output file depending on file redirections, 1044: so force output to stdout, willy-nilly 1045: [i don't see what the problem is. jfr] 1046: */ 1047: } else if (fout==stdout) { 1048: extern char _sobuf[BUFSIZ]; 1049: if (NULL==(fout=fopen(argv[i], "w"))) { 1050: pperror("Can't create %s", argv[i]); exit(8); 1051: } else {fclose(stdout); setbuf(fout,_sobuf);} 1052: # endif 1053: } else pperror("extraneous name %s", argv[i]); 1054: } 1055: } 1056: 1057: fins[ifno]=fin; 1058: exfail = 0; 1059: /* after user -I files here are the standard include libraries */ 1060: # if unix 1061: dirs[nd++] = "/usr/include"; 1062: # endif 1063: # if gcos 1064: dirs[nd++] = "cc/include"; 1065: # endif 1066: # if ibm 1067: # ifndef gimpel 1068: dirs[nd++] = "BTL$CLIB"; 1069: # endif 1070: # endif 1071: # ifdef gimpel 1072: dirs[nd++] = intss() ? "SYS3.C." : "" ; 1073: # endif 1074: /* dirs[nd++] = "/compool"; */ 1075: dirs[nd++] = 0; 1076: defloc=ppsym("define"); 1077: udfloc=ppsym("undef"); 1078: incloc=ppsym("include"); 1079: elsloc=ppsym("else"); 1080: eifloc=ppsym("endif"); 1081: ifdloc=ppsym("ifdef"); 1082: ifnloc=ppsym("ifndef"); 1083: ifloc=ppsym("if"); 1084: lneloc=ppsym("line"); 1085: for (i=sizeof(macbit)/sizeof(macbit[0]); --i>=0; ) macbit[i]=0; 1086: # if unix 1087: ysysloc=stsym("unix"); 1088: # endif 1089: # if gcos 1090: ysysloc=stsym ("gcos"); 1091: # endif 1092: # if ibm 1093: ysysloc=stsym ("ibm"); 1094: # endif 1095: # if pdp11 1096: varloc=stsym("pdp11"); 1097: # endif 1098: # if vax 1099: varloc=stsym("vax"); 1100: # endif 1101: # if interdata 1102: varloc=stsym ("interdata"); 1103: # endif 1104: # if tss 1105: varloc=stsym ("tss"); 1106: # endif 1107: # if os 1108: varloc=stsym ("os"); 1109: # endif 1110: # if mert 1111: varloc=stsym ("mert"); 1112: # endif 1113: ulnloc=stsym ("__LINE__"); 1114: uflloc=stsym ("__FILE__"); 1115: 1116: tf=fnames[ifno]; fnames[ifno]="command line"; lineno[ifno]=1; 1117: cp2=prespc; 1118: while (cp2<predef) stsym(*cp2++); 1119: cp2=punspc; 1120: while (cp2<prund) { 1121: if (p=strdex(*cp2, '=')) *p++='\0'; 1122: lookup(*cp2++, DROP); 1123: } 1124: fnames[ifno]=tf; 1125: pbeg=buffer+8; pbuf=pbeg+BUFSIZ; pend=pbuf+BUFSIZ; 1126: 1127: trulvl = 0; flslvl = 0; 1128: lineno[0] = 1; sayline(); 1129: outp=inp=pend; 1130: control(pend); 1131: return (exfail); 1132: }