Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121025195924

Diff

Diff from 1.91 to:

Annotations

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

Annotated File View

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