Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110221080042

Diff

Diff from 1.48 to:

Annotations

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

Annotated File View

ragge
1.48
1 /*      $Id: token.c,v 1.48 2011/02/21 08:00:42 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 */
ragge
1.48
126 unsigned short bptr[RECMAX];    /* currently active noexpand macro stack */
ragge
1.43
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.48
482                                 else if (c == EBLOCK) {
ragge
1.46
483                                         (void)inch();
ragge
1.48
484                                         (void)inch();
485                                 } else if (c == 1/* WARN */
ragge
1.13
486                                         wrn = 1;
487                         }
488                         if (c == 0)
489                                 return 0;
ragge
1.19
490                         if ((c = inch()) && c != '/') {
491                                 unch(c);
ragge
1.13
492                                 goto more;
493                         }
494                         if (c == 0)
495                                 return 0;
496                         if (!tflag && !Cflag && !flslvl)
ragge
1.19
497                                 unch(' ');
ragge
1.13
498                         if (wrn)
ragge
1.19
499                                 unch(1);
ragge
1.13
500                         goto zagain;
501                 }
502                 unch(ch);
503                 ch = '/';
504                 goto any;
505
ragge
1.19
506         case '.':
507                 ch = inch();
508                 if (isdigit(ch)) {
gmcgarry
1.26
509                         yytext[yyp++] = (usch)ch;
ragge
1.19
510                         goto ppnum;
ragge
1.13
511                 } else {
ragge
1.19
512                         unch(ch);
ragge
1.13
513                         ch = '.';
514                 }
ragge
1.19
515                 goto any;
ragge
1.13
516
517         case '\"':
ragge
1.42
518                 if (tflag)
519                         goto any;
ragge
1.13
520         strng:
521                 for (;;) {
ragge
1.19
522                         if ((ch = inch()) == '\\') {
gmcgarry
1.26
523                                 yytext[yyp++] = (usch)ch;
524                                 yytext[yyp++] = (usch)inch();
ragge
1.13
525                                 continue;
526                         } else 
gmcgarry
1.26
527                                 yytext[yyp++] = (usch)ch;
ragge
1.13
528                         if (ch == '\"')
529                                 break;
530                 }
531                 yytext[yyp] = 0;
ragge
1.19
532                 return(STRING);
ragge
1.13
533
534         case 'L':
ragge
1.42
535                 if ((ch = inch()) == '\"' && !tflag) {
gmcgarry
1.26
536                         yytext[yyp++] = (usch)ch;
ragge
1.13
537                         goto strng;
ragge
1.42
538                 } else if (ch == '\'' && !tflag) {
gmcgarry
1.26
539                         yytext[yyp++] = (usch)ch;
ragge
1.13
540                         goto chlit;
541                 }
ragge
1.19
542                 unch(ch);
ragge
1.13
543                 /* FALLTHROUGH */
544
545         /* Yetch, all identifiers */
546         case 'a'case 'b'case 'c'case 'd'case 'e'case 'f'
547         case 'g'case 'h'case 'i'case 'j'case 'k'case 'l'
548         case 'm'case 'n'case 'o'case 'p'case 'q'case 'r'
549         case 's'case 't'case 'u'case 'v'case 'w'case 'x'
550         case 'y'case 'z':
551         case 'A'case 'B'case 'C'case 'D'case 'E'case 'F'
552         case 'G'case 'H'case 'I'case 'J'case 'K':
553         case 'M'case 'N'case 'O'case 'P'case 'Q'case 'R'
554         case 'S'case 'T'case 'U'case 'V'case 'W'case 'X'
555         case 'Y'case 'Z':
ragge
1.19
556         case '_'/* {L}({L}|{D})* */
ragge
1.13
557
558                 /* Special hacks */
559                 for (;;) { /* get chars */
ragge
1.19
560                         ch = inch();
ragge
1.14
561                         if (isalpha(ch) || isdigit(ch) || ch == '_') {
gmcgarry
1.26
562                                 yytext[yyp++] = (usch)ch;
ragge
1.14
563                         } else {
ragge
1.19
564                                 unch(ch);
ragge
1.13
565                                 break;
ragge
1.14
566                         }
ragge
1.13
567                 }
568                 yytext[yyp] = 0/* need already string */
569                 /* end special hacks */
570
ragge
1.19
571                 return IDENT;
ragge
1.13
572         default:
573         any:
574                 yytext[yyp] = 0;
ragge
1.19
575                 return yytext[0];
ragge
1.3
576
ragge
1.13
577         } /* endcase */
ragge
1.14
578         goto zagain;
ragge
1.6
579
ragge
1.13
580 yyret:
581         yytext[yyp] = 0;
582         return ch;
ragge
1.3
583 }
584
ragge
1.19
585 int
586 yylex()
587 {
588         static int ifdefnoex;
589         struct symtab *nl;
590         int chc2;
591
592         while ((ch = sloscan()) == WSPACE)
593                 ;
594         if (ch < 128 && spechr[ch] & C_2)
595                 c2 = inpch();
596         else
597                 c2 = 0;
598
599 #define C2(a,b,c) case a: if (c2 == b) return c; break
600         switch (ch) {
601         C2('=''='EQ);
602         C2('!''='NE);
603         C2('|''|'OROR);
604         C2('&''&'ANDAND);
605         case '<':
606                 if (c2 == '<'return LS;
607                 if (c2 == '='return LE;
608                 break;
609         case '>':
610                 if (c2 == '>'return RS;
611                 if (c2 == '='return GE;
612                 break;
613         case '+':
614         case '-':
615                 if (ch == c2)
616                         badop("");
617                 break;
ragge
1.27
618
ragge
1.33
619         case '/':
620                 if (Cflag == 0 || c2 != '*')
621                         break;
622                 /* Found comment that need to be skipped */
623                 for (;;) {
624                         ch = inpch();
625                 c1:     if (ch != '*')
626                                 continue;
627                         if ((ch = inpch()) == '/')
628                                 break;
629                         goto c1;
630                 }
631                 return yylex();
632
ragge
1.19
633         case NUMBER:
ragge
1.27
634                 if (yytext[0] == '\'') {
635                         yylval.node.op = NUMBER;
636                         yylval.node.nd_val = charcon((usch *)yytext);
637                 } else
638                         cvtdig(yytext[0] != '0' ? 10 :
639                             yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
ragge
1.19
640                 return NUMBER;
ragge
1.27
641
ragge
1.19
642         case IDENT:
ragge
1.44
643                 if (strcmp((char *)yytext"defined") == 0) {
ragge
1.19
644                         ifdef = 1;
645                         return DEFINED;
646                 }
647                 nl = lookup((usch *)yytextFIND);
648                 if (ifdef) {
649                         yylval.node.nd_val = nl != NULL;
650                         ifdef = 0;
651                 } else if (nl && noex == 0) {
ragge
1.43
652                         usch *och = stringbuf;
653                         int i;
ragge
1.19
654
ragge
1.43
655                         i = kfind(nl);
656                         unch(WARN);
657                         if (i)
658                                 unpstr(stringbuf);
659                         else
660                                 unpstr(nl->namep);
ragge
1.19
661                         stringbuf = och;
662                         noex = 1;
663                         return yylex();
664                 } else {
665                         yylval.node.nd_val = 0;
666                 }
667                 yylval.node.op = NUMBER;
668                 return NUMBER;
ragge
1.43
669         case WARN:
ragge
1.19
670                 noex = 0;
671                 return yylex();
672         default:
673                 return ch;
674         }
675         unch(c2);
676         return ch;
677 }
678
ragge
1.13
679 usch *yypyybuf[CPPBUF];
680
681 int yywrap(void);
ragge
1.3
682
ragge
1.2
683 static int
ragge
1.13
684 inpch(void)
ragge
1.2
685 {
ragge
1.6
686         int len;
ragge
1.3
687
ragge
1.11
688         if (ifiles->curptr < ifiles->maxread)
ragge
1.2
689                 return *ifiles->curptr++;
ragge
1.11
690
ragge
1.38
691         if (ifiles->infil == -1)
692                 return -1;
ragge
1.6
693         if ((len = read(ifiles->infilifiles->bufferCPPBUF)) < 0)
ragge
1.13
694                 error("read error on file %s"ifiles->orgfn);
ragge
1.6
695         if (len == 0)
ragge
1.3
696                 return -1;
697         ifiles->curptr = ifiles->buffer;
ragge
1.6
698         ifiles->maxread = ifiles->buffer + len;
ragge
1.13
699         return inpch();
ragge
1.2
700 }
ragge
1.1
701
702 static int
ragge
1.13
703 inch(void)
ragge
1.1
704 {
705         int c;
706
ragge
1.13
707 again:  switch (c = inpch()) {
ragge
1.1
708         case '\\'/* continued lines */
ragge
1.13
709 msdos:          if ((c = inpch()) == '\n') {
ragge
1.1
710                         ifiles->lineno++;
711                         goto again;
ragge
1.13
712                 } else if (c == '\r')
713                         goto msdos;
714                 unch(c);
ragge
1.1
715                 return '\\';
716         case '?'/* trigraphs */
ragge
1.19
717                 if ((c = chktg())) {
ragge
1.13
718                         unch(c);
ragge
1.19
719                         goto again;
ragge
1.1
720                 }
ragge
1.19
721                 return '?';
ragge
1.1
722         default:
723                 return c;
724         }
725 }
726
ragge
1.13
727 /*
728  * Let the command-line args be faked defines at beginning of file.
729  */
730 static void
731 prinit(struct initar *itstruct includ *ic)
ragge
1.1
732 {
ragge
1.31
733         const char *pre, *post;
734         char *a;
ragge
1.1
735
ragge
1.13
736         if (it->next)
737                 prinit(it->nextic);
738         pre = post = NULL/* XXX gcc */
739         switch (it->type) {
740         case 'D':
741                 pre = "#define ";
742                 if ((a = strchr(it->str'=')) != NULL) {
743                         *a = ' ';
744                         post = "\n";
ragge
1.1
745                 } else
ragge
1.13
746                         post = " 1\n";
ragge
1.1
747                 break;
ragge
1.13
748         case 'U':
749                 pre = "#undef ";
750                 post = "\n";
ragge
1.1
751                 break;
ragge
1.13
752         case 'i':
753                 pre = "#include \"";
754                 post = "\"\n";
ragge
1.1
755                 break;
756         default:
ragge
1.13
757                 error("prinit");
ragge
1.1
758         }
ragge
1.13
759         strlcat((char *)ic->bufferpreCPPBUF+1);
760         strlcat((char *)ic->bufferit->strCPPBUF+1);
761         if (strlcat((char *)ic->bufferpostCPPBUF+1) >= CPPBUF+1)
762                 error("line exceeds buffer size");
763
764         ic->lineno--;
765         while (*ic->maxread)
766                 ic->maxread++;
ragge
1.1
767 }
768
ragge
1.4
769 /*
ragge
1.6
770  * A new file included.
771  * If ifiles == NULL, this is the first file and already opened (stdin).
ragge
1.13
772  * Return 0 on success, -1 if file to be included is not found.
ragge
1.4
773  */
774 int
ragge
1.31
775 pushfile(const usch *fileconst usch *fnint idxvoid *incs)
ragge
1.4
776 {
ragge
1.13
777         extern struct initar *initar;
ragge
1.6
778         struct includ ibuf;
779         struct includ *ic;
ragge
1.19
780         int otrulvl;
ragge
1.6
781
782         ic = &ibuf;
ragge
1.13
783         ic->next = ifiles;
ragge
1.4
784
ragge
1.6
785         if (file != NULL) {
ragge
1.31
786                 if ((ic->infil = open((const char *)fileO_RDONLY)) < 0)
ragge
1.4
787                         return -1;
ragge
1.13
788                 ic->orgfn = ic->fname = file;
789                 if (++inclevel > MAX_INCLEVEL)
790                         error("Limit for nested includes exceeded");
ragge
1.6
791         } else {
792                 ic->infil = 0;
ragge
1.31
793                 ic->orgfn = ic->fname = (const usch *)"<stdin>";
ragge
1.6
794         }
795         ic->buffer = ic->bbuf+NAMEMAX;
ragge
1.4
796         ic->curptr = ic->buffer;
797         ifiles = ic;
ragge
1.13
798         ic->lineno = 1;
ragge
1.6
799         ic->maxread = ic->curptr;
ragge
1.29
800         ic->idx = idx;
801         ic->incs = incs;
802         ic->fn = fn;
ragge
1.13
803         prtline();
804         if (initar) {
ragge
1.38
805                 int oin = ic->infil;
806                 ic->infil = -1;
ragge
1.13
807                 *ic->maxread = 0;
808                 prinit(initaric);
ragge
1.41
809                 initar = NULL;
ragge
1.13
810                 if (dMflag)
811                         write(ofdic->bufferstrlen((char *)ic->buffer));
ragge
1.38
812                 fastscan();
813                 prtline();
814                 ic->infil = oin;
ragge
1.13
815         }
ragge
1.4
816
ragge
1.13
817         otrulvl = trulvl;
ragge
1.4
818
ragge
1.19
819         fastscan();
ragge
1.13
820
821         if (otrulvl != trulvl || flslvl)
ragge
1.6
822                 error("unterminated conditional");
ragge
1.4
823
ragge
1.13
824         ifiles = ic->next;
ragge
1.6
825         close(ic->infil);
ragge
1.13
826         inclevel--;
ragge
1.6
827         return 0;
ragge
1.4
828 }
ragge
1.1
829
830 /*
831  * Print current position to output file.
832  */
833 void
834 prtline()
835 {
ragge
1.13
836         usch *s, *os = stringbuf;
837
838         if (Mflag) {
839                 if (dMflag)
840                         return/* no output */
841                 if (ifiles->lineno == 1) {
842                         s = sheap("%s: %s\n"Mfileifiles->fname);
843                         write(ofdsstrlen((char *)s));
844                 }
845         } else if (!Pflag)
ragge
1.30
846                 putstr(sheap("\n# %d \"%s\"\n"ifiles->linenoifiles->fname));
ragge
1.13
847         stringbuf = os;
ragge
1.1
848 }
849
850 void
851 cunput(int c)
852 {
ragge
1.13
853 #ifdef CPP_DEBUG
ragge
1.43
854 //      extern int dflag;
855 //      if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
ragge
1.13
856 #endif
ragge
1.19
857 #if 0
858 if (c == 10) {
859         printf("c == 10!!!\n");
860 }
861 #endif
862         unch(c);
ragge
1.1
863 }
864
ragge
1.13
865 int yywrap(void) { return 1; }
866
867 static int
868 dig2num(int c)
869 {
870         if (c >= 'a')
871                 c = c - 'a' + 10;
872         else if (c >= 'A')
873                 c = c - 'A' + 10;
874         else
875                 c = c - '0';
876         return c;
877 }
878
879 /*
880  * Convert string numbers to unsigned long long and check overflow.
881  */
882 static void
883 cvtdig(int rad)
884 {
885         unsigned long long rv = 0;
886         unsigned long long rv2 = 0;
ragge
1.44
887         usch *y = yytext;
ragge
1.13
888         int c;
889
890         c = *y++;
891         if (rad == 16)
892                 y++;
893         while (isxdigit(c)) {
894                 rv = rv * rad + dig2num(c);
895                 /* check overflow */
896                 if (rv / rad < rv2)
897                         error("Constant \"%s\" is out of range"yytext);
898                 rv2 = rv;
899                 c = *y++;
900         }
901         y--;
902         while (*y == 'l' || *y == 'L')
903                 y++;
904         yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
905         yylval.node.nd_uval = rv;
906         if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
907                 yylval.node.op = UNUMBER;
908         if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
ragge
1.19
909                 /* too large for signed, see 6.4.4.1 */
ragge
1.13
910                 error("Constant \"%s\" is out of range"yytext);
911 }
912
913 static int
914 charcon(usch *p)
915 {
916         int valc;
917
918         p++; /* skip first ' */
919         val = 0;
920         if (*p++ == '\\') {
921                 switch (*p++) {
922                 case 'a'val = '\a'break;
923                 case 'b'val = '\b'break;
924                 case 'f'val = '\f'break;
925                 case 'n'val = '\n'break;
926                 case 'r'val = '\r'break;
927                 case 't'val = '\t'break;
928                 case 'v'val = '\v'break;
929                 case '\"'val = '\"'break;
930                 case '\''val = '\''break;
931                 case '\\'val = '\\'break;
932                 case 'x':
933