Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20100613191631

Diff

Diff from 1.39 to:

Annotations

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

Annotated File View

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