Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20100420112020

Diff

Diff from 1.34 to:

Annotations

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

Annotated File View

ragge
1.34
1 /*      $Id: token.c,v 1.34 2010/04/20 11:20:20 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.34
404                                 yytext[yyp] = 0;
ragge
1.13
405                                 return CMNT;
ragge
1.33
406                         }
ragge
1.13
407
408                         wrn = 0;
ragge
1.19
409                 more:   while ((c = inch()) && c != '*') {
ragge
1.13
410                                 if (c == '\n')
411                                         putch(c), ifiles->lineno++;
412                                 else if (c == 1/* WARN */
413                                         wrn = 1;
414                         }
415                         if (c == 0)
416                                 return 0;
ragge
1.19
417                         if ((c = inch()) && c != '/') {
418                                 unch(c);
ragge
1.13
419                                 goto more;
420                         }
421                         if (c == 0)
422                                 return 0;
423                         if (!tflag && !Cflag && !flslvl)
ragge
1.19
424                                 unch(' ');
ragge
1.13
425                         if (wrn)
ragge
1.19
426                                 unch(1);
ragge
1.13
427                         goto zagain;
428                 }
429                 unch(ch);
430                 ch = '/';
431                 goto any;
432
ragge
1.19
433         case '.':
434                 ch = inch();
435                 if (isdigit(ch)) {
gmcgarry
1.26
436                         yytext[yyp++] = (usch)ch;
ragge
1.19
437                         goto ppnum;
ragge
1.13
438                 } else {
ragge
1.19
439                         unch(ch);
ragge
1.13
440                         ch = '.';
441                 }
ragge
1.19
442                 goto any;
ragge
1.13
443
444         case '\"':
445         strng:
446                 for (;;) {
ragge
1.19
447                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
448                                 yytext[yyp++] = (usch)ch;
449                                 yytext[yyp++] = (usch)inch();
ragge
1.13
450                                 continue;
451                         } else 
gmcgarry
1.26
452                                 yytext[yyp++] = (usch)ch;
ragge
1.13
453                         if (ch == '\"')
454                                 break;
455                 }
456                 yytext[yyp] = 0;
ragge
1.19
457                 return(STRING);
ragge
1.13
458
459         case 'L':
ragge
1.19
460                 if ((ch = inch()) == '\"') {
gmcgarry
1.26
461                         yytext[yyp++] = (usch)ch;
ragge
1.13
462                         goto strng;
463                 } else if (ch == '\'') {
gmcgarry
1.26
464                         yytext[yyp++] = (usch)ch;
ragge
1.13
465                         goto chlit;
466                 }
ragge
1.19
467                 unch(ch);
ragge
1.13
468                 /* FALLTHROUGH */
469
470         /* Yetch, all identifiers */
471         case 'a'case 'b'case 'c'case 'd'case 'e'case 'f'
472         case 'g'case 'h'case 'i'case 'j'case 'k'case 'l'
473         case 'm'case 'n'case 'o'case 'p'case 'q'case 'r'
474         case 's'case 't'case 'u'case 'v'case 'w'case 'x'
475         case 'y'case 'z':
476         case 'A'case 'B'case 'C'case 'D'case 'E'case 'F'
477         case 'G'case 'H'case 'I'case 'J'case 'K':
478         case 'M'case 'N'case 'O'case 'P'case 'Q'case 'R'
479         case 'S'case 'T'case 'U'case 'V'case 'W'case 'X'
480         case 'Y'case 'Z':
ragge
1.19
481         case '_'/* {L}({L}|{D})* */
ragge
1.13
482
483                 /* Special hacks */
484                 for (;;) { /* get chars */
ragge
1.19
485                         ch = inch();
ragge
1.14
486                         if (isalpha(ch) || isdigit(ch) || ch == '_') {
gmcgarry
1.26
487                                 yytext[yyp++] = (usch)ch;
ragge
1.14
488                         } else {
ragge
1.19
489                                 unch(ch);
ragge
1.13
490                                 break;
ragge
1.14
491                         }
ragge
1.13
492                 }
493                 yytext[yyp] = 0/* need already string */
494                 /* end special hacks */
495
ragge
1.19
496                 return IDENT;
ragge
1.13
497         default:
498         any:
499                 yytext[yyp] = 0;
ragge
1.19
500                 return yytext[0];
ragge
1.3
501
ragge
1.13
502         } /* endcase */
ragge
1.14
503         goto zagain;
ragge
1.6
504
ragge
1.13
505 yyret:
506         yytext[yyp] = 0;
507         return ch;
ragge
1.3
508 }
509
ragge
1.19
510 int
511 yylex()
512 {
513         static int ifdefnoex;
514         struct symtab *nl;
515         int chc2;
516
517         while ((ch = sloscan()) == WSPACE)
518                 ;
519         if (ch < 128 && spechr[ch] & C_2)
520                 c2 = inpch();
521         else
522                 c2 = 0;
523
524 #define C2(a,b,c) case a: if (c2 == b) return c; break
525         switch (ch) {
526         C2('=''='EQ);
527         C2('!''='NE);
528         C2('|''|'OROR);
529         C2('&''&'ANDAND);
530         case '<':
531                 if (c2 == '<'return LS;
532                 if (c2 == '='return LE;
533                 break;
534         case '>':
535                 if (c2 == '>'return RS;
536                 if (c2 == '='return GE;
537                 break;
538         case '+':
539         case '-':
540                 if (ch == c2)
541                         badop("");
542                 break;
ragge
1.27
543
ragge
1.33
544         case '/':
545                 if (Cflag == 0 || c2 != '*')
546                         break;
547                 /* Found comment that need to be skipped */
548                 for (;;) {
549                         ch = inpch();
550                 c1:     if (ch != '*')
551                                 continue;
552                         if ((ch = inpch()) == '/')
553                                 break;
554                         goto c1;
555                 }
556                 return yylex();
557
ragge
1.19
558         case NUMBER:
ragge
1.27
559                 if (yytext[0] == '\'') {
560                         yylval.node.op = NUMBER;
561                         yylval.node.nd_val = charcon((usch *)yytext);
562                 } else
563                         cvtdig(yytext[0] != '0' ? 10 :
564                             yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
ragge
1.19
565                 return NUMBER;
ragge
1.27
566
ragge
1.19
567         case IDENT:
568                 if (strcmp(yytext"defined") == 0) {
569                         ifdef = 1;
570                         return DEFINED;
571                 }
572                 nl = lookup((usch *)yytextFIND);
573                 if (ifdef) {
574                         yylval.node.nd_val = nl != NULL;
575                         ifdef = 0;
576                 } else if (nl && noex == 0) {
577                         usch *c, *och = stringbuf;
578
579                         c = gotident(nl);
580                         unch(1);
581                         unpstr(c);
582                         stringbuf = och;
583                         noex = 1;
584                         return yylex();
585                 } else {
586                         yylval.node.nd_val = 0;
587                 }
588                 yylval.node.op = NUMBER;
589                 return NUMBER;
590         case 1/* WARN */
591                 noex = 0;
592                 return yylex();
593         default:
594                 return ch;
595         }
596         unch(c2);
597         return ch;
598 }
599
ragge
1.13
600 usch *yypyybuf[CPPBUF];
601
602 int yywrap(void);
ragge
1.3
603
ragge
1.2
604 static int
ragge
1.13
605 inpch(void)
ragge
1.2
606 {
ragge
1.6
607         int len;
ragge
1.3
608
ragge
1.11
609         if (ifiles->curptr < ifiles->maxread)
ragge
1.2
610                 return *ifiles->curptr++;
ragge
1.11
611
ragge
1.6
612         if ((len = read(ifiles->infilifiles->bufferCPPBUF)) < 0)
ragge
1.13
613                 error("read error on file %s"ifiles->orgfn);
ragge
1.6
614         if (len == 0)
ragge
1.3
615                 return -1;
616         ifiles->curptr = ifiles->buffer;
ragge
1.6
617         ifiles->maxread = ifiles->buffer + len;
ragge
1.13
618         return inpch();
ragge
1.2
619 }
ragge
1.1
620
621 static int
ragge
1.13
622 inch(void)
ragge
1.1
623 {
624         int c;
625
ragge
1.13
626 again:  switch (c = inpch()) {
ragge
1.1
627         case '\\'/* continued lines */
ragge
1.13
628 msdos:          if ((c = inpch()) == '\n') {
ragge
1.1
629                         ifiles->lineno++;
630                         goto again;
ragge
1.13
631                 } else if (c == '\r')
632                         goto msdos;
633                 unch(c);
ragge
1.1
634                 return '\\';
635         case '?'/* trigraphs */
ragge
1.19
636                 if ((c = chktg())) {
ragge
1.13
637                         unch(c);
ragge
1.19
638                         goto again;
ragge
1.1
639                 }
ragge
1.19
640                 return '?';
ragge
1.1
641         default:
642                 return c;
643         }
644 }
645
ragge
1.13
646 /*
647  * Let the command-line args be faked defines at beginning of file.
648  */
649 static void
650 prinit(struct initar *itstruct includ *ic)
ragge
1.1
651 {
ragge
1.31
652         const char *pre, *post;
653         char *a;
ragge
1.1
654
ragge
1.13
655         if (it->next)
656                 prinit(it->nextic);
657         pre = post = NULL/* XXX gcc */
658         switch (it->type) {
659         case 'D':
660                 pre = "#define ";
661                 if ((a = strchr(it->str'=')) != NULL) {
662                         *a = ' ';
663                         post = "\n";
ragge
1.1
664                 } else
ragge
1.13
665                         post = " 1\n";
ragge
1.1
666                 break;
ragge
1.13
667         case 'U':
668                 pre = "#undef ";
669                 post = "\n";
ragge
1.1
670                 break;
ragge
1.13
671         case 'i':
672                 pre = "#include \"";
673                 post = "\"\n";
ragge
1.1
674                 break;
675         default:
ragge
1.13
676                 error("prinit");
ragge
1.1
677         }
ragge
1.13
678         strlcat((char *)ic->bufferpreCPPBUF+1);
679         strlcat((char *)ic->bufferit->strCPPBUF+1);
680         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
681                 error("line exceeds buffer size");
682
683         ic->lineno--;
684         while (*ic->maxread)
685                 ic->maxread++;
ragge
1.1
686 }
687
ragge
1.4
688 /*
ragge
1.6
689  * A new file included.
690  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
691  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
692  */
693 int
ragge
1.31
694 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
695 {
ragge
1.13
696         extern struct initar *initar;
ragge
1.6
697         struct includ ibuf;
698         struct includ *ic;
ragge
1.19
699         int otrulvl;
ragge
1.6
700
701         ic = &ibuf;
ragge
1.13
702         ic->next = ifiles;
ragge
1.4
703
ragge
1.6
704         if (file != NULL) {
ragge
1.31
705                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
706                         return -1;
ragge
1.13
707                 ic->orgfn = ic->fname = file;
708                 if (++inclevel > MAX_INCLEVEL)
709                         error("Limit for nested includes exceeded");
ragge
1.6
710         } else {
711                 ic->infil = 0;
ragge
1.31
712                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
713         }
714         ic->buffer = ic->bbuf+NAMEMAX;
ragge
1.4
715         ic->curptr = ic->buffer;
716         ifiles = ic;
ragge
1.13
717         ic->lineno = 1;
ragge
1.6
718         ic->maxread = ic->curptr;
ragge
1.29
719         ic->idx = idx;
720         ic->incs = incs;
721         ic->fn = fn;
ragge
1.13
722         prtline();
723         if (initar) {
724                 *ic->maxread = 0;
725                 prinit(initaric);
726                 if (dMflag)
727                         write(ofdic->bufferstrlen((char *)ic->buffer));
728                 initar = NULL;
729         }
ragge
1.4
730
ragge
1.13
731         otrulvl = trulvl;
ragge
1.4
732
ragge
1.19
733         fastscan();
ragge
1.13
734
735         if (otrulvl != trulvl || flslvl)
ragge
1.6
736                 error("unterminated conditional");
ragge
1.4
737
ragge
1.13
738         ifiles = ic->next;
ragge
1.6
739         close(ic->infil);
ragge
1.13
740         inclevel--;
ragge
1.6
741         return 0;
ragge
1.4
742 }
ragge
1.1
743
744 /*
745  * Print current position to output file.
746  */
747 void
748 prtline()
749 {
ragge
1.13
750         usch *s, *os = stringbuf;
751
752         if (Mflag) {
753                 if (dMflag)
754                         return/* no output */
755                 if (ifiles->lineno == 1) {
756                         s = sheap("%s: %s\n"Mfileifiles->fname);
757                         write(ofdsstrlen((char *)s));
758                 }
759         } else if (!Pflag)
ragge
1.30
760                 putstr(sheap("\n# %d \"%s\"\n"ifiles->linenoifiles->fname));
ragge
1.13
761         stringbuf = os;
ragge
1.1
762 }
763
764 void
765 cunput(int c)
766 {
ragge
1.13
767 #ifdef CPP_DEBUG
768         extern int dflag;
769         if (dflag)printf(": '%c'(%d)"c > 31 ? c : ' 'c);
770 #endif
ragge
1.19
771 #if 0
772 if (c == 10) {
773         printf("c == 10!!!\n");
774 }
775 #endif
776         unch(c);
ragge
1.1
777 }
778
ragge
1.13
779 int yywrap(void) { return 1; }
780
781 static int
782 dig2num(int c)
783 {
784         if (c >= 'a')
785                 c = c - 'a' + 10;
786         else if (c >= 'A')
787                 c = c - 'A' + 10;
788         else
789                 c = c - '0';
790         return c;
791 }
792
793 /*
794  * Convert string numbers to unsigned long long and check overflow.
795  */
796 static void
797 cvtdig(int rad)
798 {
799         unsigned long long rv = 0;
800         unsigned long long rv2 = 0;
801         char *y = yytext;
802         int c;
803
804         c = *y++;
805         if (rad == 16)
806                 y++;
807         while (isxdigit(c)) {
808                 rv = rv * rad + dig2num(c);
809                 /* check overflow */
810                 if (rv / rad < rv2)
811                         error("Constant \"%s\" is out of range"yytext);
812                 rv2 = rv;
813                 c = *y++;
814         }
815         y--;
816         while (*y == 'l' || *y == 'L')
817                 y++;
818         yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
819         yylval.node.nd_uval = rv;
820         if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
821                 yylval.node.op = UNUMBER;
822         if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
ragge
1.19
823                 /* too large for signed, see 6.4.4.1 */
ragge
1.13
824                 error("Constant \"%s\" is out of range"yytext);
825 }
826
827 static int
828 charcon(usch *p)
829 {
830         int valc;
831
832         p++; /* skip first ' */
833         val = 0;
834         if (*p++ == '\\') {
835                 switch (*p++) {
836                 case 'a'val = '\a'break;
837                 case 'b'val = '\b'break;
838                 case 'f'val = '\f'break;
839                 case 'n'val = '\n'break;
840                 case 'r'val = '\r'break;
841                 case 't'val = '\t'break;
842                 case 'v'val = '\v'break;
843                 case '\"'val = '\"'break;
844                 case '\''val = '\''break;
845                 case '\\'val = '\\'break;
846                 case 'x':
847                         while (isxdigit(c = *p)) {
848                                 val = val * 16 + dig2num(c);
849                                 p++;
850                         }
851                         break;
852                 case '0'case '1'case '2'case '3'case '4':
853                 case '5'case '6'case '7':
854                         p--;
855                         while (isdigit(c = *p)) {
856                                 val = val * 8 + (c - '0');
857                                 p++;
858                         }
859                         break;
860                 defaultval = p[-1];
861                 }
862
863         } else
864                 val = p[-1];
865         return val;
866 }
867
868 static void
869 chknl(int ignore)
870 {
871         int t;
872
ragge
1.19
873         while ((t = sloscan()) == WSPACE)
ragge
1.13
874                 ;
875         if (t != '\n') {
876                 if (ignore) {
877                         warning("newline expected, got \"%s\""yytext);
878                         /* ignore rest of line */
ragge
1.19
879                         while ((t = sloscan()) && t != '\n')
ragge
1.13
880                                 ;
881                 }
882                 else
883                         error("newline expected, got \"%s\""yytext);
884         }
885 }
886
887 static void
888 elsestmt(void)
889 {
890         if (flslvl) {
891                 if (elflvl > trulvl)
892                         ;
893                 else if (--flslvl!=0) {
894                         flslvl++;
895                 } else {
896                         trulvl++;
897                         prtline();
898                 }
899         } else if (trulvl) {
900                 flslvl++;
901                 trulvl--;
902         } else
903                 error("If-less else");
904         if (elslvl==trulvl+flslvl)
905                 error("Too many else");
906         elslvl=trulvl+flslvl;
907         chknl(1);
908 }
909
910 static void
ragge
1.20
911 skpln(void)
912 {
913         /* just ignore the rest of the line */
914         while (inch() != '\n')
915                 ;
916         unch('\n');
917         flslvl++;
918 }
919
920 static void
ragge
1.13
921 ifdefstmt(void)          
922
923         int t;
924
925         if (flslvl) {
ragge
1.20
926                 skpln();
ragge
1.13
927                 return;
928         }
929         do
ragge
1.19
930                 t = sloscan();
ragge
1.13
931         while (t == WSPACE);
932         if (t != IDENT)
933                 error("bad ifdef");
ragge
1.20
934         if (lookup((usch *)yytextFIND) == 0) {
935                 putch('\n');
936                 flslvl++;
937         } else
ragge
1.13
938                 trulvl++;
939         chknl(0);
940 }
941
942 static void
943 ifndefstmt(void)          
944
945         int t;
946
ragge
1.20
947         if (flslvl) {
948                 skpln();
949                 return;
950         }
ragge
1.13
951         do
ragge
1.19
952                 t = sloscan();
ragge
1.13
953         while (t == WSPACE);
954         if (t != IDENT)
955                 error("bad ifndef");
ragge
1.20
956         if (lookup((usch *)yytextFIND) != 0) {
957                 putch('\n');
958                 flslvl++;
959         } else
ragge
1.13
960                 trulvl++;
961         chknl(0);
962 }
963
964 static void
965 endifstmt(void)          
966 {
967         if (flslvl) {
968                 flslvl--;
ragge
1.25
969                 if (flslvl == 0) {
970                         putch('\n');
ragge
1.13
971                         prtline();
ragge
1.25
972                 }
ragge
1.13
973         } else if (trulvl)
974                 trulvl--;
975         else
976