Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20090809144149

Diff

Diff from 1.24 to:

Annotations

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

Annotated File View

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