1 /* 2 * C command 3 * written by John F. Reiser 4 * July/August 1978 5 */ 6 /* Copyright (c) 2012 Joyent, Inc. All rights reserved. */ 7 /* 8 * This implementation is based on the UNIX 32V release from 1978 9 * with permission from Caldera Inc. 10 * 11 * Copyright (c) 2010 J. Schilling 12 * All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. Neither the name of the copyright holder nor the names of contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 /* 39 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions are 43 * met: 44 * 1. Redistributions of source code and documentation must retain the above 45 * copyright notice, this list of conditions and the following 46 * disclaimer. 47 * 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 52 * 3. All advertising materials mentioning features or use of this software 53 * must display the following acknowledgement: This product includes 54 * software developed or owned by Caldera International, Inc. 55 * 56 * 4. Neither the name of Caldera International, Inc. nor the names of other 57 * contributors may be used to endorse or promote products derived from 58 * this software without specific prior written permission. 59 * 60 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 61 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 62 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 63 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 64 * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR 65 * ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 69 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 70 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 71 * POSSIBILITY OF SUCH DAMAGE. 72 */ 73 #include <stdio.h> 74 #include <unistd.h> 75 #include <stdlib.h> 76 #include <fcntl.h> 77 #include <string.h> 78 #include <stdarg.h> 79 #include <ctype.h> 80 81 #include "cpp.h" 82 83 #define SYMLEN 128 84 static int symlen = SYMLEN; 85 86 87 #define SALT '#' 88 #ifndef BUFSIZ 89 #define BUFSIZ 512 90 #endif 91 92 static char *pbeg; 93 static char *pbuf; 94 static char *pend; 95 char *outp,*inp; 96 char *newp; 97 static char cinit; 98 99 /* some code depends on whether characters are sign or zero extended */ 100 /* #if '\377' < 0 not used here, old cpp doesn't understand */ 101 #if pdp11 | vax | '\377' < 0 102 #define COFF 128 103 #else 104 #define COFF 0 105 #endif 106 107 #define ALFSIZ 256 /* alphabet size */ 108 static char macbit[ALFSIZ+11]; 109 static char toktyp[ALFSIZ]; 110 #define BLANK 1 /* white space (" \t\v\f\r") */ 111 #define IDENT 2 /* valid char for identifier names */ 112 #define NUMBR 3 /* chars is of "0123456789." */ 113 114 /* 115 * a superimposed code is used to reduce the number of calls to the 116 * symbol table lookup routine. (if the kth character of an identifier 117 * is 'a' and there are no macro names whose kth character is 'a' 118 * then the identifier cannot be a macro name, hence there is no need 119 * to look in the symbol table.) 'scw1' enables the test based on 120 * single characters and their position in the identifier. 'scw2' 121 * enables the test based on adjacent pairs of characters and their 122 * position in the identifier. scw1 typically costs 1 indexed fetch, 123 * an AND, and a jump per character of identifier, until the identifier 124 * is known as a non-macro name or until the end of the identifier. 125 * scw1 is inexpensive. scw2 typically costs 4 indexed fetches, 126 * an add, an AND, and a jump per character of identifier, but it is also 127 * slightly more effective at reducing symbol table searches. 128 * scw2 usually costs too much because the symbol table search is 129 * usually short; but if symbol table search should become expensive, 130 * the code is here. 131 * using both scw1 and scw2 is of dubious value. 132 */ 133 #define scw1 1 134 #define scw2 0 135 136 #if scw2 137 char t21[ALFSIZ],t22[ALFSIZ],t23[ALFSIZ+SYMLEN]; 138 #endif 139 140 #if scw1 141 #define b0 1 142 #define b1 2 143 #define b2 4 144 #define b3 8 145 #define b4 16 146 #define b5 32 147 #define b6 64 148 #define b7 128 149 #endif 150 151 #define IB 1 152 #define SB 2 153 #define NB 4 154 #define CB 8 155 #define QB 16 156 #define WB 32 157 char fastab[ALFSIZ]; 158 static char slotab[ALFSIZ]; 159 static char *ptrtab; 160 161 /* 162 * Cast the array index to int in order to avoid GCCs warnings: 163 * warning: subscript has type `char' 164 */ 165 #define isslo (ptrtab==(slotab+COFF)) 166 #define isid(a) ((fastab+COFF)[(int)a]&IB) 167 #define isspc(a) (ptrtab[(int)a]&SB) 168 #define isnum(a) ((fastab+COFF)[(int)a]&NB) 169 #define iscom(a) ((fastab+COFF)[(int)a]&CB) 170 #define isquo(a) ((fastab+COFF)[(int)a]&QB) 171 #define iswarn(a) ((fastab+COFF)[(int)a]&WB) 172 173 #define eob(a) ((a)>=pend) 174 #define bob(a) (pbeg>=(a)) 175 176 #define BUFFERSIZ 8192 177 static char buffer[SYMLEN+BUFFERSIZ+BUFFERSIZ+SYMLEN]; 178 179 /* 180 * SBSIZE was 12000 in 1978, we need to have a way to 181 * malloc more space. 182 */ 183 #define SBSIZE 512000 184 static char sbf[SBSIZE]; 185 static char *savch = sbf; 186 187 # define DROP 0xFE /* special character not legal ASCII or EBCDIC */ 188 # define WARN DROP 189 # define SAME 0 190 # define MAXINC 16 /* max include nesting depth */ 191 # define MAXIDIRS 20 /* max # of -I directories */ 192 # define MAXFRE 14 /* max buffers of macro pushback */ 193 # define MAXFRM 31 /* max number of formals/actuals to a macro */ 194 195 static char warnc = (char)WARN; 196 197 static int mactop; 198 static int fretop; 199 static char *instack[MAXFRE]; 200 static char *bufstack[MAXFRE]; 201 static char *endbuf[MAXFRE]; 202 203 static int plvl; /* parenthesis level during scan for macro actuals */ 204 static int maclin; /* line number of macro call requiring actuals */ 205 static char *macfil; /* file name of macro call requiring actuals */ 206 static char *macnam; /* name of macro requiring actuals */ 207 static int maclvl; /* # calls since last decrease in nesting level */ 208 static char *macforw; /* ptr which must be exceeded to decrease nesting lvl */ 209 static int macdam; /* offset to macforw due to buffer shifting */ 210 211 static int inctop[MAXINC]; 212 static char *fnames[MAXINC]; 213 static char *dirnams[MAXINC]; /* actual directory of #include files */ 214 static int fins[MAXINC]; 215 static int lineno[MAXINC]; 216 217 /* 218 * We need: 219 * "" include dir as dirs[0] + 220 * MAXIDIRS + 221 * system default include dir + 222 * a NULL pointer at the end 223 */ 224 static char *dirs[MAXIDIRS+3]; /* -I and <> directories */ 225 static int fin = STDIN_FILENO; 226 static FILE *fout; /* Init in main(), Mac OS is nonPOSIX */ 227 static int nd = 1; 228 static int pflag; /* don't put out lines "# 12 foo.c" */ 229 static int passcom; /* don't delete comments */ 230 static int rflag; /* allow macro recursion */ 231 static int hflag; /* Print included filenames */ 232 static int nopredef; /* -undef all */ 233 static int ifno; 234 # define NPREDEF 64 235 static char *prespc[NPREDEF]; 236 static char **predef = prespc; 237 static char *punspc[NPREDEF]; 238 static char **prund = punspc; 239 static int exfail; 240 static struct symtab *lastsym; 241 242 243 static void sayline(char *); 244 static void dump(void); 245 static char *refill(char *); 246 static char *cotoken(char *); 247 char *skipbl(char *); 248 static char *unfill(char *); 249 static char *doincl(char *); 250 static int equfrm(char *, char *, char *); 251 static char *dodef(char *); 252 static char *control(char *); 253 static struct symtab *stsym(char *); 254 static struct symtab *ppsym(char *); 255 void pperror(char *fmt, ...); 256 void yyerror(char *fmt, ...); 257 static void ppwarn(char *fmt, ...); 258 struct symtab *lookup(char *, int); 259 static struct symtab *slookup(char *, char *, int); 260 static char *subst(char *, struct symtab *); 261 static char *trmdir(char *); 262 static char *copy(char *); 263 static char *strdex(char *, int); 264 int yywrap(void); 265 int main(int argc, char **argav); 266 267 268 #define symsiz 16000 269 static struct symtab stab[symsiz]; 270 271 static struct symtab *defloc; 272 static struct symtab *udfloc; 273 static struct symtab *incloc; 274 static struct symtab *ifloc; 275 static struct symtab *elsloc; 276 static struct symtab *eifloc; 277 static struct symtab *elifloc; 278 static struct symtab *ifdloc; 279 static struct symtab *ifnloc; 280 static struct symtab *ysysloc; 281 static struct symtab *varloc; 282 static struct symtab *lneloc; 283 static struct symtab *ulnloc; 284 static struct symtab *uflloc; 285 static struct symtab *idtloc; 286 static struct symtab *pragmaloc; 287 static struct symtab *errorloc; 288 static int trulvl; 289 int flslvl; 290 static int elflvl; 291 static int elslvl; 292 293 /* 294 * The sun cpp prints a classification token past the 295 * "# linenumber filename" lines: 296 */ 297 #define NOINCLUDE "" /* Not related to enter/leave incl. file */ 298 #define ENTERINCLUDE "1" /* We are just entering an include file */ 299 #define LEAVEINCLUDE "2" /* We are just leaving an include file */ 300 301 /* ARGSUSED */ 302 static void 303 sayline(what) 304 char *what; 305 { 306 if (pflag==0) 307 fprintf(fout,"# %d \"%s\" %s\n", lineno[ifno], fnames[ifno], what); 308 } 309 310 /* 311 * data structure guide 312 * 313 * most of the scanning takes place in the buffer: 314 * 315 * (low address) (high address) 316 * pbeg pbuf pend 317 * | <-- BUFFERSIZ chars --> | <-- BUFFERSIZ chars --> | 318 * _______________________________________________________________________ 319 * |_______________________________________________________________________| 320 * | | | 321 * |<-- waiting -->| |<-- waiting --> 322 * | to be |<-- current -->| to be 323 * | written | token | scanned 324 * | | | 325 * outp inp p 326 * 327 * *outp first char not yet written to output file 328 * *inp first char of current token 329 * *p first char not yet scanned 330 * 331 * macro expansion: write from *outp to *inp (chars waiting to be written), 332 * ignore from *inp to *p (chars of the macro call), place generated 333 * characters in front of *p (in reverse order), update pointers, 334 * resume scanning. 335 * 336 * symbol table pointers point to just beyond the end of macro definitions; 337 * the first preceding character is the number of formal parameters. 338 * the appearance of a formal in the body of a definition is marked by 339 * 2 chars: the char WARN, and a char containing the parameter number. 340 * the first char of a definition is preceded by a zero character. 341 * 342 * when macro expansion attempts to back up over the beginning of the 343 * buffer, some characters preceding *pend are saved in a side buffer, 344 * the address of the side buffer is put on 'instack', and the rest 345 * of the main buffer is moved to the right. the end of the saved buffer 346 * is kept in 'endbuf' since there may be nulls in the saved buffer. 347 * 348 * similar action is taken when an 'include' statement is processed, 349 * except that the main buffer must be completely emptied. the array 350 * element 'inctop[ifno]' records the last side buffer saved when 351 * file 'ifno' was included. these buffers remain dormant while 352 * the file is being read, and are reactivated at end-of-file. 353 * 354 * instack[0 : mactop] holds the addresses of all pending side buffers. 355 * instack[inctop[ifno]+1 : mactop-1] holds the addresses of the side 356 * buffers which are "live"; the side buffers instack[0 : inctop[ifno]] 357 * are dormant, waiting for end-of-file on the current file. 358 * 359 * space for side buffers is obtained from 'savch' and is never returned. 360 * bufstack[0:fretop-1] holds addresses of side buffers which 361 * are available for use. 362 */ 363 364 static void 365 dump() { 366 register char *p1; 367 if ((p1=outp)==inp || flslvl!=0) return; 368 fwrite(p1, inp - p1, 1, fout); 369 outp=p1; 370 } 371 372 static char * 373 refill(p) register char *p; { 374 /* 375 * dump buffer. save chars from inp to p. read into buffer at pbuf, 376 * contiguous with p. update pointers, return new p. 377 */ 378 register char *np,*op; register int ninbuf; 379 dump(); np=pbuf-(p-inp); op=inp; 380 if (bob(np+1)) {pperror("token too long"); np=pbeg; p=inp+BUFFERSIZ;} 381 macdam += np-inp; outp=inp=np; 382 while (op<p) *np++= *op++; 383 p=np; 384 for (;;) { 385 if (mactop>inctop[ifno]) { 386 /* retrieve hunk of pushed-back macro text */ 387 op=instack[--mactop]; np=pbuf; 388 do { 389 while ((*np++= *op++) != '\0'); 390 } while (op<endbuf[mactop]); pend=np-1; 391 /* make buffer space avail for 'include' processing */ 392 if (fretop<MAXFRE) bufstack[fretop++]=instack[mactop]; 393 return(p); 394 } else {/* get more text from file(s) */ 395 maclvl=0; 396 if (0<(ninbuf=read(fin,pbuf,BUFFERSIZ))) { 397 pend=pbuf+ninbuf; *pend='\0'; 398 return(p); 399 } 400 /* end of #include file */ 401 if (ifno==0) {/* end of input */ 402 if (plvl > 0) { 403 int n=plvl,tlin=lineno[ifno]; 404 char *tfil=fnames[ifno]; 405 lineno[ifno]=maclin; 406 fnames[ifno]=macfil; 407 pperror("%s: unterminated macro call", 408 macnam); 409 lineno[ifno]=tlin; fnames[ifno]=tfil; 410 np=p; 411 /* 412 * shut off unterminated quoted string 413 */ 414 *np++='\n'; 415 /* supply missing parens */ 416 while (--n>=0) *np++=')'; 417 pend=np; *np='\0'; 418 if (plvl<0) plvl=0; 419 return(p); 420 } 421 inp=p; dump(); exit(exfail); 422 } 423 close(fin); 424 fin=fins[--ifno]; 425 dirs[0]=dirnams[ifno]; 426 sayline(LEAVEINCLUDE); 427 } 428 } 429 } 430 431 #define BEG 0 432 #define LF 1 433 434 static char * 435 cotoken(p) register char *p; { 436 register int c,i; char quoc; 437 static int state = BEG; 438 439 if (state!=BEG) goto prevlf; 440 for (;;) { 441 again: 442 while (!isspc(*p++)); 443 switch (*(inp=p-1)) { 444 case 0: { 445 if (eob(--p)) {p=refill(p); goto again;} 446 else ++p; /* ignore null byte */ 447 } break; 448 case '|': case '&': for (;;) {/* sloscan only */ 449 if (*p++== *inp) break; 450 if (eob(--p)) p=refill(p); 451 else break; 452 } break; 453 case '=': case '!': for (;;) {/* sloscan only */ 454 if (*p++=='=') break; 455 if (eob(--p)) p=refill(p); 456 else break; 457 } break; 458 case '<': case '>': for (;;) {/* sloscan only */ 459 if (*p++=='=' || p[-2]==p[-1]) break; 460 if (eob(--p)) p=refill(p); 461 else break; 462 } break; 463 case '\\': for (;;) { 464 if (*p++=='\n') {++lineno[ifno]; break;} 465 if (eob(--p)) p=refill(p); 466 else {++p; break;} 467 } break; 468 case '/': for (;;) { 469 if (*p++=='*') {/* comment */ 470 if (!passcom) {inp=p-2; dump(); ++flslvl;} 471 for (;;) { 472 while (!iscom(*p++)); 473 if (p[-1]=='*') for (;;) { 474 if (*p++=='/') goto endcom; 475 if (eob(--p)) { 476 if (!passcom) { 477 inp=p; 478 p=refill(p); 479 } else if ((p-inp)>=BUFFERSIZ) { 480 /* split long comment */ 481 inp=p; 482 /* 483 * last char written 484 * is '*' 485 */ 486 p=refill(p); 487 /* 488 * terminate first part 489 */ 490 putc('/',fout); 491 /* 492 * and fake start of 2nd 493 */ 494 outp=inp=p-=3; 495 *p++='/'; 496 *p++='*'; 497 *p++='*'; 498 } else { 499 p=refill(p); 500 } 501 } else { 502 break; 503 } 504 } else if (p[-1]=='\n') { 505 ++lineno[ifno]; 506 if (!passcom) 507 putc('\n',fout); 508 } else if (eob(--p)) { 509 if (!passcom) { 510 inp=p; p=refill(p); 511 } else if ((p-inp)>=BUFFERSIZ) { 512 /* split long comment */ 513 inp=p; p=refill(p); 514 putc('*',fout); putc('/',fout); 515 outp=inp=p-=2; 516 *p++='/'; 517 *p++='*'; 518 } else { 519 p=refill(p); 520 } 521 } else { 522 ++p; /* ignore null byte */ 523 } 524 } 525 endcom: 526 if (!passcom) {outp=inp=p; --flslvl; goto again;} 527 break; 528 } 529 if (eob(--p)) p=refill(p); 530 else break; 531 } break; 532 case '"': case '\'': { 533 quoc=p[-1]; 534 for (;;) { 535 while (!isquo(*p++)); 536 if (p[-1]==quoc) 537 break; 538 if (p[-1]=='\n') { 539 --p; 540 break; 541 } /* bare \n terminates quotation */ 542 if (p[-1]=='\\') { 543 for (;;) { 544 if (*p++=='\n') { 545 ++lineno[ifno]; 546 break; 547 } /* escaped \n ignored */ 548 if (eob(--p)) { 549 p=refill(p); 550 } else { 551 ++p; 552 break; 553 } 554 } 555 } else if (eob(--p)) { 556 p=refill(p); 557 } else { 558 ++p; /* it was a different quote character */ 559 } 560 } 561 } break; 562 case '\n': { 563 ++lineno[ifno]; if (isslo) {state=LF; return(p);} 564 prevlf: 565 state=BEG; 566 for (;;) { 567 if (*p++=='#') return(p); 568 if (eob(inp= --p)) p=refill(p); 569 else goto again; 570 } 571 } 572 /* NOTREACHED */ 573 case '0': case '1': case '2': case '3': case '4': 574 case '5': case '6': case '7': case '8': case '9': 575 for (;;) { 576 while (isnum(*p++)); 577 if (eob(--p)) p=refill(p); 578 else break; 579 } break; 580 case 'A': case 'B': case 'C': case 'D': case 'E': 581 case 'F': case 'G': case 'H': case 'I': case 'J': 582 case 'K': case 'L': case 'M': case 'N': case 'O': 583 case 'P': case 'Q': case 'R': case 'S': case 'T': 584 case 'U': case 'V': case 'W': case 'X': case 'Y': 585 case 'Z': case '_': 586 case 'a': case 'b': case 'c': case 'd': case 'e': 587 case 'f': case 'g': case 'h': case 'i': case 'j': 588 case 'k': case 'l': case 'm': case 'n': case 'o': 589 case 'p': case 'q': case 'r': case 's': case 't': 590 case 'u': case 'v': case 'w': case 'x': case 'y': 591 case 'z': 592 #if scw1 593 #define tmac1(c,bit) if (!xmac1(c,bit,&)) goto nomac 594 #define xmac1(c,bit,op) ((macbit+COFF)[c] op (bit)) 595 #else 596 #define tmac1(c,bit) 597 #define xmac1(c,bit,op) 598 #endif 599 600 #if scw2 601 #define tmac2(c0,c1,cpos) if (!xmac2(c0,c1,cpos,&)) goto nomac 602 #define xmac2(c0,c1,cpos,op)\ 603 ((macbit+COFF)[(t21+COFF)[c0]+(t22+COFF)[c1]] op (t23+COFF+cpos)[c0]) 604 #else 605 #define tmac2(c0,c1,cpos) 606 #define xmac2(c0,c1,cpos,op) 607 #endif 608 609 if (flslvl) goto nomac; 610 for (;;) { 611 c= p[-1]; tmac1(c,b0); 612 i= *p++; if (!isid(i)) goto endid; tmac1(i,b1); tmac2(c,i,0); 613 c= *p++; if (!isid(c)) goto endid; tmac1(c,b2); tmac2(i,c,1); 614 i= *p++; if (!isid(i)) goto endid; tmac1(i,b3); tmac2(c,i,2); 615 c= *p++; if (!isid(c)) goto endid; tmac1(c,b4); tmac2(i,c,3); 616 i= *p++; if (!isid(i)) goto endid; tmac1(i,b5); tmac2(c,i,4); 617 c= *p++; if (!isid(c)) goto endid; tmac1(c,b6); tmac2(i,c,5); 618 i= *p++; if (!isid(i)) goto endid; tmac1(i,b7); tmac2(c,i,6); 619 tmac2(i,0,7); 620 while (isid(*p++)); 621 if (eob(--p)) {refill(p); p=inp+1; continue;} 622 goto lokid; 623 endid: 624 if (eob(--p)) {refill(p); p=inp+1; continue;} 625 tmac2(p[-1],0,-1+(p-inp)); 626 lokid: 627 slookup(inp,p,0); if (newp) {p=newp; goto again;} 628 else break; 629 nomac: 630 while (isid(*p++)); 631 if (eob(--p)) {p=refill(p); goto nomac;} 632 else break; 633 } break; 634 } /* end of switch */ 635 636 if (isslo) return(p); 637 } /* end of infinite loop */ 638 } 639 640 /* 641 * XXX: This unconditionally consumes one token (presuming it's blank? that we 642 * already consumed it?). That's pretty terrible, but it's also very fragile, 643 * and I don't want to change it. 644 */ 645 char * 646 skipbl(p) register char *p; {/* get next non-blank token */ 647 do { 648 outp=inp=p; 649 p=cotoken(p); 650 } while ((toktyp+COFF)[(int)*inp]==BLANK); 651 return(p); 652 } 653 654 static char * 655 unfill(p) register char *p; { 656 /* 657 * take <= BUFFERSIZ chars from right end of buffer and put them on instack . 658 * slide rest of buffer to the right, update pointers, return new p. 659 */ 660 register char *np,*op; register int d; 661 if (mactop>=MAXFRE) { 662 pperror("%s: too much pushback",macnam); 663 p=inp=pend; dump(); /* begin flushing pushback */ 664 while (mactop>inctop[ifno]) {p=refill(p); p=inp=pend; dump();} 665 } 666 if (fretop>0) 667 np=bufstack[--fretop]; 668 else { 669 np=savch; savch+=BUFFERSIZ; 670 if (savch>=sbf+SBSIZE) {pperror("no space"); exit(exfail);} 671 *savch++='\0'; 672 } 673 instack[mactop]=np; op=pend-BUFFERSIZ; if (op<p) op=p; 674 for (;;) { 675 while ((*np++= *op++) != '\0'); 676 if (eob(op)) 677 break; 678 } /* out with old */ 679 endbuf[mactop++]=np; /* mark end of saved text */ 680 np=pbuf+BUFFERSIZ; 681 op=pend-BUFFERSIZ; 682 pend=np; 683 if (op<p) 684 op=p; 685 while (outp<op) *--np= *--op; /* slide over new */ 686 if (bob(np)) 687 pperror("token too long"); 688 d=np-outp; outp+=d; inp+=d; macdam+=d; 689 return(p+d); 690 } 691 692 static char * 693 doincl(p) register char *p; { 694 int filok,inctype; 695 register char *cp; char **dirp,*nfil; char filname[BUFFERSIZ]; 696 697 filname[0] = '\0'; /* Make lint quiet */ 698 p=skipbl(p); cp=filname; 699 if (*inp++=='<') {/* special <> syntax */ 700 inctype=1; 701 for (;;) { 702 outp=inp=p; p=cotoken(p); 703 if (*inp=='\n') {--p; *cp='\0'; break;} 704 if (*inp=='>') { *cp='\0'; break;} 705 # ifdef gimpel 706 if (*inp=='.' && !intss()) *inp='#'; 707 # endif 708 while (inp<p) *cp++= *inp++; 709 } 710 } else if (inp[-1]=='"') {/* regular "" syntax */ 711 inctype=0; 712 # ifdef gimpel 713 while (inp<p) {if (*inp=='.' && !intss()) *inp='#'; *cp++= *inp++;} 714 # else 715 while (inp<p) *cp++= *inp++; 716 # endif 717 if (*--cp=='"') *cp='\0'; 718 } else {pperror("bad include syntax",0); inctype=2;} 719 /* flush current file to \n , then write \n */ 720 ++flslvl; do {outp=inp=p; p=cotoken(p);} while (*inp!='\n'); --flslvl; 721 inp=p; dump(); if (inctype==2) return(p); 722 /* look for included file */ 723 if (ifno+1 >=MAXINC) { 724 pperror("Unreasonable include nesting",0); return(p); 725 } 726 if ((nfil=savch)>sbf+SBSIZE-BUFFERSIZ) { 727 pperror("no space"); 728 exit(exfail); 729 } 730 filok=0; 731 for (dirp=dirs+inctype; *dirp; ++dirp) { 732 if (filname[0]=='/' || **dirp=='\0') { 733 strcpy(nfil,filname); 734 } else { 735 strcpy(nfil,*dirp); 736 # if unix 737 strcat(nfil,"/"); 738 # endif 739 strcat(nfil,filname); 740 } 741 if (0<(fins[ifno+1]=open(nfil, O_RDONLY))) { 742 filok=1; fin=fins[++ifno]; break; 743 } 744 } 745 if (filok==0) { 746 pperror("Can't find include file %s",filname); 747 } else { 748 lineno[ifno]=1; fnames[ifno]=cp=nfil; while (*cp++); savch=cp; 749 dirnams[ifno]=dirs[0]=trmdir(copy(nfil)); 750 sayline(ENTERINCLUDE); 751 if (hflag) 752 fprintf(stderr, "%s\n", nfil); 753 /* save current contents of buffer */ 754 while (!eob(p)) p=unfill(p); 755 inctop[ifno]=mactop; 756 } 757 return(p); 758 } 759 760 static int 761 equfrm(a,p1,p2) register char *a,*p1,*p2; { 762 register char c; int flag; 763 c= *p2; *p2='\0'; 764 flag=strcmp(a,p1); *p2=c; return(flag==SAME); 765 } 766 767 static char * 768 dodef(p) char *p; {/* process '#define' */ 769 register char *pin,*psav,*cf; 770 char **pf,**qf; int b,c,params; struct symtab *np; 771 char *oldval,*oldsavch; 772 char *formal[MAXFRM]; /* formal[n] is name of nth formal */ 773 char formtxt[BUFFERSIZ]; /* space for formal names */ 774 775 formtxt[0] = '\0'; /* Make lint quiet */ 776 777 if (savch>sbf+SBSIZE-BUFFERSIZ) { 778 pperror("too much defining"); 779 return(p); 780 } 781 oldsavch=savch; /* to reclaim space if redefinition */ 782 ++flslvl; /* prevent macro expansion during 'define' */ 783 p=skipbl(p); pin=inp; 784 if ((toktyp+COFF)[(int)*pin]!=IDENT) { 785 ppwarn("illegal macro name"); 786 while (*inp!='\n') 787 p=skipbl(p); 788 return(p); 789 } 790 np=slookup(pin,p,1); 791 if (getenv("CPP_DEBUG_DEFINITIONS") != NULL) 792 fprintf(stderr, "*** defining %s at %s:%d\n", 793 np->name, fnames[ifno], lineno[ifno]); 794 if ((oldval=np->value) != NULL) 795 savch=oldsavch; /* was previously defined */ 796 b=1; cf=pin; 797 while (cf<p) {/* update macbit */ 798 c= *cf++; xmac1(c,b,|=); b=(b+b)&0xFF; 799 if (cf!=p) { 800 xmac2(c,*cf,-1+(cf-pin),|=); 801 } else { 802 xmac2(c,0,-1+(cf-pin),|=); 803 } 804 } 805 params=0; outp=inp=p; p=cotoken(p); pin=inp; 806 formal[0] = ""; /* Prepare for hack at next line... */ 807 pf = formal; /* Make gcc/lint quiet, pf only used with params!=0 */ 808 if (*pin=='(') {/* with parameters; identify the formals */ 809 cf=formtxt; pf=formal; 810 for (;;) { 811 p=skipbl(p); pin=inp; 812 if (*pin=='\n') { 813 --lineno[ifno]; 814 --p; 815 pperror("%s: missing )",np->name); 816 break; 817 } 818 if (*pin==')') break; 819 if (*pin==',') continue; 820 if ((toktyp+COFF)[(int)*pin]!=IDENT) { 821 c= *p; 822 *p='\0'; 823 pperror("bad formal: %s",pin); 824 *p=c; 825 } else if (pf>= &formal[MAXFRM]) { 826 c= *p; 827 *p='\0'; 828 pperror("too many formals: %s",pin); 829 *p=c; 830 } else { 831 *pf++=cf; 832 while (pin<p) 833 *cf++= *pin++; 834 *cf++='\0'; 835 ++params; 836 } 837 } 838 if (params==0) 839 --params; /* #define foo() ... */ 840 } else if (*pin=='\n') { 841 --lineno[ifno]; 842 --p; 843 } 844 /* 845 * remember beginning of macro body, so that we can 846 * warn if a redefinition is different from old value. 847 */ 848 oldsavch=psav=savch; 849 for (;;) {/* accumulate definition until linefeed */ 850 outp=inp=p; p=cotoken(p); pin=inp; 851 if (*pin=='\\' && pin[1]=='\n') 852 continue; /* ignore escaped lf */ 853 if (*pin=='\n') break; 854 if (params) { 855 /* mark the appearance of formals in the definiton */ 856 if ((toktyp+COFF)[(int)*pin]==IDENT) { 857 for (qf=pf; --qf>=formal; ) { 858 if (equfrm(*qf,pin,p)) { 859 *psav++=qf-formal+1; 860 *psav++=WARN; 861 pin=p; 862 break; 863 } 864 } 865 } else if (*pin=='"' || *pin=='\'') { 866 /* inside quotation marks, too */ 867 char quoc= *pin; 868 for (*psav++= *pin++; pin<p && *pin!=quoc; ) { 869 while (pin<p && !isid(*pin)) 870 *psav++= *pin++; 871 cf=pin; 872 while (cf<p && isid(*cf)) 873 ++cf; 874 for (qf=pf; --qf>=formal; ) { 875 if (equfrm(*qf,pin,cf)) { 876 *psav++=qf-formal+1; 877 *psav++=WARN; 878 pin=cf; 879 break; 880 } 881 } 882 while (pin<cf) 883 *psav++= *pin++; 884 } 885 } 886 } 887 while (pin<p) *psav++= *pin++; 888 } 889 *psav++=params; *psav++='\0'; 890 if ((cf=oldval)!=NULL) {/* redefinition */ 891 --cf; /* skip no. of params, which may be zero */ 892 while (*--cf); /* go back to the beginning */ 893 if (0!=strcmp(++cf,oldsavch)) { 894 /* redefinition different from old */ 895 --lineno[ifno]; 896 ppwarn("%s redefined",np->name); 897 ++lineno[ifno]; 898 np->value=psav-1; 899 } else { 900 psav=oldsavch; /* identical redef.; reclaim space */ 901 } 902 } else { 903 np->value=psav-1; 904 } 905 --flslvl; inp=pin; savch=psav; return(p); 906 } 907 908 #define fasscan() ptrtab=fastab+COFF 909 #define sloscan() ptrtab=slotab+COFF 910 911 static char * 912 control(p) register char *p; {/* find and handle preprocessor control lines */ 913 register struct symtab *np; 914 for (;;) { 915 fasscan(); p=cotoken(p); if (*inp=='\n') ++inp; dump(); 916 sloscan(); p=skipbl(p); 917 *--inp=SALT; outp=inp; ++flslvl; np=slookup(inp,p,0); --flslvl; 918 if (np==defloc) {/* define */ 919 if (flslvl==0) {p=dodef(p); continue;} 920 } else if (np==incloc) {/* include */ 921 if (flslvl==0) {p=doincl(p); continue;} 922 } else if (np==ifnloc) {/* ifndef */ 923 ++flslvl; p=skipbl(p); np=slookup(inp,p,0); --flslvl; 924 if (flslvl==0 && np->value==0) ++trulvl; 925 else ++flslvl; 926 } else if (np==ifdloc) {/* ifdef */ 927 ++flslvl; p=skipbl(p); np=slookup(inp,p,0); --flslvl; 928 if (flslvl==0 && np->value!=0) ++trulvl; 929 else ++flslvl; 930 } else if (np==eifloc) {/* endif */ 931 if (flslvl) {if (--flslvl==0) sayline(NOINCLUDE);} 932 else if (trulvl) --trulvl; 933 else pperror("If-less endif",0); 934 935 if (flslvl == 0) 936 elflvl = 0; 937 elslvl = 0; 938 } else if (np==elifloc) {/* elif */ 939 if (flslvl == 0) 940 elflvl = trulvl; 941 if (flslvl) { 942 if (elflvl > trulvl) { 943 ; 944 } else if (--flslvl != 0) { 945 ++flslvl; 946 } else { 947 newp = p; 948 if (yyparse()) { 949 ++trulvl; 950 sayline(NOINCLUDE); 951 } else { 952 ++flslvl; 953 } 954 p = newp; 955 } 956 } else if (trulvl) { 957 ++flslvl; 958 --trulvl; 959 } else 960 pperror("If-less elif"); 961 962 } else if (np==elsloc) {/* else */ 963 if (flslvl) { 964 if (elflvl > trulvl) 965 ; 966 else if (--flslvl!=0) ++flslvl; 967 else {++trulvl; sayline(NOINCLUDE);} 968 } 969 else if (trulvl) {++flslvl; --trulvl;} 970 else pperror("If-less else",0); 971 972 if (elslvl==trulvl+flslvl) 973 pperror("Too many #else's"); 974 elslvl=trulvl+flslvl; 975 976 } else if (np==udfloc) {/* undefine */ 977 if (flslvl==0) { 978 ++flslvl; p=skipbl(p); slookup(inp,p,DROP); --flslvl; 979 } 980 } else if (np==ifloc) {/* if */ 981 newp=p; 982 if (flslvl==0 && yyparse()) ++trulvl; else ++flslvl; 983 p=newp; 984 } else if (np == idtloc) { /* ident */ 985 if (pflag == 0) 986 while (*inp != '\n') /* pass text */ 987 p = cotoken(p); 988 } else if (np == pragmaloc) { /* pragma */ 989 while (*inp != '\n') /* pass text */ 990 p = cotoken(p); 991 #ifdef EXIT_ON_ERROR 992 } else if (np == errorloc) { /* error */ 993 if (trulvl > 0) { 994 char ebuf[BUFFERSIZ]; 995 996 p = ebuf; 997 while (*inp != '\n') { 998 if (*inp == '\0') 999 if (eob(--inp)) { 1000 inp = refill(inp); 1001 continue; 1002 } 1003 *p++ = *inp++; 1004 if (p >= &ebuf[BUFFERSIZ-1]) 1005 break; 1006 } 1007 *p = '\0'; 1008 pperror(ebuf); 1009 exit(exfail); 1010 } 1011 #endif 1012 } else if (np==lneloc) {/* line */ 1013 if (flslvl==0 && pflag==0) { 1014 outp=inp=p; 1015 *--outp='#'; 1016 while (*inp!='\n') 1017 p=cotoken(p); 1018 continue; 1019 } 1020 } else if (*++inp=='\n') { 1021 outp=inp; /* allows blank line after # */ 1022 } else { 1023 pperror("undefined control",0); 1024 } 1025 /* flush to lf */ 1026 ++flslvl; 1027 while (*inp!='\n') { 1028 outp=inp=p; 1029 p=cotoken(p); 1030 } 1031 --flslvl; 1032 } 1033 } 1034 1035 static struct symtab * 1036 stsym(s) register char *s; { 1037 char buf[BUFFERSIZ]; register char *p; 1038 1039 /* make definition look exactly like end of #define line */ 1040 /* copy to avoid running off end of world when param list is at end */ 1041 p=buf; while ((*p++= *s++) != '\0'); 1042 p=buf; while (isid(*p++)); /* skip first identifier */ 1043 if (*--p=='=') {*p++=' '; while (*p++);} 1044 else {s=" 1"; while ((*p++= *s++) != '\0');} 1045 pend=p; *--p='\n'; 1046 sloscan(); dodef(buf); return(lastsym); 1047 } 1048 1049 static struct symtab * 1050 ppsym(s) char *s; {/* kluge */ 1051 register struct symtab *sp; 1052 cinit=SALT; *savch++=SALT; sp=stsym(s); --sp->name; cinit=0; return(sp); 1053 } 1054 1055 void 1056 verror(char *fmt, va_list args) 1057 { 1058 if (fnames[ifno][0]) 1059 fprintf(stderr, "%s: ", fnames[ifno]); 1060 fprintf(stderr, "%d: ",lineno[ifno]); 1061 1062 (void)vfprintf(stderr, fmt, args); 1063 fputc('\n', stderr); 1064 } 1065 1066 /* VARARGS1 */ 1067 void 1068 pperror(char *fmt, ...) 1069 { 1070 va_list args; 1071 1072 va_start(args, fmt); 1073 verror(fmt, args); 1074 va_end(args); 1075 1076 exfail = 1; 1077 } 1078 1079 /* VARARGS1 */ 1080 void 1081 yyerror(char *fmt, ...) 1082 { 1083 va_list args; 1084 1085 va_start(args, fmt); 1086 verror(fmt, args); 1087 va_end(args); 1088 } 1089 1090 /* VARARGS1 */ 1091 static void 1092 ppwarn(char *fmt, ...) 1093 { 1094 va_list args; 1095 int fail = exfail; 1096 1097 va_start(args, fmt); 1098 verror(fmt, args); 1099 va_end(args); 1100 1101 exfail = fail; 1102 } 1103 1104 struct symtab * 1105 lookup(namep, enterf) 1106 char *namep; 1107 int enterf; 1108 { 1109 register char *np, *snp; 1110 register int c, i; int around; 1111 register struct symtab *sp; 1112 1113 /* namep had better not be too long (currently, <=symlen chars) */ 1114 np=namep; around=0; i=cinit; 1115 while ((c = *np++) != '\0') 1116 i += i+c; 1117 c=i; /* c=i for register usage on pdp11 */ 1118 c %= symsiz; 1119 if (c<0) 1120 c += symsiz; 1121 sp = &stab[c]; 1122 while ((snp=sp->name) != NULL) { 1123 np = namep; 1124 while (*snp++ == *np) 1125 if (*np++ == '\0') { 1126 if (enterf==DROP) { 1127 sp->name[0]= DROP; 1128 sp->value=0; 1129 } 1130 return(lastsym=sp); 1131 } 1132 if (--sp < &stab[0]) { 1133 if (around) { 1134 pperror("too many defines", 0); 1135 exit(exfail); 1136 } else { 1137 ++around; 1138 sp = &stab[symsiz-1]; 1139 } 1140 } 1141 } 1142 if (enterf>0) 1143 sp->name=namep; 1144 return (lastsym=sp); 1145 } 1146 1147 static struct symtab * 1148 slookup(p1,p2,enterf) register char *p1,*p2; int enterf;{ 1149 register char *p3; char c2,c3; struct symtab *np; 1150 c2= *p2; *p2='\0'; /* mark end of token */ 1151 if ((p2-p1)>symlen) 1152 p3=p1+symlen; 1153 else 1154 p3=p2; 1155 c3= *p3; *p3='\0'; /* truncate to symlen chars or less */ 1156 if (enterf==1) 1157 p1=copy(p1); 1158 np=lookup(p1,enterf); *p3=c3; *p2=c2; 1159 if (np->value!=0 && flslvl==0) 1160 newp=subst(p2,np); 1161 else 1162 newp=0; 1163 return(np); 1164 } 1165 1166 /* 1167 * When a macro substitution must happen, arrange the input stack based on the 1168 * macro definition and any parameters such that the expanded macro is what is 1169 * next read by the preprocessor as if it were input 1170 */ 1171 static char * 1172 subst(p,sp) register char *p; struct symtab *sp; { 1173 register char *ca,*vp; int params; 1174 char *actual[MAXFRM]; /* actual[n] is text of nth actual */ 1175 char acttxt[BUFFERSIZ]; /* space for actuals */ 1176 /* State while pasting, TRAIL is trailing space, INTRA is in the body */ 1177 enum { TRAIL, INTRA } state = TRAIL; 1178 int pasted = 0; /* # of character pasted */ 1179 1180 if (0==(vp=sp->value)) return(p); 1181 if ((p-macforw)<=macdam) { 1182 if (++maclvl>symsiz && !rflag) { 1183 pperror("%s: macro recursion",sp->name); 1184 return(p); 1185 } 1186 } else { 1187 maclvl=0; /* level decreased */ 1188 } 1189 macforw=p; macdam=0; /* new target for decrease in level */ 1190 macnam=sp->name; 1191 /* flush all buffered output prior to the expansion */ 1192 dump(); 1193 if (sp==ulnloc) { 1194 vp=acttxt; *vp++='\0'; 1195 sprintf(vp,"%d",lineno[ifno]); while (*vp++); 1196 } else if (sp==uflloc) { 1197 vp=acttxt; *vp++='\0'; 1198 sprintf(vp,"\"%s\"",fnames[ifno]); while (*vp++); 1199 } 1200 if (0!=(params= *--vp&0xFF)) {/* definition calls for params */ 1201 register char **pa; 1202 char *savp, *savinp, *savoutp; 1203 ca=acttxt; pa=actual; 1204 if (params==0xFF) 1205 params=1; /* #define foo() ... */ 1206 sloscan(); 1207 ++flslvl; /* no expansion during search for actuals */ 1208 plvl= -1; 1209 /* 1210 * Skip any blanks (including \n), until we hit the macro 1211 * arguments. 1212 * 1213 * save our state so we can roll back if none are called. 1214 */ 1215 savp = p; 1216 savinp = inp; 1217 savoutp = outp; 1218 do { 1219 p=skipbl(p); 1220 } while (*inp=='\n'); /* skip \n too */ 1221 1222 if (*inp=='(') { 1223 maclin=lineno[ifno]; macfil=fnames[ifno]; 1224 for (plvl=1; plvl!=0; ) { 1225 *ca++='\0'; 1226 for (;;) { 1227 outp=inp=p; p=cotoken(p); 1228 if (*inp=='(') ++plvl; 1229 if (*inp==')' && --plvl==0) { 1230 --params; 1231 break; 1232 } 1233 if (plvl==1 && *inp==',') { 1234 --params; 1235 break; 1236 } 1237 while (inp<p) { 1238 /* 1239 * Sun cpp compatibility. 1240 * Needed for kernel assembler 1241 * preprocessing. 1242 * Replace newlines in actual 1243 * macro parameters by spaces. 1244 * Keep escaped newlines, they 1245 * are assumed to be inside a 1246 * string. 1247 * 1248 * XXX: The above is actually 1249 * false in a couple of ways. 1250 * 1251 * 1) Sun cpp turns newlines 1252 * into spaces, but inserts an 1253 * equal number of newlines 1254 * prior to pasting the body. 1255 * 1256 * 2) Sun does _not_ preserved 1257 * escaped newlines, the \ is 1258 * removed, and the newline 1259 * otherwise treated 1260 * identically to in #1. 1261 */ 1262 if (*inp == '\n' && 1263 inp[-1] != '\\') 1264 *inp = ' '; 1265 *ca++= *inp++; 1266 } 1267 if (ca> &acttxt[BUFFERSIZ]) 1268 pperror("%s: actuals too long", 1269 sp->name); 1270 } 1271 if (pa>= &actual[MAXFRM]) 1272 ppwarn("%s: argument mismatch" , 1273 sp->name); 1274 else 1275 *pa++=ca; 1276 } 1277 } else { 1278 /* 1279 * Didn't find any parameters, rollback our state so 1280 * we don't chew more output than necessary 1281 */ 1282 p = savp; 1283 inp = savinp; 1284 outp = savoutp; 1285 } 1286 if (params!=0) 1287 ppwarn("%s: argument mismatch", sp->name); 1288 while (--params>=0) 1289 *pa++=""+1; /* null string for missing actuals */ 1290 --flslvl; fasscan(); 1291 } 1292 1293 for (;;) {/* push definition onto front of input stack */ 1294 /* 1295 * Loop until we hit the end of the macro, or a parameter 1296 * placement. Note that we expand the macro into the input 1297 * backwards (so it replays forwards.) 1298 */ 1299 while (!iswarn(*--vp)) { 1300 if (bob(p)) {outp=inp=p; p=unfill(p);} 1301 1302 /* Unless we are mid-paste, swallow all spaces */ 1303 if (state == TRAIL) { 1304 while (isspace(*vp) && !iswarn(*vp)) 1305 vp--; 1306 } else { 1307 /* 1308 * If we're mid-paste, compress spaces to a 1309 * single space 1310 */ 1311 while (isspace(*vp)) { 1312 if (!isspace(vp[1])) { 1313 *vp = ' '; 1314 break; 1315 } else { 1316 vp--; 1317 } 1318 } 1319 } 1320 state = INTRA; /* Hit a non-space */ 1321 1322 if (iswarn(*vp)) 1323 break; 1324 *--p= *vp; 1325 pasted++; 1326 } 1327 if (*vp==warnc) {/* insert actual param */ 1328 state = INTRA; 1329 ca=actual[*--vp-1]; 1330 while (*--ca) { 1331 if (bob(p)) {outp=inp=p; p=unfill(p);} 1332 *--p= *ca; 1333 pasted++; 1334 } 1335 } else { 1336 /* 1337 * Trim leading spaces, but only those from our pasting 1338 */ 1339 while (isspace(*p) && pasted > 0) { 1340 p++; 1341 pasted--; 1342 } 1343 break; 1344 } 1345 } 1346 outp=inp=p; 1347 return(p); 1348 } 1349 1350 static char * 1351 trmdir(s) register char *s; { 1352 register char *p = s; 1353 while (*p++); --p; while (p>s && *--p!='/'); 1354 # if unix 1355 if (p==s) *p++='.'; 1356 # endif 1357 *p='\0'; 1358 return(s); 1359 } 1360 1361 static char * 1362 copy(s) register char *s; { 1363 register char *old; 1364 1365 old = savch; while ((*savch++ = *s++) != '\0'); 1366 return(old); 1367 } 1368 1369 static char * 1370 strdex(s,c) char *s,c; { 1371 while (*s) if (*s++==c) return(--s); 1372 return(0); 1373 } 1374 1375 int 1376 yywrap() { 1377 return(1); 1378 } 1379 1380 int 1381 main(argc,argv) 1382 char *argv[]; 1383 int argc; 1384 { 1385 register int i,c; 1386 register char *p; 1387 char *tf,**cp2; 1388 char *sysdir = NULL; 1389 1390 fout = stdout; /* Mac OS X is not POSIX compliant (stdout nonconst.) */ 1391 1392 p="_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 1393 i=0; 1394 while ((c= *p++) != '\0') { 1395 (fastab+COFF)[c] |= IB|NB|SB; 1396 (toktyp+COFF)[c]=IDENT; 1397 #if scw2 1398 /* 1399 * 53 == 63-10; digits rarely appear in identifiers, 1400 * and can never be the first char of an identifier. 1401 * 11 == 53*53/sizeof(macbit) . 1402 */ 1403 ++i; (t21+COFF)[c]=(53*i)/11; (t22+COFF)[c]=i%11; 1404 #endif 1405 } 1406 p="0123456789."; 1407 while ((c = *p++) != '\0') { 1408 (fastab+COFF)[c] |= NB|SB; 1409 (toktyp+COFF)[c]=NUMBR; 1410 } 1411 p="\n\"'/\\"; 1412 while ((c = *p++) != '\0') 1413 (fastab+COFF)[c] |= SB; 1414 p="\n\"'\\"; 1415 while ((c = *p++) != '\0') 1416 (fastab+COFF)[c] |= QB; 1417 p="*\n"; 1418 while ((c = *p++)!= '\0') 1419 (fastab+COFF)[c] |= CB; 1420 (fastab+COFF)[(int)warnc] |= WB; 1421 (fastab+COFF)['\0'] |= CB|QB|SB|WB; 1422 for (i=ALFSIZ; --i>=0; ) 1423 slotab[i]=fastab[i]|SB; 1424 p=" \t\013\f\r"; /* note no \n; \v not legal for vertical tab? */ 1425 while ((c = *p++) != '\0') 1426 (toktyp+COFF)[c]=BLANK; 1427 #if scw2 1428 for ((t23+COFF)[i=ALFSIZ+7-COFF]=1; --i>=-COFF; ) 1429 if (((t23+COFF)[i]=(t23+COFF+1)[i]<<1)==0) 1430 (t23+COFF)[i]=1; 1431 #endif 1432 1433 # if unix 1434 fnames[ifno=0] = ""; 1435 dirs[0]=dirnams[0]= "."; 1436 # endif 1437 # if ibm 1438 fnames[ifno=0] = ""; 1439 # endif 1440 # if gimpel 1441 fnames[ifno=0] = (char *)inquire(stdin, _FILENAME); 1442 dirnams[0] = dirs[0] = trmdir(copy(fnames[0])); 1443 # endif 1444 for (i=1; i<argc; i++) { 1445 switch(argv[i][0]) { 1446 case '-': 1447 switch(argv[i][1]) { 1448 case 'P': 1449 pflag++; 1450 continue; 1451 case 'E': 1452 continue; 1453 case 'R': 1454 ++rflag; 1455 continue; 1456 case 'C': 1457 passcom++; 1458 continue; 1459 case 'D': 1460 if (predef>prespc+NPREDEF) { 1461 pperror("too many -D options, " 1462 "ignoring %s", argv[i]); 1463 continue; 1464 } 1465 /* ignore plain "-D" (no argument) */ 1466 if (*(argv[i]+2)) 1467 *predef++ = argv[i]+2; 1468 continue; 1469 case 'U': 1470 if (prund>punspc+NPREDEF) { 1471 pperror("too many -U options, " 1472 "ignoring %s", argv[i]); 1473 continue; 1474 } 1475 *prund++ = argv[i]+2; 1476 continue; 1477 case 'u': 1478 if (strcmp(argv[i], "-undef") == 0) 1479 nopredef = 1; 1480 else 1481 goto unknown; 1482 continue; 1483 case 'I': 1484 if (nd>=MAXIDIRS) 1485 pperror("excessive -I file " 1486 "(%s) ignored", argv[i]); 1487 else 1488 dirs[nd++] = argv[i]+2; 1489 continue; 1490 case 'T': 1491 symlen = 8; 1492 /* Compatibility with V7 */ 1493 continue; 1494 case 'H': 1495 /* Print included filenames */ 1496 hflag++; 1497 continue; 1498 case 'Y': 1499 /* Replace system include dir */ 1500 sysdir = argv[i]+2; 1501 continue; 1502 case '\0': continue; 1503 default: 1504 unknown: 1505 pperror("unknown flag %s", argv[i]); 1506 continue; 1507 } 1508 default: 1509 if (fin == STDIN_FILENO) { 1510 if (0>(fin=open(argv[i], O_RDONLY))) { 1511 pperror("No source file %s", 1512 argv[i]); 1513 exit(8); 1514 } 1515 fnames[ifno]=copy(argv[i]); 1516 dirs[0]=dirnams[ifno]=trmdir(argv[i]); 1517 /* too dangerous to have file name in same syntactic position 1518 be input or output file depending on file redirections, 1519 so force output to stdout, willy-nilly 1520 [i don't see what the problem is. jfr] 1521 */ 1522 } else if (fout==stdout) { 1523 static char _sobuff[BUFSIZ]; 1524 if (NULL==(fout=fopen(argv[i], "w"))) { 1525 pperror("Can't create %s", 1526 argv[i]); 1527 exit(8); 1528 } else { 1529 fclose(stdout); 1530 setbuf(fout,_sobuff); 1531 } 1532 } else { 1533 pperror("extraneous name %s", argv[i]); 1534 } 1535 } 1536 } 1537 1538 fins[ifno]=fin; 1539 exfail = 0; 1540 /* after user -I files here are the standard include libraries */ 1541 if (sysdir != NULL) { 1542 dirs[nd++] = sysdir; 1543 } else { 1544 # if unix 1545 dirs[nd++] = "/usr/include"; 1546 # endif 1547 /* dirs[nd++] = "/compool"; */ 1548 } 1549 dirs[nd++] = 0; 1550 defloc=ppsym("define"); 1551 udfloc=ppsym("undef"); 1552 incloc=ppsym("include"); 1553 elsloc=ppsym("else"); 1554 eifloc=ppsym("endif"); 1555 elifloc=ppsym("elif"); 1556 ifdloc=ppsym("ifdef"); 1557 ifnloc=ppsym("ifndef"); 1558 ifloc=ppsym("if"); 1559 lneloc=ppsym("line"); 1560 idtloc=ppsym("ident"); 1561 pragmaloc=ppsym("pragma"); 1562 errorloc=ppsym("error"); 1563 for (i=sizeof(macbit)/sizeof(macbit[0]); --i>=0; ) 1564 macbit[i]=0; 1565 1566 if (! nopredef) { 1567 ysysloc=stsym("unix"); 1568 ysysloc=stsym("sun"); 1569 # if __sparc__ 1570 varloc=stsym ("sparc"); 1571 # endif 1572 # if __i386__ 1573 varloc=stsym ("i386"); 1574 # endif 1575 } 1576 ulnloc=stsym ("__LINE__"); 1577 uflloc=stsym ("__FILE__"); 1578 varloc=stsym ("__BUILTIN_VA_ARG_INCR"); 1579 1580 tf=fnames[ifno]; fnames[ifno]="command line"; lineno[ifno]=1; 1581 cp2=prespc; 1582 while (cp2<predef) stsym(*cp2++); 1583 cp2=punspc; 1584 while (cp2<prund) { 1585 if ((p=strdex(*cp2, '=')) != NULL) *p++='\0'; 1586 if (strlen(*cp2) > symlen) 1587 (*cp2)[symlen] = '\0'; 1588 lookup(*cp2++, DROP); 1589 } 1590 fnames[ifno]=tf; 1591 pbeg=buffer+symlen; pbuf=pbeg+BUFFERSIZ; pend=pbuf+BUFFERSIZ; 1592 1593 trulvl = 0; flslvl = 0; 1594 lineno[0] = 1; sayline(NOINCLUDE); 1595 outp=inp=pend; 1596 control(pend); 1597 return (exfail); 1598 }