Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110116115554

Diff

Diff from 1.44 to:

Annotations

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

Annotated File View

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