Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20121029172313

Diff

Diff from 1.92 to:

Annotations

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

Annotated File View

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