Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20100607071035

Diff

Diff from 1.37 to:

Annotations

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

Annotated File View

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