Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110218212818

Diff

Diff from 1.47 to:

Annotations

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

Annotated File View

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