Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20090804192344

Diff

Diff from 1.20 to:

Annotations

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

Annotated File View

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