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