Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110522171732

Diff

Diff from 1.56 to:

Annotations

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

Annotated File View

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