Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20150627130202

Diff

Diff from 1.140 to:

Annotations

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

Annotated File View

ragge
1.140
1 /*      $Id: token.c,v 1.140 2015/06/27 13:02:02 ragge 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];
187         (void)inpbuf();
188         ifiles->curptr = dp;
189         return 0;
190 }
191 #define REFILL(x) if (ifiles->curptr+x < ifiles->maxread) refill(x)
192
193 /*
plunky
1.102
194  * return a raw character from the input stream
195  */
196 static inline int
197 inpch(void)
198 {
199
200         do {
201                 if (ifiles->curptr < ifiles->maxread)
202                         return *ifiles->curptr++;
203         } while (inpbuf() > 0);
204
205         return -1;
206 }
207
208 /*
209  * push a character back to the input stream
210  */
ragge
1.13
211 static void
212 unch(int c)
213 {
plunky
1.93
214         if (c == -1)
215                 return;
plunky
1.113
216
plunky
1.102
217         ifiles->curptr--;
ragge
1.15
218         if (ifiles->curptr < ifiles->bbuf)
219                 error("pushback buffer full");
gmcgarry
1.26
220         *ifiles->curptr = (usch)c;
ragge
1.13
221 }
ragge
1.1
222
plunky
1.102
223 /*
224  * Check for (and convert) trigraphs.
225  */
226 static int
227 chktg(void)
228 {
229         int ch;
230
231         if ((ch = inpch()) != '?') {
232                 unch(ch);
233                 return 0;
234         }
235
236         switch (ch = inpch()) {
237         case '=':  return '#';
238         case '(':  return '[';
239         case ')':  return ']';
240         case '<':  return '{';
241         case '>':  return '}';
242         case '/':  return '\\';
243         case '\''return '^';
244         case '!':  return '|';
245         case '-':  return '~';
246         }
247
248         unch(ch);
249         unch('?');
250         return 0;
251 }
252
253 /*
ragge
1.125
254  * 5.1.1.2 Translation phase 1.
plunky
1.102
255  */
256 static int
ragge
1.125
257 inc1(void)
plunky
1.102
258 {
ragge
1.125
259         int chc2;
plunky
1.102
260
ragge
1.125
261         do {
plunky
1.102
262                 ch = inpch();
ragge
1.125
263         } while (/* ch == '\r' || */ (ch == '\\' && chkucn()));
264         if (ch == '?' && (c2 = chktg()))
265                 ch = c2;
266         return ch;
267 }
268
269
270 /*
271  * 5.1.1.2 Translation phase 2.
272  */
273 static int
274 inc2(void)
275 {
276         int chc2;
277
278         if ((ch = inc1()) != '\\')
279                 return ch;
280         if ((c2 = inc1()) == '\n') {
281                 ifiles->escln++;
282                 ch = inc2();
283         } else
284                 unch(c2);
285         return ch;
286 }
287
288 /*
289  * deal with comments in the fast scanner.
290  * ps prints out the initial '/' if failing to batch comment.
291  */
292 static int
293 fastcmnt(int ps)
294 {
295         int ch;
plunky
1.102
296
ragge
1.125
297         if ((ch = inc2()) == '/') { /* C++ comment */
298                 while ((ch = inc2()) != '\n')
299                         ;
plunky
1.102
300                 unch(ch);
ragge
1.125
301         } else if (ch == '*') {
302                 for (;;) {
ragge
1.131
303                         if ((ch = inc2()) < 0)
304                                 break;
ragge
1.125
305                         if (ch == '*') {
306                                 if ((ch = inc2()) == '/') {
307                                         break;
308                                 } else
309                                         unch(ch);
310                         } else if (ch == '\n') {
311                                 ifiles->lineno++;
312                                 putch('\n');
313                         }
314                 }
315         } else {
316                 if (psPUTCH('/'); /* XXX ? */
317                 unch(ch);
318                 return 0;
319         }
ragge
1.131
320         if (ch < 0)
321                 error("file ends in comment");
ragge
1.125
322         return 1;
plunky
1.102
323 }
324
325 /*
ragge
1.125
326  * return next char, partly phase 3.
plunky
1.102
327  */
ragge
1.125
328 static int
plunky
1.102
329 inch(void)
330 {
ragge
1.125
331         int chn;
plunky
1.102
332
ragge
1.125
333         ch = inc2();
334         n = ifiles->lineno;
335         if (ch == '/' && Cflag == 0 && fastcmnt(0)) {
336                 /* Comments 5.1.1.2 p3 */
337                 /* no space if traditional or multiline */
338                 ch = (tflag || n != ifiles->lineno) ? inch() : ' ';
plunky
1.102
339         }
ragge
1.125
340         return ch;
plunky
1.102
341 }
342
plunky
1.114
343 /*
344  * check for universal-character-name on input, and
345  * unput to the pushback buffer encoded as UTF-8.
346  */
347 static int
348 chkucn(void)
349 {
350         unsigned long cpm;
351         int chn;
352
353         if ((ch = inch()) == -1)
354                 return 0;
355         if (ch == 'u')
356                 n = 4;
357         else if (ch == 'U')
358                 n = 8;
359         else {
360                 unch(ch);
361                 return 0;
362         }
363
364         cp = 0;
365         while (n-- > 0) {
366                 if ((ch = inch()) == -1 || (spechr[ch] & C_HEX) == 0) {
367                         warning("invalid universal character name");
368                         // XXX should actually unput the chars and return 0
369                         unch(ch); // XXX eof
370                         break;
371                 }
372                 cp = cp * 16 + dig2num(ch);
373         }
374
plunky
1.115
375         if ((cp < 0xa0 && cp != 0x24 && cp != 0x40 && cp != 0x60)
376             || (cp >= 0xd800 && cp <= 0xdfff))  /* 6.4.3.2 */
377                 error("universal character name cannot be used");
378
plunky
1.114
379         if (cp > 0x7fffffff)
380                 error("universal character name out of range");
381
382         n = 0;
383         m = 0x7f;
384         while (cp > m) {
385                 unch(0x80 | (cp & 0x3f));
386                 cp >>= 6;
387                 m >>= (n++ ? 1 : 2);
388         }
389         unch(((m << 1) ^ 0xfe) | cp);
390         return 1;
391 }
392
ragge
1.122
393 /*
394  * deal with comments when -C is active.
ragge
1.125
395  * Save comments in expanded macros???
ragge
1.122
396  */
ragge
1.134
397 int
ragge
1.128
398 Ccmnt(void (*d)(int))
ragge
1.122
399 {
400         int ch;
401
402         if ((ch = inch()) == '/') { /* C++ comment */
ragge
1.128
403                 d(ch);
ragge
1.122
404                 do {
ragge
1.128
405                         d(ch);
ragge
1.122
406                 } while ((ch = inch()) != '\n');
407                 unch(ch);
408                 return 1;
409         } else if (ch == '*') {
ragge
1.128
410                 d('/');
411                 d('*');
ragge
1.122
412                 for (;;) {
413                         ch = inch();
ragge
1.128
414                         d(ch);
ragge
1.122
415                         if (ch == '*') {
416                                 if ((ch = inch()) == '/') {
ragge
1.128
417                                         d(ch);
ragge
1.122
418                                         return 1;
419                                 } else
420                                         unch(ch);
421                         } else if (ch == '\n') {
422                                 ifiles->lineno++;
423                         }
424                 }
425         }
ragge
1.128
426         d('/');
ragge
1.122
427         unch(ch);
428         return 0;
429 }
430
ragge
1.125
431 /*
432  * Traverse over spaces and comments from the input stream,
ragge
1.129
433  * Returns first non-space character.
ragge
1.125
434  */
plunky
1.108
435 static int
ragge
1.129
436 fastspc(void)
ragge
1.45
437 {
438         int ch;
439
ragge
1.129
440         while ((ch = inch()), ISWS(ch))
441                 ;
ragge
1.125
442         return ch;
ragge
1.45
443 }
444
ragge
1.19
445 /*
ragge
1.125
446  * As above but only between \n and #.
ragge
1.122
447  */
448 static int
ragge
1.125
449 fastspcg(void)
ragge
1.122
450 {
ragge
1.125
451         int chc2;
ragge
1.122
452
ragge
1.125
453         while ((ch = inch()) == '/' || ch == '%' || ISWS(ch)) {
454                 if (ch == '%') {
455                         if ((c2 = inch()) == ':')
456                                 ch = '#'/* digraphs */
457                         else
458                                 unch(c2);
459                         break;
460                 }
461                 if (ch == '/') {
462                         if (Cflag)
463                                 return ch;
464                         if (fastcmnt(0) == 0)
ragge
1.122
465                                 break;
ragge
1.125
466                         putch(' ');
467                 } else
468                         putch(ch);
ragge
1.122
469         }
470         return ch;
471 }
472
473 /*
ragge
1.131
474  * readin chars and store on heap. Warn about too long names.
475  */
ragge
1.134
476 usch *
ragge
1.131
477 heapid(int ch)
478 {
ragge
1.134
479         usch *bp = stringbuf;
ragge
1.131
480         do {
481                 savch(ch);
482         } while (spechr[ch = inch()] & C_ID);
483         savch(0);
484         unch(ch);
ragge
1.134
485         return bp;
ragge
1.131
486 }
487
488 /*
ragge
1.125
489  * get a string or character constant and save it as given by d.
490  */
ragge
1.134
491 void
ragge
1.125
492 faststr(int bcvoid (*d)(int))
493 {
494         int ch;
495
496         d(bc);
497         while ((ch = inc2()) != bc) {
498                 if (ch == '\n') {
499                         warning("unterminated literal");
500                         unch(ch);
501                         return;
502                 }
503                 if (ch < 0)
504                         return;
505                 if (ch == '\\') {
506                         d(ch);
507                         ch = inc2();
508                 }
509                 d(ch);
510         }
511         d(ch);
512 }
513
514 /*
515  * get a preprocessing number and save it as given by d.
516  * Initial char ch is always stored.
517  * returns first non-pp-number char.
518  *
519  *      pp-number:      digit
520  *                      . digit
521  *                      pp-number digit
522  *                      pp-number identifier-nondigit
523  *                      pp-number e sign
524  *                      pp-number E sign
525  *                      pp-number p sign
526  *                      pp-number P sign
527  *                      pp-number .
528  */
ragge
1.134
529 int
ragge
1.125
530 fastnum(int chvoid (*d)(int))
531 {
532         int c2;
533
ragge
1.126
534         if ((spechr[ch] & C_DIGIT) == 0) {
535                 /* not digit, dot */
536                 d(ch);
537                 ch = inch();
538                 if ((spechr[ch] & C_DIGIT) == 0)
539                         return ch;
540         }
ragge
1.125
541         for (;;) {
542                 d(ch);
543                 if ((ch = inch()) < 0)
544                         return -1;
545                 if ((spechr[ch] & C_EP)) {
546                         if ((c2 = inch()) != '-' && c2 != '+') {
547                                 if (c2 >= 0)
548                                         unch(c2);
549                                 break;
550                         }
551                         d(ch);
552                         ch = c2;
553                 } else if (ch == '.' || (spechr[ch] & C_ID)) {
554                         continue;
555                 } else
556                         break;
557         }
558         return ch;
559 }
ragge
1.122
560
561 /*
ragge
1.19
562  * Scan quickly the input file searching for:
563  *      - '#' directives
564  *      - keywords (if not flslvl)
565  *      - comments
566  *
567  *      Handle strings, numbers and trigraphs with care.
568  *      Only data from pp files are scanned here, never any rescans.
ragge
1.125
569  *      This loop is always at trulvl.
ragge
1.19
570  */
571 static void
572 fastscan(void)
573 {
574         struct symtab *nl;
ragge
1.140
575         int chc2inch;
ragge
1.49
576         usch *cp;
ragge
1.19
577
578         goto run;
ragge
1.125
579
ragge
1.19
580         for (;;) {
ragge
1.125
581                 /* tight loop to find special chars */
582                 /* should use getchar/putchar here */
583                 for (;;) {
ragge
1.140
584                         if (ifiles->curptr < ifiles->maxread) {
585                                 ch = *ifiles->curptr++;
586                         } else {
587                                 if (inpbuf() > 0)
588                                         continue;
589                                 return;
590                         }
ragge
1.125
591 xloop:                  if (ch < 0)
592                                 return/* EOF */
593                         if ((spechr[ch] & C_SPEC) != 0)
594                                 break;
595                         putch(ch);
ragge
1.19
596                 }
ragge
1.125
597
ragge
1.140
598                 REFILL(2);
599                 nch = *ifiles->curptr;
ragge
1.19
600                 switch (ch) {
ragge
1.43
601                 case WARN:
602                 case CONC:
603                         error("bad char passed");
604                         break;
605
ragge
1.19
606                 case '/'/* Comments */
ragge
1.140
607                         if (nch != '/' && nch != '*') {
608                                 putch(ch);
609                                 continue;
610                         }
ragge
1.125
611                         if (Cflag == 0) {
612                                 if (fastcmnt(1))
613                                         putch(' '); /* 5.1.1.2 p3 */
614                         } else
ragge
1.128
615                                 Ccmnt(putch);
ragge
1.19
616                         break;
617
618                 case '\n'/* newlines, for pp directives */
ragge
1.125
619                         /* take care of leftover \n */
plunky
1.102
620                         i = ifiles->escln + 1;
621                         ifiles->lineno += i;
622                         ifiles->escln = 0;
623                         while (i-- > 0)
plunky
1.121
624                                 putch('\n');
ragge
1.125
625
626                         /* search for a # */
627 run:                    while ((ch = inch()) == '\t' || ch == ' ')
628                                 putch(ch);
629                         if (ch == '%') {
630                                 if ((c2 = inch()) != ':')
631                                         unch(c2);
632                                 else
633                                         ch = '#';
ragge
1.50
634                         }
ragge
1.125
635                         if (ch  == '#')
ragge
1.19
636                                 ppdir();
ragge
1.125
637                         else
638                                 goto xloop;
639                         break;
640
ragge
1.140
641                 case '?':
642                         if (nch == '?' && (ch = chktg()))
643                                 goto xloop;
644                         putch('?');
645                         break;
646
ragge
1.125
647                 case '\''/* character constant */
648                         if (tflag) {
649                                 putch(ch);
650                                 break;  /* character constants ignored */
ragge
1.19
651                         }
ragge
1.125
652                         /* FALLTHROUGH */
ragge
1.19
653                 case '\"'/* strings */
ragge
1.125
654                         faststr(chputch);
ragge
1.19
655                         break;
656
657                 case '.':  /* for pp-number */
658                 case '0'case '1'case '2'case '3'case '4':
659                 case '5'case '6'case '7'case '8'case '9':
ragge
1.125
660                         ch = fastnum(chputch);
ragge
1.19
661                         goto xloop;
662
663                 case 'L':
ragge
1.140
664                         if (nch == '\"' || nch == '\'') {
665                                 putch(ch);
666                                 break;
ragge
1.19
667                         }
668                         /* FALLTHROUGH */
669                 default:
plunky
1.102
670 #ifdef PCC_DEBUG
ragge
1.19
671                         if ((spechr[ch] & C_ID) == 0)
672                                 error("fastscan");
plunky
1.102
673 #endif
plunky
1.114
674                 ident:
ragge
1.131
675                         if (flslvl)
676                                 error("fastscan flslvl");
677                         cp = stringbuf;
678                         heapid(ch);
ragge
1.134
679                         stringbuf = cp;
680                         if ((nl = lookup(cpFIND))) {
681                                 if (kfind(nl))
682                                         putstr(cp);
683                         } else
ragge
1.131
684                                 putstr(cp);
685                         stringbuf = cp;
ragge
1.19
686                         break;
plunky
1.114
687
688                 case '\\':
ragge
1.140
689                         if (nch == '\n') {
690                                 ifiles->escln++;
691                                 ifiles->curptr++;
692                                 break;
693                         }
plunky
1.114
694                         if (chkucn()) {
695                                 ch = inch();
696                                 goto ident;
697                         }
ragge
1.125
698                         putch('\\');
plunky
1.114
699                         break;
ragge
1.19
700                 }
701         }
plunky
1.108
702
ragge
1.131
703 /*eof:*/        warning("unexpected EOF");
plunky
1.121
704         putch('\n');
ragge
1.19
705 }
ragge
1.1
706
ragge
1.136
707 /*
708  * Store an if/elif line on heap for parsing, evaluate macros and 
709  * call yyparse().
710  */
711 static usch *yyinp;
712 static int
713 exprline(void)
714 {
715         struct symtab *nl;
716         int oCflag = Cflag;
717         usch *cp, *bp = stringbuf;
718         int cifdef;
719
720         Cflag = ifdef = 0;
721
722         while ((c = inch()) != '\n') {
723                 if (ISID0(c)) {
724                         cp = heapid(c);
725                         stringbuf = cp;
726                         nl = lookup(cpFIND);
727                         if (strcmp((char *)cp"defined") == 0) {
728                                 ifdef = 1;
729                         } else if (ifdef) {
730                                 savch(nl ? '1' : '0');
731                                 ifdef = 0;
732                         } else if (nl != NULL) {
733                                 kfind(nl);
734                                 while (*stringbuf) {
735                                         if (ISID0(*stringbuf)) {
736                                                 *stringbuf++ = '0';
737                                                 while (ISID(*stringbuf))
738                                                         *stringbuf++ = ' ';
739                                         } else
740                                                 stringbuf++;
741                                 }
742                         } else
743                                 savch('0');
744                 } else
745                         savch(c);
746         }
747         savch(0);
748         unch('\n');
749         yyinp = bp;
750         c = yyparse();
751         stringbuf = bp;
752         Cflag = oCflag;
753         return c;
754 }
755
ragge
1.19
756 int
plunky
1.64
757 yylex(void)
ragge
1.19
758 {
ragge
1.136
759         int chc2t;
ragge
1.19
760
ragge
1.136
761         while ((ch = *yyinp++) == ' ' || ch == '\t')
ragge
1.19
762                 ;
ragge
1.136
763         t = ISDIGIT(ch) ? NUMBER : ch;
plunky
1.97
764         if (ch < 128 && (spechr[ch] & C_2))
ragge
1.136
765                 c2 = *yyinp++;
ragge
1.19
766         else
767                 c2 = 0;
768
ragge
1.136
769         switch (t) {
770         case 0return WARN;
plunky
1.97
771         case '=':
772                 if (c2 == '='return EQ;
773                 break;
774         case '!':
775                 if (c2 == '='return NE;
776                 break;
777         case '|':
778                 if (c2 == '|'return OROR;
779                 break;
780         case '&':
781                 if (c2 == '&'return ANDAND;
782                 break;
ragge
1.19
783         case '<':
784                 if (c2 == '<'return LS;
785                 if (c2 == '='return LE;
786                 break;
787         case '>':
788                 if (c2 == '>'return RS;
789                 if (c2 == '='return GE;
790                 break;
791         case '+':
792         case '-':
793                 if (ch == c2)
plunky
1.78
794                         error("invalid preprocessor operator %c%c"chc2);
ragge
1.19
795                 break;
ragge
1.27
796
ragge
1.136
797         case '\'':
798                 yynode.op = NUMBER;
799                 yynode.nd_val = charcon(&yyinp);
800                 return NUMBER;
ragge
1.33
801
ragge
1.19
802         case NUMBER:
ragge
1.136
803                 cvtdig(&yyinp);
ragge
1.19
804                 return NUMBER;
ragge
1.27
805
ragge
1.19
806         default:
807                 return ch;
808         }
ragge
1.136
809         yyinp--;
ragge
1.19
810         return ch;
811 }
812
ragge
1.13
813 /*
814  * Let the command-line args be faked defines at beginning of file.
815  */
816 static void
817 prinit(struct initar *itstruct includ *ic)
ragge
1.1
818 {
ragge
1.31
819         const char *pre, *post;
820         char *a;
ragge
1.1
821
ragge
1.13
822         if (it->next)
823                 prinit(it->nextic);
824         pre = post = NULL/* XXX gcc */
825         switch (it->type) {
826         case 'D':
827                 pre = "#define ";
828                 if ((a = strchr(it->str'=')) != NULL) {
829                         *a = ' ';
830                         post = "\n";
ragge
1.1
831                 } else
ragge
1.13
832                         post = " 1\n";
ragge
1.1
833                 break;
ragge
1.13
834         case 'U':
835                 pre = "#undef ";
836                 post = "\n";
ragge
1.1
837                 break;
ragge
1.13
838         case 'i':
839                 pre = "#include \"";
840                 post = "\"\n";
ragge
1.1
841                 break;
842         default:
ragge
1.13
843                 error("prinit");
ragge
1.1
844         }
ragge
1.13
845         strlcat((char *)ic->bufferpreCPPBUF+1);
846         strlcat((char *)ic->bufferit->strCPPBUF+1);
847         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
848                 error("line exceeds buffer size");
849
850         ic->lineno--;
851         while (*ic->maxread)
852                 ic->maxread++;
ragge
1.1
853 }
854
ragge
1.4
855 /*
ragge
1.6
856  * A new file included.
857  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
858  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
859  */
860 int
ragge
1.31
861 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
862 {
ragge
1.13
863         extern struct initar *initar;
ragge
1.6
864         struct includ ibuf;
865         struct includ *ic;
plunky
1.82
866         int otrulvl;
ragge
1.6
867
868         ic = &ibuf;
ragge
1.13
869         ic->next = ifiles;
ragge
1.4
870
ragge
1.6
871         if (file != NULL) {
ragge
1.31
872                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
873                         return -1;
ragge
1.13
874                 ic->orgfn = ic->fname = file;
875                 if (++inclevel > MAX_INCLEVEL)
plunky
1.102
876                         error("limit for nested includes exceeded");
ragge
1.6
877         } else {
878                 ic->infil = 0;
ragge
1.31
879                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
880         }
ragge
1.49
881 #ifndef BUF_STACK
882         ic->bbuf = malloc(BBUFSZ);
883 #endif
ragge
1.140
884         ic->buffer = ic->bbuf+PBMAX;
ragge
1.4
885         ic->curptr = ic->buffer;
886         ifiles = ic;
ragge
1.13
887         ic->lineno = 1;
plunky
1.102
888         ic->escln = 0;
ragge
1.6
889         ic->maxread = ic->curptr;
ragge
1.29
890         ic->idx = idx;
891         ic->incs = incs;
892         ic->fn = fn;
ragge
1.139
893         prtline(1);
ragge
1.13
894         if (initar) {
ragge
1.38
895                 int oin = ic->infil;
896                 ic->infil = -1;
ragge
1.13
897                 *ic->maxread = 0;
898                 prinit(initaric);
ragge
1.41
899                 initar = NULL;
ragge
1.13
900                 if (dMflag)
ragge
1.120
901                         printf("%s", (char *)ic->buffer);
ragge
1.38
902                 fastscan();
ragge
1.139
903                 prtline(1);
ragge
1.38
904                 ic->infil = oin;
ragge
1.13
905         }
ragge
1.4
906
ragge
1.13
907         otrulvl = trulvl;
ragge
1.4
908
ragge
1.19
909         fastscan();
ragge
1.13
910
911         if (otrulvl != trulvl || flslvl)
ragge
1.6
912                 error("unterminated conditional");
ragge
1.4
913
ragge
1.49
914 #ifndef BUF_STACK
915         free(ic->bbuf);
916 #endif
ragge
1.13
917         ifiles = ic->next;
ragge
1.6
918         close(ic->infil);
ragge
1.13
919         inclevel--;
ragge
1.6
920         return 0;
ragge
1.4
921 }
ragge
1.1
922
923 /*
924  * Print current position to output file.
925  */
926 void
ragge
1.139
927 prtline(int nl)
ragge
1.1
928 {
plunky
1.121
929         usch *sb = stringbuf;
930
ragge
1.13
931         if (Mflag) {
932                 if (dMflag)
933                         return/* no output */
ragge
1.117
934                 if (ifiles->lineno == 1 &&
935                     (MMDflag == 0 || ifiles->idx != SYSINC)) {
ragge
1.120
936                         printf("%s: %s\n"Mfileifiles->fname);
ragge
1.68
937                         if (MPflag &&
plunky
1.83
938                             strcmp((const char *)ifiles->fname, (char *)MPfile))
ragge
1.120
939                                 printf("%s:\n"ifiles->fname);
ragge
1.13
940                 }
ragge
1.65
941         } else if (!Pflag) {
plunky
1.121
942                 sheap("\n# %d \"%s\""ifiles->linenoifiles->fname);
ragge
1.65
943                 if (ifiles->idx == SYSINC)
plunky
1.121
944                         sheap(" 3");
ragge
1.139
945                 if (nlsheap("\n");
plunky
1.121
946                 putstr(sb);
ragge
1.65
947         }
plunky
1.121
948         stringbuf = sb;
ragge
1.1
949 }
950
951 void
952 cunput(int c)
953 {
plunky
1.59
954 #ifdef PCC_DEBUG
ragge
1.43
955 //      if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
ragge
1.13
956 #endif
ragge
1.19
957         unch(c);
ragge
1.1
958 }
959
ragge
1.13
960 static int
961 dig2num(int c)
962 {
963         if (c >= 'a')
964                 c = c - 'a' + 10;
965         else if (c >= 'A')
966                 c = c - 'A' + 10;
967         else
968