Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20101227181310

Diff

Diff from 1.41 to:

Annotations

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

Annotated File View

ragge
1.41
1 /*      $Id: token.c,v 1.41 2010/12/27 18:13:10 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);
ragge
1.39
68 static void cppwarning(void);
ragge
1.13
69 static void elifstmt(void);
70 static void badop(const char *);
ragge
1.19
71 static int chktg(void);
72 static void ppdir(void);
ragge
1.13
73 void  include(void);
ragge
1.29
74 void  include_next(void);
ragge
1.13
75 void  define(void);
ragge
1.19
76 static int inpch(void);
ragge
1.13
77
78 extern int yyget_lineno (void);
79 extern void yyset_lineno (int);
80
81 static int inch(void);
82
83 int inif;
84
ragge
1.19
85 #define PUTCH(ch) if (!flslvl) putch(ch)
ragge
1.13
86 /* protection against recursion in #include */
87 #define MAX_INCLEVEL    100
88 static int inclevel;
89
ragge
1.19
90 /* get next character unaltered */
91 #define NXTCH() (ifiles->curptr < ifiles->maxread ? *ifiles->curptr++ : inpch())
ragge
1.1
92
gmcgarry
1.16
93 #ifdef YYTEXT_POINTER
94 static char buf[CPPBUF];
95 char *yytext = buf;
96 #else
ragge
1.13
97 char yytext[CPPBUF];
gmcgarry
1.16
98 #endif
99
ragge
1.19
100 #define C_SPEC  1
101 #define C_EP    2
102 #define C_ID    4
103 #define C_I     (C_SPEC|C_ID)
104 #define C_2     8               /* for yylex() tokenizing */
105 static char spechr[256] = {
106         0,      0,      0,      0,      0,      0,      0,      0,
ragge
1.28
107         0,      0,      C_SPEC0,      0,      0,      0,      0,
ragge
1.19
108         0,      0,      0,      0,      0,      0,      0,      0,
109         0,      0,      0,      0,      0,      0,      0,      0,
110
111         0,      C_2,    C_SPEC0,      0,      0,      C_2,    C_SPEC,
ragge
1.33
112         0,      0,      0,      C_2,    0,      C_2,    0,      C_SPEC|C_2,
ragge
1.19
113         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
114         C_I,    C_I,    0,      0,      C_2,    C_2,    C_2,    C_SPEC,
115
116         0,      C_I,    C_I,    C_I,    C_I,    C_I|C_EPC_I,  C_I,
117         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
118         C_I|C_EPC_I,  C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
ragge
1.37
119         C_I,    C_I,    C_I,    0,      C_I,    0,      0,      C_I,
ragge
1.19
120
121         0,      C_I,    C_I,    C_I,    C_I,    C_I|C_EPC_I,  C_I,
122         C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
123         C_I|C_EPC_I,  C_I,    C_I,    C_I,    C_I,    C_I,    C_I,
124         C_I,    C_I,    C_I,    0,      C_2,    0,      0,      0,
125
126 };
ragge
1.1
127
ragge
1.13
128 static void
129 unch(int c)
130 {
ragge
1.15
131                 
132         --ifiles->curptr;
133         if (ifiles->curptr < ifiles->bbuf)
134                 error("pushback buffer full");
gmcgarry
1.26
135         *ifiles->curptr = (usch)c;
ragge
1.13
136 }
ragge
1.1
137
ragge
1.19
138 /*
139  * Scan quickly the input file searching for:
140  *      - '#' directives
141  *      - keywords (if not flslvl)
142  *      - comments
143  *
144  *      Handle strings, numbers and trigraphs with care.
145  *      Only data from pp files are scanned here, never any rescans.
146  *      TODO: Only print out strings before calling other functions.
147  */
148 static void
149 fastscan(void)
150 {
151         struct symtab *nl;
152         int chi;
153
154         goto run;
155         for (;;) {
156                 ch = NXTCH();
157 xloop:          if (ch == -1)
158                         return;
159                 if ((spechr[ch] & C_SPEC) == 0) {
160                         PUTCH(ch);
161                         continue;
162                 }
163                 switch (ch) {
164                 case '/'/* Comments */
165                         if ((ch = inch()) == '/') {
166                                 if (Cflag) { PUTCH(ch); } else { PUTCH(' '); }
167                                 do {
168                                         if (CflagPUTCH(ch);
169                                         ch = inch();
170                                 } while (ch != -1 && ch != '\n');
171                                 goto xloop;
172                         } else if (ch == '*') {
173                                 if (Cflag) { PUTCH('/'); PUTCH('*'); }
174                                 for (;;) {
175                                         ch = inch();
176                                         if (ch == '\n') {
177                                                 ifiles->lineno++;
178                                                 PUTCH('\n');
179                                         }
180                                         if (ch == -1)
181                                                 return;
182                                         if (ch == '*') {
183                                                 ch = inch();
184                                                 if (ch == '/') {
185                                                         if (Cflag) {
186                                                                 PUTCH('*');
187                                                                 PUTCH('/');
188                                                         } else
189                                                                 PUTCH(' ');
190                                                         break;
ragge
1.35
191                                                 }
192                                                 unch(ch);
193                                                 ch = '*';
ragge
1.19
194                                         }
195                                         if (CflagPUTCH(ch);
196                                 }
197                         } else {
198                                 PUTCH('/');
199                                 goto xloop;
200                         }
201                         break;
202
203                 case '?':  /* trigraphs */
204                         if ((ch = chktg()))
205                                 goto xloop;
206                         PUTCH('?');
207                         break;
208
ragge
1.37
209                 case '\\':
210                         if ((ch = NXTCH()) == '\n') {
211                                 ifiles->lineno++;
212                                 continue;
213                         } else {
214                                 PUTCH('\\');
215                         }
216                         goto xloop;
217
ragge
1.19
218                 case '\n'/* newlines, for pp directives */
219                         ifiles->lineno++;
220                         do {
221                                 PUTCH(ch);
222 run:                            ch = NXTCH();
223                         } while (ch == ' ' || ch == '\t');
224                         if (ch == '#') {
225                                 ppdir();
226                                 continue;
ragge
1.40
227                         } else if (ch == '%') {
228                                 ch = NXTCH();
229                                 if (ch == ':') {
230                                         ppdir();
231                                         continue;
232                                 } else {
233                                         unch(ch);
234                                         ch = '%';
235                                 }
ragge
1.19
236                         }
237                         goto xloop;
238
239                 case '\"'/* strings */
ragge
1.21
240 str:                    PUTCH(ch);
ragge
1.24
241                         while ((ch = inch()) != '\"') {
ragge
1.19
242                                 PUTCH(ch);
243                                 if (ch == '\\') {
ragge
1.24
244                                         ch = inch();
ragge
1.19
245                                         PUTCH(ch);
246                                 }
247                                 if (ch < 0)
248                                         return;
ragge
1.21
249                         }
ragge
1.19
250                         PUTCH(ch);
251                         break;
252
253                 case '.':  /* for pp-number */
254                         PUTCH(ch);
255                         ch = NXTCH();
256                         if (ch < '0' || ch > '9')
257                                 goto xloop;
258                         /* FALLTHROUGH */
259                 case '0'case '1'case '2'case '3'case '4':
260                 case '5'case '6'case '7'case '8'case '9':
261                         do {
262                                 PUTCH(ch);
263                                 ch = NXTCH();
264                                 if (spechr[ch] & C_EP) {
265                                         PUTCH(ch);
266                                         ch = NXTCH();
267                                         if (ch == '-' || ch == '+')
268                                                 continue;
269                                 }
270                         } while ((spechr[ch] & C_ID) || (ch == '.'));
271                         goto xloop;
272
273                 case '\''/* character literal */
ragge
1.21
274 con:                    PUTCH(ch);
ragge
1.23
275                         if (tflag)
276                                 continue/* character constants ignored */
ragge
1.21
277                         while ((ch = NXTCH()) != '\'') {
ragge
1.19
278                                 PUTCH(ch);
279                                 if (ch == '\\') {
ragge
1.21
280                                         ch = NXTCH();
ragge
1.19
281                                         PUTCH(ch);
ragge
1.21
282                                 } else if (ch < 0)
ragge
1.19
283                                         return;
ragge
1.21
284                                 else if (ch == '\n')
ragge
1.19
285                                         goto xloop;
ragge
1.21
286                         }
ragge
1.19
287                         PUTCH(ch);
288                         break;
ragge
1.21
289
ragge
1.19
290                 case 'L':
291                         ch = NXTCH();
292                         if (ch == '\"') {
293                                 PUTCH('L');
294                                 goto str;
295                         }
296                         if (ch == '\'') {
297                                 PUTCH('L');
298                                 goto con;
299                         }
300                         unch(ch);
301                         ch = 'L';
302                         /* FALLTHROUGH */
303                 default:
304                         if ((spechr[ch] & C_ID) == 0)
305                                 error("fastscan");
306                         if (flslvl) {
307                                 while (spechr[ch] & C_ID)
308                                         ch = NXTCH();
309                                 goto xloop;
310                         }
311                         i = 0;
312                         do {
gmcgarry
1.26
313                                 yytext[i++] = (usch)ch;
ragge
1.19
314                                 ch = NXTCH();
ragge
1.36
315                                 if (ch == '\\') {
316                                         ch = NXTCH();
317                                         if (ch != '\n') {
318                                                 unch('\n');
319                                                 ch = '\\';
320                                         } else {
321                                                 ifiles->lineno++;
322                                                 ch = NXTCH();
323                                         }
324                                 }
ragge
1.19
325                                 if (ch < 0)
326                                         return;
327                         } while (spechr[ch] & C_ID);
328                         yytext[i] = 0;
329                         unch(ch);
330                         if ((nl = lookup((usch *)yytextFIND)) != 0) {
331                                 usch *op = stringbuf;
332                                 putstr(gotident(nl));
333                                 stringbuf = op;
334                         } else
335                                 putstr((usch *)yytext);
336                         break;
337                 }
338         }
339 }
ragge
1.1
340
ragge
1.13
341 int
ragge
1.19
342 sloscan()
ragge
1.3
343 {
ragge
1.13
344         int ch;
345         int yyp;
346
347 zagain:
348         yyp = 0;
gmcgarry
1.26
349         ch = inch();
350         yytext[yyp++] = (usch)ch;
ragge
1.13
351         switch (ch) {
ragge
1.14
352         case -1:
353                 return 0;
ragge
1.13
354         case '\n':
ragge
1.19
355                 /* sloscan() never passes \n, that's up to fastscan() */
356                 unch(ch);
357                 goto yyret;
ragge
1.13
358
359         case '\r'/* Ignore CR's */
360                 yyp = 0;
361                 break;
362
363         case '0'case '1'case '2'case '3'case '4'case '5'
364         case '6'case '7'case '8'case '9':
365                 /* readin a "pp-number" */
366 ppnum:          for (;;) {
ragge
1.19
367                         ch = inch();
368                         if (spechr[ch] & C_EP) {
gmcgarry
1.26
369                                 yytext[yyp++] = (usch)ch;
ragge
1.19
370                                 ch = inch();
ragge
1.13
371                                 if (ch == '-' || ch == '+') {
gmcgarry
1.26
372                                         yytext[yyp++] = (usch)ch;
ragge
1.13
373                                 } else
ragge
1.19
374                                         unch(ch);
ragge
1.13
375                                 continue;
376                         }
ragge
1.19
377                         if ((spechr[ch] & C_ID) || ch == '.') {
gmcgarry
1.26
378                                 yytext[yyp++] = (usch)ch;
ragge
1.13
379                                 continue;
380                         } 
381                         break;
382                 }
ragge
1.19
383                 unch(ch);
ragge
1.13
384                 yytext[yyp] = 0;
385
ragge
1.19
386                 return NUMBER;
ragge
1.13
387
388         case '\'':
ragge
1.19
389 chlit:          
ragge
1.13
390                 for (;;) {
ragge
1.19
391                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
392                                 yytext[yyp++] = (usch)ch;
393                                 yytext[yyp++] = (usch)inch();
ragge
1.13
394                                 continue;
395                         } else if (ch == '\n') {
396                                 /* not a constant */
397                                 while (yyp > 1)
ragge
1.19
398                                         unch(yytext[--yyp]);
ragge
1.13
399                                 ch = '\'';
400                                 goto any;
401                         } else
gmcgarry
1.26
402                                 yytext[yyp++] = (usch)ch;
ragge
1.13
403                         if (ch == '\'')
404                                 break;
405                 }
406                 yytext[yyp] = 0;
407
ragge
1.19
408                 return (NUMBER);
ragge
1.13
409
410         case ' ':
411         case '\t':
ragge
1.19
412                 while ((ch = inch()) == ' ' || ch == '\t')
gmcgarry
1.26
413                         yytext[yyp++] = (usch)ch;
ragge
1.19
414                 unch(ch);
415                 yytext[yyp] = 0;
416                 return(WSPACE);
ragge
1.13
417
418         case '/':
ragge
1.19
419                 if ((ch = inch()) == '/') {
ragge
1.13
420                         do {
gmcgarry
1.26
421                                 yytext[yyp++] = (usch)ch;
ragge
1.19
422                                 ch = inch();
ragge
1.13
423                         } while (ch && ch != '\n');
424                         yytext[yyp] = 0;
425                         unch(ch);
426                         goto zagain;
427                 } else if (ch == '*') {
428                         int cwrn;
429                         extern int readmac;
430
ragge
1.33
431                         if (Cflag && !flslvl && readmac) {
432                                 unch(ch);
ragge
1.34
433                                 yytext[yyp] = 0;
ragge
1.13
434                                 return CMNT;
ragge
1.33
435                         }
ragge
1.13
436
437                         wrn = 0;
ragge
1.19
438                 more:   while ((c = inch()) && c != '*') {
ragge
1.13
439                                 if (c == '\n')
440                                         putch(c), ifiles->lineno++;
441                                 else if (c == 1/* WARN */
442                                         wrn = 1;
443                         }
444                         if (c == 0)
445                                 return 0;
ragge
1.19
446                         if ((c = inch()) && c != '/') {
447                                 unch(c);
ragge
1.13
448                                 goto more;
449                         }
450                         if (c == 0)
451                                 return 0;
452                         if (!tflag && !Cflag && !flslvl)
ragge
1.19
453                                 unch(' ');
ragge
1.13
454                         if (wrn)
ragge
1.19
455                                 unch(1);
ragge
1.13
456                         goto zagain;
457                 }
458                 unch(ch);
459                 ch = '/';
460                 goto any;
461
ragge
1.19
462         case '.':
463                 ch = inch();
464                 if (isdigit(ch)) {
gmcgarry
1.26
465                         yytext[yyp++] = (usch)ch;
ragge
1.19
466                         goto ppnum;
ragge
1.13
467                 } else {
ragge
1.19
468                         unch(ch);
ragge
1.13
469                         ch = '.';
470                 }
ragge
1.19
471                 goto any;
ragge
1.13
472
473         case '\"':
474         strng:
475                 for (;;) {
ragge
1.19
476                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
477                                 yytext[yyp++] = (usch)ch;
478                                 yytext[yyp++] = (usch)inch();
ragge
1.13
479                                 continue;
480                         } else 
gmcgarry
1.26
481                                 yytext[yyp++] = (usch)ch;
ragge
1.13
482                         if (ch == '\"')
483                                 break;
484                 }
485                 yytext[yyp] = 0;
ragge
1.19
486                 return(STRING);
ragge
1.13
487
488         case 'L':
ragge
1.19
489                 if ((ch = inch()) == '\"') {
gmcgarry
1.26
490                         yytext[yyp++] = (usch)ch;
ragge
1.13
491                         goto strng;
492                 } else if (ch == '\'') {
gmcgarry
1.26
493                         yytext[yyp++] = (usch)ch;
ragge
1.13
494                         goto chlit;
495                 }
ragge
1.19
496                 unch(ch);
ragge
1.13
497                 /* FALLTHROUGH */
498
499         /* Yetch, all identifiers */
500         case 'a'case 'b'case 'c'case 'd'case 'e'case 'f'
501         case 'g'case 'h'case 'i'case 'j'case 'k'case 'l'
502         case 'm'case 'n'case 'o'case 'p'case 'q'case 'r'
503         case 's'case 't'case 'u'case 'v'case 'w'case 'x'
504         case 'y'case 'z':
505         case 'A'case 'B'case 'C'case 'D'case 'E'case 'F'
506         case 'G'case 'H'case 'I'case 'J'case 'K':
507         case 'M'case 'N'case 'O'case 'P'case 'Q'case 'R'
508         case 'S'case 'T'case 'U'case 'V'case 'W'case 'X'
509         case 'Y'case 'Z':
ragge
1.19
510         case '_'/* {L}({L}|{D})* */
ragge
1.13
511
512                 /* Special hacks */
513                 for (;;) { /* get chars */
ragge
1.19
514                         ch = inch();
ragge
1.14
515                         if (isalpha(ch) || isdigit(ch) || ch == '_') {
gmcgarry
1.26
516                                 yytext[yyp++] = (usch)ch;
ragge
1.14
517                         } else {
ragge
1.19
518                                 unch(ch);
ragge
1.13
519                                 break;
ragge
1.14
520                         }
ragge
1.13
521                 }
522                 yytext[yyp] = 0/* need already string */
523                 /* end special hacks */
524
ragge
1.19
525                 return IDENT;
ragge
1.13
526         default:
527         any:
528                 yytext[yyp] = 0;
ragge
1.19
529                 return yytext[0];
ragge
1.3
530
ragge
1.13
531         } /* endcase */
ragge
1.14
532         goto zagain;
ragge
1.6
533
ragge
1.13
534 yyret:
535         yytext[yyp] = 0;
536         return ch;
ragge
1.3
537 }
538
ragge
1.19
539 int
540 yylex()
541 {
542         static int ifdefnoex;
543         struct symtab *nl;
544         int chc2;
545
546         while ((ch = sloscan()) == WSPACE)
547                 ;
548         if (ch < 128 && spechr[ch] & C_2)
549                 c2 = inpch();
550         else
551                 c2 = 0;
552
553 #define C2(a,b,c) case a: if (c2 == b) return c; break
554         switch (ch) {
555         C2('=''='EQ);
556         C2('!''='NE);
557         C2('|''|'OROR);
558         C2('&''&'ANDAND);
559         case '<':
560                 if (c2 == '<'return LS;
561                 if (c2 == '='return LE;
562                 break;
563         case '>':
564                 if (c2 == '>'return RS;
565                 if (c2 == '='return GE;
566                 break;
567         case '+':
568         case '-':
569                 if (ch == c2)
570                         badop("");
571                 break;
ragge
1.27
572
ragge
1.33
573         case '/':
574                 if (Cflag == 0 || c2 != '*')
575                         break;
576                 /* Found comment that need to be skipped */
577                 for (;;) {
578                         ch = inpch();
579                 c1:     if (ch != '*')
580                                 continue;
581                         if ((ch = inpch()) == '/')
582                                 break;
583                         goto c1;
584                 }
585                 return yylex();
586
ragge
1.19
587         case NUMBER:
ragge
1.27
588                 if (yytext[0] == '\'') {
589                         yylval.node.op = NUMBER;
590                         yylval.node.nd_val = charcon((usch *)yytext);
591                 } else
592                         cvtdig(yytext[0] != '0' ? 10 :
593                             yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
ragge
1.19
594                 return NUMBER;
ragge
1.27
595
ragge
1.19
596         case IDENT:
597                 if (strcmp(yytext"defined") == 0) {
598                         ifdef = 1;
599                         return DEFINED;
600                 }
601                 nl = lookup((usch *)yytextFIND);
602                 if (ifdef) {
603                         yylval.node.nd_val = nl != NULL;
604                         ifdef = 0;
605                 } else if (nl && noex == 0) {
606                         usch *c, *och = stringbuf;
607
608                         c = gotident(nl);
609                         unch(1);
610                         unpstr(c);
611                         stringbuf = och;
612                         noex = 1;
613                         return yylex();
614                 } else {
615                         yylval.node.nd_val = 0;
616                 }
617                 yylval.node.op = NUMBER;
618                 return NUMBER;
619         case 1/* WARN */
620                 noex = 0;
621                 return yylex();
622         default:
623                 return ch;
624         }
625         unch(c2);
626         return ch;
627 }
628
ragge
1.13
629 usch *yypyybuf[CPPBUF];
630
631 int yywrap(void);
ragge
1.3
632
ragge
1.2
633 static int
ragge
1.13
634 inpch(void)
ragge
1.2
635 {
ragge
1.6
636         int len;
ragge
1.3
637
ragge
1.11
638         if (ifiles->curptr < ifiles->maxread)
ragge
1.2
639                 return *ifiles->curptr++;
ragge
1.11
640
ragge
1.38
641         if (ifiles->infil == -1)
642                 return -1;
ragge
1.6
643         if ((len = read(ifiles->infilifiles->bufferCPPBUF)) < 0)
ragge
1.13
644                 error("read error on file %s"ifiles->orgfn);
ragge
1.6
645         if (len == 0)
ragge
1.3
646                 return -1;
647         ifiles->curptr = ifiles->buffer;
ragge
1.6
648         ifiles->maxread = ifiles->buffer + len;
ragge
1.13
649         return inpch();
ragge
1.2
650 }
ragge
1.1
651
652 static int
ragge
1.13
653 inch(void)
ragge
1.1
654 {
655         int c;
656
ragge
1.13
657 again:  switch (c = inpch()) {
ragge
1.1
658         case '\\'/* continued lines */
ragge
1.13
659 msdos:          if ((c = inpch()) == '\n') {
ragge
1.1
660                         ifiles->lineno++;
661                         goto again;
ragge
1.13
662                 } else if (c == '\r')
663                         goto msdos;
664                 unch(c);
ragge
1.1
665                 return '\\';
666         case '?'/* trigraphs */
ragge
1.19
667                 if ((c = chktg())) {
ragge
1.13
668                         unch(c);
ragge
1.19
669                         goto again;
ragge
1.1
670                 }
ragge
1.19
671                 return '?';
ragge
1.1
672         default:
673                 return c;
674         }
675 }
676
ragge
1.13
677 /*
678  * Let the command-line args be faked defines at beginning of file.
679  */
680 static void
681 prinit(struct initar *itstruct includ *ic)
ragge
1.1
682 {
ragge
1.31
683         const char *pre, *post;
684         char *a;
ragge
1.1
685
ragge
1.13
686         if (it->next)
687                 prinit(it->nextic);
688         pre = post = NULL/* XXX gcc */
689         switch (it->type) {
690         case 'D':
691                 pre = "#define ";
692                 if ((a = strchr(it->str'=')) != NULL) {
693                         *a = ' ';
694                         post = "\n";
ragge
1.1
695                 } else
ragge
1.13
696                         post = " 1\n";
ragge
1.1
697                 break;
ragge
1.13
698         case 'U':
699                 pre = "#undef ";
700                 post = "\n";
ragge
1.1
701                 break;
ragge
1.13
702         case 'i':
703                 pre = "#include \"";
704                 post = "\"\n";
ragge
1.1
705                 break;
706         default:
ragge
1.13
707                 error("prinit");
ragge
1.1
708         }
ragge
1.13
709         strlcat((char *)ic->bufferpreCPPBUF+1);
710         strlcat((char *)ic->bufferit->strCPPBUF+1);
711         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
712                 error("line exceeds buffer size");
713
714         ic->lineno--;
715         while (*ic->maxread)
716                 ic->maxread++;
ragge
1.1
717 }
718
ragge
1.4
719 /*
ragge
1.6
720  * A new file included.
721  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
722  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
723  */
724 int
ragge
1.31
725 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
726 {
ragge
1.13
727         extern struct initar *initar;
ragge
1.6
728         struct includ ibuf;
729         struct includ *ic;
ragge
1.19
730         int otrulvl;
ragge
1.6
731
732         ic = &ibuf;
ragge
1.13
733         ic->next = ifiles;
ragge
1.4
734
ragge
1.6
735         if (file != NULL) {
ragge
1.31
736                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
737                         return -1;
ragge
1.13
738                 ic->orgfn = ic->fname = file;
739                 if (++inclevel > MAX_INCLEVEL)
740                         error("Limit for nested includes exceeded");
ragge
1.6
741         } else {
742                 ic->infil = 0;
ragge
1.31
743                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
744         }
745         ic->buffer = ic->bbuf+NAMEMAX;
ragge
1.4
746         ic->curptr = ic->buffer;
747         ifiles = ic;
ragge
1.13
748         ic->lineno = 1;
ragge
1.6
749         ic->maxread = ic->curptr;
ragge
1.29
750         ic->idx = idx;
751         ic->incs = incs;
752         ic->fn = fn;
ragge
1.13
753         prtline();
754         if (initar) {
ragge
1.38
755                 int oin = ic->infil;
756                 ic->infil = -1;
ragge
1.13
757                 *ic->maxread = 0;
758                 prinit(initaric);
ragge
1.41
759                 initar = NULL;
ragge
1.13
760                 if (dMflag)
761                         write(ofdic->bufferstrlen((char *)ic->buffer));
ragge
1.38
762                 fastscan();
763                 prtline();
764                 ic->infil = oin;
ragge
1.13
765         }
ragge
1.4
766
ragge
1.13
767         otrulvl = trulvl;
ragge
1.4
768
ragge
1.19
769         fastscan();
ragge
1.13
770
771         if (otrulvl != trulvl || flslvl)
ragge
1.6
772                 error("unterminated conditional");
ragge
1.4
773
ragge
1.13
774         ifiles = ic->next;
ragge
1.6
775         close(ic->infil);
ragge
1.13
776         inclevel--;
ragge
1.6
777         return 0;
ragge
1.4
778 }
ragge
1.1
779
780 /*
781  * Print current position to output file.
782  */
783 void
784 prtline()
785 {
ragge
1.13
786         usch *s, *os = stringbuf;
787
788         if (Mflag) {
789                 if (dMflag)
790                         return/* no output */
791                 if (ifiles->lineno == 1) {
792                         s = sheap("%s: %s\n"Mfileifiles->fname);
793                         write(ofdsstrlen((char *)s));
794                 }
795         } else if (!Pflag)
ragge
1.30
796                 putstr(sheap("\n# %d \"%s\"\n"ifiles->linenoifiles->fname));
ragge
1.13
797         stringbuf = os;
ragge
1.1
798 }
799
800 void
801 cunput(int c)
802 {
ragge
1.13
803 #ifdef CPP_DEBUG
804         extern int dflag;
805         if (dflag)printf(": '%c'(%d)"c > 31 ? c : ' 'c);
806 #endif
ragge
1.19
807 #if 0
808 if (c == 10) {
809         printf("c == 10!!!\n");
810 }
811 #endif
812         unch(c);
ragge
1.1
813 }
814
ragge
1.13
815 int yywrap(void) { return 1; }
816
817 static int
818 dig2num(int c)
819 {
820         if (c >= 'a')
821                 c = c - 'a' + 10;
822         else if (c >= 'A')
823                 c = c - 'A' + 10;
824         else
825                 c = c - '0';
826         return c;
827 }
828
829 /*
830  * Convert string numbers to unsigned long long and check overflow.
831  */
832 static void
833 cvtdig(int rad)
834 {
835         unsigned long long rv = 0;
836         unsigned long long rv2 = 0;
837         char *y = yytext;
838         int c;
839
840         c = *y++;
841         if (rad == 16)
842                 y++;
843         while (isxdigit(c)) {
844                 rv = rv * rad + dig2num(c);
845                 /* check overflow */
846                 if (rv / rad < rv2)
847                         error("Constant \"%s\" is out of range"yytext);
848                 rv2 = rv;
849                 c = *y++;
850         }
851         y--;
852         while (*y == 'l' || *y == 'L')
853                 y++;
854         yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
855         yylval.node.nd_uval = rv;
856         if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
857                 yylval.node.op = UNUMBER;
858         if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
ragge
1.19
859                 /* too large for signed, see 6.4.4.1 */
ragge
1.13
860                 error("Constant \"%s\" is out of range"yytext);
861 }
862
863 static int
864 charcon(usch *p)
865 {
866         int valc;
867
868         p++; /* skip first ' */
869         val = 0;
870         if (*p++ == '\\') {
871                 switch (*p++) {
872                 case 'a'val = '\a'break;
873                 case 'b'val = '\b'break;
874                 case 'f'val = '\f'break;
875                 case 'n'val = '\n'break;
876                 case 'r'val = '\r'break;
877                 case 't'val = '\t'break;
878                 case 'v'val = '\v'break;
879                 case '\"'val = '\"'break;
880                 case '\''val = '\''break;
881                 case '\\'val = '\\'break;
882                 case 'x':
883                         while (isxdigit(c = *p)) {
884                                 val = val * 16 + dig2num(c);
885                                 p++;
886                         }
887                         break;
888                 case '0'case '1'case '2'case '3'case '4':
889                 case '5'case '6'case '7':
890                         p--;
891                         while (isdigit(c = *p)) {
892                                 val = val * 8 + (c - '0');
893                                 p++;
894                         }
895                         break;
896                 defaultval = p[-1];
897                 }
898
899         } else
900                 val = p[-1];
901         return val;
902 }
903
904 static void
905 chknl(int ignore)
906 {
907         int t;
908
ragge
1.19
909         while ((t = sloscan()) == WSPACE)
ragge
1.13
910                 ;
911         if (t != '\n') {
912                 if (ignore) {
913                         warning("newline expected, got \"%s\""yytext);
914                         /* ignore rest of line */
ragge
1.19
915                         while ((t = sloscan()) && t != '\n')
ragge
1.13
916                                 ;
917                 }
918                 else
919                         error("newline expected, got \"%s\""yytext);
920         }
921 }
922
923 static void
924 elsestmt(void)
925 {
926         if (flslvl) {
927                 if (elflvl > trulvl)
928                         ;
929                 else if (--flslvl!=0) {
930                         flslvl++;
931                 } else {
932                         trulvl++;
933                         prtline();
934                 }
935         } else if (trulvl) {
936                 flslvl++;
937                 trulvl--;
938         } else
939                 error("If-less else");
940         if (elslvl==trulvl+flslvl)
941                 error("Too many else");
942         elslvl=trulvl+flslvl;
943         chknl(1);
944 }
945
946 static void
ragge
1.20
947 skpln(void)
948 {
949         /* just ignore the rest of the line */
950         while (inch() != '\n')
951                 ;
952         unch('\n');
953         flslvl++;
954 }
955
956 static void
ragge
1.13
957 ifdefstmt(void)          
958
959         int t;
960
961         if (flslvl) {
ragge
1.20
962                 skpln();
ragge
1.13
963                 return;
964