Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121002095607

Diff

Diff from 1.78 to:

Annotations

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

Annotated File View

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