Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110319091518

Diff

Diff from 1.52 to:

Annotations

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

Annotated File View

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