Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:gmcgarry:20090813080125

Diff

Diff from 1.26 to:

Annotations

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

Annotated File View

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