* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / cc / cpp / token.c
blob9f086ee8f3a5047c7e076bc4dc18216ffdb63660
1 /* $Id: token.c,v 1.48.2.2 2011/03/12 17:08:26 ragge Exp $ */
3 /*
4 * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved.
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.
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.
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.
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.
43 #include "config.h"
45 #include <stdlib.h>
46 #include <string.h>
47 #include <ctype.h>
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 #include <fcntl.h>
52 #include <errno.h>
54 #include "compat.h"
55 #include "cpp.h"
56 #include "y.tab.h"
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 cppwarning(void);
69 static void elifstmt(void);
70 static void badop(const char *);
71 static int chktg(void);
72 static void ppdir(void);
73 void include(void);
74 void include_next(void);
75 void define(void);
76 static int inpch(void);
78 extern int yyget_lineno (void);
79 extern void yyset_lineno (int);
81 static int inch(void);
83 int inif;
84 extern int dflag;
86 #define PUTCH(ch) if (!flslvl) putch(ch)
87 /* protection against recursion in #include */
88 #define MAX_INCLEVEL 100
89 static int inclevel;
91 /* get next character unaltered */
92 #define NXTCH() (ifiles->curptr < ifiles->maxread ? *ifiles->curptr++ : inpch())
94 usch yytext[CPPBUF];
96 char spechr[256] = {
97 0, 0, 0, 0, C_SPEC, C_SPEC, 0, 0,
98 0, C_WSNL, C_SPEC|C_WSNL, 0,
99 0, C_WSNL, 0, 0,
100 0, 0, 0, 0, 0, 0, 0, 0,
101 0, 0, 0, 0, 0, 0, 0, 0,
103 C_WSNL, C_2, C_SPEC, 0, 0, 0, C_2, C_SPEC,
104 0, 0, 0, C_2, 0, C_2, 0, C_SPEC|C_2,
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,
108 0, C_I, C_I, C_I, C_I, C_I|C_EP, C_I, C_I,
109 C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I,
110 C_I|C_EP, C_I, C_I, C_I, C_I, C_I, C_I, C_I,
111 C_I, C_I, C_I, 0, C_I, 0, 0, C_I,
113 0, C_I, C_I, C_I, C_I, C_I|C_EP, C_I, C_I,
114 C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I,
115 C_I|C_EP, C_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,
121 * No-replacement array. If a macro is found and exists in this array
122 * then no replacement shall occur. This is a stack.
124 struct symtab *norep[RECMAX]; /* Symbol table index table */
125 int norepptr = 1; /* Top of index table */
126 unsigned short bptr[RECMAX]; /* currently active noexpand macro stack */
127 int bidx; /* Top of bptr stack */
129 static void
130 unch(int c)
133 --ifiles->curptr;
134 if (ifiles->curptr < ifiles->bbuf)
135 error("pushback buffer full");
136 *ifiles->curptr = (usch)c;
139 static int
140 eatcmnt(void)
142 int ch;
144 if (Cflag) { PUTCH('/'); PUTCH('*'); }
145 for (;;) {
146 ch = inch();
147 if (ch == '\n') {
148 ifiles->lineno++;
149 PUTCH('\n');
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;
163 unch(ch);
164 ch = '*';
166 if (Cflag) PUTCH(ch);
168 return 0;
172 * Scan quickly the input file searching for:
173 * - '#' directives
174 * - keywords (if not flslvl)
175 * - comments
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.
181 static void
182 fastscan(void)
184 struct symtab *nl;
185 int ch, i, ccnt, onemore;
186 usch *cp;
188 goto run;
189 for (;;) {
190 ch = NXTCH();
191 xloop: if (ch == -1)
192 return;
193 if (dflag>1)
194 printf("fastscan ch %d (%c)\n", ch, ch > 31 ? ch : '@');
195 if ((spechr[ch] & C_SPEC) == 0) {
196 PUTCH(ch);
197 continue;
199 switch (ch) {
200 case EBLOCK:
201 case WARN:
202 case CONC:
203 error("bad char passed");
204 break;
206 case '/': /* Comments */
207 if ((ch = inch()) == '/') {
208 cppcmt: if (Cflag) { PUTCH(ch); } else { PUTCH(' '); }
209 do {
210 if (Cflag) PUTCH(ch);
211 ch = inch();
212 } while (ch != -1 && ch != '\n');
213 goto xloop;
214 } else if (ch == '*') {
215 if (eatcmnt())
216 return;
217 } else {
218 PUTCH('/');
219 goto xloop;
221 break;
223 case '?': /* trigraphs */
224 if ((ch = chktg()))
225 goto xloop;
226 PUTCH('?');
227 break;
229 case '\\':
230 if ((ch = NXTCH()) == '\n') {
231 ifiles->lineno++;
232 continue;
233 } else {
234 PUTCH('\\');
236 goto xloop;
238 case '\n': /* newlines, for pp directives */
239 run2: ifiles->lineno++;
240 do {
241 PUTCH(ch);
242 run: ch = NXTCH();
243 if (ch == '/') {
244 ch = NXTCH();
245 if (ch == '/')
246 goto cppcmt;
247 if (ch == '*') {
248 if (eatcmnt())
249 return;
250 goto run;
252 unch(ch);
253 ch = '/';
255 } while (ch == ' ' || ch == '\t');
256 if (ch == '\\') {
257 ch = NXTCH();
258 if (ch == '\n')
259 goto run2;
260 unch(ch);
261 ch = '\\';
263 if (ch == '#') {
264 ppdir();
265 continue;
266 } else if (ch == '%') {
267 ch = NXTCH();
268 if (ch == ':') {
269 ppdir();
270 continue;
271 } else {
272 unch(ch);
273 ch = '%';
276 goto xloop;
278 case '\"': /* strings */
279 str: PUTCH(ch);
280 while ((ch = inch()) != '\"') {
281 PUTCH(ch);
282 if (ch == '\\') {
283 ch = inch();
284 PUTCH(ch);
286 if (ch < 0)
287 return;
289 PUTCH(ch);
290 break;
292 case '.': /* for pp-number */
293 PUTCH(ch);
294 ch = NXTCH();
295 if (ch < '0' || ch > '9')
296 goto xloop;
297 /* FALLTHROUGH */
298 case '0': case '1': case '2': case '3': case '4':
299 case '5': case '6': case '7': case '8': case '9':
300 do {
301 PUTCH(ch);
302 nxt: ch = NXTCH();
303 if (ch == '\\') {
304 ch = NXTCH();
305 if (ch == '\n') {
306 goto nxt;
307 } else {
308 unch(ch);
309 ch = '\\';
312 if (spechr[ch] & C_EP) {
313 PUTCH(ch);
314 ch = NXTCH();
315 if (ch == '-' || ch == '+')
316 continue;
318 } while ((spechr[ch] & C_ID) || (ch == '.'));
319 goto xloop;
321 case '\'': /* character literal */
322 con: PUTCH(ch);
323 if (tflag)
324 continue; /* character constants ignored */
325 while ((ch = NXTCH()) != '\'') {
326 PUTCH(ch);
327 if (ch == '\\') {
328 ch = NXTCH();
329 PUTCH(ch);
330 } else if (ch < 0)
331 return;
332 else if (ch == '\n')
333 goto xloop;
335 PUTCH(ch);
336 break;
338 case 'L':
339 ch = NXTCH();
340 if (ch == '\"') {
341 PUTCH('L');
342 goto str;
344 if (ch == '\'') {
345 PUTCH('L');
346 goto con;
348 unch(ch);
349 ch = 'L';
350 /* FALLTHROUGH */
351 default:
352 if ((spechr[ch] & C_ID) == 0)
353 error("fastscan");
354 if (flslvl) {
355 while (spechr[ch] & C_ID)
356 ch = NXTCH();
357 goto xloop;
359 onemore = i = ccnt = 0;
360 do {
361 yytext[i++] = (usch)ch;
362 ch = NXTCH();
363 if (ch == '\\') {
364 ch = NXTCH();
365 if (ch != '\n') {
366 unch('\n');
367 ch = '\\';
368 } else {
369 ifiles->lineno++;
370 ch = NXTCH();
373 if (ch < 0)
374 return;
375 } while (spechr[ch] & C_ID);
377 yytext[i] = 0;
378 unch(ch);
380 cp = stringbuf;
381 if ((nl = lookup((usch *)yytext, FIND)) && kfind(nl)) {
382 putstr(stringbuf);
383 } else
384 putstr((usch *)yytext);
385 stringbuf = cp;
387 break;
393 sloscan()
395 int ch;
396 int yyp;
398 zagain:
399 yyp = 0;
400 ch = inch();
401 yytext[yyp++] = (usch)ch;
402 switch (ch) {
403 case -1:
404 return 0;
405 case '\n':
406 /* sloscan() never passes \n, that's up to fastscan() */
407 unch(ch);
408 goto yyret;
410 case '\r': /* Ignore CR's */
411 yyp = 0;
412 break;
414 case '0': case '1': case '2': case '3': case '4': case '5':
415 case '6': case '7': case '8': case '9':
416 /* readin a "pp-number" */
417 ppnum: for (;;) {
418 ch = inch();
419 if (spechr[ch] & C_EP) {
420 yytext[yyp++] = (usch)ch;
421 ch = inch();
422 if (ch == '-' || ch == '+') {
423 yytext[yyp++] = (usch)ch;
424 } else
425 unch(ch);
426 continue;
428 if ((spechr[ch] & C_ID) || ch == '.') {
429 yytext[yyp++] = (usch)ch;
430 continue;
432 break;
434 unch(ch);
435 yytext[yyp] = 0;
437 return NUMBER;
439 case '\'':
440 chlit:
441 for (;;) {
442 if ((ch = inch()) == '\\') {
443 yytext[yyp++] = (usch)ch;
444 yytext[yyp++] = (usch)inch();
445 continue;
446 } else if (ch == '\n') {
447 /* not a constant */
448 while (yyp > 1)
449 unch(yytext[--yyp]);
450 ch = '\'';
451 goto any;
452 } else
453 yytext[yyp++] = (usch)ch;
454 if (ch == '\'')
455 break;
457 yytext[yyp] = 0;
459 return (NUMBER);
461 case ' ':
462 case '\t':
463 while ((ch = inch()) == ' ' || ch == '\t')
464 yytext[yyp++] = (usch)ch;
465 unch(ch);
466 yytext[yyp] = 0;
467 return(WSPACE);
469 case '/':
470 if ((ch = inch()) == '/') {
471 do {
472 yytext[yyp++] = (usch)ch;
473 ch = inch();
474 } while (ch && ch != '\n');
475 yytext[yyp] = 0;
476 unch(ch);
477 goto zagain;
478 } else if (ch == '*') {
479 int c, wrn;
480 extern int readmac;
482 if (Cflag && !flslvl && readmac) {
483 unch(ch);
484 yytext[yyp] = 0;
485 return CMNT;
488 wrn = 0;
489 more: while ((c = inch()) && c != '*') {
490 if (c == '\n')
491 putch(c), ifiles->lineno++;
492 else if (c == EBLOCK) {
493 (void)inch();
494 (void)inch();
495 } else if (c == 1) /* WARN */
496 wrn = 1;
498 if (c == 0)
499 return 0;
500 if ((c = inch()) && c != '/') {
501 unch(c);
502 goto more;
504 if (c == 0)
505 return 0;
506 if (!tflag && !Cflag && !flslvl)
507 unch(' ');
508 if (wrn)
509 unch(1);
510 goto zagain;
512 unch(ch);
513 ch = '/';
514 goto any;
516 case '.':
517 ch = inch();
518 if (isdigit(ch)) {
519 yytext[yyp++] = (usch)ch;
520 goto ppnum;
521 } else {
522 unch(ch);
523 ch = '.';
525 goto any;
527 case '\"':
528 if (tflag)
529 goto any;
530 strng:
531 for (;;) {
532 if ((ch = inch()) == '\\') {
533 yytext[yyp++] = (usch)ch;
534 yytext[yyp++] = (usch)inch();
535 continue;
536 } else
537 yytext[yyp++] = (usch)ch;
538 if (ch == '\"')
539 break;
541 yytext[yyp] = 0;
542 return(STRING);
544 case 'L':
545 if ((ch = inch()) == '\"' && !tflag) {
546 yytext[yyp++] = (usch)ch;
547 goto strng;
548 } else if (ch == '\'' && !tflag) {
549 yytext[yyp++] = (usch)ch;
550 goto chlit;
552 unch(ch);
553 /* FALLTHROUGH */
555 /* Yetch, all identifiers */
556 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
557 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
558 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
559 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
560 case 'y': case 'z':
561 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
562 case 'G': case 'H': case 'I': case 'J': case 'K':
563 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
564 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
565 case 'Y': case 'Z':
566 case '_': /* {L}({L}|{D})* */
568 /* Special hacks */
569 for (;;) { /* get chars */
570 ch = inch();
571 if (isalpha(ch) || isdigit(ch) || ch == '_') {
572 yytext[yyp++] = (usch)ch;
573 } else {
574 unch(ch);
575 break;
578 yytext[yyp] = 0; /* need already string */
579 /* end special hacks */
581 return IDENT;
582 default:
583 any:
584 yytext[yyp] = 0;
585 return yytext[0];
587 } /* endcase */
588 goto zagain;
590 yyret:
591 yytext[yyp] = 0;
592 return ch;
596 yylex()
598 static int ifdef, noex;
599 struct symtab *nl;
600 int ch, c2;
602 while ((ch = sloscan()) == WSPACE)
604 if (ch < 128 && spechr[ch] & C_2)
605 c2 = inpch();
606 else
607 c2 = 0;
609 #define C2(a,b,c) case a: if (c2 == b) return c; break
610 switch (ch) {
611 C2('=', '=', EQ);
612 C2('!', '=', NE);
613 C2('|', '|', OROR);
614 C2('&', '&', ANDAND);
615 case '<':
616 if (c2 == '<') return LS;
617 if (c2 == '=') return LE;
618 break;
619 case '>':
620 if (c2 == '>') return RS;
621 if (c2 == '=') return GE;
622 break;
623 case '+':
624 case '-':
625 if (ch == c2)
626 badop("");
627 break;
629 case '/':
630 if (Cflag == 0 || c2 != '*')
631 break;
632 /* Found comment that need to be skipped */
633 for (;;) {
634 ch = inpch();
635 c1: if (ch != '*')
636 continue;
637 if ((ch = inpch()) == '/')
638 break;
639 goto c1;
641 return yylex();
643 case NUMBER:
644 if (yytext[0] == '\'') {
645 yylval.node.op = NUMBER;
646 yylval.node.nd_val = charcon((usch *)yytext);
647 } else
648 cvtdig(yytext[0] != '0' ? 10 :
649 yytext[1] == 'x' || yytext[1] == 'X' ? 16 : 8);
650 return NUMBER;
652 case IDENT:
653 if (strcmp((char *)yytext, "defined") == 0) {
654 ifdef = 1;
655 return DEFINED;
657 nl = lookup((usch *)yytext, FIND);
658 if (ifdef) {
659 yylval.node.nd_val = nl != NULL;
660 ifdef = 0;
661 } else if (nl && noex == 0) {
662 usch *och = stringbuf;
663 int i;
665 i = kfind(nl);
666 unch(WARN);
667 if (i)
668 unpstr(stringbuf);
669 else
670 unpstr(nl->namep);
671 stringbuf = och;
672 noex = 1;
673 return yylex();
674 } else {
675 yylval.node.nd_val = 0;
677 yylval.node.op = NUMBER;
678 return NUMBER;
679 case WARN:
680 noex = 0;
681 return yylex();
682 default:
683 return ch;
685 unch(c2);
686 return ch;
689 usch *yyp, yybuf[CPPBUF];
691 int yywrap(void);
693 static int
694 inpch(void)
696 int len;
698 if (ifiles->curptr < ifiles->maxread)
699 return *ifiles->curptr++;
701 if (ifiles->infil == -1)
702 return -1;
703 if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0)
704 error("read error on file %s", ifiles->orgfn);
705 if (len == 0)
706 return -1;
707 ifiles->curptr = ifiles->buffer;
708 ifiles->maxread = ifiles->buffer + len;
709 return inpch();
712 static int
713 inch(void)
715 int c;
717 again: switch (c = inpch()) {
718 case '\\': /* continued lines */
719 msdos: if ((c = inpch()) == '\n') {
720 ifiles->lineno++;
721 goto again;
722 } else if (c == '\r')
723 goto msdos;
724 unch(c);
725 return '\\';
726 case '?': /* trigraphs */
727 if ((c = chktg())) {
728 unch(c);
729 goto again;
731 return '?';
732 default:
733 return c;
738 * Let the command-line args be faked defines at beginning of file.
740 static void
741 prinit(struct initar *it, struct includ *ic)
743 const char *pre, *post;
744 char *a;
746 if (it->next)
747 prinit(it->next, ic);
748 pre = post = NULL; /* XXX gcc */
749 switch (it->type) {
750 case 'D':
751 pre = "#define ";
752 if ((a = strchr(it->str, '=')) != NULL) {
753 *a = ' ';
754 post = "\n";
755 } else
756 post = " 1\n";
757 break;
758 case 'U':
759 pre = "#undef ";
760 post = "\n";
761 break;
762 case 'i':
763 pre = "#include \"";
764 post = "\"\n";
765 break;
766 default:
767 error("prinit");
769 strlcat((char *)ic->buffer, pre, CPPBUF+1);
770 strlcat((char *)ic->buffer, it->str, CPPBUF+1);
771 if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1)
772 error("line exceeds buffer size");
774 ic->lineno--;
775 while (*ic->maxread)
776 ic->maxread++;
780 * A new file included.
781 * If ifiles == NULL, this is the first file and already opened (stdin).
782 * Return 0 on success, -1 if file to be included is not found.
785 pushfile(const usch *file, const usch *fn, int idx, void *incs)
787 extern struct initar *initar;
788 struct includ ibuf;
789 struct includ *ic;
790 int otrulvl;
792 ic = &ibuf;
793 ic->next = ifiles;
795 if (file != NULL) {
796 if ((ic->infil = open((const char *)file, O_RDONLY)) < 0)
797 return -1;
798 ic->orgfn = ic->fname = file;
799 if (++inclevel > MAX_INCLEVEL)
800 error("Limit for nested includes exceeded");
801 } else {
802 ic->infil = 0;
803 ic->orgfn = ic->fname = (const usch *)"<stdin>";
805 #ifndef BUF_STACK
806 ic->bbuf = malloc(BBUFSZ);
807 #endif
808 ic->buffer = ic->bbuf+NAMEMAX;
809 ic->curptr = ic->buffer;
810 ifiles = ic;
811 ic->lineno = 1;
812 ic->maxread = ic->curptr;
813 ic->idx = idx;
814 ic->incs = incs;
815 ic->fn = fn;
816 prtline();
817 if (initar) {
818 int oin = ic->infil;
819 ic->infil = -1;
820 *ic->maxread = 0;
821 prinit(initar, ic);
822 initar = NULL;
823 if (dMflag)
824 write(ofd, ic->buffer, strlen((char *)ic->buffer));
825 fastscan();
826 prtline();
827 ic->infil = oin;
830 otrulvl = trulvl;
832 fastscan();
834 if (otrulvl != trulvl || flslvl)
835 error("unterminated conditional");
837 #ifndef BUF_STACK
838 free(ic->bbuf);
839 #endif
840 ifiles = ic->next;
841 close(ic->infil);
842 inclevel--;
843 return 0;
847 * Print current position to output file.
849 void
850 prtline()
852 usch *s, *os = stringbuf;
854 if (Mflag) {
855 if (dMflag)
856 return; /* no output */
857 if (ifiles->lineno == 1) {
858 s = sheap("%s: %s\n", Mfile, ifiles->fname);
859 write(ofd, s, strlen((char *)s));
861 } else if (!Pflag)
862 putstr(sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname));
863 stringbuf = os;
866 void
867 cunput(int c)
869 #ifdef CPP_DEBUG
870 // extern int dflag;
871 // if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
872 #endif
873 #if 0
874 if (c == 10) {
875 printf("c == 10!!!\n");
877 #endif
878 unch(c);
881 int yywrap(void) { return 1; }
883 static int
884 dig2num(int c)
886 if (c >= 'a')
887 c = c - 'a' + 10;
888 else if (c >= 'A')
889 c = c - 'A' + 10;
890 else
891 c = c - '0';
892 return c;
896 * Convert string numbers to unsigned long long and check overflow.
898 static void
899 cvtdig(int rad)
901 unsigned long long rv = 0;
902 unsigned long long rv2 = 0;
903 usch *y = yytext;
904 int c;
906 c = *y++;
907 if (rad == 16)
908 y++;
909 while (isxdigit(c)) {
910 rv = rv * rad + dig2num(c);
911 /* check overflow */
912 if (rv / rad < rv2)
913 error("Constant \"%s\" is out of range", yytext);
914 rv2 = rv;
915 c = *y++;
917 y--;
918 while (*y == 'l' || *y == 'L')
919 y++;
920 yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
921 yylval.node.nd_uval = rv;
922 if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
923 yylval.node.op = UNUMBER;
924 if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
925 /* too large for signed, see 6.4.4.1 */
926 error("Constant \"%s\" is out of range", yytext);
929 static int
930 charcon(usch *p)
932 int val, c;
934 p++; /* skip first ' */
935 val = 0;
936 if (*p++ == '\\') {
937 switch (*p++) {
938 case 'a': val = '\a'; break;
939 case 'b': val = '\b'; break;
940 case 'f': val = '\f'; break;
941 case 'n': val = '\n'; break;
942 case 'r': val = '\r'; break;
943 case 't': val = '\t'; break;
944 case 'v': val = '\v'; break;
945 case '\"': val = '\"'; break;
946 case '\'': val = '\''; break;
947 case '\\': val = '\\'; break;
948 case 'x':
949 while (isxdigit(c = *p)) {
950 val = val * 16 + dig2num(c);
951 p++;
953 break;
954 case '0': case '1': case '2': case '3': case '4':
955 case '5': case '6': case '7':
956 p--;
957 while (isdigit(c = *p)) {
958 val = val * 8 + (c - '0');
959 p++;
961 break;
962 default: val = p[-1];
965 } else
966 val = p[-1];
967 return val;
970 static void
971 chknl(int ignore)
973 int t;
975 while ((t = sloscan()) == WSPACE)
977 if (t != '\n') {
978 if (ignore) {
979 warning("newline expected, got \"%s\"", yytext);
980 /* ignore rest of line */
981 while ((t = sloscan()) && t != '\n')
984 else
985 error("newline expected, got \"%s\"", yytext);
989 static void
990 elsestmt(void)
992 if (flslvl) {
993 if (elflvl > trulvl)
995 else if (--flslvl!=0) {
996 flslvl++;
997 } else {
998 trulvl++;
999 prtline();
1001 } else if (trulvl) {
1002 flslvl++;
1003 trulvl--;
1004 } else
1005 error("If-less else");
1006 if (elslvl==trulvl+flslvl)
1007 error("Too many else");
1008 elslvl=trulvl+flslvl;
1009 chknl(1);
1012 static void
1013 skpln(void)
1015 /* just ignore the rest of the line */
1016 while (inch() != '\n')
1018 unch('\n');
1019 flslvl++;
1022 static void
1023 ifdefstmt(void)
1025 int t;
1027 if (flslvl) {
1028 skpln();
1029 return;
1032 t = sloscan();
1033 while (t == WSPACE);
1034 if (t != IDENT)
1035 error("bad ifdef");
1036 if (lookup((usch *)yytext, FIND) == 0) {
1037 putch('\n');
1038 flslvl++;
1039 } else
1040 trulvl++;
1041 chknl(0);
1044 static void
1045 ifndefstmt(void)
1047 int t;
1049 if (flslvl) {
1050 skpln();
1051 return;
1054 t = sloscan();
1055 while (t == WSPACE);
1056 if (t != IDENT)
1057 error("bad ifndef");
1058 if (lookup((usch *)yytext, FIND) != 0) {
1059 putch('\n');
1060 flslvl++;
1061 } else
1062 trulvl++;
1063 chknl(0);
1066 static void
1067 endifstmt(void)
1069 if (flslvl) {
1070 flslvl--;
1071 if (flslvl == 0) {
1072 putch('\n');
1073 prtline();
1075 } else if (trulvl)
1076 trulvl--;
1077 else
1078 error("If-less endif");
1079 if (flslvl == 0)
1080 elflvl = 0;
1081 elslvl = 0;
1082 chknl(1);
1085 static void
1086 ifstmt(void)
1088 if (flslvl == 0) {
1089 if (yyparse() == 0) {
1090 putch('\n');
1091 ++flslvl;
1092 } else
1093 ++trulvl;
1094 } else
1095 ++flslvl;
1098 static void
1099 elifstmt(void)
1101 if (flslvl == 0)
1102 elflvl = trulvl;
1103 if (flslvl) {
1104 if (elflvl > trulvl)
1106 else if (--flslvl!=0)
1107 ++flslvl;
1108 else {
1109 if (yyparse()) {
1110 ++trulvl;
1111 prtline();
1112 } else {
1113 putch('\n');
1114 ++flslvl;
1117 } else if (trulvl) {
1118 ++flslvl;
1119 --trulvl;
1120 } else
1121 error("If-less elif");
1124 static usch *
1125 svinp(void)
1127 int c;
1128 usch *cp = stringbuf;
1130 while ((c = inch()) && c != '\n')
1131 savch(c);
1132 savch('\n');
1133 savch(0);
1134 return cp;
1137 static void
1138 cpperror(void)
1140 usch *cp;
1141 int c;
1143 if (flslvl)
1144 return;
1145 c = sloscan();
1146 if (c != WSPACE && c != '\n')
1147 error("bad error");
1148 cp = svinp();
1149 if (flslvl)
1150 stringbuf = cp;
1151 else
1152 error("%s", cp);
1155 static void
1156 cppwarning(void)
1158 usch *cp;
1159 int c;
1161 if (flslvl)
1162 return;
1163 c = sloscan();
1164 if (c != WSPACE && c != '\n')
1165 error("bad warning");
1167 /* svinp() add an unwanted \n */
1168 cp = stringbuf;
1169 while ((c = inch()) && c != '\n')
1170 savch(c);
1171 savch(0);
1173 if (flslvl)
1174 stringbuf = cp;
1175 else
1176 warning("#warning %s", cp);
1178 unch('\n');
1181 static void
1182 undefstmt(void)
1184 struct symtab *np;
1186 if (sloscan() != WSPACE || sloscan() != IDENT)
1187 error("bad undef");
1188 if (flslvl == 0 && (np = lookup((usch *)yytext, FIND)))
1189 np->value = 0;
1190 chknl(0);
1193 static void
1194 pragmastmt(void)
1196 int c;
1198 if (sloscan() != WSPACE)
1199 error("bad pragma");
1200 if (!flslvl)
1201 putstr((const usch *)"\n#pragma ");
1202 do {
1203 c = inch();
1204 if (!flslvl)
1205 putch(c); /* Do arg expansion instead? */
1206 } while (c && c != '\n');
1207 if (c == '\n')
1208 unch(c);
1209 prtline();
1212 static void
1213 badop(const char *op)
1215 error("invalid operator in preprocessor expression: %s", op);
1219 cinput()
1221 return inch();
1225 * Check for (and convert) trigraphs.
1228 chktg()
1230 int c;
1232 if ((c = inpch()) != '?') {
1233 unch(c);
1234 return 0;
1236 switch (c = inpch()) {
1237 case '=': c = '#'; break;
1238 case '(': c = '['; break;
1239 case ')': c = ']'; break;
1240 case '<': c = '{'; break;
1241 case '>': c = '}'; break;
1242 case '/': c = '\\'; break;
1243 case '\'': c = '^'; break;
1244 case '!': c = '|'; break;
1245 case '-': c = '~'; break;
1246 default:
1247 unch(c);
1248 unch('?');
1249 c = 0;
1251 return c;
1254 static struct {
1255 const char *name;
1256 void (*fun)(void);
1257 } ppd[] = {
1258 { "ifndef", ifndefstmt },
1259 { "ifdef", ifdefstmt },
1260 { "if", ifstmt },
1261 { "include", include },
1262 { "else", elsestmt },
1263 { "endif", endifstmt },
1264 { "error", cpperror },
1265 { "warning", cppwarning },
1266 { "define", define },
1267 { "undef", undefstmt },
1268 { "line", line },
1269 { "pragma", pragmastmt },
1270 { "elif", elifstmt },
1271 #ifdef GCC_COMPAT
1272 { "include_next", include_next },
1273 #endif
1277 * Handle a preprocessor directive.
1279 void
1280 ppdir(void)
1282 char bp[20];
1283 int ch, i;
1285 while ((ch = inch()) == ' ' || ch == '\t')
1287 if (ch == '\n') { /* empty directive */
1288 unch(ch);
1289 return;
1291 if (ch < 'a' || ch > 'z')
1292 goto out; /* something else, ignore */
1293 i = 0;
1294 do {
1295 bp[i++] = (usch)ch;
1296 if (i == sizeof(bp)-1)
1297 goto out; /* too long */
1298 ch = inch();
1299 } while ((ch >= 'a' && ch <= 'z') || (ch == '_'));
1300 unch(ch);
1301 bp[i++] = 0;
1303 /* got keyword */
1304 #define SZ (int)(sizeof(ppd)/sizeof(ppd[0]))
1305 for (i = 0; i < SZ; i++)
1306 if (bp[0] == ppd[i].name[0] && strcmp(bp, ppd[i].name) == 0)
1307 break;
1308 if (i == SZ)
1309 goto out;
1311 /* Found matching keyword */
1312 (*ppd[i].fun)();
1313 return;
1315 out: while ((ch = inch()) != '\n' && ch != -1)
1317 unch('\n');