Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20091231114613

Diff

Diff from 1.29 to:

Annotations

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

Annotated File View

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