source: mainline/uspace/app/pcc/cc/cpp/token.c@ 2e08dce7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2e08dce7 was 2e08dce7, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

cpp: minor changes and added binary to the iso image

  • Property mode set to 100644
File size: 23.7 KB
Line 
1/* $Id: token.c,v 1.48.2.2 2011/03/12 17:08:26 ragge Exp $ */
2
3/*
4 * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved.
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
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
43#include "config.h"
44
45#include <stdlib.h>
46#include <string.h>
47#include <compat/ctype.h>
48#ifdef HAVE_UNISTD_H
49#include <unistd.h>
50#endif
51#include <fcntl.h>
52#include <errno.h>
53
54#include "compat.h"
55#include "cpp.h"
56#include "y.tab.h"
57
58static void cvtdig(int rad);
59static int charcon(usch *);
60static void elsestmt(void);
61static void ifdefstmt(void);
62static void ifndefstmt(void);
63static void endifstmt(void);
64static void ifstmt(void);
65static void cpperror(void);
66static void pragmastmt(void);
67static void undefstmt(void);
68static void cppwarning(void);
69static void elifstmt(void);
70static void badop(const char *);
71static int chktg(void);
72static void ppdir(void);
73void include(void);
74void include_next(void);
75void define(void);
76static int inpch(void);
77
78extern int yyget_lineno (void);
79extern void yyset_lineno (int);
80
81static int inch(void);
82
83int inif;
84extern int dflag;
85
86#define PUTCH(ch) if (!flslvl) putch(ch)
87/* protection against recursion in #include */
88#define MAX_INCLEVEL 100
89static int inclevel;
90
91/* get next character unaltered */
92#define NXTCH() (ifiles->curptr < ifiles->maxread ? *ifiles->curptr++ : inpch())
93
94usch yytext[CPPBUF];
95
96char 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,
102
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,
107
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,
112
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,
117
118};
119
120/*
121 * No-replacement array. If a macro is found and exists in this array
122 * then no replacement shall occur. This is a stack.
123 */
124struct symtab *norep[RECMAX]; /* Symbol table index table */
125int norepptr = 1; /* Top of index table */
126unsigned short bptr[RECMAX]; /* currently active noexpand macro stack */
127int bidx; /* Top of bptr stack */
128
129static void
130unch(int c)
131{
132
133 --ifiles->curptr;
134 if (ifiles->curptr < ifiles->bbuf)
135 error("pushback buffer full");
136 *ifiles->curptr = (usch)c;
137}
138
139static int
140eatcmnt(void)
141{
142 int ch;
143
144 if (Cflag) { PUTCH('/'); PUTCH('*'); }
145 for (;;) {
146 ch = inch();
147 if (ch == '\n') {
148 ifiles->lineno++;
149 PUTCH('\n');
150 }
151 if (ch == -1)
152 return -1;
153 if (ch == '*') {
154 ch = inch();
155 if (ch == '/') {
156 if (Cflag) {
157 PUTCH('*');
158 PUTCH('/');
159 } else
160 PUTCH(' ');
161 break;
162 }
163 unch(ch);
164 ch = '*';
165 }
166 if (Cflag) PUTCH(ch);
167 }
168 return 0;
169}
170
171/*
172 * Scan quickly the input file searching for:
173 * - '#' directives
174 * - keywords (if not flslvl)
175 * - comments
176 *
177 * Handle strings, numbers and trigraphs with care.
178 * Only data from pp files are scanned here, never any rescans.
179 * TODO: Only print out strings before calling other functions.
180 */
181static void
182fastscan(void)
183{
184 struct symtab *nl;
185 int ch, i, ccnt;
186 usch *cp;
187
188 goto run;
189 for (;;) {
190 ch = NXTCH();
191xloop: 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;
198 }
199 switch (ch) {
200 case EBLOCK:
201 case WARN:
202 case CONC:
203 error("bad char passed");
204 break;
205
206 case '/': /* Comments */
207 if ((ch = inch()) == '/') {
208cppcmt: 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;
220 }
221 break;
222
223 case '?': /* trigraphs */
224 if ((ch = chktg()))
225 goto xloop;
226 PUTCH('?');
227 break;
228
229 case '\\':
230 if ((ch = NXTCH()) == '\n') {
231 ifiles->lineno++;
232 continue;
233 } else {
234 PUTCH('\\');
235 }
236 goto xloop;
237
238 case '\n': /* newlines, for pp directives */
239run2: ifiles->lineno++;
240 do {
241 PUTCH(ch);
242run: 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;
251 }
252 unch(ch);
253 ch = '/';
254 }
255 } while (ch == ' ' || ch == '\t');
256 if (ch == '\\') {
257 ch = NXTCH();
258 if (ch == '\n')
259 goto run2;
260 unch(ch);
261 ch = '\\';
262 }
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 = '%';
274 }
275 }
276 goto xloop;
277
278 case '\"': /* strings */
279str: PUTCH(ch);
280 while ((ch = inch()) != '\"') {
281 PUTCH(ch);
282 if (ch == '\\') {
283 ch = inch();
284 PUTCH(ch);
285 }
286 if (ch < 0)
287 return;
288 }
289 PUTCH(ch);
290 break;
291
292 case '.': /* for pp-number */
293 PUTCH(ch);
294 ch = NXTCH();
295 if (ch < '0' || ch > '9')
296 goto xloop;
297 /* FALLTHROUGH */
298 case '0': case '1': case '2': case '3': case '4':
299 case '5': case '6': case '7': case '8': case '9':
300 do {
301 PUTCH(ch);
302nxt: ch = NXTCH();
303 if (ch == '\\') {
304 ch = NXTCH();
305 if (ch == '\n') {
306 goto nxt;
307 } else {
308 unch(ch);
309 ch = '\\';
310 }
311 }
312 if (spechr[ch] & C_EP) {
313 PUTCH(ch);
314 ch = NXTCH();
315 if (ch == '-' || ch == '+')
316 continue;
317 }
318 } while ((spechr[ch] & C_ID) || (ch == '.'));
319 goto xloop;
320
321 case '\'': /* character literal */
322con: 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;
334 }
335 PUTCH(ch);
336 break;
337
338 case 'L':
339 ch = NXTCH();
340 if (ch == '\"') {
341 PUTCH('L');
342 goto str;
343 }
344 if (ch == '\'') {
345 PUTCH('L');
346 goto con;
347 }
348 unch(ch);
349 ch = 'L';
350 /* FALLTHROUGH */
351 default:
352 if ((spechr[ch] & C_ID) == 0)
353 error("fastscan");
354 if (flslvl) {
355 while (spechr[ch] & C_ID)
356 ch = NXTCH();
357 goto xloop;
358 }
359 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();
371 }
372 }
373 if (ch < 0)
374 return;
375 } while (spechr[ch] & C_ID);
376
377 yytext[i] = 0;
378 unch(ch);
379
380 cp = stringbuf;
381 if ((nl = lookup((usch *)yytext, FIND)) && kfind(nl)) {
382 putstr(stringbuf);
383 } else
384 putstr((usch *)yytext);
385 stringbuf = cp;
386
387 break;
388 }
389 }
390}
391
392int
393sloscan()
394{
395 int ch;
396 int yyp;
397
398zagain:
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;
409
410 case '\r': /* Ignore CR's */
411 yyp = 0;
412 break;
413
414 case '0': case '1': case '2': case '3': case '4': case '5':
415 case '6': case '7': case '8': case '9':
416 /* readin a "pp-number" */
417ppnum: 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;
427 }
428 if ((spechr[ch] & C_ID) || ch == '.') {
429 yytext[yyp++] = (usch)ch;
430 continue;
431 }
432 break;
433 }
434 unch(ch);
435 yytext[yyp] = 0;
436
437 return NUMBER;
438
439 case '\'':
440chlit:
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;
456 }
457 yytext[yyp] = 0;
458
459 return (NUMBER);
460
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);
468
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;
481
482 if (Cflag && !flslvl && readmac) {
483 unch(ch);
484 yytext[yyp] = 0;
485 return CMNT;
486 }
487
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;
497 }
498 if (c == 0)
499 return 0;
500 if ((c = inch()) && c != '/') {
501 unch(c);
502 goto more;
503 }
504 if (c == 0)
505 return 0;
506 if (!tflag && !Cflag && !flslvl)
507 unch(' ');
508 if (wrn)
509 unch(1);
510 goto zagain;
511 }
512 unch(ch);
513 ch = '/';
514 goto any;
515
516 case '.':
517 ch = inch();
518 if (isdigit(ch)) {
519 yytext[yyp++] = (usch)ch;
520 goto ppnum;
521 } else {
522 unch(ch);
523 ch = '.';
524 }
525 goto any;
526
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;
540 }
541 yytext[yyp] = 0;
542 return(STRING);
543
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;
551 }
552 unch(ch);
553 /* FALLTHROUGH */
554
555 /* Yetch, all identifiers */
556 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
557 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
558 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
559 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
560 case 'y': case 'z':
561 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
562 case 'G': case 'H': case 'I': case 'J': case 'K':
563 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
564 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
565 case 'Y': case 'Z':
566 case '_': /* {L}({L}|{D})* */
567
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;
576 }
577 }
578 yytext[yyp] = 0; /* need already string */
579 /* end special hacks */
580
581 return IDENT;
582 default:
583 any:
584 yytext[yyp] = 0;
585 return yytext[0];
586
587 } /* endcase */
588 goto zagain;
589
590yyret:
591 yytext[yyp] = 0;
592 return ch;
593}
594
595int
596yylex()
597{
598 static int ifdef, noex;
599 struct symtab *nl;
600 int ch, c2;
601
602 while ((ch = sloscan()) == WSPACE)
603 ;
604 if (ch < 128 && spechr[ch] & C_2)
605 c2 = inpch();
606 else
607 c2 = 0;
608
609#define C2(a,b,c) case a: if (c2 == b) return c; break
610 switch (ch) {
611 C2('=', '=', EQ);
612 C2('!', '=', NE);
613 C2('|', '|', OROR);
614 C2('&', '&', ANDAND);
615 case '<':
616 if (c2 == '<') return LS;
617 if (c2 == '=') return LE;
618 break;
619 case '>':
620 if (c2 == '>') return RS;
621 if (c2 == '=') return GE;
622 break;
623 case '+':
624 case '-':
625 if (ch == c2)
626 badop("");
627 break;
628
629 case '/':
630 if (Cflag == 0 || c2 != '*')
631 break;
632 /* Found comment that need to be skipped */
633 for (;;) {
634 ch = inpch();
635 c1: if (ch != '*')
636 continue;
637 if ((ch = inpch()) == '/')
638 break;
639 goto c1;
640 }
641 return yylex();
642
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;
651
652 case IDENT:
653 if (strcmp((char *)yytext, "defined") == 0) {
654 ifdef = 1;
655 return DEFINED;
656 }
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;
664
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;
676 }
677 yylval.node.op = NUMBER;
678 return NUMBER;
679 case WARN:
680 noex = 0;
681 return yylex();
682 default:
683 return ch;
684 }
685 unch(c2);
686 return ch;
687}
688
689usch *yyp, yybuf[CPPBUF];
690
691int yywrap(void);
692
693static int
694inpch(void)
695{
696 int len;
697
698 if (ifiles->curptr < ifiles->maxread)
699 return *ifiles->curptr++;
700
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();
710}
711
712static int
713inch(void)
714{
715 int c;
716
717again: switch (c = inpch()) {
718 case '\\': /* continued lines */
719msdos: 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;
730 }
731 return '?';
732 default:
733 return c;
734 }
735}
736
737/*
738 * Let the command-line args be faked defines at beginning of file.
739 */
740static void
741prinit(struct initar *it, struct includ *ic)
742{
743 const char *pre, *post;
744 char *a;
745
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");
768 }
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");
773
774 ic->lineno--;
775 while (*ic->maxread)
776 ic->maxread++;
777}
778
779/*
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.
783 */
784int
785pushfile(const usch *file, const usch *fn, int idx, void *incs)
786{
787 extern struct initar *initar;
788 struct includ ibuf;
789 struct includ *ic;
790 int otrulvl;
791
792 ic = &ibuf;
793 ic->next = ifiles;
794
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 error("Reading from stdin is disabled on HelenOS.");
803 ic->infil = fileno(stdin);
804 ic->orgfn = ic->fname = (const usch *)"<stdin>";
805 }
806#ifndef BUF_STACK
807 ic->bbuf = malloc(BBUFSZ);
808#endif
809 ic->buffer = ic->bbuf+NAMEMAX;
810 ic->curptr = ic->buffer;
811 ifiles = ic;
812 ic->lineno = 1;
813 ic->maxread = ic->curptr;
814 ic->idx = idx;
815 ic->incs = incs;
816 ic->fn = fn;
817 prtline();
818 if (initar) {
819 int oin = ic->infil;
820 ic->infil = -1;
821 *ic->maxread = 0;
822 prinit(initar, ic);
823 initar = NULL;
824 if (dMflag)
825 write(ofd, ic->buffer, strlen((char *)ic->buffer));
826 fastscan();
827 prtline();
828 ic->infil = oin;
829 }
830
831 otrulvl = trulvl;
832
833 fastscan();
834
835 if (otrulvl != trulvl || flslvl)
836 error("unterminated conditional");
837
838#ifndef BUF_STACK
839 free(ic->bbuf);
840#endif
841 ifiles = ic->next;
842 close(ic->infil);
843 inclevel--;
844 return 0;
845}
846
847/*
848 * Print current position to output file.
849 */
850void
851prtline()
852{
853 usch *s, *os = stringbuf;
854
855 if (Mflag) {
856 if (dMflag)
857 return; /* no output */
858 if (ifiles->lineno == 1) {
859 s = sheap("%s: %s\n", Mfile, ifiles->fname);
860 write(ofd, s, strlen((char *)s));
861 }
862 } else if (!Pflag)
863 putstr(sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname));
864 stringbuf = os;
865}
866
867void
868cunput(int c)
869{
870#ifdef CPP_DEBUG
871// extern int dflag;
872// if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c);
873#endif
874#if 0
875if (c == 10) {
876 printf("c == 10!!!\n");
877}
878#endif
879 unch(c);
880}
881
882int yywrap(void) { return 1; }
883
884static int
885dig2num(int c)
886{
887 if (c >= 'a')
888 c = c - 'a' + 10;
889 else if (c >= 'A')
890 c = c - 'A' + 10;
891 else
892 c = c - '0';
893 return c;
894}
895
896/*
897 * Convert string numbers to unsigned long long and check overflow.
898 */
899static void
900cvtdig(int rad)
901{
902 unsigned long long rv = 0;
903 unsigned long long rv2 = 0;
904 usch *y = yytext;
905 int c;
906
907 c = *y++;
908 if (rad == 16)
909 y++;
910 while (isxdigit(c)) {
911 rv = rv * rad + dig2num(c);
912 /* check overflow */
913 if (rv / rad < rv2)
914 error("Constant \"%s\" is out of range", yytext);
915 rv2 = rv;
916 c = *y++;
917 }
918 y--;
919 while (*y == 'l' || *y == 'L')
920 y++;
921 yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER;
922 yylval.node.nd_uval = rv;
923 if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0)
924 yylval.node.op = UNUMBER;
925 if (yylval.node.op == NUMBER && yylval.node.nd_val < 0)
926 /* too large for signed, see 6.4.4.1 */
927 error("Constant \"%s\" is out of range", yytext);
928}
929
930static int
931charcon(usch *p)
932{
933 int val, c;
934
935 p++; /* skip first ' */
936 val = 0;
937 if (*p++ == '\\') {
938 switch (*p++) {
939 case 'a': val = '\a'; break;
940 case 'b': val = '\b'; break;
941 case 'f': val = '\f'; break;
942 case 'n': val = '\n'; break;
943 case 'r': val = '\r'; break;
944 case 't': val = '\t'; break;
945 case 'v': val = '\v'; break;
946 case '\"': val = '\"'; break;
947 case '\'': val = '\''; break;
948 case '\\': val = '\\'; break;
949 case 'x':
950 while (isxdigit(c = *p)) {
951 val = val * 16 + dig2num(c);
952 p++;
953 }
954 break;
955 case '0': case '1': case '2': case '3': case '4':
956 case '5': case '6': case '7':
957 p--;
958 while (isdigit(c = *p)) {
959 val = val * 8 + (c - '0');
960 p++;
961 }
962 break;
963 default: val = p[-1];
964 }
965
966 } else
967 val = p[-1];
968 return val;
969}
970
971static void
972chknl(int ignore)
973{
974 int t;
975
976 while ((t = sloscan()) == WSPACE)
977 ;
978 if (t != '\n') {
979 if (ignore) {
980 warning("newline expected, got \"%s\"", yytext);
981 /* ignore rest of line */
982 while ((t = sloscan()) && t != '\n')
983 ;
984 }
985 else
986 error("newline expected, got \"%s\"", yytext);
987 }
988}
989
990static void
991elsestmt(void)
992{
993 if (flslvl) {
994 if (elflvl > trulvl)
995 ;
996 else if (--flslvl!=0) {
997 flslvl++;
998 } else {
999 trulvl++;
1000 prtline();
1001 }
1002 } else if (trulvl) {
1003 flslvl++;
1004 trulvl--;
1005 } else
1006 error("If-less else");
1007 if (elslvl==trulvl+flslvl)
1008 error("Too many else");
1009 elslvl=trulvl+flslvl;
1010 chknl(1);
1011}
1012
1013static void
1014skpln(void)
1015{
1016 /* just ignore the rest of the line */
1017 while (inch() != '\n')
1018 ;
1019 unch('\n');
1020 flslvl++;
1021}
1022
1023static void
1024ifdefstmt(void)
1025{
1026 int t;
1027
1028 if (flslvl) {
1029 skpln();
1030 return;
1031 }
1032 do
1033 t = sloscan();
1034 while (t == WSPACE);
1035 if (t != IDENT)
1036 error("bad ifdef");
1037 if (lookup((usch *)yytext, FIND) == 0) {
1038 putch('\n');
1039 flslvl++;
1040 } else
1041 trulvl++;
1042 chknl(0);
1043}
1044
1045static void
1046ifndefstmt(void)
1047{
1048 int t;
1049
1050 if (flslvl) {
1051 skpln();
1052 return;
1053 }
1054 do
1055 t = sloscan();
1056 while (t == WSPACE);
1057 if (t != IDENT)
1058 error("bad ifndef");
1059 if (lookup((usch *)yytext, FIND) != 0) {
1060 putch('\n');
1061 flslvl++;
1062 } else
1063 trulvl++;
1064 chknl(0);
1065}
1066
1067static void
1068endifstmt(void)
1069{
1070 if (flslvl) {
1071 flslvl--;
1072 if (flslvl == 0) {
1073 putch('\n');
1074 prtline();
1075 }
1076 } else if (trulvl)
1077 trulvl--;
1078 else
1079 error("If-less endif");
1080 if (flslvl == 0)
1081 elflvl = 0;
1082 elslvl = 0;
1083 chknl(1);
1084}
1085
1086static void
1087ifstmt(void)
1088{
1089 if (flslvl == 0) {
1090 if (yyparse() == 0) {
1091 putch('\n');
1092 ++flslvl;
1093 } else
1094 ++trulvl;
1095 } else
1096 ++flslvl;
1097}
1098
1099static void
1100elifstmt(void)
1101{
1102 if (flslvl == 0)
1103 elflvl = trulvl;
1104 if (flslvl) {
1105 if (elflvl > trulvl)
1106 ;
1107 else if (--flslvl!=0)
1108 ++flslvl;
1109 else {
1110 if (yyparse()) {
1111 ++trulvl;
1112 prtline();
1113 } else {
1114 putch('\n');
1115 ++flslvl;
1116 }
1117 }
1118 } else if (trulvl) {
1119 ++flslvl;
1120 --trulvl;
1121 } else
1122 error("If-less elif");
1123}
1124
1125static usch *
1126svinp(void)
1127{
1128 int c;
1129 usch *cp = stringbuf;
1130
1131 while ((c = inch()) && c != '\n')
1132 savch(c);
1133 savch('\n');
1134 savch(0);
1135 return cp;
1136}
1137
1138static void
1139cpperror(void)
1140{
1141 usch *cp;
1142 int c;
1143
1144 if (flslvl)
1145 return;
1146 c = sloscan();
1147 if (c != WSPACE && c != '\n')
1148 error("bad error");
1149 cp = svinp();
1150 if (flslvl)
1151 stringbuf = cp;
1152 else
1153 error("%s", cp);
1154}
1155
1156static void
1157cppwarning(void)
1158{
1159 usch *cp;
1160 int c;
1161
1162 if (flslvl)
1163 return;
1164 c = sloscan();
1165 if (c != WSPACE && c != '\n')
1166 error("bad warning");
1167
1168 /* svinp() add an unwanted \n */
1169 cp = stringbuf;
1170 while ((c = inch()) && c != '\n')
1171 savch(c);
1172 savch(0);
1173
1174 if (flslvl)
1175 stringbuf = cp;
1176 else
1177 warning("#warning %s", cp);
1178
1179 unch('\n');
1180}
1181
1182static void
1183undefstmt(void)
1184{
1185 struct symtab *np;
1186
1187 if (sloscan() != WSPACE || sloscan() != IDENT)
1188 error("bad undef");
1189 if (flslvl == 0 && (np = lookup((usch *)yytext, FIND)))
1190 np->value = 0;
1191 chknl(0);
1192}
1193
1194static void
1195pragmastmt(void)
1196{
1197 int c;
1198
1199 if (sloscan() != WSPACE)
1200 error("bad pragma");
1201 if (!flslvl)
1202 putstr((const usch *)"\n#pragma ");
1203 do {
1204 c = inch();
1205 if (!flslvl)
1206 putch(c); /* Do arg expansion instead? */
1207 } while (c && c != '\n');
1208 if (c == '\n')
1209 unch(c);
1210 prtline();
1211}
1212
1213static void
1214badop(const char *op)
1215{
1216 error("invalid operator in preprocessor expression: %s", op);
1217}
1218
1219int
1220cinput()
1221{
1222 return inch();
1223}
1224
1225/*
1226 * Check for (and convert) trigraphs.
1227 */
1228int
1229chktg()
1230{
1231 int c;
1232
1233 if ((c = inpch()) != '?') {
1234 unch(c);
1235 return 0;
1236 }
1237 switch (c = inpch()) {
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 case '-': c = '~'; break;
1247 default:
1248 unch(c);
1249 unch('?');
1250 c = 0;
1251 }
1252 return c;
1253}
1254
1255static struct {
1256 const char *name;
1257 void (*fun)(void);
1258} ppd[] = {
1259 { "ifndef", ifndefstmt },
1260 { "ifdef", ifdefstmt },
1261 { "if", ifstmt },
1262 { "include", include },
1263 { "else", elsestmt },
1264 { "endif", endifstmt },
1265 { "error", cpperror },
1266 { "warning", cppwarning },
1267 { "define", define },
1268 { "undef", undefstmt },
1269 { "line", line },
1270 { "pragma", pragmastmt },
1271 { "elif", elifstmt },
1272#ifdef GCC_COMPAT
1273 { "include_next", include_next },
1274#endif
1275};
1276
1277/*
1278 * Handle a preprocessor directive.
1279 */
1280void
1281ppdir(void)
1282{
1283 char bp[20];
1284 int ch, i;
1285
1286 while ((ch = inch()) == ' ' || ch == '\t')
1287 ;
1288 if (ch == '\n') { /* empty directive */
1289 unch(ch);
1290 return;
1291 }
1292 if (ch < 'a' || ch > 'z')
1293 goto out; /* something else, ignore */
1294 i = 0;
1295 do {
1296 bp[i++] = (usch)ch;
1297 if (i == sizeof(bp)-1)
1298 goto out; /* too long */
1299 ch = inch();
1300 } while ((ch >= 'a' && ch <= 'z') || (ch == '_'));
1301 unch(ch);
1302 bp[i++] = 0;
1303
1304 /* got keyword */
1305#define SZ (int)(sizeof(ppd)/sizeof(ppd[0]))
1306 for (i = 0; i < SZ; i++)
1307 if (bp[0] == ppd[i].name[0] && strcmp(bp, ppd[i].name) == 0)
1308 break;
1309 if (i == SZ)
1310 goto out;
1311
1312 /* Found matching keyword */
1313 (*ppd[i].fun)();
1314 return;
1315
1316out: while ((ch = inch()) != '\n' && ch != -1)
1317 ;
1318 unch('\n');
1319}
Note: See TracBrowser for help on using the repository browser.