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