Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121107095702

Diff

Diff from 1.103 to:

Annotations

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

Annotated File View

plunky
1.103
1 /*      $Id: token.c,v 1.103 2012/11/07 09:57:02 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.
32  *      - sloscan() tokenize the input stream and returns tokens.
33  *              It may recurse into itself during expansion.
34  *      - yylex() returns something from the input stream that 
35  *              is suitable for yacc.
36  *
37  *      Other functions of common use:
38  *      - inpch() returns a raw character from the current input stream.
39  *      - inch() is like inpch but \\n and trigraphs are expanded.
40  *      - unch() pushes back a character to the input stream.
41  */
42
ragge
1.13
43 #include "config.h"
44
ragge
1.1
45 #include <stdlib.h>
46 #include <string.h>
ragge
1.13
47 #ifdef HAVE_UNISTD_H
ragge
1.2
48 #include <unistd.h>
ragge
1.13
49 #endif
ragge
1.2
50 #include <fcntl.h>
ragge
1.1
51
ragge
1.13
52 #include "compat.h"
ragge
1.1
53 #include "cpp.h"
plunky
1.72
54 #include "cpy.h"
ragge
1.13
55
56 static void cvtdig(int rad);
57 static int charcon(usch *);
58 static void elsestmt(void);
59 static void ifdefstmt(void);
60 static void ifndefstmt(void);
61 static void endifstmt(void);
62 static void ifstmt(void);
63 static void cpperror(void);
plunky
1.102
64 static void cppwarning(void);
65 static void undefstmt(void);
ragge
1.13
66 static void pragmastmt(void);
67 static void elifstmt(void);
68
ragge
1.19
69 #define PUTCH(ch) if (!flslvl) putch(ch)
ragge
1.13
70 /* protection against recursion in #include */
71 #define MAX_INCLEVEL    100
72 static int inclevel;
73
ragge
1.44
74 usch yytext[CPPBUF];
gmcgarry
1.16
75
plunky
1.81
76 struct includ *ifiles;
77
plunky
1.97
78 /* some common special combos for init */
79 #define C_NL    (C_SPEC|C_WSNL)
80 #define C_DX    (C_SPEC|C_ID|C_DIGIT|C_HEX)
81 #define C_I     (C_SPEC|C_ID|C_ID0)
82 #define C_IP    (C_SPEC|C_ID|C_ID0|C_EP)
83 #define C_IX    (C_SPEC|C_ID|C_ID0|C_HEX)
84 #define C_IXE   (C_SPEC|C_ID|C_ID0|C_HEX|C_EP)
85
86 usch spechr[256] = {
ragge
1.43
87         0,      0,      0,      0,      C_SPECC_SPEC0,      0,
plunky
1.97
88         0,      C_WSNLC_NL,   0,      0,      C_WSNL0,      0,
ragge
1.19
89         0,      0,      0,      0,      0,      0,      0,      0,
90         0,      0,      0,      0,      0,      0,      0,      0,
91
ragge
1.43
92         C_WSNLC_2,    C_SPEC0,      0,      0,      C_2,    C_SPEC,
ragge
1.33
93         0,      0,      0,      C_2,    0,      C_2,    0,      C_SPEC|C_2,
plunky
1.97
94         C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,   C_DX,
plunky
1.102
95         C_DX,   C_DX,   0,      0,      C_2,    C_2,    C_2,    0,
ragge
1.19
96
plunky
1.97
97         0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
ragge
1.19
98         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.97
99         C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.102
100         C_I,    C_I,    C_I,    0,      0,      0,      0,      C_I,
ragge
1.19
101
plunky
1.97
102         0,      C_IX,   C_IX,   C_IX,   C_IX,   C_IXE,  C_IX,   C_I,
ragge
1.19
103         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
plunky
1.97
104         C_IP,   C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
ragge
1.19
105         C_I,    C_I,    C_I,    0,      C_2,    0,      0,      0,
106 };
ragge
1.1
107
plunky
1.102
108 /*
109  * fill up the input buffer
110  */
111 static int
112 inpbuf(void)
113 {
114         int len;
115
116         if (ifiles->infil == -1)
117                 return 0;
118         len = read(ifiles->infilifiles->bufferCPPBUF);
119         if (len == -1)
120                 error("read error on file %s"ifiles->orgfn);
121         if (len > 0) {
122                 ifiles->buffer[len] = 0;
123                 ifiles->curptr = ifiles->buffer;
124                 ifiles->maxread = ifiles->buffer + len;
125         }
126         return len;
127 }
128
129 /*
130  * return a raw character from the input stream
131  */
132 static inline int
133 inpch(void)
134 {
135
136         do {
137                 if (ifiles->curptr < ifiles->maxread)
138                         return *ifiles->curptr++;
139         } while (inpbuf() > 0);
140
141         return -1;
142 }
143
144 /*
145  * push a character back to the input stream
146  */
ragge
1.13
147 static void
148 unch(int c)
149 {
plunky
1.93
150         if (c == -1)
151                 return;
ragge
1.15
152                 
plunky
1.102
153         ifiles->curptr--;
ragge
1.15
154         if (ifiles->curptr < ifiles->bbuf)
155                 error("pushback buffer full");
gmcgarry
1.26
156         *ifiles->curptr = (usch)c;
ragge
1.13
157 }
ragge
1.1
158
plunky
1.102
159 /*
160  * Check for (and convert) trigraphs.
161  */
162 static int
163 chktg(void)
164 {
165         int ch;
166
167         if ((ch = inpch()) != '?') {
168                 unch(ch);
169                 return 0;
170         }
171
172         switch (ch = inpch()) {
173         case '=':  return '#';
174         case '(':  return '[';
175         case ')':  return ']';
176         case '<':  return '{';
177         case '>':  return '}';
178         case '/':  return '\\';
179         case '\''return '^';
180         case '!':  return '|';
181         case '-':  return '~';
182         }
183
184         unch(ch);
185         unch('?');
186         return 0;
187 }
188
189 /*
190  * check for (and eat) end-of-line
191  */
192 static int
193 chkeol(void)
194 {
195         int ch;
196
197         ch = inpch();
198         if (ch == '\r') {
199                 ch = inpch();
200                 if (ch == '\n')
201                         return '\n';
202
203                 unch(ch);
204                 unch('\r');
205                 return 0;
206         }
207         if (ch == '\n')
208                 return '\n';
209
210         unch(ch);
211         return 0;
212 }
213
214 /*
215  * return next char, after converting trigraphs and
216  * skipping escaped line endings
217  */
218 static inline int
219 inch(void)
220 {
221         int ch;
222
223         for (;;) {
224                 ch = inpch();
225                 if (ch == '?' && (ch = chktg()) == 0)
226                         return '?';
227                 if (ch != '\\' || chkeol() == 0)
228                         return ch;
229                 ifiles->escln++;
230         }
231 }
232
plunky
1.92
233 static void
ragge
1.45
234 eatcmnt(void)
235 {
236         int ch;
237
238         if (Cflag) { PUTCH('/'); PUTCH('*'); }
239         for (;;) {
240                 ch = inch();
241                 if (ch == '\n') {
242                         ifiles->lineno++;
plunky
1.102
243                         putch('\n');
244                         continue;
ragge
1.45
245                 }
246                 if (ch == -1)
plunky
1.92
247                         break;
ragge
1.45
248                 if (ch == '*') {
249                         ch = inch();
250                         if (ch == '/') {
251                                 if (Cflag) {
252                                         PUTCH('*');
253                                         PUTCH('/');
254                                 } else
255                                         PUTCH(' ');
256                                 break;
257                         }
258                         unch(ch);
259                         ch = '*';
260                 }
261                 if (CflagPUTCH(ch);
262         }
263 }
264
ragge
1.19
265 /*
266  * Scan quickly the input file searching for:
267  *      - '#' directives
268  *      - keywords (if not flslvl)
269  *      - comments
270  *
271  *      Handle strings, numbers and trigraphs with care.
272  *      Only data from pp files are scanned here, never any rescans.
273  *      TODO: Only print out strings before calling other functions.
274  */
275 static void
276 fastscan(void)
277 {
278         struct symtab *nl;
plunky
1.102
279         int chi;
ragge
1.49
280         usch *cp;
ragge
1.19
281
282         goto run;
283         for (;;) {
plunky
1.102
284                 ch = inch();
ragge
1.19
285 xloop:          if (ch == -1)
286                         return;
plunky
1.60
287 #ifdef PCC_DEBUG
ragge
1.43
288                 if (dflag>1)
289                         printf("fastscan ch %d (%c)\n"chch > 31 ? ch : '@');
plunky
1.60
290 #endif
ragge
1.19
291                 if ((spechr[ch] & C_SPEC) == 0) {
292                         PUTCH(ch);
293                         continue;
294                 }
295                 switch (ch) {
ragge
1.44
296                 case EBLOCK:
ragge
1.43
297                 case WARN:
298                 case CONC:
299                         error("bad char passed");
300                         break;
301
ragge
1.19
302                 case '/'/* Comments */
303                         if ((ch = inch()) == '/') {
ragge
1.45
304 cppcmt:                         if (Cflag) { PUTCH(ch); } else { PUTCH(' '); }
ragge
1.19
305                                 do {
306                                         if (CflagPUTCH(ch);
307                                         ch = inch();
308                                 } while (ch != -1 && ch != '\n');
309                                 goto xloop;
310                         } else if (ch == '*') {
plunky
1.92
311                                 eatcmnt();
ragge
1.19
312                         } else {
313                                 PUTCH('/');
314                                 goto xloop;
315                         }
316                         break;
317
318                 case '\n'/* newlines, for pp directives */
plunky
1.102
319                         i = ifiles->escln + 1;
320                         ifiles->lineno += i;
321                         ifiles->escln = 0;
322                         while (i-- > 0)
323                                 putch('\n');
324 run:                    for(;;) {
325                                 ch = inch();
ragge
1.45
326                                 if (ch == '/') {
plunky
1.102
327                                         ch = inch();
ragge
1.45
328                                         if (ch == '/')
329                                                 goto cppcmt;
330                                         if (ch == '*') {
plunky
1.92
331                                                 eatcmnt();
plunky
1.102
332                                                 continue;
plunky
1.92
333                                         }
ragge
1.45
334                                         unch(ch);
335                                         ch = '/';
336                                 }
plunky
1.102
337                                 if (ch != ' ' && ch != '\t')
338                                         break;
339                                 PUTCH(ch);
ragge
1.50
340                         }
ragge
1.19
341                         if (ch == '#') {
342                                 ppdir();
343                                 continue;
ragge
1.40
344                         } else if (ch == '%') {
plunky
1.102
345                                 ch = inch();
ragge
1.40
346                                 if (ch == ':') {
347                                         ppdir();
348                                         continue;
349                                 }
plunky
1.92
350                                 unch(ch);
351                                 ch = '%';
ragge
1.19
352                         }
353                         goto xloop;
354
355                 case '\"'/* strings */
ragge
1.21
356 str:                    PUTCH(ch);
plunky
1.102
357                         while ((ch = inch()) != '\"') {
358                                 if (ch == '\\') {
359                                         PUTCH('\\');
360                                         ch = inch();
361                                 }
ragge
1.53
362                                 if (ch == '\n')
363                                         goto xloop;
plunky
1.90
364                                 if (ch == -1)
ragge
1.19
365                                         return;
ragge
1.53
366                                 PUTCH(ch);
ragge
1.21
367                         }
ragge
1.19
368                         PUTCH(ch);
369                         break;
370
371                 case '.':  /* for pp-number */
372                         PUTCH(ch);
plunky
1.102
373                         ch = inch();
ragge
1.19
374                         if (ch < '0' || ch > '9')
375                                 goto xloop;
plunky
1.102
376
ragge
1.19
377                         /* FALLTHROUGH */
378                 case '0'case '1'case '2'case '3'case '4':
379                 case '5'case '6'case '7'case '8'case '9':
380                         do {
plunky
1.99
381 nxp:                            PUTCH(ch);
plunky
1.102
382                                 ch = inch();
plunky
1.94
383                                 if (ch == -1)
384                                         return;
ragge
1.19
385                                 if (spechr[ch] & C_EP) {
386                                         PUTCH(ch);
plunky
1.102
387                                         ch = inch();
ragge
1.19
388                                         if (ch == '-' || ch == '+')
plunky
1.99
389                                                 goto nxp;
plunky
1.94
390                                         if (ch == -1)
391                                                 return;
ragge
1.19
392                                 }
393                         } while ((spechr[ch] & C_ID) || (ch == '.'));
394                         goto xloop;
395
396                 case '\''/* character literal */
ragge
1.21
397 con:                    PUTCH(ch);
ragge
1.23
398                         if (tflag)
plunky
1.102
399                                 break/* character constants ignored */
400                         while ((ch = inch()) != '\'') {
401                                 if (ch == '\\') {
402                                         PUTCH('\\');
403                                         ch = inch();
404                                 }
ragge
1.52
405                                 if (ch == '\n')
406                                         goto xloop;
plunky
1.90
407                                 if (ch == -1)
ragge
1.19
408                                         return;
ragge
1.52
409                                 PUTCH(ch);
ragge
1.21
410                         }
ragge
1.19
411                         PUTCH(ch);
412                         break;
ragge
1.21
413
ragge
1.19
414                 case 'L':
plunky
1.102
415                         ch = inch();
ragge
1.19
416                         if (ch == '\"') {
417                                 PUTCH('L');
418                                 goto str;
419                         }
420                         if (ch == '\'') {
421                                 PUTCH('L');
422                                 goto con;
423                         }
424                         unch(ch);
425                         ch = 'L';
plunky
1.102
426
ragge
1.19
427                         /* FALLTHROUGH */
428                 default:
plunky
1.102
429 #ifdef PCC_DEBUG
ragge
1.19
430                         if ((spechr[ch] & C_ID) == 0)
431                                 error("fastscan");
plunky
1.102
432 #endif
gmcgarry
1.58
433                         i = 0;
ragge
1.19
434                         do {
gmcgarry
1.26
435                                 yytext[i++] = (usch)ch;
plunky
1.102
436                                 ch = inch();
437                         } while (ch != -1 && (spechr[ch] & C_ID));
438
439                         if (flslvl)
440                                 goto xloop;
ragge
1.43
441
ragge
1.19
442                         yytext[i] = 0;
443                         unch(ch);
ragge
1.43
444
ragge
1.49
445                         cp = stringbuf;
plunky
1.73
446                         if ((nl = lookup(yytextFIND)) && kfind(nl)) {
ragge
1.43
447                                 putstr(stringbuf);
ragge
1.19
448                         } else
plunky
1.73
449                                 putstr(yytext);
ragge
1.49
450                         stringbuf = cp;
ragge
1.43
451
ragge
1.19
452                         break;
453                 }
454         }
455 }
ragge
1.1
456
ragge
1.13
457 int
plunky
1.64
458 sloscan(void)
ragge
1.3
459 {
ragge
1.13
460         int ch;
461         int yyp;
462
463 zagain:
464         yyp = 0;
gmcgarry
1.26
465         ch = inch();
466         yytext[yyp++] = (usch)ch;
ragge
1.13
467         switch (ch) {
ragge
1.14
468         case -1:
469                 return 0;
ragge
1.13
470         case '\n':
ragge
1.19
471                 /* sloscan() never passes \n, that's up to fastscan() */
472                 unch(ch);
plunky
1.94
473                 yytext[yyp] = 0;
474                 return ch;
ragge
1.13
475
476         case '\r'/* Ignore CR's */
477                 yyp = 0;
478                 break;
479
480         case '0'case '1'case '2'case '3'case '4'case '5'
481         case '6'case '7'case '8'case '9':
482                 /* readin a "pp-number" */
483 ppnum:          for (;;) {
ragge
1.19
484                         ch = inch();
plunky
1.94
485                         if (ch == -1)
486                                 break;
ragge
1.19
487                         if (spechr[ch] & C_EP) {
gmcgarry
1.26
488                                 yytext[yyp++] = (usch)ch;
ragge
1.19
489                                 ch = inch();
ragge
1.13
490                                 if (ch == '-' || ch == '+') {
gmcgarry
1.26
491                                         yytext[yyp++] = (usch)ch;
ragge
1.13
492                                 } else
ragge
1.19
493                                         unch(ch);
ragge
1.13
494                                 continue;
495                         }
ragge
1.19
496                         if ((spechr[ch] & C_ID) || ch == '.') {
gmcgarry
1.26
497                                 yytext[yyp++] = (usch)ch;
ragge
1.13
498                                 continue;
499                         } 
500                         break;
501                 }
ragge
1.19
502                 unch(ch);
ragge
1.13
503                 yytext[yyp] = 0;
504
ragge
1.19
505                 return NUMBER;
ragge
1.13
506
507         case '\'':
ragge
1.19
508 chlit:          
ragge
1.13
509                 for (;;) {
ragge
1.19
510                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
511                                 yytext[yyp++] = (usch)ch;
512                                 yytext[yyp++] = (usch)inch();
ragge
1.13
513                                 continue;
plunky
1.94
514                         } else if (ch == -1 || ch == '\n') {
ragge
1.13
515                                 /* not a constant */
516                                 while (yyp > 1)
ragge
1.19
517                                         unch(yytext[--yyp]);
ragge
1.13
518                                 ch = '\'';
519                                 goto any;
520                         } else
gmcgarry
1.26
521                                 yytext[yyp++] = (usch)ch;
ragge
1.13
522                         if (ch == '\'')
523                                 break;
524                 }
525                 yytext[yyp] = 0;
526
plunky
1.74
527                 return NUMBER;
ragge
1.13
528
529         case ' ':
530         case '\t':
ragge
1.19
531                 while ((ch = inch()) == ' ' || ch == '\t')
gmcgarry
1.26
532                         yytext[yyp++] = (usch)ch;
ragge
1.19
533                 unch(ch);
534                 yytext[yyp] = 0;
plunky
1.74
535                 return WSPACE;
ragge
1.13
536
537         case '/':
ragge
1.19
538                 if ((ch = inch()) == '/') {
ragge
1.13
539                         do {
gmcgarry
1.26
540                                 yytext[yyp++] = (usch)ch;
ragge
1.19
541                                 ch = inch();
plunky
1.94
542                         } while (ch != -1 && ch != '\n');
ragge
1.13
543                         yytext[yyp] = 0;
544                         unch(ch);
545                         goto zagain;
546                 } else if (ch == '*') {
547                         int cwrn;
548                         extern int readmac;
549
ragge
1.33
550                         if (Cflag && !flslvl && readmac) {
551                                 unch(ch);
ragge
1.34
552                                 yytext[yyp] = 0;
ragge
1.13
553                                 return CMNT;
ragge
1.33
554                         }
ragge
1.13
555
556                         wrn = 0;
plunky
1.94
557                 more:   while ((c = inch()) != '*') {
558                                 if (c == -1)
559                                         return 0;       
ragge
1.13
560                                 if (c == '\n')
561                                         putch(c), ifiles->lineno++;
ragge
1.48
562                                 else if (c == EBLOCK) {
ragge
1.46
563                                         (void)inch();
ragge
1.48
564                                         (void)inch();
plunky
1.96
565                                 } else if (c == WARN)
ragge
1.13
566                                         wrn = 1;
567                         }
plunky
1.94
568                         if ((c = inch()) == -1)
ragge
1.13
569                                 return 0;
plunky
1.94
570                         if (c != '/') {
ragge
1.19
571                                 unch(c);
ragge
1.13
572                                 goto more;
573                         }
574                         if (!tflag && !Cflag && !flslvl)
ragge
1.19
575                                 unch(' ');
ragge
1.13
576                         if (wrn)
plunky
1.96
577                                 unch(WARN);
ragge
1.13
578                         goto zagain;
579                 }
580                 unch(ch);
581                 ch = '/';
582                 goto any;
583
ragge
1.19
584         case '.':
plunky
1.94
585                 if ((ch = inch()) == -1)
586                         return 0;
plunky
1.97
587                 if ((spechr[ch] & C_DIGIT)) {
gmcgarry
1.26
588                         yytext[yyp++] = (usch)ch;
ragge
1.19
589                         goto ppnum;
ragge
1.13
590                 } else {
ragge
1.19
591                         unch(ch);
ragge
1.13
592                         ch = '.';
593                 }
ragge
1.19
594                 goto any;
ragge
1.13
595
596         case '\"':
ragge
1.62
597                 if (tflag && defining)
ragge
1.42
598                         goto any;
ragge
1.13
599         strng:
600                 for (;;) {
ragge
1.19
601                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
602                                 yytext[yyp++] = (usch)ch;
603                                 yytext[yyp++] = (usch)inch();
ragge
1.13
604                                 continue;
plunky
1.94
605                         } else if (ch == -1) {
606                                 break;
ragge
1.13
607                         } else 
gmcgarry
1.26
608                                 yytext[yyp++] = (usch)ch;
ragge
1.13
609                         if (ch == '\"')
610                                 break;
611                 }
612                 yytext[yyp] = 0;
plunky
1.74
613                 return STRING;
ragge
1.13
614
615         case 'L':
ragge
1.42
616                 if ((ch = inch()) == '\"' && !tflag) {
gmcgarry
1.26
617                         yytext[yyp++] = (usch)ch;
ragge
1.13
618                         goto strng;
ragge
1.42
619                 } else if (ch == '\'' && !tflag) {
gmcgarry
1.26
620                         yytext[yyp++] = (usch)ch;
ragge
1.13
621                         goto chlit;
622                 }
ragge
1.19
623                 unch(ch);
ragge
1.13
624                 /* FALLTHROUGH */
625
626         /* Yetch, all identifiers */
627         case 'a'case 'b'case 'c'case 'd'case 'e'case 'f'
628         case 'g'case 'h'case 'i'case 'j'case 'k'case 'l'
629         case 'm'case 'n'case 'o'case 'p'case 'q'case 'r'
630         case 's'case 't'case 'u'case 'v'case 'w'case 'x'
631         case 'y'case 'z':
632         case 'A'case 'B'case 'C'case 'D'case 'E'case 'F'
633         case 'G'case 'H'case 'I'case 'J'case 'K':
634         case 'M'case 'N'case 'O'case 'P'case 'Q'case 'R'
635         case 'S'case 'T'case 'U'case 'V'case 'W'case 'X'
636         case 'Y'case 'Z':
ragge
1.19
637         case '_'/* {L}({L}|{D})* */
ragge
1.13
638
639                 /* Special hacks */
640                 for (;;) { /* get chars */
plunky
1.94
641                         if ((ch = inch()) == -1)
642                                 break;
plunky
1.97
643                         if ((spechr[ch] & C_ID)) {
gmcgarry
1.26
644                                 yytext[yyp++] = (usch)ch;
ragge
1.14
645                         } else {
plunky
1.94
646                                 unch(ch);
ragge
1.13
647                                 break;
ragge
1.14
648                         }
ragge
1.13
649                 }
650                 yytext[yyp] = 0/* need already string */
651                 /* end special hacks */
652
ragge
1.19
653                 return IDENT;
ragge
1.13
654         default:
655         any:
656                 yytext[yyp] = 0;
ragge
1.19
657                 return yytext[0];
ragge
1.3
658
ragge
1.13
659         } /* endcase */
ragge
1.14
660         goto zagain;
ragge
1.3
661 }
662
ragge
1.19
663 int
plunky
1.64
664 yylex(void)
ragge
1.19
665 {
666         static int ifdefnoex;
667         struct symtab *nl;
668         int chc2;
669
670         while ((ch = sloscan()) == WSPACE)
671                 ;
plunky
1.97
672         if (ch < 128 && (spechr[ch] & C_2))
plunky
1.102
673                 c2 = inch();
ragge
1.19
674         else
675                 c2 = 0;
676
677         switch (ch) {
plunky
1.97
678         case '=':
679                 if (c2 == '='return EQ;
680                 break;
681         case '!':
682                 if (c2 == '='return NE;
683                 break;
684         case '|':
685                 if (c2 == '|'return OROR;
686                 break;
687         case '&':
688                 if (c2 == '&'return ANDAND;
689                 break;
ragge
1.19
690         case '<':
691                 if (c2 == '<'return LS;
692                 if (c2 == '='return LE;
693                 break;
694         case '>':
695                 if (c2 == '>'return RS;
696                 if (c2 == '='return GE;
697                 break;
698         case '+':
699         case '-':
700                 if (ch == c2)
plunky
1.78
701                         error("invalid preprocessor operator %c%c"chc2);
ragge
1.19
702                 break;
ragge
1.27
703
ragge
1.33
704         case '/':
705                 if (Cflag == 0 || c2 != '*')
706                         break;
707                 /* Found comment that need to be skipped */
708                 for (;;) {
plunky
1.102
709                         ch = inch();
ragge
1.33
710                 c1:     if (ch != '*')
711                                 continue;
plunky
1.102
712                         if ((ch = inch()) == '/')
ragge
1.33
713                                 break;
714                         goto c1;
715                 }
716                 return yylex();
717
ragge
1.19
718         case NUMBER:
ragge
1.27
719                 if (yytext[0] == '\'') {
720                         yylval.node.op = NUMBER;
plunky
1.73
721                         yylval.node.nd_val = charcon(yytext);
ragge
1.27
722                 } else
723                         cvtdig(yytext[0] != '0' ? 10 :
724                             yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
ragge
1.19
725                 return NUMBER;
ragge
1.27
726
ragge
1.19
727         case IDENT:
ragge
1.44
728                 if (strcmp((char *)yytext"defined") == 0) {
ragge
1.19
729                         ifdef = 1;
730                         return DEFINED;
731                 }
plunky
1.73
732                 nl = lookup(yytextFIND);
ragge
1.19
733                 if (ifdef) {
734                         yylval.node.nd_val = nl != NULL;
735                         ifdef = 0;
736                 } else if (nl && noex == 0) {
ragge
1.43
737                         usch *och = stringbuf;
738                         int i;
ragge
1.19
739
ragge
1.43
740                         i = kfind(nl);
741                         unch(WARN);
742                         if (i)
743                                 unpstr(stringbuf);
744                         else
745                                 unpstr(nl->namep);
ragge
1.19
746                         stringbuf = och;
747                         noex = 1;
748                         return yylex();
749                 } else {
750                         yylval.node.nd_val = 0;
751                 }
752                 yylval.node.op = NUMBER;
753                 return NUMBER;
ragge
1.43
754         case WARN:
ragge
1.19
755                 noex = 0;
ragge
1.70
756                 /* FALLTHROUGH */
757         case PHOLD:
ragge
1.19
758                 return yylex();
759         default:
760                 return ch;
761         }
762         unch(c2);
763         return ch;
764 }
765
ragge
1.13
766 /*
767  * Let the command-line args be faked defines at beginning of file.
768  */
769 static void
770 prinit(struct initar *itstruct includ *ic)
ragge
1.1
771 {
ragge
1.31
772         const char *pre, *post;
773         char *a;
ragge
1.1
774
ragge
1.13
775         if (it->next)
776                 prinit(it->nextic);
777         pre = post = NULL/* XXX gcc */
778         switch (it->type) {
779         case 'D':
780                 pre = "#define ";
781                 if ((a = strchr(it->str'=')) != NULL) {
782                         *a = ' ';
783                         post = "\n";
ragge
1.1
784                 } else
ragge
1.13
785                         post = " 1\n";
ragge
1.1
786                 break;
ragge
1.13
787         case 'U':
788                 pre = "#undef ";
789                 post = "\n";
ragge
1.1
790                 break;
ragge
1.13
791         case 'i':
792                 pre = "#include \"";
793                 post = "\"\n";
ragge
1.1
794                 break;
795         default:
ragge
1.13
796                 error("prinit");
ragge
1.1
797         }
ragge
1.13
798         strlcat((char *)ic->bufferpreCPPBUF+1);
799         strlcat((char *)ic->bufferit->strCPPBUF+1);
800         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
801                 error("line exceeds buffer size");
802
803         ic->lineno--;
804         while (*ic->maxread)
805                 ic->maxread++;
ragge
1.1
806 }
807
ragge
1.4
808 /*
ragge
1.6
809  * A new file included.
810  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
811  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
812  */
813 int
ragge
1.31
814 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
815 {
ragge
1.13
816         extern struct initar *initar;
ragge
1.6
817         struct includ ibuf;
818         struct includ *ic;
plunky
1.82
819         int otrulvl;
ragge
1.6
820
821         ic = &ibuf;
ragge
1.13
822         ic->next = ifiles;
ragge
1.4
823
ragge
1.6
824         if (file != NULL) {
ragge
1.31
825                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
826                         return -1;
ragge
1.13
827                 ic->orgfn = ic->fname = file;
828                 if (++inclevel > MAX_INCLEVEL)
plunky
1.102
829                         error("limit for nested includes exceeded");
ragge
1.6
830         } else {
831                 ic->infil = 0;
ragge
1.31
832                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
833         }
ragge
1.49
834 #ifndef BUF_STACK
835         ic->bbuf = malloc(BBUFSZ);
836 #endif
ragge
1.6
837         ic->buffer = ic->bbuf+NAMEMAX;
ragge
1.4
838         ic->curptr = ic->buffer;
839         ifiles = ic;
ragge
1.13
840         ic->lineno = 1;
plunky
1.102
841         ic->escln = 0;
ragge
1.6
842         ic->maxread = ic->curptr;
ragge
1.29
843         ic->idx = idx;
844         ic->incs = incs;
845         ic->fn = fn;
ragge
1.13
846         prtline();
847         if (initar) {
ragge
1.38
848                 int oin = ic->infil;
849                 ic->infil = -1;
ragge
1.13
850                 *ic->maxread = 0;
851                 prinit(initaric);
ragge
1.41
852                 initar = NULL;
ragge
1.13
853                 if (dMflag)
plunky
1.82
854                         xwrite(ofdic->bufferstrlen((char *)ic->buffer));
ragge
1.38
855                 fastscan();
856                 prtline();
857                 ic->infil = oin;
ragge
1.13
858         }
ragge
1.4
859
ragge
1.13
860         otrulvl = trulvl;
ragge
1.4
861
ragge
1.19
862         fastscan();
ragge
1.13
863
864         if (otrulvl != trulvl || flslvl)
ragge
1.6
865                 error("unterminated conditional");
ragge
1.4
866
ragge
1.49
867 #ifndef BUF_STACK
868         free(ic->bbuf);
869 #endif
ragge
1.13
870         ifiles = ic->next;
ragge
1.6
871         close(ic->infil);
ragge
1.13
872         inclevel--;
ragge
1.6
873         return 0;
ragge
1.4
874 }
ragge
1.1
875
876 /*
877  * Print current position to output file.
878  */
879 void
plunky
1.64
880 prtline(void)
ragge
1.1
881 {
plunky
1.83
882         usch *sb = stringbuf;
ragge
1.13
883
884         if (Mflag) {
885                 if (dMflag)
886                         return/* no output */
887                 if (ifiles->lineno == 1) {
plunky
1.83
888                         sheap("%s: %s\n"Mfileifiles->fname);
ragge
1.68
889                         if (MPflag &&
plunky
1.83
890                             strcmp((const char *)ifiles->fname, (char *)MPfile))
891                                 sheap("%s:\n"ifiles->fname);
892                         xwrite(ofdsbstringbuf - sb);
ragge
1.13
893                 }
ragge
1.65
894         } else if (!Pflag) {
plunky
1.83
895                 sheap("\n# %d \"%s\""ifiles->linenoifiles->fname);
ragge
1.65
896                 if (ifiles->idx == SYSINC)
plunky
1.83
897                         sheap(" 3");
898                 sheap("\n");
899                 putstr(sb);
ragge
1.65
900         }
plunky
1.83
901         stringbuf = sb;
ragge
1.1
902 }
903
904 void
905 cunput(int c)
906 {
plunky
1.59
907 #ifdef PCC_DEBUG