Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20150510072819

Diff

Diff from 1.133 to:

Annotations

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

Annotated File View

ragge
1.133
1 /*      $Id: token.c,v 1.133 2015/05/10 07:28:19 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.
32  *      - sloscan() tokenize the input stream and returns tokens.
plunky
1.113
33  *      - yylex() returns something from the input stream that
ragge
1.19
34  *              is suitable for yacc.
35  *
36  *      Other functions of common use:
37  *      - inpch() returns a raw character from the current input stream.
38  *      - inch() is like inpch but \\n and trigraphs are expanded.
39  *      - unch() pushes back a character to the input stream.
ragge
1.125
40  *
41  * Input data can be read from either stdio or a buffer.
ragge
1.132
42  * If a buffer is read, it will return EOF when ended and then jump back
43  * to the previous buffer.
44  *      - setibuf(usch *ptr). Buffer to read from, until NULL, return EOF.
45  *              When EOF returned, pop buffer.
46  *      - setobuf(usch *ptr).  Buffer to write to
ragge
1.125
47  *
48  * There are three places data is read:
49  *      - fastscan() which has a small loop that will scan over input data.
50  *      - flscan() where everything is skipped except directives (flslvl)
ragge
1.132
51  *      - inch() that everything else uses.
ragge
1.125
52  *
53  * 5.1.1.2 Translation phases:
54  *      1) Convert UCN to UTF-8 which is what pcc uses internally (chkucn).
55  *         Remove \r (unwanted)
56  *         Convert trigraphs (chktg)
57  *      2) Remove \\\n.  Need extra care for identifiers and #line.
58  *      3) Tokenize.
59  *         Remove comments (fastcmnt)
ragge
1.19
60  */
61
ragge
1.13
62 #include "config.h"
63
ragge
1.1
64 #include <stdlib.h>
65 #include <string.h>
ragge
1.13
66 #ifdef HAVE_UNISTD_H
ragge
1.2
67 #include <unistd.h>
ragge
1.13
68 #endif
ragge
1.2
69 #include <fcntl.h>
ragge
1.1
70
ragge
1.13
71 #include "compat.h"
ragge
1.1
72 #include "cpp.h"
ragge
1.13
73
plunky
1.112
74 static void cvtdig(int);
plunky
1.114
75 static int dig2num(int);
ragge
1.13
76 static int charcon(usch *);
77 static void elsestmt(void);
78 static void ifdefstmt(void);
79 static void ifndefstmt(void);
80 static void endifstmt(void);
81 static void ifstmt(void);
82 static void cpperror(void);
plunky
1.102
83 static void cppwarning(void);
84 static void undefstmt(void);
ragge
1.13
85 static void pragmastmt(void);
86 static void elifstmt(void);
87
ragge
1.122
88 static int inpch(void);
89 static int chktg(void);
90 static int chkucn(void);
91 static void unch(int c);
92
plunky
1.121
93 #define PUTCH(ch) if (!flslvl) putch(ch)
ragge
1.13
94 /* protection against recursion in #include */
95 #define MAX_INCLEVEL    100
96 static int inclevel;
97
ragge
1.44
98 usch yytext[CPPBUF];
gmcgarry
1.16
99
plunky
1.81
100 struct includ *ifiles;
101
plunky
1.97
102 /* some common special combos for init */
103 #define C_NL    (C_SPEC|C_WSNL)
104 #define C_DX    (C_SPEC|C_ID|C_DIGIT|C_HEX)
105 #define C_I     (C_SPEC|C_ID|C_ID0)
106 #define C_IP    (C_SPEC|C_ID|C_ID0|C_EP)
107 #define C_IX    (C_SPEC|C_ID|C_ID0|C_HEX)
108 #define C_IXE   (C_SPEC|C_ID|C_ID0|C_HEX|C_EP)
109
110 usch spechr[256] = {
ragge
1.43
111         0,      0,      0,      0,      C_SPECC_SPEC0,      0,
plunky
1.97
112         0,      C_WSNLC_NL,   0,      0,      C_WSNL0,      0,
ragge
1.19
113         0,      0,      0,      0,      0,      0,      0,      0,
114         0,      0,      0,      0,      0,      0,      0,      0,
115
ragge
1.43
116         C_WSNLC_2,    C_SPEC0,      0,      0,      C_2,    C_SPEC,
ragge
1.33
117         0,      0,      0,      C_2,    0,      C_2,    0,      C_SPEC|C_2,
plunky
1.97
118         C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,
plunky
1.102
119         C_DX,   C_DX,   0,      0,      C_2,    C_2,    C_2,    0,
ragge
1.19
120
plunky
1.97
121         0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
ragge
1.19
122         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.97
123         C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.114
124         C_I,    C_I,    C_I,    0,      C_SPEC0,      0,      C_I,
ragge
1.19
125
plunky
1.97
126         0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
ragge
1.19
127         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.97
128         C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
ragge
1.19
129         C_I,    C_I,    C_I,    0,      C_2,    0,      0,      0,
ragge
1.111
130
131 /* utf-8 */
132         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
133         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
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
137         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
138         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
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
142         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
143         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
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
147         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
148         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
149         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.112
150         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
ragge
1.19
151 };
ragge
1.1
152
plunky
1.102
153 /*
154  * fill up the input buffer
155  */
156 static int
157 inpbuf(void)
158 {
159         int len;
160
161         if (ifiles->infil == -1)
162                 return 0;
163         len = read(ifiles->infilifiles->bufferCPPBUF);
164         if (len == -1)
165                 error("read error on file %s"ifiles->orgfn);
166         if (len > 0) {
167                 ifiles->buffer[len] = 0;
168                 ifiles->curptr = ifiles->buffer;
169                 ifiles->maxread = ifiles->buffer + len;
170         }
171         return len;
172 }
173
174 /*
175  * return a raw character from the input stream
176  */
177 static inline int
178 inpch(void)
179 {
180
181         do {
182                 if (ifiles->curptr < ifiles->maxread)
183                         return *ifiles->curptr++;
184         } while (inpbuf() > 0);
185
186         return -1;
187 }
188
189 /*
190  * push a character back to the input stream
191  */
ragge
1.13
192 static void
193 unch(int c)
194 {
plunky
1.93
195         if (c == -1)
196                 return;
plunky
1.113
197
ragge
1.132
198         if (ibufp) {
199                 ibufp--;
200                 if (*ibufp != c)
201                         error("unch");
202                 return;
203         }
204
plunky
1.102
205         ifiles->curptr--;
ragge
1.15
206         if (ifiles->curptr < ifiles->bbuf)
207                 error("pushback buffer full");
gmcgarry
1.26
208         *ifiles->curptr = (usch)c;
ragge
1.13
209 }
ragge
1.1
210
ragge
1.132
211 static int
212 ibread(void)
213 {
214         int ch = *ibufp++;
215         if (ch == 0) {
216                 ibufp = NULL;
217                 ch = WARN;
218         }
219         return ch;
220 }
221
plunky
1.102
222 /*
223  * Check for (and convert) trigraphs.
224  */
225 static int
226 chktg(void)
227 {
228         int ch;
229
230         if ((ch = inpch()) != '?') {
231                 unch(ch);
232                 return 0;
233         }
234
235         switch (ch = inpch()) {
236         case '=':  return '#';
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         }
246
247         unch(ch);
248         unch('?');
249         return 0;
250 }
251
252 /*
ragge
1.125
253  * 5.1.1.2 Translation phase 1.
plunky
1.102
254  */
255 static int
ragge
1.125
256 inc1(void)
plunky
1.102
257 {
ragge
1.125
258         int chc2;
plunky
1.102
259
ragge
1.125
260         do {
plunky
1.102
261                 ch = inpch();
ragge
1.125
262         } while (/* ch == '\r' || */ (ch == '\\' && chkucn()));
263         if (ch == '?' && (c2 = chktg()))
264                 ch = c2;
265         return ch;
266 }
267
268
269 /*
270  * 5.1.1.2 Translation phase 2.
271  */
272 static int
273 inc2(void)
274 {
275         int chc2;
276
ragge
1.132
277         if (ibufp)
278                 return ibread();
279
ragge
1.125
280         if ((ch = inc1()) != '\\')
281                 return ch;
282         if ((c2 = inc1()) == '\n') {
283                 ifiles->escln++;
284                 ch = inc2();
285         } else
286                 unch(c2);
287         return ch;
288 }
289
290 /*
291  * deal with comments in the fast scanner.
292  * ps prints out the initial '/' if failing to batch comment.
293  */
294 static int
295 fastcmnt(int ps)
296 {
297         int ch;
plunky
1.102
298
ragge
1.125
299         if ((ch = inc2()) == '/') { /* C++ comment */
300                 while ((ch = inc2()) != '\n')
301                         ;
plunky
1.102
302                 unch(ch);
ragge
1.125
303         } else if (ch == '*') {
304                 for (;;) {
ragge
1.131
305                         if ((ch = inc2()) < 0)
306                                 break;
ragge
1.125
307                         if (ch == '*') {
308                                 if ((ch = inc2()) == '/') {
309                                         break;
310                                 } else
311                                         unch(ch);
312                         } else if (ch == '\n') {
313                                 ifiles->lineno++;
314                                 putch('\n');
315                         }
316                 }
317         } else {
318                 if (psPUTCH('/'); /* XXX ? */
319                 unch(ch);
320                 return 0;
321         }
ragge
1.131
322         if (ch < 0)
323                 error("file ends in comment");
ragge
1.125
324         return 1;
plunky
1.102
325 }
326
327 /*
ragge
1.125
328  * return next char, partly phase 3.
plunky
1.102
329  */
ragge
1.125
330 static int
plunky
1.102
331 inch(void)
332 {
ragge
1.125
333         int chn;
plunky
1.102
334
ragge
1.132
335         if (ibufp)
336                 return ibread();
337
ragge
1.125
338         ch = inc2();
339         n = ifiles->lineno;
340         if (ch == '/' && Cflag == 0 && fastcmnt(0)) {
341                 /* Comments 5.1.1.2 p3 */
342                 /* no space if traditional or multiline */
343                 ch = (tflag || n != ifiles->lineno) ? inch() : ' ';
plunky
1.102
344         }
ragge
1.125
345         return ch;
plunky
1.102
346 }
347
plunky
1.114
348 /*
349  * check for universal-character-name on input, and
350  * unput to the pushback buffer encoded as UTF-8.
351  */
352 static int
353 chkucn(void)
354 {
355         unsigned long cpm;
356         int chn;
357
358         if ((ch = inch()) == -1)
359                 return 0;
360         if (ch == 'u')
361                 n = 4;
362         else if (ch == 'U')
363                 n = 8;
364         else {
365                 unch(ch);
366                 return 0;
367         }
368
369         cp = 0;
370         while (n-- > 0) {
371                 if ((ch = inch()) == -1 || (spechr[ch] & C_HEX) == 0) {
372                         warning("invalid universal character name");
373                         // XXX should actually unput the chars and return 0
374                         unch(ch); // XXX eof
375                         break;
376                 }
377                 cp = cp * 16 + dig2num(ch);
378         }
379
plunky
1.115
380         if ((cp < 0xa0 && cp != 0x24 && cp != 0x40 && cp != 0x60)
381             || (cp >= 0xd800 && cp <= 0xdfff))  /* 6.4.3.2 */
382                 error("universal character name cannot be used");
383
plunky
1.114
384         if (cp > 0x7fffffff)
385                 error("universal character name out of range");
386
387         n = 0;
388         m = 0x7f;
389         while (cp > m) {
390                 unch(0x80 | (cp & 0x3f));
391                 cp >>= 6;
392                 m >>= (n++ ? 1 : 2);
393         }
394         unch(((m << 1) ^ 0xfe) | cp);
395         return 1;
396 }
397
ragge
1.122
398 /*
399  * deal with comments when -C is active.
ragge
1.125
400  * Save comments in expanded macros???
ragge
1.122
401  */
402 static int
ragge
1.128
403 Ccmnt(void (*d)(int))
ragge
1.122
404 {
405         int ch;
406
407         if ((ch = inch()) == '/') { /* C++ comment */
ragge
1.128
408                 d(ch);
ragge
1.122
409                 do {
ragge
1.128
410                         d(ch);
ragge
1.122
411                 } while ((ch = inch()) != '\n');
412                 unch(ch);
413                 return 1;
414         } else if (ch == '*') {
ragge
1.128
415                 d('/');
416                 d('*');
ragge
1.122
417                 for (;;) {
418                         ch = inch();
ragge
1.128
419                         d(ch);
ragge
1.122
420                         if (ch == '*') {
421                                 if ((ch = inch()) == '/') {
ragge
1.128
422                                         d(ch);
ragge
1.122
423                                         return 1;
424                                 } else
425                                         unch(ch);
426                         } else if (ch == '\n') {
427                                 ifiles->lineno++;
428                         }
429                 }
430         }
ragge
1.128
431         d('/');
ragge
1.122
432         unch(ch);
433         return 0;
434 }
435
ragge
1.125
436 /*
437  * Traverse over spaces and comments from the input stream,
ragge
1.129
438  * Returns first non-space character.
ragge
1.125
439  */
plunky
1.108
440 static int
ragge
1.129
441 fastspc(void)
ragge
1.45
442 {
443         int ch;
444
ragge
1.129
445         while ((ch = inch()), ISWS(ch))
446                 ;
ragge
1.125
447         return ch;
ragge
1.45
448 }
449
ragge
1.19
450 /*
ragge
1.125
451  * As above but only between \n and #.
ragge
1.122
452  */
453 static int
ragge
1.125
454 fastspcg(void)
ragge
1.122
455 {
ragge
1.125
456         int chc2;
ragge
1.122
457
ragge
1.125
458         while ((ch = inch()) == '/' || ch == '%' || ISWS(ch)) {
459                 if (ch == '%') {
460                         if ((c2 = inch()) == ':')
461                                 ch = '#'/* digraphs */
462                         else
463                                 unch(c2);
464                         break;
465                 }
466                 if (ch == '/') {
467                         if (Cflag)
468                                 return ch;
469                         if (fastcmnt(0) == 0)
ragge
1.122
470                                 break;
ragge
1.125
471                         putch(' ');
472                 } else
473                         putch(ch);
ragge
1.122
474         }
475         return ch;
476 }
477
478 /*
479  * readin chars and store in yytext. Warn about too long names.
480  */
481 static void
482 fastid(int ch)
483 {
484         int i = 0;
485
486         do {
487                 yytext[i++] = ch;
488         } while (spechr[ch = inch()] & C_ID);
489         yytext[i] = 0;
490         unch(ch);
491 }
492
ragge
1.125
493 /*
ragge
1.131
494  * readin chars and store on heap. Warn about too long names.
495  */
496 static void
497 heapid(int ch)
498 {
499         do {
500                 savch(ch);
501         } while (spechr[ch = inch()] & C_ID);
502         savch(0);
503         unch(ch);
504 }
505
506 /*
ragge
1.125
507  * get a string or character constant and save it as given by d.
508  */
509 static void
510 faststr(int bcvoid (*d)(int))
511 {
512         int ch;
513
514         d(bc);
515         while ((ch = inc2()) != bc) {
516                 if (ch == '\n') {
517                         warning("unterminated literal");
518                         unch(ch);
519                         return;
520                 }
521                 if (ch < 0)
522                         return;
523                 if (ch == '\\') {
524                         d(ch);
525                         ch = inc2();
526                 }
527                 d(ch);
528         }
529         d(ch);
530 }
531
532 /*
533  * get a preprocessing number and save it as given by d.
534  * Initial char ch is always stored.
535  * returns first non-pp-number char.
536  *
537  *      pp-number:      digit
538  *                      . digit
539  *                      pp-number digit
540  *                      pp-number identifier-nondigit
541  *                      pp-number e sign
542  *                      pp-number E sign
543  *                      pp-number p sign
544  *                      pp-number P sign
545  *                      pp-number .
546  */
547 static int
548 fastnum(int chvoid (*d)(int))
549 {
550         int c2;
551
ragge
1.126
552         if ((spechr[ch] & C_DIGIT) == 0) {
553                 /* not digit, dot */
554                 d(ch);
555                 ch = inch();
556                 if ((spechr[ch] & C_DIGIT) == 0)
557                         return ch;
558         }
ragge
1.125
559         for (;;) {
560                 d(ch);
561                 if ((ch = inch()) < 0)
562                         return -1;
563                 if ((spechr[ch] & C_EP)) {
564                         if ((c2 = inch()) != '-' && c2 != '+') {
565                                 if (c2 >= 0)
566                                         unch(c2);
567                                 break;
568                         }
569                         d(ch);
570                         ch = c2;
571                 } else if (ch == '.' || (spechr[ch] & C_ID)) {
572                         continue;
573                 } else
574                         break;
575         }
576         return ch;
577 }
ragge
1.122
578
579 /*
ragge
1.19
580  * Scan quickly the input file searching for:
581  *      - '#' directives
582  *      - keywords (if not flslvl)
583  *      - comments
584  *
585  *      Handle strings, numbers and trigraphs with care.
586  *      Only data from pp files are scanned here, never any rescans.
ragge
1.125
587  *      This loop is always at trulvl.
ragge
1.19
588  */
589 static void
590 fastscan(void)
591 {
592         struct symtab *nl;
ragge
1.125
593         int chc2i;
ragge
1.49
594         usch *cp;
ragge
1.19
595
596         goto run;
ragge
1.125
597
ragge
1.19
598         for (;;) {
ragge
1.125
599                 /* tight loop to find special chars */
600                 /* should use getchar/putchar here */
601                 for (;;) {
602                         ch = inch();
603 xloop:                  if (ch < 0)
604                                 return/* EOF */
605                         if ((spechr[ch] & C_SPEC) != 0)
606                                 break;
607                         putch(ch);
ragge
1.19
608                 }
ragge
1.125
609
ragge
1.19
610                 switch (ch) {
ragge
1.44
611                 case EBLOCK:
ragge
1.43
612                 case WARN:
613                 case CONC:
614                         error("bad char passed");
615                         break;
616
ragge
1.19
617                 case '/'/* Comments */
ragge
1.125
618                         if (Cflag == 0) {
619                                 if (fastcmnt(1))
620                                         putch(' '); /* 5.1.1.2 p3 */
621                         } else
ragge
1.128
622                                 Ccmnt(putch);
ragge
1.19
623                         break;
624
625                 case '\n'/* newlines, for pp directives */
ragge
1.125
626                         /* take care of leftover \n */
plunky
1.102
627                         i = ifiles->escln + 1;
628                         ifiles->lineno += i;
629                         ifiles->escln = 0;
630                         while (i-- > 0)
plunky
1.121
631                                 putch('\n');
ragge
1.125
632
633                         /* search for a # */
634 run:                    while ((ch = inch()) == '\t' || ch == ' ')
635                                 putch(ch);
636                         if (ch == '%') {
637                                 if ((c2 = inch()) != ':')
638                                         unch(c2);
639                                 else
640                                         ch = '#';
ragge
1.50
641                         }
ragge
1.125
642                         if (ch  == '#')
ragge
1.19
643                                 ppdir();
ragge
1.125
644                         else
645                                 goto xloop;
646                         break;
647
648                 case '\''/* character constant */
649                         if (tflag) {
650                                 putch(ch);
651                                 break;  /* character constants ignored */
ragge
1.19
652                         }
ragge
1.125
653                         /* FALLTHROUGH */
ragge
1.19
654                 case '\"'/* strings */
ragge
1.125
655                         faststr(chputch);
ragge
1.19
656                         break;
657
658                 case '.':  /* for pp-number */
659                 case '0'case '1'case '2'case '3'case '4':
660                 case '5'case '6'case '7'case '8'case '9':
ragge
1.125
661                         ch = fastnum(chputch);
ragge
1.19
662                         goto xloop;
663
664                 case 'L':
ragge
1.125
665                         if ((ch = inch()) == '\"' || ch == '\'') {
666                                 putch('L');
667                                 goto xloop;
ragge
1.19
668                         }
669                         unch(ch);
670                         ch = 'L';
plunky
1.102
671
ragge
1.19
672                         /* FALLTHROUGH */
673                 default:
plunky
1.102
674 #ifdef PCC_DEBUG
ragge
1.19
675                         if ((spechr[ch] & C_ID) == 0)
676                                 error("fastscan");
plunky
1.102
677 #endif
plunky
1.114
678                 ident:
ragge
1.131
679                         if (flslvl)
680                                 error("fastscan flslvl");
681                         cp = stringbuf;
682                         heapid(ch);
683                         if ((nl = lookup(cpFIND)) && kfind(nl))
684                                 putstr(stringbuf);
685                         else
686                                 putstr(cp);
687                         stringbuf = cp;
ragge
1.19
688                         break;
plunky
1.114
689
690                 case '\\':
691                         if (chkucn()) {
692                                 ch = inch();
693                                 goto ident;
694                         }
ragge
1.125
695                         putch('\\');
plunky
1.114
696                         break;
ragge
1.19
697                 }
698         }
plunky
1.108
699
ragge
1.131
700 /*eof:*/        warning("unexpected EOF");
plunky
1.121
701         putch('\n');
ragge
1.19
702 }
ragge
1.1
703
ragge
1.126
704 static int yytp;
705 static void
706 yyts(int c)
707 {
708         yytext[yytp++] = c;
709 }
710
ragge
1.13
711 int
ragge
1.130
712 sloscan(void (*d)(int), int flags)
ragge
1.3
713 {
ragge
1.127
714         int chc2;
ragge
1.13
715         int yyp;
716
717 zagain:
plunky
1.113
718         ch = inch();
ragge
1.130
719
720 yagainyyp = 0;
gmcgarry
1.26
721         yytext[yyp++] = (usch)ch;
ragge
1.13
722         switch (ch) {
plunky
1.108
723         case -1/* EOF */
ragge
1.14
724                 return 0;
plunky
1.108
725
726         case '\n'/* do not pass NL */
ragge
1.19
727                 unch(ch);
plunky
1.94
728                 yytext[yyp] = 0;
729                 return ch;
ragge
1.13
730
plunky
1.108
731         case '\r'/* Ignore CR */
732                 goto zagain;
ragge
1.13
733
ragge
1.126
734         case '.':
plunky
1.113
735         case '0'case '1'case '2'case '3'case '4'case '5':
ragge
1.13
736         case '6'case '7'case '8'case '9':
ragge
1.126
737                 yytp = 0;
738                 unch(fastnum(chyyts));
739                 yyts(0);
740                 if (yytext[0] == '.' && yytext[1] == 0)
741                         return '.';
ragge
1.19
742                 return NUMBER;
ragge
1.13
743
744         case '\'':
ragge
1.127
745                 if (tflag)
746                         goto any;
ragge
1.126
747                 yytp = 0;
748                 faststr(chyyts);
749                 yyts(0);
plunky
1.74
750                 return NUMBER;
ragge
1.13
751
752         case ' ':
753         case '\t':
ragge
1.127
754                 do {
755                         ch = inch();
756                 } while (ISWS(ch));
ragge
1.130
757                 if (flags & SLO_IGNOREWS)
758                         goto yagain;
ragge
1.19
759                 unch(ch);
760                 yytext[yyp] = 0;
plunky
1.74
761                 return WSPACE;
ragge
1.13
762
763         case '/':
ragge
1.127
764                 if (Cflag == 0) {
765                         if (fastcmnt(0))
766                                 error("comment and no Cflag");
767                 } else {
ragge
1.128
768                         extern int readmac;
769
ragge
1.129
770 #if 0
ragge
1.128
771                         if (readmac) {
772                                 unch(c2 = inch());
773                                 yytext[1] = 0;
774                                 if (c2 == '*')
775                                         return CMNT;
776                         }
ragge
1.129
777 #endif
778                         yytp = 1;
779                         Ccmnt(d ? d : putch);
ragge
1.128
780                         yyts(0);
ragge
1.129
781                         if (readmac)
782                                 return CMNT;
ragge
1.13
783                         goto zagain;
784                 }
785                 goto any;
786
787         case '\"':
ragge
1.62
788                 if (tflag && defining)
ragge
1.42
789                         goto any;
ragge
1.127
790                 yytp = 0;
ragge
1.126
791                 faststr(chyyts);
792                 yyts(0);
plunky
1.74
793                 return STRING;
ragge
1.13
794
plunky
1.114
795         case '\\':
796                 if (chkucn()) {
797                         --yyp;
798                         goto ident;
799                 }
800                 goto any;
801
ragge
1.13
802         case 'L':
ragge
1.127
803                 c2 = inch();
804                 if ((c2 == '\"' || c2 == '\'') && !tflag) {
805                         yytp = 0;
806                         yyts(ch);
ragge
1.133
807                         faststr(c2yyts);
808                         yyts(0);
809                         return c2 == '\'' ? NUMBER : STRING;
ragge
1.13
810                 }
ragge
1.127
811                 unch(c2);
ragge
1.13
812                 /* FALLTHROUGH */
813
814         /* Yetch, all identifiers */
plunky
1.113
815         case 'a'case 'b'case 'c'case 'd'case 'e'case 'f':
816         case 'g'case 'h'case 'i'case 'j'case 'k'case 'l':
817         case 'm'case 'n'case 'o'case 'p'case 'q'case 'r':
818         case 's'case 't'case 'u'case 'v'case 'w'case 'x':
ragge
1.13
819         case 'y'case 'z':
plunky
1.113
820         case 'A'case 'B'case 'C'case 'D'case 'E'case 'F':
ragge
1.13
821         case 'G'case 'H'case 'I'case 'J'case 'K':
plunky
1.113
822         case 'M'case 'N'case 'O'case 'P'case 'Q'case 'R':
823         case 'S'case 'T'case 'U'case 'V'case 'W'case 'X':
ragge
1.13
824         case 'Y'case 'Z':
ragge
1.19
825         case '_'/* {L}({L}|{D})* */
ragge
1.13
826
plunky
1.114
827         ident:
ragge
1.127
828                 fastid(ch);
plunky
1.108
829                 return IDENT;
ragge
1.13
830
ragge
1.125
831         case EBLOCK:
832                 unch(ch);
833                 return cinput();
834
ragge
1.13
835         default:
plunky
1.114
836                 if ((ch & 0x80))
837                         goto ident;
838
ragge
1.13
839         any:
840                 yytext[yyp] = 0;
ragge
1.19
841                 return yytext[0];
plunky
1.108
842         } /* endcase */
ragge
1.3
843
plunky
1.108
844         /* NOTREACHED */
ragge
1.3
845 }
846
ragge
1.19
847 int
plunky
1.64
848 yylex(void)
ragge
1.19
849 {
850         static int ifdefnoex;
851         struct symtab *nl;
852         int chc2;
853
ragge
1.130
854         ch = sloscan(NULLSLO_IGNOREWS);
ragge
1.19
855                 ;
plunky
1.97
856         if (ch < 128 && (spechr[ch] & C_2))
plunky
1.102
857                 c2 = inch();
ragge
1.19
858         else
859                 c2 = 0;
860
861         switch (ch) {
plunky
1.97
862         case '=':
863                 if (c2 == '='return EQ;
864                 break;
865         case '!':
866                 if (c2 == '='return NE;
867                 break;
868         case '|':
869                 if (c2 == '|'return OROR;
870                 break;
871         case '&':
872                 if (c2 == '&'return ANDAND;
873                 break;
ragge
1.19
874         case '<':
875                 if (c2 == '<'return LS;
876                 if (c2 == '='return LE;
877                 break;
878         case '>':
879                 if (c2 == '>'return RS;
880                 if (c2 == '='return GE;
881                 break;
882         case '+':
883         case '-':
884                 if (ch == c2)
plunky
1.78
885                         error("invalid preprocessor operator %c%c"chc2);
ragge
1.19
886                 break;
ragge
1.27
887
ragge
1.33
888         case '/':
889                 if (Cflag == 0 || c2 != '*')
890                         break;
891                 /* Found comment that need to be skipped */
892                 for (;;) {
plunky
1.102
893                         ch = inch();
ragge
1.33
894                 c1:     if (ch != '*')
895                                 continue;
plunky
1.102
896                         if ((ch = inch()) == '/')
ragge
1.33
897                                 break;
898                         goto c1;
899                 }
900                 return yylex();
901
ragge
1.19
902         case NUMBER:
ragge
1.27
903                 if (yytext[0] == '\'') {
ragge
1.119
904                         yynode.op = NUMBER;
905                         yynode.nd_val = charcon(yytext);
ragge
1.27
906                 } else
907                         cvtdig(yytext[0] != '0' ? 10 :
908                             yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
ragge
1.19
909                 return NUMBER;
ragge
1.27
910
ragge
1.19
911         case IDENT:
ragge
1.44
912                 if (strcmp((char *)yytext"defined") == 0) {
ragge
1.19
913                         ifdef = 1;
914                         return DEFINED;
915                 }
plunky
1.73
916                 nl = lookup(yytextFIND);
ragge
1.19
917                 if (ifdef) {
ragge
1.119
918                         yynode.nd_val = nl != NULL;
ragge
1.19
919                         ifdef = 0;
920                 } else if (nl && noex == 0) {
ragge
1.43
921                         usch *och = stringbuf;
922                         int i;
ragge
1.19
923
ragge
1.43
924                         i = kfind(nl);
925                         unch(WARN);
926                         if (i)
927                                 unpstr(stringbuf);
928                         else
929                                 unpstr(nl->namep);
ragge
1.19
930                         stringbuf = och;
931                         noex = 1;
932                         return yylex();
933                 } else {
ragge
1.119
934                         yynode.nd_val = 0;
ragge
1.19
935                 }
ragge
1.119
936                 yynode.op = NUMBER;
ragge
1.19
937                 return NUMBER;
ragge
1.43
938         case WARN:
ragge
1.19
939                 noex = 0;
ragge
1.70
940                 /* FALLTHROUGH */
941         case PHOLD:
ragge
1.19
942                 return yylex();
943         default:
944                 return ch;
945         }
946         unch(c2);
947         return ch;
948 }
949
ragge
1.13
950 /*
951  * Let the command-line args be faked defines at beginning of file.
952  */
953 static void
954 prinit(struct initar *itstruct includ *ic)
ragge
1.1
955 {
ragge
1.31
956         const char *pre, *post;
957         char *a;
ragge
1.1
958
ragge
1.13
959         if (it->next)
960                 prinit(it->nextic);
961         pre = post = NULL/* XXX gcc */
962         switch (it->type) {
963         case 'D':
964                 pre = "#define ";
965                 if ((a = strchr(it->str'=')) != NULL) {
966                         *a = ' ';
967                         post = "\n";
ragge
1.1
968                 } else
ragge
1.13
969                         post = " 1\n";
ragge
1.1
970                 break;
ragge
1.13
971         case 'U':
972                 pre = "#undef ";
973                 post = "\n";
ragge
1.1
974                 break;
ragge