cpp.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
cpp.c (19265B)
---
1 #include <ctype.h>
2 #include <limits.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <time.h>
7
8 #include <scc/cstd.h>
9 #include <scc/scc.h>
10 #include "cc1.h"
11
12 struct ifstate {
13 unsigned char enabled;
14 unsigned char iselse;
15 };
16
17 static unsigned ncmdlines;
18 static Symbol *symline, *symfile;
19 static struct ifstate ifstate[NR_COND];
20 static int cppoff;
21 static struct items dirinclude;
22
23 unsigned cppctx;
24 int disexpand;
25 int disescape;
26
27 void
28 defdefine(char *name, char *val, char *source)
29 {
30 char buffer[INPUTSIZ+1];
31 char *def, *fmt = "#define %s %s\n";
32 Symbol *sym = &(Symbol) {
33 .name = name,
34 .flags = SDECLARED,
35 };
36
37 if (!val)
38 val = "";
39 if (strlen(fmt) + strlen(name) + strlen(val) > INPUTSIZ) {
40 errorp("macro definition '%s' too big", name);
41 return;
42 }
43
44 sprintf(buffer, fmt, name, val);
45 lineno = ++ncmdlines;
46
47 addinput(IPARAM, buffer, FAIL);
48 cpp();
49 delinput();
50 }
51
52 void
53 undefmacro(char *s)
54 {
55 killsym(lookup(NS_CPP, s, NOALLOC));
56 }
57
58 void
59 icpp(void)
60 {
61 struct tm *tm;
62 time_t t;
63 static char sdate[14], stime[11];
64 static struct {
65 char *name;
66 char *value;
67 } *bp, list[] = {
68 {"__STDC__", "1"},
69 {"__STDC_HOSTED__", "1"},
70 {"__SCC__", "1"},
71 {"__DATE__", sdate},
72 {"__TIME__", stime},
73 {"__STDC_VERSION__", STDC_VERSION},
74 {"__LINE__", NULL},
75 {"__FILE__", NULL},
76 {NULL, NULL}
77 };
78
79 t = time(NULL);
80 tm = localtime(&t);
81 strftime(sdate, sizeof(sdate), "\"%b %d %Y\"", tm);
82 strftime(stime, sizeof(stime), "\"%H:%M:%S\"", tm);
83
84 for (bp = list; bp->name; ++bp)
85 defdefine(bp->name, bp->value, "built-in");
86
87 symline = lookup(NS_CPP, "__LINE__", ALLOC);
88 symfile = lookup(NS_CPP, "__FILE__", ALLOC);
89
90 ncmdlines = 0;
91 }
92
93 static void
94 nextcpp(Macro *mp)
95 {
96 int len, siz;
97 char *arg;
98
99 next();
100 if (yytoken == EOFTOK) {
101 error("unterminated argument list invoking macro \"%s\"",
102 mp->sym->name);
103 }
104
105 if (yytoken == IDEN)
106 yylval.sym->flags |= SUSED;
107
108 len = strlen(yytext);
109 siz = mp->argsiz;
110 if (len+1 > INT_MAX - siz) {
111 error("too long argument invoking macro \"%s\"",
112 mp->sym->name);
113 }
114
115 arg = xrealloc(mp->arg, siz + len + 1);
116 if (siz > 0) {
117 arg[siz-1] = ' ';
118 memcpy(arg + siz, yytext, len+1);
119 } else {
120 memcpy(arg, yytext, len+1);
121 }
122
123 mp->arg = arg;
124 mp->argsiz = siz + len + 1;
125 }
126
127 static void
128 paren(Macro *mp)
129 {
130 for (;;) {
131 nextcpp(mp);
132 switch (yytoken) {
133 case ')':
134 return;
135 case '(':
136 paren(mp);
137 break;
138 }
139 }
140 }
141
142 static char *
143 parameter(Macro *mp)
144 {
145 int siz;
146 char *s, *begin, *end;
147 Input *ip = input;
148
149 mp->arg = NULL;
150 mp->argsiz = 0;
151 for (;;) {
152 nextcpp(mp);
153 switch (yytoken) {
154 case ')':
155 case ',':
156 /* remove "," or ")"*/
157 begin = mp->arg;
158 end = mp->arg + mp->argsiz - 2;
159
160 while (end > begin && isspace(end[-1]))
161 --end;
162 while (begin < end && isspace(begin[0]))
163 ++begin;
164
165 siz = end - begin;
166 s = memcpy(xmalloc(siz+1), begin, siz);
167 s[siz] = '\0';
168 free(mp->arg);
169
170 return s;
171 case '(':
172 paren(mp);
173 break;
174 }
175 }
176 }
177
178 static int
179 parsepars(Macro *mp)
180 {
181 int n;
182
183 if (mp->npars == -1)
184 return 1;
185 if (ahead() != '(')
186 return 0;
187
188 disexpand = 1;
189 next();
190 n = 0;
191
192 if (mp->npars == 0 && ahead() == ')') {
193 next();
194 } else {
195 do {
196 mp->arglist = xrealloc(mp->arglist, (n+1)*sizeof(char *));
197 mp->arglist[n] = parameter(mp);
198 DBG("MACRO fetched arg '%s'", mp->arglist[n]);
199 } while (++n < NR_MACROARG && yytoken == ',');
200 }
201
202 if (yytoken != ')')
203 error("incorrect macro function-alike invocation");
204 disexpand = 0;
205
206 if (n == NR_MACROARG)
207 error("too many parameters in macro \"%s\"", mp->sym->name);
208 if (n != mp->npars) {
209 error("macro \"%s\" received %d arguments, but it takes %d",
210 mp->sym->name, n, mp->npars);
211 }
212
213 return 1;
214 }
215
216 static int
217 concatoper(char *def, char *cur)
218 {
219 char *s;
220
221 for (s = cur + 4; isspace(*s); ++s)
222 ;
223 if (*s == CONCAT)
224 return 1;
225
226 for (s = cur; s > def && isspace(s[-1]); --s)
227 ;
228 if (s > def && s[-1] == CONCAT)
229 return 1;
230
231 return 0;
232 }
233
234 static int
235 expandarg(char *arg, char *def, char *curdef, char *buf, int bufsiz)
236 {
237 int siz;
238 char *s = buf;
239
240 /* gives priority to concatenation operators */
241 if (concatoper(def, curdef)) {
242 siz = strlen(arg);
243 if (siz >= bufsiz) {
244 siz = -1;
245 } else {
246 memcpy(buf, arg, siz);
247 buf += siz;
248 }
249 } else {
250 addinput(IPARAM, arg, FAIL);
251 for (siz = 0; next() != EOFTOK; siz += yylen+1) {
252 if (yylen > bufsiz-2) {
253 siz = -1;
254 break;
255 }
256 memcpy(buf, yytext, yylen);
257 bufsiz -= yylen + 1;
258 buf += yylen;
259 *buf++ = ' ';
260 }
261
262 delinput();
263 }
264 *buf = '\0';
265
266 DBG("MACRO parameter '%s' expanded to '%s'", arg, s);
267
268 return siz;
269 }
270
271 static int
272 copymacro(Macro *mp)
273 {
274 int delim, c, esc;
275 char *s, *p, *arg, *bp;
276 int size, bufsiz;
277
278 if (mp->sym == symfile)
279 return sprintf(mp->buffer, "\"%s\" ", filenam);
280 if (mp->sym == symline)
281 return sprintf(mp->buffer, "%d ", lineno);
282
283 bp = mp->buffer;
284 bufsiz = mp->bufsiz;
285 for (s = mp->def; c = *s; ++s) {
286 switch (c) {
287 case '\'':
288 delim = '\'';
289 goto search_delim;
290 case '\"':
291 delim = '"';
292 search_delim:
293 esc = 0;
294 p = s;
295 for (++s; c = *s; ++s) {
296 if (c == '\\' && !esc)
297 esc = 1;
298 else if (c == delim &&!esc)
299 break;
300 else
301 esc = 0;
302 }
303 size = s - p + 1;
304 if (size > bufsiz)
305 goto expansion_too_long;
306 memcpy(bp, p, size);
307 bufsiz -= size;
308 bp += size;
309 break;
310 case CONCAT:
311 /* token concatenation operator */
312 DBG("MACRO concat");
313 while (bp[-1] == ' ')
314 --bp, ++bufsiz;
315 while (s[1] == ' ')
316 ++s;
317 break;
318 case STRINGIZE:
319 /* stringfier operator */
320 DBG("MACRO stringize");
321 arg = mp->arglist[atoi(s += 2)];
322 s += 2;
323
324 if (bufsiz < 3)
325 goto expansion_too_long;
326
327 *bp++ = '"';
328 while ((c = *arg++) != '\0') {
329 if (c == '"') {
330 if (bufsiz < 3)
331 goto expansion_too_long;
332 *bp++ = '\\';
333 *bp++ = '"';
334 bufsiz -= 2;
335 } else {
336 if (bufsiz < 2)
337 goto expansion_too_long;
338 *bp++ = c;
339 bufsiz--;
340 }
341 }
342 *bp++ = '"';
343
344 break;
345 case MACROPAR:
346 /* parameter substitution */
347 arg = mp->arglist[atoi(s+1)];
348 size = expandarg(arg, mp->def, s, bp, bufsiz);
349 if (size < 0)
350 goto expansion_too_long;
351 bp += size;
352 bufsiz -= size;
353 s += 3;
354 break;
355 default:
356 if (bufsiz-- == 0)
357 goto expansion_too_long;
358 *bp++ = c;
359 break;
360 }
361 }
362 *bp = '\0';
363
364 return bp - mp->buffer;
365
366 expansion_too_long:
367 error("macro expansion of \"%s\" too long", mp->sym->name);
368 }
369
370 static void
371 addhideset(Input *ip, Symbol *sym)
372 {
373 Symbol **set;
374 Symbol **p;
375
376 set = ip->macro->hideset;
377 for (p = set; p < &set[NR_MACROARG] && *p; ++p) {
378 if (*p == sym)
379 return;
380 }
381
382 if (p == &set[NR_MACROARG])
383 error("too complex macro expansion");
384
385 *p = sym;
386 DBG("MACRO Adding %s to hideset of %s",
387 sym->name, ip->macro->sym->name);
388 }
389
390 static void
391 hide(Symbol *sym)
392 {
393 DBG("SYM: hidding symbol %s %d", sym->name, sym->hide);
394 sym->hide = 1;
395 }
396
397 static void
398 unhide(Symbol *sym)
399 {
400 DBG("SYM: unhidding symbol %s %d", sym->name, sym->hide);
401 sym->hide = 0;
402 }
403
404 void
405 delmacro(Macro *mp)
406 {
407 int i;
408 Symbol **p;
409
410 if (!mp)
411 return;
412
413 if (mp->arglist) {
414 for (i = 0; i < mp->npars; i++)
415 free(mp->arglist[i]);
416 }
417
418 for (p = mp->hideset; p < &mp->hideset[NR_MACROARG] && *p; ++p)
419 unhide(*p);
420
421 free(mp->arglist);
422 free(mp);
423 }
424
425 Macro *
426 newmacro(Symbol *sym)
427 {
428 Macro *mp;
429
430 mp = xmalloc(sizeof(*mp));
431 *mp = (Macro) {0};
432 mp->sym = sym;
433 mp->def = sym->u.s + 3;
434 if (sym->u.s)
435 mp->npars = atoi(sym->u.s);
436
437 return mp;
438 }
439
440 int
441 expand(Symbol *sym)
442 {
443 int siz;
444 Macro *mp;
445 Input *ip;
446 Symbol **p;
447
448 DBG("MACRO '%s' detected disexpand=%d hide=%d",
449 sym->name, disexpand, sym->hide);
450
451 if (disexpand || sym->hide || sym->token != IDEN)
452 return 0;
453
454 mp = newmacro(sym);
455 mp->fname = filenam;
456
457 if (!parsepars(mp)) {
458 delmacro(mp);
459 return 0;
460 }
461
462 addinput(IMACRO, mp, FAIL);
463 mp->buffer = input->line;
464 mp->bufsiz = INPUTSIZ-1;
465
466 siz = copymacro(mp);
467 mp->buffer[siz] = '\0';
468
469 for (ip = input; ip; ip = ip->next) {
470 if ((ip->flags & ITYPE) == IMACRO)
471 addhideset(ip, sym);
472 }
473
474 for (p = mp->hideset; p < &mp->hideset[NR_MACROARG] && *p; ++p)
475 hide(*p);
476
477 DBG("MACRO '%s' expanded to :'%s'", mp->sym->name, mp->buffer);
478
479 return 1;
480 }
481
482 static int
483 getpars(Symbol *args[NR_MACROARG])
484 {
485 int n, c;
486 Symbol *sym;
487
488 c = *input->p;
489 next();
490 if (c != '(')
491 return -1;
492
493 /* skip the '(' */
494 next();
495 if (accept(')'))
496 return 0;
497
498 n = 0;
499 do {
500 if (n == NR_MACROARG) {
501 cpperror("too many parameters in macro");
502 return NR_MACROARG;
503 }
504 if (accept(ELLIPSIS)) {
505 args[n++] = NULL;
506 break;
507 }
508 if (yytoken != IDEN) {
509 cpperror("macro arguments must be identifiers");
510 return NR_MACROARG;
511 }
512 if ((sym = install(NS_IDEN, yylval.sym)) == NULL) {
513 errorp("duplicated macro parameter '%s'", yytext);
514 } else {
515 sym->flags |= SUSED;
516 args[n++] = sym;
517 }
518 next();
519 } while (accept(','));
520 expect(')');
521
522 return n;
523 }
524
525 static int
526 getdefs(Symbol *args[NR_MACROARG], int nargs, char *bp, size_t bufsiz)
527 {
528 Symbol **argp;
529 int siz;
530 size_t len;
531 int prevc = 0, ispar;
532
533 if (yytoken == CONCAT)
534 goto wrong_concat;
535
536 for (;;) {
537 ispar = 0;
538 if (yytoken == IDEN && nargs >= 0) {
539 for (argp = args; argp < &args[nargs]; ++argp) {
540 if (*argp == yylval.sym)
541 break;
542 }
543 if (argp != &args[nargs]) {
544 siz = argp - args;
545 sprintf(yytext,
546 "%c%02d%c", MACROPAR, siz, MACROPAR);
547 ispar = 1;
548 }
549 }
550 if (prevc == STRINGIZE && !ispar) {
551 cpperror("'#' is not followed by a macro parameter");
552 return 0;
553 }
554 if (yytoken == '\n')
555 break;
556
557 if ((len = strlen(yytext)) >= bufsiz) {
558 cpperror("macro too long");
559 return 0;
560 }
561 if (yytoken == CONCAT || yytoken == STRINGIZE) {
562 *bp++ = yytoken;
563 --bufsiz;
564 } else {
565 memcpy(bp, yytext, len);
566 bp += len;
567 bufsiz -= len;
568 }
569 if ((prevc = yytoken) != STRINGIZE) {
570 *bp++ = ' ';
571 --bufsiz;
572 }
573 next();
574 }
575
576 if (prevc == CONCAT)
577 goto wrong_concat;
578
579 *bp = '\0';
580 return 1;
581
582 wrong_concat:
583 cpperror("'##' cannot appear at either ends of a macro expansion");
584 return 0;
585 }
586
587 static void
588 define(void)
589 {
590 Symbol *sym,*args[NR_MACROARG];
591 char buff[LINESIZ+1];
592 int n;
593
594 if (cppoff)
595 return;
596
597 disescape = 1;
598 namespace = NS_CPP;
599 next();
600
601 if (yytoken != IDEN) {
602 cpperror("macro names must be identifiers");
603 return;
604 }
605 sym = yylval.sym;
606 if (sym->flags & SDECLARED) {
607 warn("'%s' redefined", yytext);
608 free(sym->u.s);
609 } else {
610 sym = install(NS_CPP, sym);
611 sym->flags |= SDECLARED|SSTRING;
612 }
613
614 namespace = NS_IDEN; /* Avoid polution in NS_CPP */
615 if ((n = getpars(args)) == NR_MACROARG)
616 goto delete;
617 if (n > 0 && !args[n-1]) /* it is a variadic function */
618 --n;
619
620 sprintf(buff, "%02d#", n);
621 if (!getdefs(args, n, buff+3, LINESIZ-3))
622 goto delete;
623 sym->u.s = xstrdup(buff);
624 DBG("MACRO '%s' defined as '%s'", sym->name, buff);
625 return;
626
627 delete:
628 killsym(sym);
629 }
630
631 void
632 incdir(char *dir)
633 {
634 if (!dir || *dir == '\0')
635 die("cc1: incorrect -I flag");
636 newitem(&dirinclude, dir);
637 }
638
639 static int
640 includefile(char *dir, char *file, size_t filelen)
641 {
642 size_t dirlen;
643 char path[FILENAME_MAX];
644
645 if (!dir) {
646 dirlen = 0;
647 if (filelen > FILENAME_MAX-1)
648 return 0;
649 } else {
650 dirlen = strlen(dir);
651 if (dirlen + filelen > FILENAME_MAX-2)
652 return 0;
653 memcpy(path, dir, dirlen);
654 if (dir[dirlen-1] != '/')
655 path[dirlen++] = '/';
656 }
657 memcpy(path+dirlen, file, filelen);
658 path[dirlen + filelen] = '\0';
659
660 return addinput(IFILE, path, NOFAIL);
661 }
662
663 static char *
664 cwd(char *buf)
665 {
666 char *p, *s = filenam;
667 size_t len;
668
669 if ((p = strrchr(s, '/')) == NULL)
670 return NULL;
671 if ((len = p - s) >= FILENAME_MAX)
672 die("cc1: current work directory too long");
673 memcpy(buf, s, len);
674 buf[len] = '\0';
675 return buf;
676 }
677
678 static void
679 include(void)
680 {
681 char dir[FILENAME_MAX], file[FILENAME_MAX], *p, **bp;
682 size_t filelen;
683 int n;
684
685 if (cppoff)
686 return;
687
688 disexpand = 0;
689 namespace = NS_IDEN;
690 next();
691
692 switch (*yytext) {
693 case '<':
694 if ((p = strchr(input->begin, '>')) == NULL || p[-1] == '<')
695 goto bad_include;
696 filelen = p - input->begin;
697 if (filelen >= FILENAME_MAX)
698 goto too_long;
699 memcpy(file, input->begin, filelen);
700 file[filelen] = '\0';
701
702 input->begin = input->p = p+1;
703 if (next() != '\n')
704 goto trailing_characters;
705
706 break;
707 case '"':
708 if (yylen < 3)
709 goto bad_include;
710 filelen = yylen-2;
711 if (filelen >= FILENAME_MAX)
712 goto too_long;
713 memcpy(file, yytext+1, filelen);
714 file[filelen] = '\0';
715
716 if (next() != '\n')
717 goto trailing_characters;
718
719 if (includefile(cwd(dir), file, filelen))
720 goto its_done;
721 break;
722 default:
723 goto bad_include;
724 }
725
726 n = dirinclude.n;
727 for (bp = dirinclude.s; n--; ++bp) {
728 if (includefile(*bp, file, filelen))
729 goto its_done;
730 }
731 cpperror("included file '%s' not found", file);
732
733 its_done:
734 return;
735
736 trailing_characters:
737 cpperror("trailing characters after preprocessor directive");
738 return;
739
740 too_long:
741 cpperror("too long file name in #include");
742 return;
743
744 bad_include:
745 cpperror("#include expects \"FILENAME\" or <FILENAME>");
746 return;
747 }
748
749 static void
750 line(void)
751 {
752 long n;
753 char *endp, *fname;
754
755 if (cppoff)
756 return;
757
758 disexpand = 0;
759 next();
760 n = strtol(yytext, &endp, 10);
761 if (n <= 0 || n > USHRT_MAX || *endp != '\0') {
762 cpperror("first parameter of #line is not a positive integer");
763 return;
764 }
765
766 next();
767 if (yytoken == '\n') {
768 fname = NULL;
769 } else {
770 if (*yytext != '\"' || yylen == 1) {
771 cpperror("second parameter of #line is not a valid filename");
772 return;
773 }
774 fname = yylval.sym->u.s;
775 }
776 setloc(fname, n - 1);
777 if (yytoken != '\n')
778 next();
779 }
780
781 static void
782 pragma(void)
783 {
784 if (cppoff)
785 return;
786 next();
787 warn("ignoring pragma '%s'", yytext);
788 *input->p = '\0';
789 next();
790 }
791
792 static void
793 usererr(void)
794 {
795 if (cppoff)
796 return;
797 cpperror("#error %s", input->p);
798 exit(EXIT_FAILURE);
799 next();
800 }
801
802
803 Node *
804 defined(void)
805 {
806 Symbol *sym;
807 int paren;
808
809 disexpand = 1;
810 next();
811 paren = accept('(');
812 if (yytoken != IDEN && yytoken != TYPEIDEN)
813 cpperror("operator 'defined' requires an identifier");
814 if (yytoken == TYPEIDEN || !(yylval.sym->flags & SDECLARED))
815 sym = zero;
816 else
817 sym = one;
818 disexpand = 0;
819 next();
820 if (paren)
821 expect(')');
822 return constnode(sym);
823 }
824
825 static void
826 ifclause(int negate, int isifdef)
827 {
828 Symbol *sym;
829 unsigned n;
830 int status;
831 Node *expr;
832
833 if (cppctx == NR_COND-1)
834 error("too many nesting levels of conditional inclusion");
835 n = cppctx++;
836
837 if (cppoff) {
838 status = 0;
839 goto disabled;
840 }
841
842 namespace = NS_CPP;
843 next();
844
845 if (isifdef) {
846 if (yytoken != IDEN) {
847 cpperror("no macro name given in #%s directive",
848 (negate) ? "ifndef" : "ifdef");
849 return;
850 }
851 sym = yylval.sym;
852 next();
853 status = (sym->flags & SDECLARED) != 0;
854 if (!status)
855 killsym(sym);
856 } else {
857 /* TODO: catch recovery here */
858 if ((expr = constexpr()) == NULL) {
859 cpperror("parameter of #if is not an integer constant expression");
860 return;
861 }
862 DBG("CPP if expr=%d", expr->sym->u.i);
863 status = expr->sym->u.i != 0;
864 freetree(expr);
865 }
866
867 if (negate)
868 status = !status;
869
870 disabled:
871 if (status == 0)
872 ++cppoff;
873 DBG("CPP if result=%d", status);
874 ifstate[n].enabled = status;
875 ifstate[n].iselse = 0;
876 }
877
878 static void
879 cppif(void)
880 {
881 disexpand = 0;
882 ifclause(0, 0);
883 }
884
885 static void
886 ifdef(void)
887 {
888 ifclause(0, 1);
889 }
890
891 static void
892 ifndef(void)
893 {
894 ifclause(1, 1);
895 }
896
897 static void
898 elseclause(void)
899 {
900 int status;
901
902 status = ifstate[cppctx-1].enabled;
903 ifstate[cppctx-1].enabled = !status;
904 cppoff += (status) ? 1 : -1;
905 }
906
907 static void
908 cppelse(void)
909 {
910 if (cppctx == 0 || ifstate[cppctx-1].iselse) {
911 cpperror("#else without #ifdef/ifndef");
912 return;
913 }
914
915 ifstate[cppctx-1].iselse = 1;
916 elseclause();
917 next();
918 }
919
920 static void
921 elif(void)
922 {
923 if (cppctx == 0 || ifstate[cppctx-1].iselse) {
924 cpperror("#elif without #ifdef/ifndef");
925 return;
926 }
927
928 elseclause();
929 if (ifstate[cppctx-1].enabled) {
930 --cppctx;
931 cppif();
932 }
933 }
934
935 static void
936 endif(void)
937 {
938 if (cppctx == 0)
939 error("#endif without #if");
940 if (!ifstate[--cppctx].enabled)
941 --cppoff;
942 next();
943 }
944
945 static void
946 undef(void)
947 {
948 if (cppoff)
949 return;
950
951 namespace = NS_CPP;
952 next();
953 if (yytoken != IDEN) {
954 error("no macro name given in #undef directive");
955 return;
956 }
957 killsym(yylval.sym);
958 next();
959 }
960
961 int
962 cpp(void)
963 {
964 static struct {
965 unsigned char token;
966 void (*fun)(void);
967 } *bp, clauses [] = {
968 {DEFINE, define},
969 {INCLUDE, include},
970 {LINE, line},
971 {IFDEF, ifdef},
972 {IF, cppif},
973 {ELIF, elif},
974 {IFNDEF, ifndef},
975 {ELSE, cppelse},
976 {ENDIF, endif},
977 {UNDEF, undef},
978 {PRAGMA, pragma},
979 {ERROR, usererr},
980 {0, NULL}
981 };
982 int ns;
983 char *p;
984
985 for (p = input->p; isspace(*p); ++p)
986 ;
987
988 if (*p != '#') {
989 if (cppoff)
990 *input->p = '\0';
991 return cppoff;
992 }
993 input->p = p+1;
994
995 disexpand = 1;
996 lexmode = CPPMODE;
997 ns = namespace;
998 namespace = NS_CPPCLAUSES;
999 next();
1000 namespace = NS_IDEN;
1001
1002 if (yytoken == '\n')
1003 goto ret;
1004
1005 for (bp = clauses; bp->token && bp->token != yytoken; ++bp)
1006 ;
1007 if (!bp->token) {
1008 errorp("incorrect preprocessor directive '%s'", yytext);
1009 goto ret;
1010 }
1011
1012 DBG("CPP %s", yytext);
1013
1014 /*
1015 * create a new context to avoid polish the current context,
1016 * and to get all the symbols freed at the end
1017 */
1018 pushctx();
1019 (*bp->fun)();
1020 popctx();
1021
1022 /*
1023 * #include changes the content of input->line, so the correctness
1024 * of the line must be checked in the own include(), and we have
1025 * to skip this tests. For the same reason include() is the only
1026 * function which does not prepare the next token
1027 */
1028 if (bp->token == INCLUDE)
1029 goto ret;
1030
1031 if (yytoken != '\n' && yytoken != EOFTOK && !cppoff)
1032 cpperror("trailing characters after preprocessor directive");
1033
1034 ret:
1035 disescape = 0;
1036 disexpand = 0;
1037 lexmode = CCMODE;
1038 namespace = ns;
1039
1040 /*
1041 * at this point we know that the cpp line is processed, and any error
1042 * is generated but as next is called we cannot be sure that input is
1043 * valid anymore, but in case of begin valid we want to discard any
1044 * pending input in the current line
1045 */
1046 if (input)
1047 *input->p = '\0';
1048
1049 return 1;
1050 }
1051
1052 void
1053 ppragmaln(void)
1054 {
1055 static char file[FILENAME_MAX];
1056 static unsigned nline;
1057 char *s;
1058
1059 putchar('\n');
1060 if (strcmp(file, filenam)) {
1061 strcpy(file, filenam);
1062 s = "#line %u \"%s\"\n";
1063 } else if (nline+1 != lineno) {
1064 s = "#line %u\n";
1065 } else {
1066 s = "";
1067 }
1068 nline = lineno;
1069 printf(s, nline, file);
1070 }
1071
1072 void
1073 outcpp(void)
1074 {
1075 int c;
1076 char *s, *t;
1077
1078 for (next(); yytoken != EOFTOK; next()) {
1079 if (onlyheader)
1080 continue;
1081 if (yytoken != STRING) {
1082 printf("%s ", yytext);
1083 continue;
1084 }
1085 for (s = yytext; (c = *s) != '\0'; ++s) {
1086 switch (c) {
1087 case '\n':
1088 t = "\\n";
1089 goto print_str;
1090 case '\v':
1091 t = "\\v";
1092 goto print_str;
1093 case '\b':
1094 t = "\\b";
1095 goto print_str;
1096 case '\t':
1097 t = "\\t";
1098 goto print_str;
1099 case '\a':
1100 t = "\\a";
1101 goto print_str;
1102 case '\f':
1103 t = "\\f";
1104 goto print_str;
1105 case '\r':
1106 t = "\\r";
1107 goto print_str;
1108 case '"':
1109 if (s == yytext || s[1] == '\0')
1110 goto print_chr;
1111 t = "\\\"";
1112 goto print_str;
1113 case '\'':
1114 t = "\\'";
1115 goto print_str;
1116 case '\?':
1117 t = "\\\?";
1118 goto print_str;
1119 case '\\':
1120 putchar('\\');
1121 default:
1122 print_chr:
1123 if (!isprint(c))
1124 printf("\\x%x", c);
1125 else
1126 putchar(c);
1127 break;
1128 print_str:
1129 fputs(t, stdout);
1130 break;
1131 }
1132 }
1133 putchar(' ');
1134 }
1135 putchar('\n');
1136 }