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