Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110518100222

Diff

Diff from 1.55 to:

Annotations

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

Annotated File View

ragge
1.55
1 /*      $Id: token.c,v 1.55 2011/05/18 10:02:22 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.19
594                                 unch(ch);
ragge
1.13
595                                 break;
ragge
1.14
596                         }
ragge
1.13
597                 }
598                 yytext[yyp] = 0/* need already string */
599                 /* end special hacks */
600
ragge
1.19
601                 return IDENT;
ragge
1.13
602         default:
603         any:
604                 yytext[yyp] = 0;
ragge
1.19
605                 return yytext[0];
ragge
1.3
606
ragge
1.13
607         } /* endcase */
ragge
1.14
608         goto zagain;
ragge
1.6
609
ragge
1.13
610 yyret:
611         yytext[yyp] = 0;
612         return ch;
ragge
1.3
613 }
614
ragge
1.19
615 int
616 yylex()
617 {
618         static int ifdefnoex;
619         struct symtab *nl;
620         int chc2;
621
622         while ((ch = sloscan()) == WSPACE)
623                 ;
624         if (ch < 128 && spechr[ch] & C_2)
625                 c2 = inpch();
626         else
627                 c2 = 0;
628
629 #define C2(a,b,c) case a: if (c2 == b) return c; break
630         switch (ch) {
631         C2('=''='EQ);
632         C2('!''='NE);
633         C2('|''|'OROR);
634         C2('&''&'ANDAND);
635         case '<':
636                 if (c2 == '<'return LS;
637                 if (c2 == '='return LE;
638                 break;
639         case '>':
640                 if (c2 == '>'return RS;
641                 if (c2 == '='return GE;
642                 break;
643         case '+':
644         case '-':
645                 if (ch == c2)
646                         badop("");
647                 break;
ragge
1.27
648
ragge
1.33
649         case '/':
650                 if (Cflag == 0 || c2 != '*')
651                         break;
652                 /* Found comment that need to be skipped */
653                 for (;;) {
654                         ch = inpch();
655                 c1:     if (ch != '*')
656                                 continue;
657                         if ((ch = inpch()) == '/')
658                                 break;
659                         goto c1;
660                 }
661                 return yylex();
662
ragge
1.19
663         case NUMBER:
ragge
1.27
664                 if (yytext[0] == '\'') {
665                         yylval.node.op = NUMBER;
666                         yylval.node.nd_val = charcon((usch *)yytext);
667                 } else
668                         cvtdig(yytext[0] != '0' ? 10 :
669                             yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
ragge
1.19
670                 return NUMBER;
ragge
1.27
671
ragge
1.19
672         case IDENT:
ragge
1.44
673                 if (strcmp((char *)yytext"defined") == 0) {
ragge
1.19
674                         ifdef = 1;
675                         return DEFINED;
676                 }
677                 nl = lookup((usch *)yytextFIND);
678                 if (ifdef) {
679                         yylval.node.nd_val = nl != NULL;
680                         ifdef = 0;
681                 } else if (nl && noex == 0) {
ragge
1.43
682                         usch *och = stringbuf;
683                         int i;
ragge
1.19
684
ragge
1.43
685                         i = kfind(nl);
686                         unch(WARN);
687                         if (i)
688                                 unpstr(stringbuf);
689                         else
690                                 unpstr(nl->namep);
ragge
1.19
691                         stringbuf = och;
692                         noex = 1;
693                         return yylex();
694                 } else {
695                         yylval.node.nd_val = 0;
696                 }
697                 yylval.node.op = NUMBER;
698                 return NUMBER;
ragge
1.43
699         case WARN:
ragge
1.19
700                 noex = 0;
701                 return yylex();
702         default:
703                 return ch;
704         }
705         unch(c2);
706         return ch;
707 }
708
ragge
1.13
709 usch *yypyybuf[CPPBUF];
710
711 int yywrap(void);
ragge
1.3
712
ragge
1.2
713 static int
ragge
1.13
714 inpch(void)
ragge
1.2
715 {
ragge
1.6
716         int len;
ragge
1.3
717
ragge
1.11
718         if (ifiles->curptr < ifiles->maxread)
ragge
1.2
719                 return *ifiles->curptr++;
ragge
1.11
720
ragge
1.38
721         if (ifiles->infil == -1)
722                 return -1;
ragge
1.6
723         if ((len = read(ifiles->infilifiles->bufferCPPBUF)) < 0)
ragge
1.13
724                 error("read error on file %s"ifiles->orgfn);
ragge
1.6
725         if (len == 0)
ragge
1.3
726                 return -1;
727         ifiles->curptr = ifiles->buffer;
ragge
1.6
728         ifiles->maxread = ifiles->buffer + len;
ragge
1.13
729         return inpch();
ragge
1.2
730 }
ragge
1.1
731
732 static int
ragge
1.13
733 inch(void)
ragge
1.1
734 {
735         int c;
736
ragge
1.13
737 again:  switch (c = inpch()) {
ragge
1.1
738         case '\\'/* continued lines */
ragge
1.13
739 msdos:          if ((c = inpch()) == '\n') {
ragge
1.1
740                         ifiles->lineno++;
741                         goto again;
ragge
1.13
742                 } else if (c == '\r')
743                         goto msdos;
744                 unch(c);
ragge
1.1
745                 return '\\';
746         case '?'/* trigraphs */
ragge
1.19
747                 if ((c = chktg())) {
ragge
1.13
748                         unch(c);
ragge
1.19
749                         goto again;
ragge
1.1
750                 }
ragge
1.19
751                 return '?';
ragge
1.1
752         default:
753                 return c;
754         }
755 }
756
ragge
1.13
757 /*
758  * Let the command-line args be faked defines at beginning of file.
759  */
760 static void
761 prinit(struct initar *itstruct includ *ic)
ragge
1.1
762 {
ragge
1.31
763         const char *pre, *post;
764         char *a;
ragge
1.1
765
ragge
1.13
766         if (it->next)
767                 prinit(it->nextic);
768         pre = post = NULL/* XXX gcc */
769         switch (it->type) {
770         case 'D':
771                 pre = "#define ";
772                 if ((a = strchr(it->str'=')) != NULL) {
773                         *a = ' ';
774                         post = "\n";
ragge
1.1
775                 } else
ragge
1.13
776                         post = " 1\n";
ragge
1.1
777                 break;
ragge
1.13
778         case 'U':
779                 pre = "#undef ";
780                 post = "\n";
ragge
1.1
781                 break;
ragge
1.13
782         case 'i':
783                 pre = "#include \"";
784                 post = "\"\n";
ragge
1.1
785                 break;
786         default:
ragge
1.13
787                 error("prinit");
ragge
1.1
788         }
ragge
1.13
789         strlcat((char *)ic->bufferpreCPPBUF+1);
790         strlcat((char *)ic->bufferit->strCPPBUF+1);
791         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
792                 error("line exceeds buffer size");
793
794         ic->lineno--;
795         while (*ic->maxread)
796                 ic->maxread++;
ragge
1.1
797 }
798
ragge
1.4
799 /*
ragge
1.6
800  * A new file included.
801  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
802  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
803  */
804 int
ragge
1.31
805 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
806 {
ragge
1.13
807         extern struct initar *initar;
ragge
1.6
808         struct includ ibuf;
809         struct includ *ic;
ragge
1.19
810         int otrulvl;
ragge
1.6
811
812         ic = &ibuf;
ragge
1.13
813         ic->next = ifiles;
ragge
1.4
814
ragge
1.6
815         if (file != NULL) {
ragge
1.31
816                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
817                         return -1;
ragge
1.13
818                 ic->orgfn = ic->fname = file;
819                 if (++inclevel > MAX_INCLEVEL)
820                         error("Limit for nested includes exceeded");
ragge
1.6
821         } else {
822                 ic->infil = 0;
ragge
1.31
823                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
824         }
ragge
1.49
825 #ifndef BUF_STACK
826         ic->bbuf = malloc(BBUFSZ);
827 #endif
ragge
1.6
828         ic->buffer = ic->bbuf+NAMEMAX;
ragge
1.4
829         ic->curptr = ic->buffer;
830         ifiles = ic;
ragge
1.13
831         ic->lineno = 1;
ragge
1.6
832         ic->maxread = ic->curptr;
ragge
1.29
833         ic->idx = idx;
834         ic->incs = incs;
835         ic->fn = fn;
ragge
1.13
836         prtline();
837         if (initar) {
ragge
1.38
838                 int oin = ic->infil;
839                 ic->infil = -1;
ragge
1.13
840                 *ic->maxread = 0;
841                 prinit(initaric);
ragge
1.41
842                 initar = NULL;
ragge
1.13
843                 if (dMflag)
844                         write(ofdic->bufferstrlen((char *)ic->buffer));
ragge
1.38
845                 fastscan();
846                 prtline();
847                 ic->infil = oin;
ragge
1.13
848         }
ragge
1.4
849
ragge
1.13
850         otrulvl = trulvl;
ragge
1.4
851
ragge
1.19
852         fastscan();
ragge
1.13
853
854         if (otrulvl != trulvl || flslvl)
ragge
1.6
855                 error("unterminated conditional");
ragge
1.4
856
ragge
1.49
857 #ifndef BUF_STACK
858         free(ic->bbuf);
859 #endif
ragge
1.13
860         ifiles = ic->next;
ragge
1.6
861         close(ic->infil);
ragge
1.13
862         inclevel--;
ragge
1.6
863         return 0;
ragge
1.4
864 }
ragge
1.1
865
866 /*
867  * Print current position to output file.
868  */
869 void
870 prtline()
871 {
ragge
1.13
872         usch *s, *os = stringbuf;
873
874         if (Mflag) {
875                 if (dMflag)
876                         return/* no output */
877                 if (ifiles->lineno == 1) {
878                         s = sheap("%s: %s\n"Mfileifiles->fname);
879                         write(ofdsstrlen((char *)s));
880                 }
881         } else if (!Pflag)
ragge
1.30
882                 putstr(sheap("\n# %d \"%s\"\n"ifiles->linenoifiles->fname));
ragge
1.13
883         stringbuf = os;
ragge
1.1
884 }
885
886 void
887 cunput(int c)
888 {
ragge
1.13
889 #ifdef CPP_DEBUG
ragge
1.43
890 //      extern int dflag;
891 //      if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
ragge
1.13
892 #endif
ragge
1.19
893 #if 0
894 if (c == 10) {
895         printf("c == 10!!!\n");
896 }
897 #endif
898         unch(c);
ragge
1.1
899 }
900
ragge
1.13
901 int yywrap(void) { return 1; }
902
903 static int
904 dig2num(int c)
905 {
906         if (c >= 'a')
907                 c = c - 'a' + 10;
908         else if (c >= 'A')
909                 c = c - 'A' + 10;
910         else
911                 c = c - '0';
912         return c;
913 }
914
915 /*
916  * Convert string numbers to unsigned long long and check overflow.
917  */
918 static void
919 cvtdig(int rad)
920 {
921         unsigned long long rv = 0;