Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20100418164232

Diff

Diff from 1.33 to:

Annotations

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

Annotated File View

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