Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20100605114717

Diff

Diff from 1.35 to:

Annotations

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

Annotated File View

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