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