Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20120729172712

Diff

Diff from 1.67 to:

Annotations

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

Annotated File View

ragge
1.67
1 /*      $Id: token.c,v 1.67 2012/07/29 17:27:12 ragge 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;
ragge
1.67
725         ifiles->buffer[len] = 0;
ragge
1.3
726         ifiles->curptr = ifiles->buffer;
ragge
1.6
727         ifiles->maxread = ifiles->buffer + len;
ragge
1.13
728         return inpch();
ragge
1.2
729 }
ragge
1.1
730
731 static int
ragge
1.13
732 inch(void)
ragge
1.1
733 {
734         int c;
735
ragge
1.13
736 again:  switch (c = inpch()) {
ragge
1.1
737         case '\\'/* continued lines */
ragge
1.13
738 msdos:          if ((c = inpch()) == '\n') {
ragge
1.1
739                         ifiles->lineno++;
ragge
1.66
740                         putch('\n');
ragge
1.1
741                         goto again;
ragge
1.13
742                 } else if (c == '\r')
743                         goto msdos;
744                 unch(c);
ragge
1.1
745                 return '\\';
746         case '?'/* trigraphs */
ragge
1.19
747                 if ((c = chktg())) {
ragge
1.13
748                         unch(c);
ragge
1.19
749                         goto again;
ragge
1.1
750                 }
ragge
1.19
751                 return '?';
ragge
1.1
752         default:
753                 return c;
754         }
755 }
756
ragge
1.13
757 /*
758  * Let the command-line args be faked defines at beginning of file.
759  */
760 static void
761 prinit(struct initar *itstruct includ *ic)
ragge
1.1
762 {
ragge
1.31
763         const char *pre, *post;
764         char *a;
ragge
1.1
765
ragge
1.13
766         if (it->next)
767                 prinit(it->nextic);
768         pre = post = NULL/* XXX gcc */
769         switch (it->type) {
770         case 'D':
771                 pre = "#define ";
772                 if ((a = strchr(it->str'=')) != NULL) {
773                         *a = ' ';
774                         post = "\n";
ragge
1.1
775                 } else
ragge
1.13
776                         post = " 1\n";
ragge
1.1
777                 break;
ragge
1.13
778         case 'U':
779                 pre = "#undef ";
780                 post = "\n";
ragge
1.1
781                 break;
ragge
1.13
782         case 'i':
783                 pre = "#include \"";
784                 post = "\"\n";
ragge
1.1
785                 break;
786         default:
ragge
1.13
787                 error("prinit");
ragge
1.1
788         }
ragge
1.13
789         strlcat((char *)ic->bufferpreCPPBUF+1);
790         strlcat((char *)ic->bufferit->strCPPBUF+1);
791         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
792                 error("line exceeds buffer size");
793
794         ic->lineno--;
795         while (*ic->maxread)
796                 ic->maxread++;
ragge
1.1
797 }
798
ragge
1.4
799 /*
ragge
1.6
800  * A new file included.
801  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
802  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
803  */
804 int
ragge
1.31
805 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
806 {
ragge
1.13
807         extern struct initar *initar;
ragge
1.6
808         struct includ ibuf;
809         struct includ *ic;
ragge
1.19
810         int otrulvl;
ragge
1.6
811
812         ic = &ibuf;
ragge
1.13
813         ic->next = ifiles;
ragge
1.4
814
ragge
1.6
815         if (file != NULL) {
ragge
1.31
816                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
817                         return -1;
ragge
1.13
818                 ic->orgfn = ic->fname = file;
819                 if (++inclevel > MAX_INCLEVEL)
820                         error("Limit for nested includes exceeded");
ragge
1.6
821         } else {
822                 ic->infil = 0;
ragge
1.31
823                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
824         }
ragge
1.49
825 #ifndef BUF_STACK
826         ic->bbuf = malloc(BBUFSZ);
827 #endif
ragge
1.6
828         ic->buffer = ic->bbuf+NAMEMAX;
ragge
1.4
829         ic->curptr = ic->buffer;
830         ifiles = ic;
ragge
1.13
831         ic->lineno = 1;
ragge
1.6
832         ic->maxread = ic->curptr;
ragge
1.29
833         ic->idx = idx;
834         ic->incs = incs;
835         ic->fn = fn;
ragge
1.13
836         prtline();
837         if (initar) {
ragge
1.38
838                 int oin = ic->infil;
839                 ic->infil = -1;
ragge
1.13
840                 *ic->maxread = 0;
841                 prinit(initaric);
ragge
1.41
842                 initar = NULL;
ragge
1.13
843                 if (dMflag)
844                         write(ofdic->bufferstrlen((char *)ic->buffer));
ragge
1.38
845                 fastscan();
846                 prtline();
847                 ic->infil = oin;
ragge
1.13
848         }
ragge
1.4
849
ragge
1.13
850         otrulvl = trulvl;
ragge
1.4
851
ragge
1.19
852         fastscan();
ragge
1.13
853
854         if (otrulvl != trulvl || flslvl)
ragge
1.6
855                 error("unterminated conditional");
ragge
1.4
856
ragge
1.49
857 #ifndef BUF_STACK
858         free(ic->bbuf);
859 #endif
ragge
1.13
860         ifiles = ic->next;
ragge
1.6
861         close(ic->infil);
ragge
1.13
862         inclevel--;
ragge
1.6
863         return 0;
ragge
1.4
864 }
ragge
1.1
865
866 /*
867  * Print current position to output file.
868  */
869 void
plunky
1.64
870 prtline(void)
ragge
1.1
871 {
ragge
1.13
872         usch *s, *os = stringbuf;
873
874         if (Mflag) {
875                 if (dMflag)
876                         return/* no output */
877                 if (ifiles->lineno == 1) {
878                         s = sheap("%s: %s\n"Mfileifiles->fname);
879                         write(ofdsstrlen((char *)s));
880                 }
ragge
1.65
881         } else if (!Pflag) {
882                 putstr(sheap("\n# %d \"%s\""ifiles->linenoifiles->fname));
883                 if (ifiles->idx == SYSINC)
884                         putstr(sheap(" 3"));
885                 putstr(sheap("\n"));
886         }
ragge
1.13
887         stringbuf = os;
ragge
1.1
888 }
889
890 void
891 cunput(int c)
892 {
plunky
1.59
893 #ifdef PCC_DEBUG
ragge
1.43
894 //      extern int dflag;
895 //      if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
ragge
1.13
896 #endif
ragge
1.19
897 #if 0
898 if (c == 10) {
899         printf("c == 10!!!\n");
900 }
901 #endif
902         unch(c);
ragge
1.1
903 }
904
ragge
1.13
905 int yywrap(void) { return 1; }
906
907 static int
908 dig2num(int c)
909 {
910         if (c >= 'a')
911                 c = c - 'a' + 10;
912         else if (c >= 'A')
913                 c = c - 'A' + 10;
914         else
915                 c = c - '0';
916         return c;
917