Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20130226192738

Diff

Diff from 1.106 to:

Annotations

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

Annotated File View

plunky
1.106
1 /*      $Id: token.c,v 1.106 2013/02/26 19:27:38 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                                 }
plunky
1.104
362                                 if (ch == '\n') {
363                                         warning("unterminated string literal");
ragge
1.53
364                                         goto xloop;
plunky
1.104
365                                 }
plunky
1.90
366                                 if (ch == -1)
ragge
1.19
367                                         return;
ragge
1.53
368                                 PUTCH(ch);
ragge
1.21
369                         }
ragge
1.19
370                         PUTCH(ch);
371                         break;
372
373                 case '.':  /* for pp-number */
374                         PUTCH(ch);
plunky
1.102
375                         ch = inch();
ragge
1.19
376                         if (ch < '0' || ch > '9')
377                                 goto xloop;
plunky
1.102
378
ragge
1.19
379                         /* FALLTHROUGH */
380                 case '0'case '1'case '2'case '3'case '4':
381                 case '5'case '6'case '7'case '8'case '9':
382                         do {
plunky
1.99
383 nxp:                            PUTCH(ch);
plunky
1.102
384                                 ch = inch();
plunky
1.94
385                                 if (ch == -1)
386                                         return;
ragge
1.19
387                                 if (spechr[ch] & C_EP) {
388                                         PUTCH(ch);
plunky
1.102
389                                         ch = inch();
ragge
1.19
390                                         if (ch == '-' || ch == '+')
plunky
1.99
391                                                 goto nxp;
plunky
1.94
392                                         if (ch == -1)
393                                                 return;
ragge
1.19
394                                 }
395                         } while ((spechr[ch] & C_ID) || (ch == '.'));
396                         goto xloop;
397
plunky
1.104
398                 case '\''/* character constant */
ragge
1.21
399 con:                    PUTCH(ch);
ragge
1.23
400                         if (tflag)
plunky
1.102
401                                 break/* character constants ignored */
402                         while ((ch = inch()) != '\'') {
403                                 if (ch == '\\') {
404                                         PUTCH('\\');
405                                         ch = inch();
406                                 }
plunky
1.104
407                                 if (ch == '\n') {
408                                         warning("unterminated character constant");
ragge
1.52
409                                         goto xloop;
plunky
1.104
410                                 }
plunky
1.90
411                                 if (ch == -1)
ragge
1.19
412                                         return;
ragge
1.52
413                                 PUTCH(ch);
ragge
1.21
414                         }
ragge
1.19
415                         PUTCH(ch);
416                         break;
ragge
1.21
417
ragge
1.19
418                 case 'L':
plunky
1.102
419                         ch = inch();
ragge
1.19
420                         if (ch == '\"') {
421                                 PUTCH('L');
422                                 goto str;
423                         }
424                         if (ch == '\'') {
425                                 PUTCH('L');
426                                 goto con;
427                         }
428                         unch(ch);
429                         ch = 'L';
plunky
1.102
430
ragge
1.19
431                         /* FALLTHROUGH */
432                 default:
plunky
1.102
433 #ifdef PCC_DEBUG
ragge
1.19
434                         if ((spechr[ch] & C_ID) == 0)
435                                 error("fastscan");
plunky
1.102
436 #endif
gmcgarry
1.58
437                         i = 0;
ragge
1.19
438                         do {
gmcgarry
1.26
439                                 yytext[i++] = (usch)ch;
plunky
1.102
440                                 ch = inch();
441                         } while (ch != -1 && (spechr[ch] & C_ID));
442
443                         if (flslvl)
444                                 goto xloop;
ragge
1.43
445
ragge
1.19
446                         yytext[i] = 0;
447                         unch(ch);
ragge
1.43
448
ragge
1.49
449                         cp = stringbuf;
plunky
1.73
450                         if ((nl = lookup(yytextFIND)) && kfind(nl)) {
ragge
1.43
451                                 putstr(stringbuf);
ragge
1.19
452                         } else
plunky
1.73
453                                 putstr(yytext);
ragge
1.49
454                         stringbuf = cp;
ragge
1.43
455
ragge
1.19
456                         break;
457                 }
458         }
459 }
ragge
1.1
460
ragge
1.13
461 int
plunky
1.64
462 sloscan(void)
ragge
1.3
463 {
ragge
1.13
464         int ch;
465         int yyp;
466
467 zagain:
468         yyp = 0;
gmcgarry
1.26
469         ch = inch();
470         yytext[yyp++] = (usch)ch;
ragge
1.13
471         switch (ch) {
ragge
1.14
472         case -1:
473                 return 0;
ragge
1.13
474         case '\n':
ragge
1.19
475                 /* sloscan() never passes \n, that's up to fastscan() */
476                 unch(ch);
plunky
1.94
477                 yytext[yyp] = 0;
478                 return ch;
ragge
1.13
479
480         case '\r'/* Ignore CR's */
481                 yyp = 0;
482                 break;
483
484         case '0'case '1'case '2'case '3'case '4'case '5'
485         case '6'case '7'case '8'case '9':
486                 /* readin a "pp-number" */
487 ppnum:          for (;;) {
ragge
1.19
488                         ch = inch();
plunky
1.94
489                         if (ch == -1)
490                                 break;
ragge
1.19
491                         if (spechr[ch] & C_EP) {
gmcgarry
1.26
492                                 yytext[yyp++] = (usch)ch;
ragge
1.19
493                                 ch = inch();
ragge
1.13
494                                 if (ch == '-' || ch == '+') {
gmcgarry
1.26
495                                         yytext[yyp++] = (usch)ch;
ragge
1.13
496                                 } else
ragge
1.19
497                                         unch(ch);
ragge
1.13
498                                 continue;
499                         }
ragge
1.19
500                         if ((spechr[ch] & C_ID) || ch == '.') {
gmcgarry
1.26
501                                 yytext[yyp++] = (usch)ch;
ragge
1.13
502                                 continue;
503                         } 
504                         break;
505                 }
ragge
1.19
506                 unch(ch);
ragge
1.13
507                 yytext[yyp] = 0;
508
ragge
1.19
509                 return NUMBER;
ragge
1.13
510
511         case '\'':
ragge
1.19
512 chlit:          
ragge
1.13
513                 for (;;) {
ragge
1.19
514                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
515                                 yytext[yyp++] = (usch)ch;
516                                 yytext[yyp++] = (usch)inch();
ragge
1.13
517                                 continue;
plunky
1.94
518                         } else if (ch == -1 || ch == '\n') {
ragge
1.13
519                                 /* not a constant */
520                                 while (yyp > 1)
ragge
1.19
521                                         unch(yytext[--yyp]);
ragge
1.13
522                                 ch = '\'';
523                                 goto any;
524                         } else
gmcgarry
1.26
525                                 yytext[yyp++] = (usch)ch;
ragge
1.13
526                         if (ch == '\'')
527                                 break;
528                 }
529                 yytext[yyp] = 0;
530
plunky
1.74
531                 return NUMBER;
ragge
1.13
532
533         case ' ':
534         case '\t':
ragge
1.19
535                 while ((ch = inch()) == ' ' || ch == '\t')
gmcgarry
1.26
536                         yytext[yyp++] = (usch)ch;
ragge
1.19
537                 unch(ch);
538                 yytext[yyp] = 0;
plunky
1.74
539                 return WSPACE;
ragge
1.13
540
541         case '/':
ragge
1.19
542                 if ((ch = inch()) == '/') {
ragge
1.13
543                         do {
gmcgarry
1.26
544                                 yytext[yyp++] = (usch)ch;
ragge
1.19
545                                 ch = inch();
plunky
1.94
546                         } while (ch != -1 && ch != '\n');
ragge
1.13
547                         yytext[yyp] = 0;
548                         unch(ch);
549                         goto zagain;
550                 } else if (ch == '*') {
551                         int cwrn;
552                         extern int readmac;
553
ragge
1.33
554                         if (Cflag && !flslvl && readmac) {
555                                 unch(ch);
ragge
1.34
556                                 yytext[yyp] = 0;
ragge
1.13
557                                 return CMNT;
ragge
1.33
558                         }
ragge
1.13
559
560                         wrn = 0;
plunky
1.94
561                 more:   while ((c = inch()) != '*') {
562                                 if (c == -1)
563                                         return 0;       
ragge
1.13
564                                 if (c == '\n')
565                                         putch(c), ifiles->lineno++;
ragge
1.48
566                                 else if (c == EBLOCK) {
ragge
1.46
567                                         (void)inch();
ragge
1.48
568                                         (void)inch();
plunky
1.96
569                                 } else if (c == WARN)
ragge
1.13
570                                         wrn = 1;
571                         }
plunky
1.94
572                         if ((c = inch()) == -1)
ragge
1.13
573                                 return 0;
plunky
1.94
574                         if (c != '/') {
ragge
1.19
575                                 unch(c);
ragge
1.13
576                                 goto more;
577                         }
578                         if (!tflag && !Cflag && !flslvl)
ragge
1.19
579                                 unch(' ');
ragge
1.13
580                         if (wrn)
plunky
1.96
581                                 unch(WARN);
ragge
1.13
582                         goto zagain;
583                 }
584                 unch(ch);
585                 ch = '/';
586                 goto any;
587
ragge
1.19
588         case '.':
plunky
1.94
589                 if ((ch = inch()) == -1)
590                         return 0;
plunky
1.97
591                 if ((spechr[ch] & C_DIGIT)) {
gmcgarry
1.26
592                         yytext[yyp++] = (usch)ch;
ragge
1.19
593                         goto ppnum;
ragge
1.13
594                 } else {
ragge
1.19
595                         unch(ch);
ragge
1.13
596                         ch = '.';
597                 }
ragge
1.19
598                 goto any;
ragge
1.13
599
600         case '\"':
ragge
1.62
601                 if (tflag && defining)
ragge
1.42
602                         goto any;
ragge
1.13
603         strng:
604                 for (;;) {
ragge
1.19
605                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
606                                 yytext[yyp++] = (usch)ch;
607                                 yytext[yyp++] = (usch)inch();
ragge
1.13
608                                 continue;
plunky
1.94
609                         } else if (ch == -1) {
610                                 break;
ragge
1.13
611                         } else 
gmcgarry
1.26
612                                 yytext[yyp++] = (usch)ch;
ragge
1.13
613                         if (ch == '\"')
614                                 break;
615                 }
616                 yytext[yyp] = 0;
plunky
1.74
617                 return STRING;
ragge
1.13
618
619         case 'L':
ragge
1.42
620                 if ((ch = inch()) == '\"' && !tflag) {
gmcgarry
1.26
621                         yytext[yyp++] = (usch)ch;
ragge
1.13
622                         goto strng;
ragge
1.42
623                 } else if (ch == '\'' && !tflag) {
gmcgarry
1.26
624                         yytext[yyp++] = (usch)ch;
ragge
1.13
625                         goto chlit;
626                 }
ragge
1.19
627                 unch(ch);
ragge
1.13
628                 /* FALLTHROUGH */
629
630         /* Yetch, all identifiers */
631         case 'a'case 'b'case 'c'case 'd'case 'e'case 'f'
632         case 'g'case 'h'case 'i'case 'j'case 'k'case 'l'
633         case 'm'case 'n'case 'o'case 'p'case 'q'case 'r'
634         case 's'case 't'case 'u'case 'v'case 'w'case 'x'
635         case 'y'case 'z':
636         case 'A'case 'B'case 'C'case 'D'case 'E'case 'F'
637         case 'G'case 'H'case 'I'case 'J'case 'K':
638         case 'M'case 'N'case 'O'case 'P'case 'Q'case 'R'
639         case 'S'case 'T'case 'U'case 'V'case 'W'case 'X'
640         case 'Y'case 'Z':
ragge
1.19
641         case '_'/* {L}({L}|{D})* */
ragge
1.13
642
643                 /* Special hacks */
644                 for (;;) { /* get chars */
plunky
1.94
645                         if ((ch = inch()) == -1)
646                                 break;
plunky
1.97
647                         if ((spechr[ch] & C_ID)) {
gmcgarry
1.26
648                                 yytext[yyp++] = (usch)ch;
ragge
1.14
649                         } else {
plunky
1.94
650                                 unch(ch);
ragge
1.13
651                                 break;
ragge
1.14
652                         }
ragge
1.13
653                 }
654                 yytext[yyp] = 0/* need already string */
655                 /* end special hacks */
656
ragge
1.19
657                 return IDENT;
ragge
1.13
658         default:
659         any:
660                 yytext[yyp] = 0;
ragge
1.19
661                 return yytext[0];
ragge
1.3
662
ragge
1.13
663         } /* endcase */
ragge
1.14
664         goto zagain;
ragge
1.3
665 }
666
ragge
1.19
667 int
plunky
1.64
668 yylex(void)
ragge
1.19
669 {
670         static int ifdefnoex;
671         struct symtab *nl;
672         int chc2;
673
674         while ((ch = sloscan()) == WSPACE)
675                 ;
plunky
1.97
676         if (ch < 128 && (spechr[ch] & C_2))
plunky
1.102
677                 c2 = inch();
ragge
1.19
678         else
679                 c2 = 0;
680
681         switch (ch) {
plunky
1.97
682         case '=':
683                 if (c2 == '='return EQ;
684                 break;
685         case '!':
686                 if (c2 == '='return NE;
687                 break;
688         case '|':
689                 if (c2 == '|'return OROR;
690                 break;
691         case '&':
692                 if (c2 == '&'return ANDAND;
693                 break;
ragge
1.19
694         case '<':
695                 if (c2 == '<'return LS;
696                 if (c2 == '='return LE;
697                 break;
698         case '>':
699                 if (c2 == '>'return RS;
700                 if (c2 == '='return GE;
701                 break;
702         case '+':
703         case '-':
704                 if (ch == c2)
plunky
1.78
705                         error("invalid preprocessor operator %c%c"chc2);
ragge
1.19
706                 break;
ragge
1.27
707
ragge
1.33
708         case '/':
709                 if (Cflag == 0 || c2 != '*')
710                         break;
711                 /* Found comment that need to be skipped */
712                 for (;;) {
plunky
1.102
713                         ch = inch();
ragge
1.33
714                 c1:     if (ch != '*')
715                                 continue;
plunky
1.102
716                         if ((ch = inch()) == '/')
ragge
1.33
717                                 break;
718                         goto c1;
719                 }
720                 return yylex();
721
ragge
1.19
722         case NUMBER:
ragge
1.27
723                 if (yytext[0] == '\'') {
724                         yylval.node.op = NUMBER;
plunky
1.73
725                         yylval.node.nd_val = charcon(yytext);
ragge
1.27
726                 } else
727                         cvtdig(yytext[0] != '0' ? 10 :
728                             yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
ragge
1.19
729                 return NUMBER;
ragge
1.27
730
ragge
1.19
731         case IDENT:
ragge
1.44
732                 if (strcmp((char *)yytext"defined") == 0) {
ragge
1.19
733                         ifdef = 1;
734                         return DEFINED;
735                 }
plunky
1.73
736                 nl = lookup(yytextFIND);
ragge
1.19
737                 if (ifdef) {
738                         yylval.node.nd_val = nl != NULL;
739                         ifdef = 0;
740                 } else if (nl && noex == 0) {
ragge
1.43
741                         usch *och = stringbuf;
742                         int i;
ragge
1.19
743
ragge
1.43
744                         i = kfind(nl);
745                         unch(WARN);
746                         if (i)
747                                 unpstr(stringbuf);
748                         else
749                                 unpstr(nl->namep);
ragge
1.19
750                         stringbuf = och;
751                         noex = 1;
752                         return yylex();
753                 } else {
754                         yylval.node.nd_val = 0;
755                 }
756                 yylval.node.op = NUMBER;
757                 return NUMBER;
ragge
1.43
758         case WARN:
ragge
1.19
759                 noex = 0;
ragge
1.70
760                 /* FALLTHROUGH */
761         case PHOLD:
ragge
1.19
762                 return yylex();
763         default:
764                 return ch;
765         }
766         unch(c2);
767         return ch;
768 }
769
ragge
1.13
770 /*
771  * Let the command-line args be faked defines at beginning of file.
772  */
773 static void
774 prinit(struct initar *itstruct includ *ic)
ragge
1.1
775 {
ragge
1.31
776         const char *pre, *post;
777         char *a;
ragge
1.1
778
ragge
1.13
779         if (it->next)
780                 prinit(it->nextic);
781         pre = post = NULL/* XXX gcc */
782         switch (it->type) {
783         case 'D':
784                 pre = "#define ";
785                 if ((a = strchr(it->str'=')) != NULL) {
786                         *a = ' ';
787                         post = "\n";
ragge
1.1
788                 } else
ragge
1.13
789                         post = " 1\n";
ragge
1.1
790                 break;
ragge
1.13
791         case 'U':
792                 pre = "#undef ";
793                 post = "\n";
ragge
1.1
794                 break;
ragge
1.13
795         case 'i':
796                 pre = "#include \"";
797                 post = "\"\n";
ragge
1.1
798                 break;
799         default:
ragge
1.13
800                 error("prinit");
ragge
1.1
801         }
ragge
1.13
802         strlcat((char *)ic->bufferpreCPPBUF+1);
803         strlcat((char *)ic->bufferit->strCPPBUF+1);
804         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
805                 error("line exceeds buffer size");
806
807         ic->lineno--;
808         while (*ic->maxread)
809                 ic->maxread++;
ragge
1.1
810 }
811
ragge
1.4
812 /*
ragge
1.6
813  * A new file included.
814  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
815  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
816  */
817 int
ragge
1.31
818 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
819 {
ragge
1.13
820         extern struct initar *initar;
ragge
1.6
821         struct includ ibuf;
822         struct includ *ic;
plunky
1.82
823         int otrulvl;
ragge
1.6
824
825         ic = &ibuf;
ragge
1.13
826         ic->next = ifiles;
ragge
1.4
827
ragge
1.6
828         if (file != NULL) {
ragge
1.31
829                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
830                         return -1;
ragge
1.13
831                 ic->orgfn = ic->fname = file;
832                 if (++inclevel > MAX_INCLEVEL)
plunky
1.102
833                         error("limit for nested includes exceeded");
ragge
1.6
834         } else {
835                 ic->infil = 0;
ragge
1.31
836                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
837         }
ragge
1.49
838 #ifndef BUF_STACK
839         ic->bbuf = malloc(BBUFSZ);
840 #endif
ragge
1.6
841         ic->buffer = ic->bbuf+NAMEMAX;
ragge
1.4
842         ic->curptr = ic->buffer;
843         ifiles = ic;
ragge
1.13
844         ic->lineno = 1;
plunky
1.102
845         ic->escln = 0;
ragge
1.6
846         ic->maxread = ic->curptr;
ragge
1.29
847         ic->idx = idx;
848         ic->incs = incs;
849         ic->fn = fn;
ragge
1.13
850         prtline();
851         if (initar) {
ragge
1.38
852                 int oin = ic->infil;
853                 ic->infil = -1;
ragge
1.13
854                 *ic->maxread = 0;
855                 prinit(initaric);
ragge
1.41
856                 initar = NULL;
ragge
1.13
857                 if (dMflag)
plunky
1.82
858                         xwrite(ofdic->bufferstrlen((char *)ic->buffer));
ragge
1.38
859                 fastscan();
860                 prtline();
861                 ic->infil = oin;
ragge
1.13
862         }
ragge
1.4
863
ragge
1.13
864         otrulvl = trulvl;
ragge
1.4
865
ragge
1.19
866         fastscan();
ragge
1.13
867
868         if (otrulvl != trulvl || flslvl)
ragge
1.6
869                 error("unterminated conditional");
ragge
1.4
870
ragge
1.49
871 #ifndef BUF_STACK
872         free(ic->bbuf);
873 #endif
ragge
1.13
874         ifiles = ic->next;
ragge
1.6
875         close(ic->infil);
ragge
1.13
876         inclevel--;
ragge
1.6
877         return 0;
ragge
1.4
878 }
ragge
1.1
879
880 /*
881  * Print current position to output file.
882  */
883 void
plunky
1.64
884 prtline(void)
ragge
1.1
885 {
plunky
1.83
886         usch *sb = stringbuf;
ragge
1.13
887
888         if (Mflag) {
889                 if (dMflag)
890                         return/* no output */
891                 if (ifiles->lineno == 1) {
plunky
1.83
892                         sheap("%s: %s\n"Mfileifiles->fname);
ragge
1.68
893                         if (MPflag &&
plunky
1.83
894                             strcmp((const char *)ifiles->fname, (char *)MPfile))
895                                 sheap("%s:\n"ifiles->fname);
896                         xwrite(ofdsbstringbuf - sb);
ragge
1.13
897                 }
ragge
1.65
898         } else if (!Pflag) {
plunky
1.83
899                 sheap("\n# %d \"%s\""ifiles->linenoifiles->fname);
ragge
1.65
900                 if (ifiles->idx == SYSINC)
plunky
1.83
901                         sheap(" 3");
902                 sheap("\n");
903                 putstr(sb);
ragge
1.65
904         }