Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110129134848

Diff

Diff from 1.45 to:

Annotations

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

Annotated File View

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