Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121029172623

Diff

Diff from 1.93 to:

Annotations

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

Annotated File View

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