Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20090823122313

Diff

Diff from 1.28 to:

Annotations

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

Annotated File View

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