Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110706160123

Diff

Diff from 1.61 to:

Annotations

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

Annotated File View

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