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 4000
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 }