Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110312170645

Diff

Diff from 1.50 to:

Annotations

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

Annotated File View

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