Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121002093732

Diff

Diff from 1.76 to:

Annotations

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

Annotated File View

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