Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20120810081235

Diff

Diff from 1.71 to:

Annotations

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

Annotated File View

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