Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20100225154900

Diff

Diff from 1.31 to:

Annotations

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

Annotated File View

ragge
1.31
1 /*      $Id: token.c,v 1.31 2010/02/25 15:49:00 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.31
635         const char *pre, *post;
636         char *a;
ragge
1.1
637
ragge
1.13
638         if (it->next)
639                 prinit(it->nextic);
640         pre = post = NULL/* XXX gcc */
641         switch (it->type) {
642         case 'D':
643                 pre = "#define ";
644                 if ((a = strchr(it->str'=')) != NULL) {
645                         *a = ' ';
646                         post = "\n";
ragge
1.1
647                 } else
ragge
1.13
648                         post = " 1\n";
ragge
1.1
649                 break;
ragge
1.13
650         case 'U':
651                 pre = "#undef ";
652                 post = "\n";
ragge
1.1
653                 break;
ragge
1.13
654         case 'i':
655                 pre = "#include \"";
656                 post = "\"\n";
ragge
1.1
657                 break;
658         default:
ragge
1.13
659                 error("prinit");
ragge
1.1
660         }
ragge
1.13
661         strlcat((char *)ic->bufferpreCPPBUF+1);
662         strlcat((char *)ic->bufferit->strCPPBUF+1);
663         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
664                 error("line exceeds buffer size");
665
666         ic->lineno--;
667         while (*ic->maxread)
668                 ic->maxread++;
ragge
1.1
669 }
670
ragge
1.4
671 /*
ragge
1.6
672  * A new file included.
673  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
674  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
675  */
676 int
ragge
1.31
677 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
678 {
ragge
1.13
679         extern struct initar *initar;
ragge
1.6
680         struct includ ibuf;
681         struct includ *ic;
ragge
1.19
682         int otrulvl;
ragge
1.6
683
684         ic = &ibuf;
ragge
1.13
685         ic->next = ifiles;
ragge
1.4
686
ragge
1.6
687         if (file != NULL) {
ragge
1.31
688                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
689                         return -1;
ragge
1.13
690                 ic->orgfn = ic->fname = file;
691                 if (++inclevel > MAX_INCLEVEL)
692                         error("Limit for nested includes exceeded");
ragge
1.6
693         } else {
694                 ic->infil = 0;
ragge
1.31
695                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
696         }
697         ic->buffer = ic->bbuf+NAMEMAX;
ragge
1.4
698         ic->curptr = ic->buffer;
699         ifiles = ic;
ragge
1.13
700         ic->lineno = 1;
ragge
1.6
701         ic->maxread = ic->curptr;
ragge
1.29
702         ic->idx = idx;
703         ic->incs = incs;
704         ic->fn = fn;
ragge
1.13
705         prtline();
706         if (initar) {
707                 *ic->maxread = 0;
708                 prinit(initaric);
709                 if (dMflag)
710                         write(ofdic->bufferstrlen((char *)ic->buffer));
711                 initar = NULL;
712         }
ragge
1.4
713
ragge
1.13
714         otrulvl = trulvl;
ragge
1.4
715
ragge
1.19
716         fastscan();
ragge
1.13
717
718         if (otrulvl != trulvl || flslvl)
ragge
1.6
719                 error("unterminated conditional");
ragge
1.4
720
ragge
1.13
721         ifiles = ic->next;
ragge
1.6
722         close(ic->infil);
ragge
1.13
723         inclevel--;
ragge
1.6
724         return 0;
ragge
1.4
725 }
ragge
1.1
726
727 /*
728  * Print current position to output file.
729  */
730 void
731 prtline()
732 {
ragge
1.13
733         usch *s, *os = stringbuf;
734
735         if (Mflag) {
736                 if (dMflag)
737                         return/* no output */
738                 if (ifiles->lineno == 1) {
739                         s = sheap("%s: %s\n"Mfileifiles->fname);
740                         write(ofdsstrlen((char *)s));
741                 }
742         } else if (!Pflag)
ragge
1.30
743                 putstr(sheap("\n# %d \"%s\"\n"ifiles->linenoifiles->fname));
ragge
1.13
744         stringbuf = os;
ragge
1.1
745 }
746
747 void
748 cunput(int c)
749 {
ragge
1.13
750 #ifdef CPP_DEBUG
751         extern int dflag;
752         if (dflag)printf(": '%c'(%d)"c > 31 ? c : ' 'c);
753 #endif
ragge
1.19
754 #if 0
755 if (c == 10) {
756         printf("c == 10!!!\n");
757 }
758 #endif
759         unch(c);
ragge
1.1
760 }
761
ragge
1.13
762 int yywrap(void) { return 1; }
763
764 static int
765 dig2num(int c)
766 {
767         if (c >= 'a')
768                 c = c - 'a' + 10;
769         else if (c >= 'A')
770                 c = c - 'A' + 10;
771         else
772                 c = c - '0';
773         return c;
774 }
775
776 /*
777  * Convert string numbers to unsigned long long and check overflow.
778  */
779 static void
780 cvtdig(int rad)
781 {
782         unsigned long long rv = 0;
783         unsigned long long rv2 = 0;
784         char *y = yytext;
785         int c;
786
787         c = *y++;
788         if (rad == 16)
789                 y++;
790         while (isxdigit(c)) {
791                 rv = rv * rad + dig2num(c);
792                 /* check overflow */
793                 if (rv / rad < rv2)
794                         error("Constant \"%s\" is out of range"yytext);
795                 rv2 = rv;
796                 c = *y++;
797         }
798         y--;
799         while (*y == 'l' || *y == 'L')
800                 y++;
801         yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
802         yylval.node.nd_uval = rv;
803         if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
804                 yylval.node.op = UNUMBER;
805         if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
ragge
1.19
806                 /* too large for signed, see 6.4.4.1 */
ragge
1.13
807                 error("Constant \"%s\" is out of range"yytext);
808 }
809
810 static int
811 charcon(usch *p)
812 {
813         int valc;
814
815         p++; /* skip first ' */
816         val = 0;
817         if (*p++ == '\\') {
818                 switch (*p++) {
819                 case 'a'val = '\a'break;
820                 case 'b'val = '\b'break;
821                 case 'f'val = '\f'break;
822                 case 'n'val = '\n'break;
823                 case 'r'val = '\r'break;
824                 case 't'val = '\t'break;
825                 case 'v'val = '\v'break;
826                 case '\"'val = '\"'break;
827                 case '\''val = '\''break;
828                 case '\\'val = '\\'break;
829                 case 'x':
830                         while (isxdigit(c = *p)) {
831                                 val = val * 16 + dig2num(c);
832                                 p++;
833                         }
834                         break;
835                 case '0'case '1'case '2'case '3'case '4':
836                 case '5'case '6'case '7':
837                         p--;
838                         while (isdigit(c = *p)) {
839                                 val = val * 8 + (c - '0');
840                                 p++;
841                         }
842                         break;
843                 defaultval = p[-1];
844                 }
845
846         } else
847                 val = p[-1];
848         return val;
849 }
850
851 static void
852 chknl(int ignore)
853 {
854         int t;
855
ragge
1.19
856         while ((t = sloscan()) == WSPACE)
ragge
1.13
857                 ;
858         if (t != '\n') {
859                 if (ignore) {
860                         warning("newline expected, got \"%s\""yytext);
861                         /* ignore rest of line */
ragge
1.19
862                         while ((t = sloscan()) && t != '\n')
ragge
1.13
863                                 ;
864                 }
865                 else
866                         error("newline expected, got \"%s\""yytext);
867         }
868 }
869
870 static void
871 elsestmt(void)
872 {
873         if (flslvl) {
874                 if (elflvl > trulvl)
875                         ;
876                 else if (--flslvl!=0) {
877                         flslvl++;
878                 } else {
879                         trulvl++;
880                         prtline();
881                 }
882         } else if (trulvl) {
883                 flslvl++;
884                 trulvl--;
885         } else
886                 error("If-less else");
887         if (elslvl==trulvl+flslvl)
888                 error("Too many else");
889         elslvl=trulvl+flslvl;
890         chknl(1);
891 }
892
893 static void
ragge
1.20
894 skpln(void)
895 {
896         /* just ignore the rest of the line */
897         while (inch() != '\n')
898                 ;
899         unch('\n');
900         flslvl++;
901 }
902
903 static void
ragge
1.13
904 ifdefstmt(void)          
905
906         int t;
907
908         if (flslvl) {
ragge
1.20
909                 skpln();
ragge
1.13
910                 return;
911         }
912         do
ragge
1.19
913                 t = sloscan();
ragge
1.13
914         while (t == WSPACE);
915         if (t != IDENT)
916                 error("bad ifdef");
ragge
1.20
917         if (lookup((usch *)yytextFIND) == 0) {
918                 putch('\n');
919                 flslvl++;
920         } else
ragge
1.13
921                 trulvl++;
922         chknl(0);
923 }
924
925 static void
926 ifndefstmt(void)          
927
928         int t;
929
ragge
1.20
930         if (flslvl) {
931                 skpln();
932                 return;
933         }
ragge
1.13
934         do
ragge
1.19
935                 t = sloscan();
ragge
1.13
936         while (t == WSPACE);
937         if (t != IDENT)
938                 error("bad ifndef");
ragge
1.20
939         if (lookup((usch *)yytextFIND) != 0) {
940                 putch('\n');
941                 flslvl++;
942         } else
ragge
1.13
943                 trulvl++;
944         chknl(0);
945 }
946
947 static void
948 endifstmt(void)          
949 {
950         if (flslvl) {
951                 flslvl--;
ragge
1.25
952                 if (flslvl == 0) {
953                         putch('\n');
ragge
1.13
954                         prtline();
ragge
1.25
955                 }
ragge
1.13
956         } else if (trulvl)
957                 trulvl--;
958         else
959                 error("If-less endif");
960         if (flslvl == 0)
961                 elflvl = 0;
962         elslvl = 0;
963         chknl(1);
964 }
965
966 static void
967 ifstmt(void)
968 {
969         if (flslvl == 0) {
ragge
1.20
970                 if (yyparse() == 0) {
971                         putch('\n');
972                         ++flslvl;
973                 } else
ragge
1.13
974                         ++trulvl;
975         } else
976                 ++flslvl;
977 }
978
979 static void
980 elifstmt(void)
981 {