Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20150819120612

Diff

Diff from 1.152 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/pcc/pcc/cc/cpp/token.c

Annotated File View

plunky
1.152
1 /*      $Id: token.c,v 1.152 2015/08/19 12:06:12 plunky Exp $   */
ragge
1.1
2
3 /*
ragge
1.13
4  * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved.
ragge
1.1
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
ragge
1.19
27 /*
28  * Tokenizer for the C preprocessor.
29  * There are three main routines:
30  *      - fastscan() loops over the input stream searching for magic
31  *              characters that may require actions.
plunky
1.113
32  *      - yylex() returns something from the input stream that
ragge
1.19
33  *              is suitable for yacc.
34  *
35  *      Other functions of common use:
36  *      - inpch() returns a raw character from the current input stream.
37  *      - inch() is like inpch but \\n and trigraphs are expanded.
38  *      - unch() pushes back a character to the input stream.
ragge
1.125
39  *
40  * Input data can be read from either stdio or a buffer.
ragge
1.132
41  * If a buffer is read, it will return EOF when ended and then jump back
42  * to the previous buffer.
43  *      - setibuf(usch *ptr). Buffer to read from, until NULL, return EOF.
44  *              When EOF returned, pop buffer.
45  *      - setobuf(usch *ptr).  Buffer to write to
ragge
1.125
46  *
47  * There are three places data is read:
48  *      - fastscan() which has a small loop that will scan over input data.
49  *      - flscan() where everything is skipped except directives (flslvl)
ragge
1.132
50  *      - inch() that everything else uses.
ragge
1.125
51  *
52  * 5.1.1.2 Translation phases:
53  *      1) Convert UCN to UTF-8 which is what pcc uses internally (chkucn).
54  *         Remove \r (unwanted)
55  *         Convert trigraphs (chktg)
56  *      2) Remove \\\n.  Need extra care for identifiers and #line.
57  *      3) Tokenize.
58  *         Remove comments (fastcmnt)
ragge
1.19
59  */
60
ragge
1.13
61 #include "config.h"
62
ragge
1.1
63 #include <stdlib.h>
64 #include <string.h>
ragge
1.13
65 #ifdef HAVE_UNISTD_H
ragge
1.2
66 #include <unistd.h>
ragge
1.13
67 #endif
ragge
1.2
68 #include <fcntl.h>
ragge
1.1
69
ragge
1.13
70 #include "compat.h"
ragge
1.1
71 #include "cpp.h"
ragge
1.13
72
ragge
1.136
73 static void cvtdig(usch **);
plunky
1.114
74 static int dig2num(int);
ragge
1.136
75 static int charcon(usch **);
ragge
1.13
76 static void elsestmt(void);
77 static void ifdefstmt(void);
78 static void ifndefstmt(void);
79 static void endifstmt(void);
80 static void ifstmt(void);
81 static void cpperror(void);
plunky
1.102
82 static void cppwarning(void);
83 static void undefstmt(void);
ragge
1.13
84 static void pragmastmt(void);
85 static void elifstmt(void);
86
ragge
1.122
87 static int inpch(void);
88 static int chktg(void);
89 static int chkucn(void);
90 static void unch(int c);
91
plunky
1.121
92 #define PUTCH(ch) if (!flslvl) putch(ch)
ragge
1.13
93 /* protection against recursion in #include */
94 #define MAX_INCLEVEL    100
95 static int inclevel;
96
plunky
1.81
97 struct includ *ifiles;
98
plunky
1.97
99 /* some common special combos for init */
100 #define C_NL    (C_SPEC|C_WSNL)
101 #define C_DX    (C_SPEC|C_ID|C_DIGIT|C_HEX)
102 #define C_I     (C_SPEC|C_ID|C_ID0)
103 #define C_IP    (C_SPEC|C_ID|C_ID0|C_EP)
104 #define C_IX    (C_SPEC|C_ID|C_ID0|C_HEX)
105 #define C_IXE   (C_SPEC|C_ID|C_ID0|C_HEX|C_EP)
106
107 usch spechr[256] = {
ragge
1.43
108         0,      0,      0,      0,      C_SPECC_SPEC0,      0,
plunky
1.97
109         0,      C_WSNLC_NL,   0,      0,      C_WSNL0,      0,
ragge
1.19
110         0,      0,      0,      0,      0,      0,      0,      0,
111         0,      0,      0,      0,      0,      0,      0,      0,
112
ragge
1.43
113         C_WSNLC_2,    C_SPEC0,      0,      0,      C_2,    C_SPEC,
ragge
1.33
114         0,      0,      0,      C_2,    0,      C_2,    0,      C_SPEC|C_2,
plunky
1.97
115         C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,
ragge
1.140
116         C_DX,   C_DX,   0,      0,      C_2,    C_2,    C_2,    C_SPEC,
ragge
1.19
117
plunky
1.97
118         0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
ragge
1.19
119         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.97
120         C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.114
121         C_I,    C_I,    C_I,    0,      C_SPEC0,      0,      C_I,
ragge
1.19
122
plunky
1.97
123         0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
ragge
1.19
124         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.97
125         C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
ragge
1.19
126         C_I,    C_I,    C_I,    0,      C_2,    0,      0,      0,
ragge
1.111
127
128 /* utf-8 */
129         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
130         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
131         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
132         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
133
134         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
135         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
136         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
137         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
138
139         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
140         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
141         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
142         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
143
144         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
145         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
146         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.112
147         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
ragge
1.19
148 };
ragge
1.1
149
plunky
1.102
150 /*
151  * fill up the input buffer
152  */
153 static int
154 inpbuf(void)
155 {
156         int len;
157
158         if (ifiles->infil == -1)
159                 return 0;
160         len = read(ifiles->infilifiles->bufferCPPBUF);
161         if (len == -1)
162                 error("read error on file %s"ifiles->orgfn);
163         if (len > 0) {
164                 ifiles->buffer[len] = 0;
165                 ifiles->curptr = ifiles->buffer;
166                 ifiles->maxread = ifiles->buffer + len;
167         }
168         return len;
169 }
170
171 /*
ragge
1.140
172  * Fillup input buffer to contain at least minsz characters.
173  */
174 static int
175 refill(int minsz)
176 {
177         usch *dp;
178         int isz;
179
180         if (ifiles->curptr+minsz < ifiles->maxread)
181                 return 0/* already enough in input buffer */
182
183         sz = ifiles->maxread - ifiles->curptr;
184         dp = ifiles->buffer - sz;
185         for (i = 0i < szi++)
186                 dp[i] = ifiles->curptr[i];
ragge
1.151
187         i = inpbuf();
ragge
1.140
188         ifiles->curptr = dp;
ragge
1.151
189         if (i == 0) {
190                 ifiles->maxread = ifiles->buffer;
191                 ifiles->buffer[0] = 0;
192         }
ragge
1.140
193         return 0;
194 }
ragge
1.151
195 #define REFILL(x) if (ifiles->curptr+x >= ifiles->maxread) refill(x)
ragge
1.140
196
197 /*
plunky
1.102
198  * return a raw character from the input stream
199  */
200 static inline int
201 inpch(void)
202 {
203
204         do {
205                 if (ifiles->curptr < ifiles->maxread)
206                         return *ifiles->curptr++;
207         } while (inpbuf() > 0);
208
209         return -1;
210 }
211
212 /*
213  * push a character back to the input stream
214  */
ragge
1.13
215 static void
216 unch(int c)
217 {
plunky
1.93
218         if (c == -1)
219                 return;
plunky
1.113
220
plunky
1.102
221         ifiles->curptr--;
ragge
1.15
222         if (ifiles->curptr < ifiles->bbuf)
223                 error("pushback buffer full");
gmcgarry
1.26
224         *ifiles->curptr = (usch)c;
ragge
1.13
225 }
ragge
1.1
226
plunky
1.102
227 /*
228  * Check for (and convert) trigraphs.
229  */
230 static int
231 chktg(void)
232 {
233         int ch;
234
235         if ((ch = inpch()) != '?') {
236                 unch(ch);
237                 return 0;
238         }
239
240         switch (ch = inpch()) {
241         case '=':  return '#';
242         case '(':  return '[';
243         case ')':  return ']';
244         case '<':  return '{';
245         case '>':  return '}';
246         case '/':  return '\\';
247         case '\''return '^';
248         case '!':  return '|';
249         case '-':  return '~';
250         }
251
252         unch(ch);
253         unch('?');
254         return 0;
255 }
256
257 /*
ragge
1.125
258  * 5.1.1.2 Translation phase 1.
plunky
1.102
259  */
260 static int
ragge
1.125
261 inc1(void)
plunky
1.102
262 {
ragge
1.125
263         int chc2;
plunky
1.102
264
ragge
1.125
265         do {
plunky
1.102
266                 ch = inpch();
ragge
1.125
267         } while (/* ch == '\r' || */ (ch == '\\' && chkucn()));
268         if (ch == '?' && (c2 = chktg()))
269                 ch = c2;
270         return ch;
271 }
272
273
274 /*
275  * 5.1.1.2 Translation phase 2.
276  */
ragge
1.141
277 int
ragge
1.125
278 inc2(void)
279 {
280         int chc2;
281
282         if ((ch = inc1()) != '\\')
283                 return ch;
284         if ((c2 = inc1()) == '\n') {
285                 ifiles->escln++;
286                 ch = inc2();
287         } else
288                 unch(c2);
289         return ch;
290 }
291
ragge
1.144
292 static int incmnt;
ragge
1.125
293 /*
294  * deal with comments in the fast scanner.
295  * ps prints out the initial '/' if failing to batch comment.
296  */
297 static int
298 fastcmnt(int ps)
299 {
ragge
1.144
300         int chrv = 1;
plunky
1.102
301
ragge
1.144
302         incmnt = 1;
ragge
1.125
303         if ((ch = inc2()) == '/') { /* C++ comment */
304                 while ((ch = inc2()) != '\n')
305                         ;
plunky
1.102
306                 unch(ch);
ragge
1.125
307         } else if (ch == '*') {
308                 for (;;) {
ragge
1.131
309                         if ((ch = inc2()) < 0)
310                                 break;
ragge
1.125
311                         if (ch == '*') {
312                                 if ((ch = inc2()) == '/') {
313                                         break;
314                                 } else
315                                         unch(ch);
316                         } else if (ch == '\n') {
317                                 ifiles->lineno++;
318                                 putch('\n');
319                         }
320                 }
321         } else {
322                 if (psPUTCH('/'); /* XXX ? */
323                 unch(ch);
ragge
1.144
324                 rv = 0;
ragge
1.125
325         }
ragge
1.131
326         if (ch < 0)
327                 error("file ends in comment");
ragge
1.144
328         incmnt = 0;
329         return rv;
plunky
1.102
330 }
331
332 /*
ragge
1.125
333  * return next char, partly phase 3.
plunky
1.102
334  */
ragge
1.125
335 static int
plunky
1.102
336 inch(void)
337 {
ragge
1.125
338         int chn;
plunky
1.102
339
ragge
1.125
340         ch = inc2();
341         n = ifiles->lineno;
342         if (ch == '/' && Cflag == 0 && fastcmnt(0)) {
343                 /* Comments 5.1.1.2 p3 */
344                 /* no space if traditional or multiline */
345                 ch = (tflag || n != ifiles->lineno) ? inch() : ' ';
plunky
1.102
346         }
ragge
1.125
347         return ch;
plunky
1.102
348 }
349
plunky
1.114
350 /*
351  * check for universal-character-name on input, and
352  * unput to the pushback buffer encoded as UTF-8.
353  */
354 static int
355 chkucn(void)
356 {
357         unsigned long cpm;
358         int chn;
359
ragge
1.144
360         if (incmnt)
361                 return 0;
ragge
1.142
362         if ((ch = inpch()) == -1)
plunky
1.114
363                 return 0;
364         if (ch == 'u')
365                 n = 4;
366         else if (ch == 'U')
367                 n = 8;
368         else {
369                 unch(ch);
370                 return 0;
371         }
372
373         cp = 0;
374         while (n-- > 0) {
ragge
1.142
375                 if ((ch = inpch()) == -1 || (spechr[ch] & C_HEX) == 0) {
plunky
1.114
376                         warning("invalid universal character name");
377                         // XXX should actually unput the chars and return 0
378                         unch(ch); // XXX eof
379                         break;
380                 }
381                 cp = cp * 16 + dig2num(ch);
382         }
383
plunky
1.115
384         if ((cp < 0xa0 && cp != 0x24 && cp != 0x40 && cp != 0x60)
385             || (cp >= 0xd800 && cp <= 0xdfff))  /* 6.4.3.2 */
386                 error("universal character name cannot be used");
387
plunky
1.114
388         if (cp > 0x7fffffff)
389                 error("universal character name out of range");
390
391         n = 0;
392         m = 0x7f;
393         while (cp > m) {
394                 unch(0x80 | (cp & 0x3f));
395                 cp >>= 6;
396                 m >>= (n++ ? 1 : 2);
397         }
398         unch(((m << 1) ^ 0xfe) | cp);
399         return 1;
400 }
401
ragge
1.122
402 /*
403  * deal with comments when -C is active.
ragge
1.125
404  * Save comments in expanded macros???
ragge
1.122
405  */
ragge
1.134
406 int
ragge
1.128
407 Ccmnt(void (*d)(int))
ragge
1.122
408 {
409         int ch;
410
411         if ((ch = inch()) == '/') { /* C++ comment */
ragge
1.128
412                 d(ch);
ragge
1.122
413                 do {
ragge
1.128
414                         d(ch);
ragge
1.122
415                 } while ((ch = inch()) != '\n');
416                 unch(ch);
417                 return 1;
418         } else if (ch == '*') {
ragge
1.128
419                 d('/');
420                 d('*');
ragge
1.122
421                 for (;;) {
422                         ch = inch();
ragge
1.128
423                         d(ch);
ragge
1.122
424                         if (ch == '*') {
425                                 if ((ch = inch()) == '/') {
ragge
1.128
426                                         d(ch);
ragge
1.122
427                                         return 1;
428                                 } else
429                                         unch(ch);
430                         } else if (ch == '\n') {
431                                 ifiles->lineno++;
432                         }
433                 }
434         }
ragge
1.128
435         d('/');
ragge
1.122
436         unch(ch);
437         return 0;
438 }
439
ragge
1.125
440 /*
441  * Traverse over spaces and comments from the input stream,
ragge
1.129
442  * Returns first non-space character.
ragge
1.125
443  */
plunky
1.108
444 static int
ragge
1.129
445 fastspc(void)
ragge
1.45
446 {
447         int ch;
448
ragge
1.129
449         while ((ch = inch()), ISWS(ch))
450                 ;
ragge
1.125
451         return ch;
ragge
1.45
452 }
453
ragge
1.19
454 /*
ragge
1.125
455  * As above but only between \n and #.
ragge
1.122
456  */
457 static int
ragge
1.125
458 fastspcg(void)
ragge
1.122
459 {
ragge
1.125
460         int chc2;
ragge
1.122
461
ragge
1.125
462         while ((ch = inch()) == '/' || ch == '%' || ISWS(ch)) {
463                 if (ch == '%') {
464                         if ((c2 = inch()) == ':')
465                                 ch = '#'/* digraphs */
466                         else
467                                 unch(c2);
468                         break;
469                 }
470                 if (ch == '/') {
471                         if (Cflag)
472                                 return ch;
473                         if (fastcmnt(0) == 0)
ragge
1.122
474                                 break;
ragge
1.125
475                         putch(' ');
476                 } else
477                         putch(ch);
ragge
1.122
478         }
479         return ch;
480 }
481
482 /*
ragge
1.131
483  * readin chars and store on heap. Warn about too long names.
484  */
ragge
1.134
485 usch *
ragge
1.131
486 heapid(int ch)
487 {
ragge
1.134
488         usch *bp = stringbuf;
ragge
1.131
489         do {
490                 savch(ch);
491         } while (spechr[ch = inch()] & C_ID);
492         savch(0);
493         unch(ch);
ragge
1.134
494         return bp;
ragge
1.131
495 }
496
497 /*
ragge
1.125
498  * get a string or character constant and save it as given by d.
499  */
ragge
1.134
500 void
ragge
1.125
501 faststr(int bcvoid (*d)(int))
502 {
503         int ch;
504
ragge
1.146
505         incmnt = 1;
ragge
1.125
506         d(bc);
507         while ((ch = inc2()) != bc) {
508                 if (ch == '\n') {
509                         warning("unterminated literal");
ragge
1.146
510                         incmnt = 0;
ragge
1.125
511                         unch(ch);
512                         return;
513                 }
514                 if (ch < 0)
515                         return;
516                 if (ch == '\\') {
ragge
1.146
517                         incmnt = 0;
ragge
1.145
518                         if (chkucn())
519                                 continue;
ragge
1.146
520                         incmnt = 1;
ragge
1.125
521                         d(ch);
522                         ch = inc2();
523                 }
524                 d(ch);
525         }
526         d(ch);
ragge
1.146
527         incmnt = 0;
ragge
1.125
528 }
529
530 /*
531  * get a preprocessing number and save it as given by d.
532  * Initial char ch is always stored.
533  * returns first non-pp-number char.
534  *
535  *      pp-number:      digit
536  *                      . digit
537  *                      pp-number digit
538  *                      pp-number identifier-nondigit
539  *                      pp-number e sign
540  *                      pp-number E sign
541  *                      pp-number p sign
542  *                      pp-number P sign
543  *                      pp-number .
544  */
ragge
1.134
545 int
ragge
1.125
546 fastnum(int chvoid (*d)(int))
547 {
548         int c2;
549
ragge
1.126
550         if ((spechr[ch] & C_DIGIT) == 0) {
551                 /* not digit, dot */
552                 d(ch);
553                 ch = inch();
554                 if ((spechr[ch] & C_DIGIT) == 0)
555                         return ch;
556         }
ragge
1.125
557         for (;;) {
558                 d(ch);
559                 if ((ch = inch()) < 0)
560                         return -1;
561                 if ((spechr[ch] & C_EP)) {
562                         if ((c2 = inch()) != '-' && c2 != '+') {
563                                 if (c2 >= 0)
564                                         unch(c2);
565                                 break;
566                         }
567                         d(ch);
568                         ch = c2;
569                 } else if (ch == '.' || (spechr[ch] & C_ID)) {
570                         continue;
571                 } else
572                         break;
573         }
574         return ch;
575 }
ragge
1.122
576
577 /*
ragge
1.19
578  * Scan quickly the input file searching for:
579  *      - '#' directives
580  *      - keywords (if not flslvl)
581  *      - comments
582  *
583  *      Handle strings, numbers and trigraphs with care.
584  *      Only data from pp files are scanned here, never any rescans.
ragge
1.125
585  *      This loop is always at trulvl.
ragge
1.19
586  */
587 static void
588 fastscan(void)
589 {
590         struct symtab *nl;
ragge
1.140
591         int chc2inch;
ragge
1.49
592         usch *cp;
ragge
1.19
593
594         goto run;
ragge
1.125
595
ragge
1.19
596         for (;;) {
ragge
1.125
597                 /* tight loop to find special chars */
598                 /* should use getchar/putchar here */
599                 for (;;) {
ragge
1.140
600                         if (ifiles->curptr < ifiles->maxread) {
601                                 ch = *ifiles->curptr++;
602                         } else {
603                                 if (inpbuf() > 0)
604                                         continue;
605                                 return;
606                         }
ragge
1.125
607 xloop:                  if (ch < 0)
608                                 return/* EOF */
609                         if ((spechr[ch] & C_SPEC) != 0)
610                                 break;
611                         putch(ch);
ragge
1.19
612                 }
ragge
1.125
613
ragge
1.140
614                 REFILL(2);
615                 nch = *ifiles->curptr;
ragge
1.19
616                 switch (ch) {
ragge
1.43
617                 case WARN:
618                 case CONC:
619                         error("bad char passed");
620                         break;
621
ragge
1.19
622                 case '/'/* Comments */
ragge
1.140
623                         if (nch != '/' && nch != '*') {
624                                 putch(ch);
625                                 continue;
626                         }
ragge
1.125
627                         if (Cflag == 0) {
628                                 if (fastcmnt(1))
629                                         putch(' '); /* 5.1.1.2 p3 */
630                         } else
ragge
1.128
631                                 Ccmnt(putch);
ragge
1.19
632                         break;
633
634                 case '\n'/* newlines, for pp directives */
ragge
1.125
635                         /* take care of leftover \n */
plunky
1.102
636                         i = ifiles->escln + 1;
637                         ifiles->lineno += i;
638                         ifiles->escln = 0;
639                         while (i-- > 0)
plunky
1.121
640                                 putch('\n');
ragge
1.125
641
642                         /* search for a # */
643 run:                    while ((ch = inch()) == '\t' || ch == ' ')
644                                 putch(ch);
645                         if (ch == '%') {
646                                 if ((c2 = inch()) != ':')
647                                         unch(c2);
648                                 else
649                                         ch = '#';
ragge
1.50
650                         }
ragge
1.125
651                         if (ch  == '#')
ragge
1.19
652                                 ppdir();
ragge
1.125
653                         else
654                                 goto xloop;
655                         break;
656
ragge
1.140
657                 case '?':
658                         if (nch == '?' && (ch = chktg()))
659                                 goto xloop;
660                         putch('?');
661                         break;
662
ragge
1.125
663                 case '\''/* character constant */
664                         if (tflag) {
665                                 putch(ch);
666                                 break;  /* character constants ignored */
ragge
1.19
667                         }
ragge
1.125
668                         /* FALLTHROUGH */
ragge
1.19
669                 case '\"'/* strings */
ragge
1.125
670                         faststr(chputch);
ragge
1.19
671                         break;
672
673                 case '.':  /* for pp-number */
674                 case '0'case '1'case '2'case '3'case '4':
675                 case '5'case '6'case '7'case '8'case '9':
ragge
1.125
676                         ch = fastnum(chputch);
ragge
1.19
677                         goto xloop;
678
ragge
1.150
679                 case 'u':
680                         if (nch == '8' && ifiles->curptr[1] == '\"') {
681                                 putch(ch);
682                                 break;
683                         }
684                         /* FALLTHROUGH */
ragge
1.19
685                 case 'L':
ragge
1.150
686                 case 'U':
ragge
1.140
687                         if (nch == '\"' || nch == '\'') {
688                                 putch(ch);
689                                 break;
ragge
1.19
690                         }
691                         /* FALLTHROUGH */
692                 default:
plunky
1.102
693 #ifdef PCC_DEBUG
ragge
1.19
694                         if ((spechr[ch] & C_ID) == 0)
695                                 error("fastscan");
plunky
1.102
696 #endif
plunky
1.114
697                 ident:
ragge
1.131
698                         if (flslvl)
699                                 error("fastscan flslvl");
700                         cp = stringbuf;
701                         heapid(ch);
ragge
1.134
702                         stringbuf = cp;
703                         if ((nl = lookup(cpFIND))) {
704                                 if (kfind(nl))
705                                         putstr(cp);
706                         } else
ragge
1.131
707                                 putstr(cp);
708                         stringbuf = cp;
ragge
1.19
709                         break;
plunky
1.114
710
711                 case '\\':
ragge
1.140
712                         if (nch == '\n') {
713                                 ifiles->escln++;
714                                 ifiles->curptr++;
715                                 break;
716                         }
plunky
1.114
717                         if (chkucn()) {
718                                 ch = inch();
719                                 goto ident;
720                         }
ragge
1.125
721                         putch('\\');
plunky
1.114
722                         break;
ragge
1.19
723                 }
724         }
plunky
1.108
725
ragge
1.131
726 /*eof:*/        warning("unexpected EOF");
plunky
1.121
727         putch('\n');
ragge
1.19
728 }
ragge
1.1
729
ragge
1.136
730 /*
731  * Store an if/elif line on heap for parsing, evaluate macros and 
732  * call yyparse().
733  */
734 static usch *yyinp;
ragge
1.143
735 int inexpr;
ragge
1.136
736 static int
737 exprline(void)
738 {
739         struct symtab *nl;
740         int oCflag = Cflag;
741         usch *cp, *bp = stringbuf;
742         int cifdef;
743
744         Cflag = ifdef = 0;
745
746         while ((c = inch()) != '\n') {
ragge
1.148
747                 if (c == '\'' || c == '\"') {
748                         faststr(csavch);
749                         continue;
750                 }
751                 if (ISDIGIT(c) || c == '.') {
ragge
1.147
752                         c = fastnum(csavch);
ragge
1.148
753                         if (c == '\n')
754                                 break;
755                         unch(c);
756                         continue;
757                 }
ragge
1.136
758                 if (ISID0(c)) {
759                         cp = heapid(c);
760                         stringbuf = cp;
761                         nl = lookup(cpFIND);
762                         if (strcmp((char *)cp"defined") == 0) {
763                                 ifdef = 1;
764                         } else if (ifdef) {
765                                 savch(nl ? '1' : '0');
766                                 ifdef = 0;
767                         } else if (nl != NULL) {
ragge
1.143
768                                 inexpr = 1;
ragge
1.136
769                                 kfind(nl);
ragge
1.143
770                                 inexpr = 0;
771                                 while (*stringbuf)
772                                         stringbuf++;
ragge
1.136
773                         } else
774                                 savch('0');
775                 } else
776                         savch(c);
777         }
778         savch(0);
779         unch('\n');
780         yyinp = bp;
781         c = yyparse();
782         stringbuf = bp;
783         Cflag = oCflag;
784         return c;
785 }
786
ragge
1.19
787 int
plunky
1.64
788 yylex(void)
ragge
1.19
789 {
ragge
1.136
790         int chc2t;
ragge
1.19
791
ragge
1.136
792         while ((ch = *yyinp++) == ' ' || ch == '\t')
ragge
1.19
793                 ;
ragge
1.136
794         t = ISDIGIT(ch) ? NUMBER : ch;
plunky
1.97
795         if (ch < 128 && (spechr[ch] & C_2))
ragge
1.136
796                 c2 = *yyinp++;
ragge
1.19
797         else
798                 c2 = 0;
799
ragge
1.136
800         switch (t) {
801         case 0return WARN;
plunky
1.97
802         case '=':
803                 if (c2 == '='return EQ;
804                 break;
805         case '!':
806                 if (c2 == '='return NE;
807                 break;
808         case '|':
809                 if (c2 == '|'return OROR;
810                 break;
811         case '&':
812                 if (c2 == '&'return ANDAND;
813                 break;
ragge
1.19
814         case '<':
815                 if (c2 == '<'return LS;
816                 if (c2 == '='return LE;
817                 break;
818         case '>':
819                 if (c2 == '>'return RS;
820                 if (c2 == '='return GE;
821                 break;
822         case '+':
823         case '-':
824                 if (ch == c2)
plunky
1.78
825                         error("invalid preprocessor operator %c%c"chc2);
ragge
1.19
826                 break;
ragge
1.27
827
ragge
1.136
828         case '\'':
829                 yynode.op = NUMBER;
830                 yynode.nd_val = charcon(&yyinp);
831                 return NUMBER;
ragge
1.33
832
ragge
1.19
833         case NUMBER:
ragge
1.136
834                 cvtdig(&yyinp);
ragge
1.19
835                 return NUMBER;
ragge
1.27
836
ragge
1.19
837         default:
ragge
1.143
838                 if (ISID0(t)) {
839                         yyinp--;
840                         while (ISID(*yyinp))
841                                 yyinp++;
842                         yynode.nd_val = 0;
843                         return NUMBER;
844                 }
ragge
1.19
845                 return ch;
846         }
ragge
1.136
847         yyinp--;
ragge
1.19
848         return ch;
849 }
850
ragge
1.13
851 /*
852  * Let the command-line args be faked defines at beginning of file.
853  */
854 static void
855 prinit(struct initar *itstruct includ *ic)
ragge
1.1
856 {
ragge
1.31
857         const char *pre, *post;
858         char *a;
ragge
1.1
859
ragge
1.13
860         if (it->next)
861                 prinit(it->nextic);
862         pre = post = NULL/* XXX gcc */
863         switch (it->type) {
864         case 'D':
865                 pre = "#define ";
866                 if ((a = strchr(it->str'=')) != NULL) {
867                         *a = ' ';
868                         post = "\n";
ragge
1.1
869                 } else
ragge
1.13
870                         post = " 1\n";
ragge
1.1
871                 break;
ragge
1.13
872         case 'U':
873                 pre = "#undef ";
874                 post = "\n";
ragge
1.1
875                 break;
ragge
1.13
876         case 'i':
877                 pre = "#include \"";
878                 post = "\"\n";
ragge
1.1
879                 break;
880         default:
ragge
1.13
881                 error("prinit");
ragge
1.1
882         }
ragge
1.13
883         strlcat((char *)ic->bufferpreCPPBUF+1);
884         strlcat((char *)ic->bufferit->strCPPBUF+1);
885         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
886                 error("line exceeds buffer size");
887
888         ic->lineno--;
889         while (*ic->maxread)
890                 ic->maxread++;
ragge
1.1
891 }
892
ragge
1.4
893 /*
ragge
1.6
894  * A new file included.
895  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
896  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
897  */
898 int
ragge
1.31
899 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
900 {
ragge
1.13
901         extern struct initar *initar;
ragge
1.6
902         struct includ ibuf;
903         struct includ *ic;
plunky
1.82
904         int otrulvl;
ragge
1.6
905
906         ic = &ibuf;
ragge
1.13
907         ic->next = ifiles;
ragge
1.4
908
ragge
1.6
909         if (file != NULL) {
ragge
1.31
910                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
911                         return -1;
ragge
1.13
912                 ic->orgfn = ic->fname = file;
913                 if (++inclevel > MAX_INCLEVEL)
plunky
1.102
914                         error("limit for nested includes exceeded");
ragge
1.6
915         } else {
916                 ic->infil = 0;
ragge
1.31
917                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
918         }
ragge
1.49
919 #ifndef BUF_STACK
920         ic->bbuf = malloc(BBUFSZ);
921 #endif
ragge
1.140
922         ic->buffer = ic->bbuf+PBMAX;
ragge
1.4
923         ic->curptr = ic->buffer;
924         ifiles = ic;
ragge
1.13
925         ic->lineno = 1;
plunky
1.102
926         ic->escln = 0;
ragge
1.6
927         ic->maxread = ic->curptr;
ragge
1.29
928         ic->idx = idx;
929         ic->incs = incs;
930         ic->fn = fn;
ragge
1.139
931         prtline(1);
ragge
1.13
932         if (initar) {
ragge
1.38
933                 int oin = ic->infil;
934                 ic->infil = -1;
ragge
1.13
935                 *ic->maxread = 0;
936                 prinit(initaric);
ragge
1.41
937                 initar = NULL;
ragge
1.13
938                 if (dMflag)
ragge
1.120
939                         printf("%s", (char *)ic->buffer);
ragge
1.38
940                 fastscan();
ragge
1.139
941                 prtline(1);
ragge
1.38
942                 ic->infil = oin;
ragge
1.13
943         }
ragge
1.4
944
ragge
1.13
945         otrulvl = trulvl;
ragge
1.4
946
ragge
1.19
947         fastscan();
ragge
1.13
948
949         if (otrulvl != trulvl || flslvl)
ragge
1.6
950                 error("unterminated conditional");
ragge
1.4
951