Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20110830201221

Diff

Diff from 1.64 to:

Annotations

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

Annotated File View

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