Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121011101742

Diff

Diff from 1.80 to:

Annotations

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

Annotated File View

plunky
1.80
1 /*      $Id: token.c,v 1.80 2012/10/11 10:17:42 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
ragge
1.43
83 char spechr[256] = {
84         0,      0,      0,      0,      C_SPECC_SPEC0,      0,
85         0,      C_WSNLC_SPEC|C_WSNL,  0,
86         0,      C_WSNL0,      0,
ragge
1.19
87         0,      0,      0,      0,      0,      0,      0,      0,
88         0,      0,      0,      0,      0,      0,      0,      0,
89
ragge
1.43
90         C_WSNLC_2,    C_SPEC0,      0,      0,      C_2,    C_SPEC,
ragge
1.33
91         0,      0,      0,      C_2,    0,      C_2,    0,      C_SPEC|C_2,
ragge
1.19
92         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
93         C_I,    C_I,    0,      0,      C_2,    C_2,    C_2,    C_SPEC,
94
95         0,      C_I,    C_I,    C_I,    C_I,    C_I|C_EPC_I,  C_I,
96         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
97         C_I|C_EPC_I,  C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
ragge
1.51
98         C_I,    C_I,    C_I,    0,      C_SPEC0,      0,      C_I,
ragge
1.19
99
100         0,      C_I,    C_I,    C_I,    C_I,    C_I|C_EPC_I,  C_I,
101         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
102         C_I|C_EPC_I,  C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
103         C_I,    C_I,    C_I,    0,      C_2,    0,      0,      0,
104
105 };
ragge
1.1
106
ragge
1.13
107 static void
108 unch(int c)
109 {
ragge
1.15
110                 
111         --ifiles->curptr;
112         if (ifiles->curptr < ifiles->bbuf)
113                 error("pushback buffer full");
gmcgarry
1.26
114         *ifiles->curptr = (usch)c;
ragge
1.13
115 }
ragge
1.1
116
ragge
1.45
117 static int
118 eatcmnt(void)
119 {
120         int ch;
121
122         if (Cflag) { PUTCH('/'); PUTCH('*'); }
123         for (;;) {
124                 ch = inch();
125                 if (ch == '\n') {
126                         ifiles->lineno++;
127                         PUTCH('\n');
128                 }
129                 if (ch == -1)
130                         return -1;
131                 if (ch == '*') {
132                         ch = inch();
133                         if (ch == '/') {
134                                 if (Cflag) {
135                                         PUTCH('*');
136                                         PUTCH('/');
137                                 } else
138                                         PUTCH(' ');
139                                 break;
140                         }
141                         unch(ch);
142                         ch = '*';
143                 }
144                 if (CflagPUTCH(ch);
145         }
146         return 0;
147 }
148
ragge
1.19
149 /*
150  * Scan quickly the input file searching for:
151  *      - '#' directives
152  *      - keywords (if not flslvl)
153  *      - comments
154  *
155  *      Handle strings, numbers and trigraphs with care.
156  *      Only data from pp files are scanned here, never any rescans.
157  *      TODO: Only print out strings before calling other functions.
158  */
159 static void
160 fastscan(void)
161 {
162         struct symtab *nl;
gmcgarry
1.57
163         int chi = 0;
ragge
1.52
164         int nnl = 0;
ragge
1.49
165         usch *cp;
ragge
1.19
166
167         goto run;
168         for (;;) {
169                 ch = NXTCH();
170 xloop:          if (ch == -1)
171                         return;
plunky
1.60
172 #ifdef PCC_DEBUG
ragge
1.43
173                 if (dflag>1)
174                         printf("fastscan ch %d (%c)\n"chch > 31 ? ch : '@');
plunky
1.60
175 #endif
ragge
1.19
176                 if ((spechr[ch] & C_SPEC) == 0) {
177                         PUTCH(ch);
178                         continue;
179                 }
180                 switch (ch) {
ragge
1.44
181                 case EBLOCK:
ragge
1.43
182                 case WARN:
183                 case CONC:
184                         error("bad char passed");
185                         break;
186
ragge
1.19
187                 case '/'/* Comments */
188                         if ((ch = inch()) == '/') {
ragge
1.45
189 cppcmt:                         if (Cflag) { PUTCH(ch); } else { PUTCH(' '); }
ragge
1.19
190                                 do {
191                                         if (CflagPUTCH(ch);
192                                         ch = inch();
193                                 } while (ch != -1 && ch != '\n');
194                                 goto xloop;
195                         } else if (ch == '*') {
ragge
1.45
196                                 if (eatcmnt())
197                                         return;
ragge
1.19
198                         } else {
199                                 PUTCH('/');
200                                 goto xloop;
201                         }
202                         break;
203
204                 case '?':  /* trigraphs */
205                         if ((ch = chktg()))
206                                 goto xloop;
207                         PUTCH('?');
208                         break;
209
ragge
1.37
210                 case '\\':
211                         if ((ch = NXTCH()) == '\n') {
212                                 ifiles->lineno++;
213                                 continue;
214                         } else {
215                                 PUTCH('\\');
216                         }
217                         goto xloop;
218
ragge
1.19
219                 case '\n'/* newlines, for pp directives */
ragge
1.52
220                         while (nnl > 0) { PUTCH('\n'); nnl--; }
ragge
1.50
221 run2:                   ifiles->lineno++;
ragge
1.19
222                         do {
223                                 PUTCH(ch);
224 run:                            ch = NXTCH();
ragge
1.45
225                                 if (ch == '/') {
226                                         ch = NXTCH();
227                                         if (ch == '/')
228                                                 goto cppcmt;
229                                         if (ch == '*') {
230                                                 if (eatcmnt())
231                                                         return;
232                                                 goto run;
233                                         } 
234                                         unch(ch);
235                                         ch = '/';
236                                 }
ragge
1.19
237                         } while (ch == ' ' || ch == '\t');
ragge
1.50
238                         if (ch == '\\') {
239                                 ch = NXTCH();
240                                 if (ch == '\n')
241                                         goto run2;
242                                 unch(ch);
243                                 ch = '\\';
244                         }
ragge
1.19
245                         if (ch == '#') {
246                                 ppdir();
247                                 continue;
ragge
1.40
248                         } else if (ch == '%') {
249                                 ch = NXTCH();
250                                 if (ch == ':') {
251                                         ppdir();
252                                         continue;
253                                 } else {
254                                         unch(ch);
255                                         ch = '%';
256                                 }
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                                 }
ragge
1.19
279                                 if (ch < 0)
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') {
300                                                 goto nxt;
301                                         } else {
302                                                 unch(ch);
303                                                 ch = '\\';
304                                         }
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                                 }
330                                 if (ch < 0)
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                                 }
ragge
1.19
373                                 if (ch < 0)
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;
ragge
1.68
791         int otrulvli;
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)
ragge
1.68
825                         i = write(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 {
ragge
1.13
853         usch *s, *os = stringbuf;
ragge
1.68
854         int i;
ragge
1.13
855
856         if (Mflag) {
857                 if (dMflag)
858                         return/* no output */
859                 if (ifiles->lineno == 1) {
860                         s = sheap("%s: %s\n"Mfileifiles->fname);
ragge
1.68
861                         i = write(ofdsstrlen((char *)s));
862                         if (MPflag &&
plunky
1.69
863                             strcmp((const char *)ifiles->fname, (char *)MPfile)) {
ragge
1.68
864                                 s = sheap("%s:\n"ifiles->fname);
865                                 i = write(ofdsstrlen((char *)s));
866                         }
ragge
1.13
867                 }
ragge
1.65
868         } else if (!Pflag) {
869                 putstr(sheap("\n# %d \"%s\""ifiles->linenoifiles->fname));
870                 if (ifiles->idx == SYSINC)
871                         putstr(sheap(" 3"));
872                 putstr(sheap("\n"));
873         }
ragge
1.13
874         stringbuf = os;
ragge
1.1
875 }
876
877 void
878 cunput(int c)
879 {
plunky
1.59
880 #ifdef PCC_DEBUG
ragge
1.43
881 //      if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
ragge
1.13
882 #endif
ragge
1.19
883         unch(c);
ragge
1.1
884 }
885
ragge
1.13
886 static int
887 dig2num(int c)
888 {
889         if (c >= 'a')
890                 c = c - 'a' + 10;
891         else if (c >= 'A')
892                 c = c - 'A' + 10;
893         else
894                 c = c - '0';
895         return c;
896 }
897
898 /*
899  * Convert string numbers to unsigned long long and check overflow.
900  */
901 static void
902 cvtdig(int rad)
903 {
904         unsigned long long rv = 0;
905         unsigned long long rv2 = 0;
ragge