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