Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121019143543

Diff

Diff from 1.87 to:

Annotations

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

Annotated File View

plunky
1.87
1 /*      $Id: token.c,v 1.87 2012/10/19 14:35:43 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++;
129                         PUTCH('\n');
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 == '*') {
ragge
1.45
198                                 if (eatcmnt())
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 */
ragge
1.52
222                         while (nnl > 0) { PUTCH('\n'); nnl--; }
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 == '*') {
232                                                 if (eatcmnt())
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                                 }
ragge
1.19
281                                 if (ch < 0)
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') {
302                                                 goto nxt;
303                                         } else {
304                                                 unch(ch);
305                                                 ch = '\\';
306                                         }
307                                 }
ragge
1.19
308                                 if (spechr[ch] & C_EP) {
309                                         PUTCH(ch);
310                                         ch = NXTCH();
311                                         if (ch == '-' || ch == '+')
312                                                 continue;
313                                 }
314                         } while ((spechr[ch] & C_ID) || (ch == '.'));
315                         goto xloop;
316
317                 case '\''/* character literal */
ragge
1.21
318 con:                    PUTCH(ch);
ragge
1.23
319                         if (tflag)
320                                 continue/* character constants ignored */
ragge
1.21
321                         while ((ch = NXTCH()) != '\'') {
ragge
1.52
322                                 if (ch == '\n')
323                                         goto xloop;
ragge
1.19
324                                 if (ch == '\\') {
ragge
1.52
325                                         if ((ch = NXTCH()) != '\n') {
326                                                 PUTCH('\\');
327                                                 PUTCH(ch);
328                                         } else
329                                                 nnl++;
330                                         continue;
331                                 }
332                                 if (ch < 0)
ragge
1.19
333                                         return;
ragge
1.52
334                                 PUTCH(ch);
ragge
1.21
335                         }
ragge
1.19
336                         PUTCH(ch);
337                         break;
ragge
1.21
338
ragge
1.19
339                 case 'L':
340                         ch = NXTCH();
341                         if (ch == '\"') {
342                                 PUTCH('L');
343                                 goto str;
344                         }
345                         if (ch == '\'') {
346                                 PUTCH('L');
347                                 goto con;
348                         }
349                         unch(ch);
350                         ch = 'L';
351                         /* FALLTHROUGH */
352                 default:
353                         if ((spechr[ch] & C_ID) == 0)
354                                 error("fastscan");
355                         if (flslvl) {
356                                 while (spechr[ch] & C_ID)
357                                         ch = NXTCH();
358                                 goto xloop;
359                         }
gmcgarry
1.58
360                         i = 0;
ragge
1.19
361                         do {
gmcgarry
1.26
362                                 yytext[i++] = (usch)ch;
ragge
1.19
363                                 ch = NXTCH();
ragge
1.36
364                                 if (ch == '\\') {
365                                         ch = NXTCH();
366                                         if (ch != '\n') {
ragge
1.51
367                                                 unch(ch);
ragge
1.36
368                                                 ch = '\\';
369                                         } else {
ragge
1.51
370                                                 putch('\n');
ragge
1.36
371                                                 ifiles->lineno++;
372                                                 ch = NXTCH();
373                                         }
374                                 }
ragge
1.19
375                                 if (ch < 0)
376                                         return;
377                         } while (spechr[ch] & C_ID);
ragge
1.43
378
ragge
1.19
379                         yytext[i] = 0;
380                         unch(ch);
ragge
1.43
381
ragge
1.49
382                         cp = stringbuf;
plunky
1.73
383                         if ((nl = lookup(yytextFIND)) && kfind(nl)) {
ragge
1.43
384                                 putstr(stringbuf);
ragge
1.19
385                         } else
plunky
1.73
386                                 putstr(yytext);
ragge
1.49
387                         stringbuf = cp;
ragge
1.43
388
ragge
1.19
389                         break;
390                 }
391         }
392 }
ragge
1.1
393
ragge
1.13
394 int
plunky
1.64
395 sloscan(void)
ragge
1.3
396 {
ragge
1.13
397         int ch;
398         int yyp;
399
400 zagain:
401         yyp = 0;
gmcgarry
1.26
402         ch = inch();
403         yytext[yyp++] = (usch)ch;
ragge
1.13
404         switch (ch) {
ragge
1.14
405         case -1:
406                 return 0;
ragge
1.13
407         case '\n':
ragge
1.19
408                 /* sloscan() never passes \n, that's up to fastscan() */
409                 unch(ch);
410                 goto yyret;
ragge
1.13
411
412         case '\r'/* Ignore CR's */
413                 yyp = 0;
414                 break;
415
416         case '0'case '1'case '2'case '3'case '4'case '5'
417         case '6'case '7'case '8'case '9':
418                 /* readin a "pp-number" */
419 ppnum:          for (;;) {
ragge
1.19
420                         ch = inch();
421                         if (spechr[ch] & C_EP) {
gmcgarry
1.26
422                                 yytext[yyp++] = (usch)ch;
ragge
1.19
423                                 ch = inch();
ragge
1.13
424                                 if (ch == '-' || ch == '+') {
gmcgarry
1.26
425                                         yytext[yyp++] = (usch)ch;
ragge
1.13
426                                 } else
ragge
1.19
427                                         unch(ch);
ragge
1.13
428                                 continue;
429                         }
ragge
1.19
430                         if ((spechr[ch] & C_ID) || ch == '.') {
gmcgarry
1.26
431                                 yytext[yyp++] = (usch)ch;
ragge
1.13
432                                 continue;
433                         } 
434                         break;
435                 }
ragge
1.19
436                 unch(ch);
ragge
1.13
437                 yytext[yyp] = 0;
438
ragge
1.19
439                 return NUMBER;
ragge
1.13
440
441         case '\'':
ragge
1.19
442 chlit:          
ragge
1.13
443                 for (;;) {
ragge
1.19
444                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
445                                 yytext[yyp++] = (usch)ch;
446                                 yytext[yyp++] = (usch)inch();
ragge
1.13
447                                 continue;
448                         } else if (ch == '\n') {
449                                 /* not a constant */
450                                 while (yyp > 1)
ragge
1.19
451                                         unch(yytext[--yyp]);
ragge
1.13
452                                 ch = '\'';
453                                 goto any;
454                         } else
gmcgarry
1.26
455                                 yytext[yyp++] = (usch)ch;
ragge
1.13
456                         if (ch == '\'')
457                                 break;
458                 }
459                 yytext[yyp] = 0;
460
plunky
1.74
461                 return NUMBER;
ragge
1.13
462
463         case ' ':
464         case '\t':
ragge
1.19
465                 while ((ch = inch()) == ' ' || ch == '\t')
gmcgarry
1.26
466                         yytext[yyp++] = (usch)ch;
ragge
1.19
467                 unch(ch);
468                 yytext[yyp] = 0;
plunky
1.74
469                 return WSPACE;
ragge
1.13
470
471         case '/':
ragge
1.19
472                 if ((ch = inch()) == '/') {
ragge
1.13
473                         do {
gmcgarry
1.26
474                                 yytext[yyp++] = (usch)ch;
ragge
1.19
475                                 ch = inch();
ragge
1.13
476                         } while (ch && ch != '\n');
477                         yytext[yyp] = 0;
478                         unch(ch);
479                         goto zagain;
480                 } else if (ch == '*') {
481                         int cwrn;
482                         extern int readmac;
483
ragge
1.33
484                         if (Cflag && !flslvl && readmac) {
485                                 unch(ch);
ragge
1.34
486                                 yytext[yyp] = 0;
ragge
1.13
487                                 return CMNT;
ragge
1.33
488                         }
ragge
1.13
489
490                         wrn = 0;
ragge
1.19
491                 more:   while ((c = inch()) && c != '*') {
ragge
1.13
492                                 if (c == '\n')
493                                         putch(c), ifiles->lineno++;
ragge
1.48
494                                 else if (c == EBLOCK) {
ragge
1.46
495                                         (void)inch();
ragge
1.48
496                                         (void)inch();
497                                 } else if (c == 1/* WARN */
ragge
1.13
498                                         wrn = 1;
499                         }
500                         if (c == 0)
501                                 return 0;
ragge
1.19
502                         if ((c = inch()) && c != '/') {
503                                 unch(c);
ragge
1.13
504                                 goto more;
505                         }
506                         if (c == 0)
507                                 return 0;
508                         if (!tflag && !Cflag && !flslvl)
ragge
1.19
509                                 unch(' ');
ragge
1.13
510                         if (wrn)
ragge
1.19
511                                 unch(1);
ragge
1.13
512                         goto zagain;
513                 }
514                 unch(ch);
515                 ch = '/';
516                 goto any;
517
ragge
1.19
518         case '.':
519                 ch = inch();
520                 if (isdigit(ch)) {
gmcgarry
1.26
521                         yytext[yyp++] = (usch)ch;
ragge
1.19
522                         goto ppnum;
ragge
1.13
523                 } else {
ragge
1.19
524                         unch(ch);
ragge
1.13
525                         ch = '.';
526                 }
ragge
1.19
527                 goto any;
ragge
1.13
528
529         case '\"':
ragge
1.62
530                 if (tflag && defining)
ragge
1.42
531                         goto any;
ragge
1.13
532         strng:
533                 for (;;) {
ragge
1.19
534                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
535                                 yytext[yyp++] = (usch)ch;
536                                 yytext[yyp++] = (usch)inch();
ragge
1.13
537                                 continue;
538                         } else 
gmcgarry
1.26
539                                 yytext[yyp++] = (usch)ch;
ragge
1.13
540                         if (ch == '\"')
541                                 break;
542                 }
543                 yytext[yyp] = 0;
plunky
1.74
544                 return STRING;
ragge
1.13
545
546         case 'L':
ragge
1.42
547                 if ((ch = inch()) == '\"' && !tflag) {
gmcgarry
1.26
548                         yytext[yyp++] = (usch)ch;
ragge
1.13
549                         goto strng;
ragge
1.42
550                 } else if (ch == '\'' && !tflag) {
gmcgarry
1.26
551                         yytext[yyp++] = (usch)ch;
ragge
1.13
552                         goto chlit;
553                 }
ragge
1.19
554                 unch(ch);
ragge
1.13
555                 /* FALLTHROUGH */
556
557         /* Yetch, all identifiers */
558         case 'a'case 'b'case 'c'case 'd'case 'e'case 'f'
559         case 'g'case 'h'case 'i'case 'j'case 'k'case 'l'
560         case 'm'case 'n'case 'o'case 'p'case 'q'case 'r'
561         case 's'case 't'case 'u'case 'v'case 'w'case 'x'
562         case 'y'case 'z':
563         case 'A'case 'B'case 'C'case 'D'case 'E'case 'F'
564         case 'G'case 'H'case 'I'case 'J'case 'K':
565         case 'M'case 'N'case 'O'case 'P'case 'Q'case 'R'
566         case 'S'case 'T'case 'U'case 'V'case 'W'case 'X'
567         case 'Y'case 'Z':
ragge
1.19
568         case '_'/* {L}({L}|{D})* */
ragge
1.13
569
570                 /* Special hacks */
571                 for (;;) { /* get chars */
ragge
1.19
572                         ch = inch();
ragge
1.14
573                         if (isalpha(ch) || isdigit(ch) || ch == '_') {
gmcgarry
1.26
574                                 yytext[yyp++] = (usch)ch;
ragge
1.14
575                         } else {
ragge
1.56
576                                 if (ch != -1)
577                                         unch(ch);
ragge
1.13
578                                 break;
ragge
1.14
579                         }
ragge
1.13
580                 }
581                 yytext[yyp] = 0/* need already string */
582                 /* end special hacks */
583
ragge
1.19
584                 return IDENT;
ragge
1.13
585         default:
586         any:
587                 yytext[yyp] = 0;
ragge
1.19
588                 return yytext[0];
ragge
1.3
589
ragge
1.13
590         } /* endcase */
ragge
1.14
591         goto zagain;
ragge
1.6
592
ragge
1.13
593 yyret:
594         yytext[yyp] = 0;
595         return ch;
ragge
1.3
596 }
597
ragge
1.19
598 int
plunky
1.64
599 yylex(void)
ragge
1.19
600 {
601         static int ifdefnoex;
602         struct symtab *nl;
603         int chc2;
604
605         while ((ch = sloscan()) == WSPACE)
606                 ;
607         if (ch < 128 && spechr[ch] & C_2)
608                 c2 = inpch();
609         else
610                 c2 = 0;
611
612 #define C2(a,b,c) case a: if (c2 == b) return c; break
613         switch (ch) {
614         C2('=''='EQ);
615         C2('!''='NE);
616         C2('|''|'OROR);
617         C2('&''&'ANDAND);
618         case '<':
619                 if (c2 == '<'return LS;
620                 if (c2 == '='return LE;
621                 break;
622         case '>':
623                 if (c2 == '>'return RS;
624                 if (c2 == '='return GE;
625                 break;
626         case '+':
627         case '-':
628                 if (ch == c2)
plunky
1.78
629                         error("invalid preprocessor operator %c%c"chc2);
ragge
1.19
630                 break;
ragge
1.27
631
ragge
1.33
632         case '/':
633                 if (Cflag == 0 || c2 != '*')
634                         break;
635                 /* Found comment that need to be skipped */
636                 for (;;) {
637                         ch = inpch();
638                 c1:     if (ch != '*')
639                                 continue;
640                         if ((ch = inpch()) == '/')
641                                 break;
642                         goto c1;
643                 }
644                 return yylex();
645
ragge
1.19
646         case NUMBER:
ragge
1.27
647                 if (yytext[0] == '\'') {
648                         yylval.node.op = NUMBER;
plunky
1.73
649                         yylval.node.nd_val = charcon(yytext);
ragge
1.27
650                 } else
651                         cvtdig(yytext[0] != '0' ? 10 :
652                             yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
ragge
1.19
653                 return NUMBER;
ragge
1.27
654
ragge
1.19
655         case IDENT:
ragge
1.44
656                 if (strcmp((char *)yytext"defined") == 0) {
ragge
1.19
657                         ifdef = 1;
658                         return DEFINED;
659                 }
plunky
1.73
660                 nl = lookup(yytextFIND);
ragge
1.19
661                 if (ifdef) {
662                         yylval.node.nd_val = nl != NULL;
663                         ifdef = 0;
664                 } else if (nl && noex == 0) {
ragge
1.43
665                         usch *och = stringbuf;
666                         int i;
ragge
1.19
667
ragge
1.43
668                         i = kfind(nl);
669                         unch(WARN);
670                         if (i)
671                                 unpstr(stringbuf);
672                         else
673                                 unpstr(nl->namep);
ragge
1.19
674                         stringbuf = och;
675                         noex = 1;
676                         return yylex();
677                 } else {
678                         yylval.node.nd_val = 0;
679                 }
680                 yylval.node.op = NUMBER;
681                 return NUMBER;
ragge
1.43
682         case WARN:
ragge
1.19
683                 noex = 0;
ragge
1.70
684                 /* FALLTHROUGH */
685         case PHOLD:
ragge
1.19
686                 return yylex();
687         default:
688                 return ch;
689         }
690         unch(c2);
691         return ch;
692 }
693
ragge
1.2
694 static int
ragge
1.13
695 inpch(void)
ragge
1.2
696 {
ragge
1.6
697         int len;
ragge
1.3
698
ragge
1.11
699         if (ifiles->curptr < ifiles->maxread)
ragge
1.2
700                 return *ifiles->curptr++;
ragge
1.11
701
ragge
1.38
702         if (ifiles->infil == -1)
703                 return -1;
ragge
1.6
704         if ((len = read(ifiles->infilifiles->bufferCPPBUF)) < 0)
ragge
1.13
705                 error("read error on file %s"ifiles->orgfn);
ragge
1.6
706         if (len == 0)
ragge
1.3
707                 return -1;
ragge
1.67
708         ifiles->buffer[len] = 0;
ragge
1.3
709         ifiles->curptr = ifiles->buffer;
ragge
1.6
710         ifiles->maxread = ifiles->buffer + len;
ragge
1.13
711         return inpch();
ragge
1.2
712 }
ragge
1.1
713
714 static int
ragge
1.13
715 inch(void)
ragge
1.1
716 {
717         int c;
718
ragge
1.13
719 again:  switch (c = inpch()) {
ragge
1.1
720         case '\\'/* continued lines */
ragge
1.13
721 msdos:          if ((c = inpch()) == '\n') {
ragge
1.1
722                         ifiles->lineno++;
ragge
1.66
723                         putch('\n');
ragge
1.1
724                         goto again;
ragge
1.13
725                 } else if (c == '\r')
726                         goto msdos;
727                 unch(c);
ragge
1.1
728                 return '\\';
729         case '?'/* trigraphs */
ragge
1.19
730                 if ((c = chktg())) {
ragge
1.13
731                         unch(c);
ragge
1.19
732                         goto again;
ragge
1.1
733                 }
ragge
1.19
734                 return '?';
ragge
1.1
735         default:
736                 return c;
737         }
738 }
739
ragge
1.13
740 /*
741  * Let the command-line args be faked defines at beginning of file.
742  */
743 static void
744 prinit(struct initar *itstruct includ *ic)
ragge
1.1
745 {
ragge
1.31
746         const char *pre, *post;
747         char *a;
ragge
1.1
748
ragge
1.13
749         if (it->next)
750                 prinit(it->nextic);
751         pre = post = NULL/* XXX gcc */
752         switch (it->type) {
753         case 'D':
754                 pre = "#define ";
755                 if ((a = strchr(it->str'=')) != NULL) {
756                         *a = ' ';
757                         post = "\n";
ragge
1.1
758                 } else
ragge
1.13
759                         post = " 1\n";
ragge
1.1
760                 break;
ragge
1.13
761         case 'U':
762                 pre = "#undef ";
763                 post = "\n";
ragge
1.1
764                 break;
ragge
1.13
765         case 'i':
766                 pre = "#include \"";
767                 post = "\"\n";
ragge
1.1
768                 break;
769         default:
ragge
1.13
770                 error("prinit");
ragge
1.1
771         }
ragge
1.13
772         strlcat((char *)ic->bufferpreCPPBUF+1);
773         strlcat((char *)ic->bufferit->strCPPBUF+1);
774         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
775                 error("line exceeds buffer size");
776
777         ic->lineno--;
778         while (*ic->maxread)
779                 ic->maxread++;
ragge
1.1
780 }
781
ragge
1.4
782 /*
ragge
1.6
783  * A new file included.
784  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
785  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
786  */
787 int
ragge
1.31
788 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
789 {
ragge
1.13
790         extern struct initar *initar;
ragge
1.6
791         struct includ ibuf;
792         struct includ *ic;
plunky
1.82
793         int otrulvl;
ragge
1.6
794
795         ic = &ibuf;
ragge
1.13
796         ic->next = ifiles;
ragge
1.4
797
ragge
1.6
798         if (file != NULL) {
ragge
1.31
799                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
800                         return -1;
ragge
1.13
801                 ic->orgfn = ic->fname = file;
802                 if (++inclevel > MAX_INCLEVEL)
803                         error("Limit for nested includes exceeded");
ragge
1.6
804         } else {
805                 ic->infil = 0;
ragge
1.31
806                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
807         }
ragge
1.49
808 #ifndef BUF_STACK
809         ic->bbuf = malloc(BBUFSZ);
810 #endif
ragge
1.6
811         ic->buffer = ic->bbuf+NAMEMAX;
ragge
1.4
812         ic->curptr = ic->buffer;
813         ifiles = ic;
ragge
1.13
814         ic->lineno = 1;
ragge
1.6
815         ic->maxread = ic->curptr;
ragge
1.29
816         ic->idx = idx;
817         ic->incs = incs;
818         ic->fn = fn;
ragge
1.13
819         prtline();
820         if (initar) {
ragge
1.38
821                 int oin = ic->infil;
822                 ic->infil = -1;
ragge
1.13
823                 *ic->maxread = 0;
824                 prinit(initaric);
ragge
1.41
825                 initar = NULL;
ragge
1.13
826                 if (dMflag)
plunky
1.82
827                         xwrite(ofdic->bufferstrlen((char *)ic->buffer));
ragge
1.38
828                 fastscan();
829                 prtline();
830                 ic->infil = oin;
ragge
1.13
831         }
ragge
1.4
832
ragge
1.13
833         otrulvl = trulvl;
ragge
1.4
834
ragge
1.19
835         fastscan();
ragge
1.13
836
837         if (otrulvl != trulvl || flslvl)
ragge
1.6
838                 error("unterminated conditional");
ragge
1.4
839
ragge
1.49
840 #ifndef BUF_STACK
841         free(ic->bbuf);
842 #endif
ragge
1.13
843         ifiles = ic->next;
ragge
1.6
844         close(ic->infil);
ragge
1.13
845         inclevel--;
ragge
1.6
846         return 0;
ragge
1.4
847 }
ragge
1.1
848
849 /*
850  * Print current position to output file.
851  */
852 void
plunky
1.64
853 prtline(void)
ragge
1.1
854 {
plunky
1.83
855         usch *sb = stringbuf;
ragge
1.13
856
857         if (Mflag) {
858                 if (dMflag)
859                         return/* no output */
860                 if (ifiles->lineno == 1) {
plunky
1.83
861                         sheap("%s: %s\n"Mfileifiles->fname);
ragge
1.68
862                         if (MPflag &&
plunky
1.83
863                             strcmp((const char *)ifiles->fname, (char *)MPfile))
864                                 sheap("%s:\n"ifiles->fname);
865                         xwrite(ofdsbstringbuf - sb);
ragge
1.13
866                 }
ragge
1.65
867         } else if (!Pflag) {
plunky
1.83
868                 sheap("\n# %d \"%s\""ifiles->linenoifiles->fname);
ragge
1.65
869                 if (ifiles->idx == SYSINC)
plunky
1.83
870                         sheap(" 3");
871                 sheap("\n");
872                 putstr(sb);
ragge
1.65
873         }
plunky
1.83
874         stringbuf = sb;
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)