Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110319093132

Diff

Diff from 1.53 to:

Annotations

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

Annotated File View

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