Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110317153714

Diff

Diff from 1.51 to:

Annotations

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

Annotated File View

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