Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20100606201031

Diff

Diff from 1.36 to:

Annotations

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

Annotated File View

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