Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110109152539

Diff

Diff from 1.43 to:

Annotations

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

Annotated File View

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