Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20090808074123

Diff

Diff from 1.23 to:

Annotations

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

Annotated File View

ragge
1.23
1 /*      $Id: token.c,v 1.23 2009/08/08 07:41:23 ragge Exp $     */
ragge
1.1
2
3 /*
ragge
1.13
4  * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved.
ragge
1.1
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
ragge
1.19
27 /*
28  * Tokenizer for the C preprocessor.
29  * There are three main routines:
30  *      - fastscan() loops over the input stream searching for magic
31  *              characters that may require actions.
32  *      - sloscan() tokenize the input stream and returns tokens.
33  *              It may recurse into itself during expansion.
34  *      - yylex() returns something from the input stream that 
35  *              is suitable for yacc.
36  *
37  *      Other functions of common use:
38  *      - inpch() returns a raw character from the current input stream.
39  *      - inch() is like inpch but \\n and trigraphs are expanded.
40  *      - unch() pushes back a character to the input stream.
41  */
42
ragge
1.13
43 #include "config.h"
44
ragge
1.1
45 #include <stdlib.h>
46 #include <string.h>
47 #include <ctype.h>
ragge
1.13
48 #ifdef HAVE_UNISTD_H
ragge
1.2
49 #include <unistd.h>
ragge
1.13
50 #endif
ragge
1.2
51 #include <fcntl.h>
ragge
1.13
52 #include <errno.h>
ragge
1.1
53
ragge
1.13
54 #include "compat.h"
ragge
1.1
55 #include "cpp.h"
ragge
1.13
56 #include "y.tab.h"
57
58 static void cvtdig(int rad);
59 static int charcon(usch *);
60 static void elsestmt(void);
61 static void ifdefstmt(void);
62 static void ifndefstmt(void);
63 static void endifstmt(void);
64 static void ifstmt(void);
65 static void cpperror(void);
66 static void pragmastmt(void);
67 static void undefstmt(void);
68 static void cpperror(void);
69 static void elifstmt(void);
70 static void badop(const char *);
ragge
1.19
71 static int chktg(void);
72 static void ppdir(void);
ragge
1.13
73 void  include(void);
74 void  define(void);
ragge
1.19
75 static int inpch(void);
ragge
1.13
76
77 extern int yyget_lineno (void);
78 extern void yyset_lineno (int);
79
80 static int inch(void);
81
82 int inif;
83
ragge
1.19
84 #define PUTCH(ch) if (!flslvl) putch(ch)
ragge
1.13
85 /* protection against recursion in #include */
86 #define MAX_INCLEVEL    100
87 static int inclevel;
88
ragge
1.19
89 /* get next character unaltered */
90 #define NXTCH() (ifiles->curptr < ifiles->maxread ? *ifiles->curptr++ : inpch())
ragge
1.1
91
gmcgarry
1.16
92 #ifdef YYTEXT_POINTER
93 static char buf[CPPBUF];
94 char *yytext = buf;
95 #else
ragge
1.13
96 char yytext[CPPBUF];
gmcgarry
1.16
97 #endif
98
ragge
1.19
99 #define C_SPEC  1
100 #define C_EP    2
101 #define C_ID    4
102 #define C_I     (C_SPEC|C_ID)
103 #define C_2     8               /* for yylex() tokenizing */
104 static char spechr[256] = {
105         0,      0,      0,      0,      0,      0,      0,      0,
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");
134         *ifiles->curptr = 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);
221                         while ((ch = NXTCH()) != '\"') {
ragge
1.19
222                                 PUTCH(ch);
223                                 if (ch == '\\') {
ragge
1.21
224                                         ch = NXTCH();
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 {
293                                 yytext[i++] = ch;
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;
319         yytext[yyp++] = ch = inch();
320         switch (ch) {
ragge
1.14
321         case -1:
322                 return 0;
ragge
1.13
323         case '\n':
ragge
1.19
324                 /* sloscan() never passes \n, that's up to fastscan() */
325                 unch(ch);
326                 goto yyret;
ragge
1.13
327
328         case '\r'/* Ignore CR's */
329                 yyp = 0;
330                 break;
331
332         case '0'case '1'case '2'case '3'case '4'case '5'
333         case '6'case '7'case '8'case '9':
334                 /* readin a "pp-number" */
335 ppnum:          for (;;) {
ragge
1.19
336                         ch = inch();
337                         if (spechr[ch] & C_EP) {
ragge
1.13
338                                 yytext[yyp++] = ch;
ragge
1.19
339                                 ch = inch();
ragge
1.13
340                                 if (ch == '-' || ch == '+') {
341                                         yytext[yyp++] = ch;
342                                 } else
ragge
1.19
343                                         unch(ch);
ragge
1.13
344                                 continue;
345                         }
ragge
1.19
346                         if ((spechr[ch] & C_ID) || ch == '.') {
ragge
1.13
347                                 yytext[yyp++] = ch;
348                                 continue;
349                         } 
350                         break;
351                 }
ragge
1.19
352                 unch(ch);
ragge
1.13
353                 yytext[yyp] = 0;
354
ragge
1.19
355                 return NUMBER;
ragge
1.13
356
357         case '\'':
ragge
1.19
358 chlit:          
ragge
1.13
359                 for (;;) {
ragge
1.19
360                         if ((ch = inch()) == '\\') {
ragge
1.13
361                                 yytext[yyp++] = ch;
ragge
1.19
362                                 yytext[yyp++] = inch();
ragge
1.13
363                                 continue;
364                         } else if (ch == '\n') {
365                                 /* not a constant */
366                                 while (yyp > 1)
ragge
1.19
367                                         unch(yytext[--yyp]);
ragge
1.13
368                                 ch = '\'';
369                                 goto any;
370                         } else
371                                 yytext[yyp++] = ch;
372                         if (ch == '\'')
373                                 break;
374                 }
375                 yytext[yyp] = 0;
376
ragge
1.19
377                 yylval.node.op = NUMBER;
378                 yylval.node.nd_val = charcon((usch *)yytext);
379                 return (NUMBER);
ragge
1.13
380
381         case ' ':
382         case '\t':
ragge
1.19
383                 while ((ch = inch()) == ' ' || ch == '\t')
ragge
1.13
384                         yytext[yyp++] = 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 {
392                                 yytext[yyp++] = 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)) {
ragge
1.13
433                         yytext[yyp++] = 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()) == '\\') {
ragge
1.13
445                                 yytext[yyp++] = ch;
ragge
1.19
446                                 yytext[yyp++] = inch();
ragge
1.13
447                                 continue;
448                         } else 
449                                 yytext[yyp++] = ch;
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()) == '\"') {
ragge
1.13
458                         yytext[yyp++] = ch;
459                         goto strng;
460                 } else if (ch == '\'') {
461                         yytext[yyp++] = ch;
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 == '_') {
ragge
1.13
484                                 yytext[yyp++] = 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;
540         case NUMBER:
541                 cvtdig(yytext[0] != '0' ? 10 :
542                     yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
543                 return NUMBER;
544         case IDENT:
545                 if (strcmp(yytext"defined") == 0) {
546                         ifdef = 1;
547                         return DEFINED;
548                 }
549                 nl = lookup((usch *)yytextFIND);
550                 if (ifdef) {
551                         yylval.node.nd_val = nl != NULL;
552                         ifdef = 0;
553                 } else if (nl && noex == 0) {
554                         usch *c, *och = stringbuf;
555
556                         c = gotident(nl);
557                         unch(1);
558                         unpstr(c);
559                         stringbuf = och;
560                         noex = 1;
561                         return yylex();
562                 } else {
563                         yylval.node.nd_val = 0;
564                 }
565                 yylval.node.op = NUMBER;
566                 return NUMBER;
567         case 1/* WARN */
568                 noex = 0;
569                 return yylex();
570         default:
571                 return ch;
572         }
573         unch(c2);
574         return ch;
575 }
576
ragge
1.13
577 usch *yypyybuf[CPPBUF];
578
579 int yywrap(void);
ragge
1.3
580
ragge
1.2
581 static int
ragge
1.13
582 inpch(void)
ragge
1.2
583 {
ragge
1.6
584         int len;
ragge
1.3
585
ragge
1.11
586         if (ifiles->curptr < ifiles->maxread)
ragge
1.2
587                 return *ifiles->curptr++;
ragge
1.11
588
ragge
1.6
589         if ((len = read(ifiles->infilifiles->bufferCPPBUF)) < 0)
ragge
1.13
590                 error("read error on file %s"ifiles->orgfn);
ragge
1.6
591         if (len == 0)
ragge
1.3
592                 return -1;
593         ifiles->curptr = ifiles->buffer;
ragge
1.6
594         ifiles->maxread = ifiles->buffer + len;
ragge
1.13
595         return inpch();
ragge
1.2
596 }
ragge
1.1
597
598 static int
ragge
1.13
599 inch(void)
ragge
1.1
600 {
601         int c;
602
ragge
1.13
603 again:  switch (c = inpch()) {
ragge
1.1
604         case '\\'/* continued lines */
ragge
1.13
605 msdos:          if ((c = inpch()) == '\n') {
ragge
1.1
606                         ifiles->lineno++;
ragge
1.13
607                         putch('\n');
ragge
1.1
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--;
943                 if (flslvl == 0)
944                         prtline();
945         } else if (trulvl)
946                 trulvl--;
947         else
948                 error("If-less endif");
949         if (flslvl == 0)
950                 elflvl = 0;
951         elslvl = 0;
952         chknl(1);
953 }
954
955 static void
956 ifstmt(void)
957 {
958         if (flslvl == 0) {
ragge
1.20
959                 if (yyparse() == 0) {
960                         putch('\n');
961                         ++flslvl;
962                 } else
ragge
1.13
963                         ++trulvl;
964         } else
965                 ++flslvl;
966 }
967
968 static void
969 elifstmt(void)
970 {
971         if (flslvl == 0)
972                 elflvl = trulvl;
973         if (flslvl) {
974                 if (elflvl > trulvl)
975                         ;
976                 else if (--flslvl!=0)
977                         ++flslvl;
978                 else {
979                         if (yyparse()) {
980                                 ++trulvl;
981                                 prtline();
ragge
1.20
982                         } else {
983                                 putch('\n');
ragge
1.13
984                                 ++flslvl;
ragge
1.20
985                         }
ragge
1.13
986                 }
987         } else if (trulvl) {
988                 ++flslvl;
989                 --trulvl;
990         } else
991                 error("If-less elif");
992 }
993
994 static usch *
995 svinp(void)
996 {
997         int c;
998         usch *cp = stringbuf;
999
ragge
1.19
1000         while ((c = inch()) && c != '\n')
ragge
1.13
1001                 savch(c);
1002