cpp.c (14562B)
1 static char sccsid[] = "@(#) ./cc1/cpp.c"; 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 <cstd.h> 10 #include "../inc/scc.h" 11 #include "cc1.h" 12 13 static char *argp, *macroname; 14 static unsigned arglen; 15 static unsigned ncmdlines; 16 static Symbol *symline, *symfile; 17 static unsigned char ifstatus[NR_COND]; 18 static int cppoff; 19 static struct items dirinclude; 20 21 unsigned cppctx; 22 int disexpand; 23 24 void 25 defdefine(char *macro, char *val, char *source) 26 { 27 char *def, *fmt = "#define %s %s\n"; 28 Symbol dummy = {.flags = SDECLARED}; 29 30 if (!val) 31 val = ""; 32 def = xmalloc(strlen(fmt) + strlen(macro) + strlen(val)); 33 34 sprintf(def, fmt, macro, val); 35 lineno = ++ncmdlines; 36 addinput(source, &dummy, def); 37 cpp(); 38 delinput(); 39 } 40 41 void 42 undefmacro(char *s) 43 { 44 killsym(lookup(NS_CPP, s, NOALLOC)); 45 } 46 47 void 48 icpp(void) 49 { 50 static char sdate[14], stime[11]; 51 struct tm *tm; 52 time_t t; 53 static char **bp, *list[] = { 54 "__STDC__", 55 "__STDC_HOSTED__", 56 "__SCC__", 57 NULL 58 }; 59 static struct keyword keys[] = { 60 {"define", DEFINE, DEFINE}, 61 {"include", INCLUDE, INCLUDE}, 62 {"line", LINE, LINE}, 63 {"ifdef", IFDEF, IFDEF}, 64 {"if", IF, IF}, 65 {"elif", ELIF, ELIF}, 66 {"else", ELSE, ELSE}, 67 {"ifndef", IFNDEF, IFNDEF}, 68 {"endif", ENDIF, ENDIF}, 69 {"undef", UNDEF, UNDEF}, 70 {"pragma", PRAGMA, PRAGMA}, 71 {"error", ERROR, ERROR}, 72 {NULL, 0, 0} 73 }; 74 75 keywords(keys, NS_CPPCLAUSES); 76 77 t = time(NULL); 78 tm = localtime(&t); 79 strftime(sdate, sizeof(sdate), "\"%b %d %Y\"", tm); 80 strftime(stime, sizeof(stime), "\"%H:%M:%S\"", tm); 81 defdefine("__DATE__", sdate, "built-in"); 82 defdefine("__TIME__", stime, "built-in"); 83 defdefine("__STDC_VERSION__", STDC_VERSION, "built-in"); 84 defdefine("__LINE__", NULL, "built-in"); 85 defdefine("__FILE__", NULL, "built-in"); 86 87 symline = lookup(NS_CPP, "__LINE__", ALLOC); 88 symfile = lookup(NS_CPP, "__FILE__", ALLOC); 89 90 for (bp = list; *bp; ++bp) 91 defdefine(*bp, "1", "built-in"); 92 93 ncmdlines = 0; 94 } 95 96 static void 97 nextcpp(void) 98 { 99 next(); 100 if (yytoken == EOFTOK) 101 error("unterminated argument list invoking macro \"%s\"", 102 macroname); 103 if (yylen + 1 > arglen) 104 error("argument overflow invoking macro \"%s\"", 105 macroname); 106 if (yytoken == IDEN) 107 yylval.sym->flags |= SUSED; 108 memcpy(argp, yytext, yylen); 109 argp += yylen; 110 *argp++ = ' '; 111 arglen -= yylen + 1; 112 } 113 114 static void 115 paren(void) 116 { 117 for (;;) { 118 nextcpp(); 119 switch (yytoken) { 120 case ')': 121 return; 122 case '(': 123 paren(); 124 break; 125 } 126 } 127 } 128 129 static void 130 parameter(void) 131 { 132 for (;;) { 133 nextcpp(); 134 switch (yytoken) { 135 case ')': 136 case ',': 137 argp -= 3; /* remove " , " or " ) "*/ 138 *argp++ = '\0'; 139 return; 140 case '(': 141 paren(); 142 break; 143 } 144 } 145 } 146 147 static int 148 parsepars(char *buffer, char **listp, int nargs) 149 { 150 int n; 151 152 if (nargs == -1) 153 return -1; 154 if (ahead() != '(' && nargs > 0) 155 return 0; 156 157 disexpand = 1; 158 next(); 159 n = 0; 160 argp = buffer; 161 arglen = INPUTSIZ; 162 if (ahead() == ')') { 163 next(); 164 } else { 165 do { 166 *listp++ = argp; 167 parameter(); 168 } while (++n < NR_MACROARG && yytoken == ','); 169 } 170 if (yytoken != ')') 171 error("incorrect macro function-alike invocation"); 172 disexpand = 0; 173 174 if (n == NR_MACROARG) 175 error("too many parameters in macro \"%s\"", macroname); 176 if (n != nargs) { 177 error("macro \"%s\" received %d arguments, but it takes %d", 178 macroname, n, nargs); 179 } 180 181 return 1; 182 } 183 184 static size_t 185 copymacro(char *buffer, char *s, size_t bufsiz, char *arglist[]) 186 { 187 int delim, prevc, c; 188 char *p, *arg, *bp = buffer; 189 size_t size; 190 191 for (prevc = '\0'; c = *s; prevc = c, ++s) { 192 switch (c) { 193 case '$': 194 while (bp[-1] == ' ') 195 --bp, ++bufsiz; 196 while (s[1] == ' ') 197 ++s; 198 case '#': 199 break; 200 case '\'': 201 delim = '\''; 202 goto search_delim; 203 case '\"': 204 delim = '"'; 205 search_delim: 206 for (p = s; *++s != delim; ) 207 /* nothing */; 208 size = s - p + 1; 209 if (size > bufsiz) 210 goto expansion_too_long; 211 memcpy(bp, p, size); 212 bufsiz -= size; 213 bp += size; 214 break; 215 case '@': 216 if (prevc == '#') 217 bufsiz -= 2; 218 arg = arglist[atoi(++s)]; 219 size = strlen(arg); 220 if (size > bufsiz) 221 goto expansion_too_long; 222 if (prevc == '#') 223 *bp++ = '"'; 224 memcpy(bp, arg, size); 225 bp += size; 226 if (prevc == '#') 227 *bp++ = '"'; 228 bufsiz -= size; 229 s += 2; 230 break; 231 default: 232 if (bufsiz-- == 0) 233 goto expansion_too_long; 234 *bp++ = c; 235 break; 236 } 237 } 238 *bp = '\0'; 239 240 return bp - buffer; 241 242 expansion_too_long: 243 error("macro expansion of \"%s\" too long", macroname); 244 } 245 246 int 247 expand(char *begin, Symbol *sym) 248 { 249 size_t elen; 250 int n, i; 251 char *s = sym->u.s; 252 char *arglist[NR_MACROARG], arguments[INPUTSIZ], buffer[INPUTSIZ]; 253 254 macroname = sym->name; 255 if (sym == symfile) { 256 elen = sprintf(buffer, "\"%s\" ", filenam); 257 goto substitute; 258 } 259 if (sym == symline) { 260 elen = sprintf(buffer, "%d ", lineno); 261 goto substitute; 262 } 263 if (!s) 264 return 1; 265 266 n = atoi(s); 267 if (!parsepars(arguments, arglist, atoi(s))) 268 return 0; 269 for (i = 0; i < n; ++i) 270 DBG("MACRO par%d:%s", i, arglist[i]); 271 272 elen = copymacro(buffer, s+3, INPUTSIZ-1, arglist); 273 274 substitute: 275 DBG("MACRO '%s' expanded to :'%s'", macroname, buffer); 276 buffer[elen] = '\0'; 277 addinput(filenam, sym, xstrdup(buffer)); 278 279 return 1; 280 } 281 282 static int 283 getpars(Symbol *args[NR_MACROARG]) 284 { 285 int n, c; 286 Symbol *sym; 287 288 c = *input->p; 289 next(); 290 if (c != '(') 291 return -1; 292 next(); /* skip the '(' */ 293 if (accept(')')) 294 return 0; 295 296 n = 0; 297 do { 298 if (n == NR_MACROARG) { 299 cpperror("too many parameters in macro"); 300 return NR_MACROARG; 301 } 302 if (accept(ELLIPSIS)) { 303 args[n++] = NULL; 304 break; 305 } 306 if (yytoken != IDEN) { 307 cpperror("macro arguments must be identifiers"); 308 return NR_MACROARG; 309 } 310 sym = install(NS_IDEN, yylval.sym); 311 sym->flags |= SUSED; 312 args[n++] = sym; 313 next(); 314 } while (accept(',')); 315 expect(')'); 316 317 return n; 318 } 319 320 static int 321 getdefs(Symbol *args[NR_MACROARG], int nargs, char *bp, size_t bufsiz) 322 { 323 Symbol **argp; 324 size_t len; 325 int prevc = 0, ispar; 326 327 if (yytoken == '$') { 328 cpperror("'##' cannot appear at either ends of a macro expansion"); 329 return 0; 330 } 331 332 for (;;) { 333 ispar = 0; 334 if (yytoken == IDEN && nargs >= 0) { 335 for (argp = args; argp < &args[nargs]; ++argp) { 336 if (*argp == yylval.sym) 337 break; 338 } 339 if (argp != &args[nargs]) { 340 sprintf(yytext, "@%02d@", (int) (argp - args)); 341 ispar = 1; 342 } 343 } 344 if (prevc == '#' && !ispar) { 345 cpperror("'#' is not followed by a macro parameter"); 346 return 0; 347 } 348 if (yytoken == '\n') 349 break; 350 351 if ((len = strlen(yytext)) >= bufsiz) { 352 cpperror("macro too long"); 353 return 0; 354 } 355 if (yytoken == '$') { 356 *bp++ = '$'; 357 --bufsiz; 358 } else { 359 memcpy(bp, yytext, len); 360 bp += len; 361 bufsiz -= len; 362 } 363 if ((prevc = yytoken) != '#') { 364 *bp++ = ' '; 365 --bufsiz; 366 } 367 next(); 368 } 369 *bp = '\0'; 370 return 1; 371 } 372 373 static void 374 define(void) 375 { 376 Symbol *sym,*args[NR_MACROARG]; 377 char buff[LINESIZ+1]; 378 int n; 379 380 if (cppoff) 381 return; 382 383 namespace = NS_CPP; 384 next(); 385 386 if (yytoken != IDEN) { 387 cpperror("macro names must be identifiers"); 388 return; 389 } 390 sym = yylval.sym; 391 if (sym->flags & SDECLARED) { 392 warn("'%s' redefined", yytext); 393 free(sym->u.s); 394 } else { 395 sym = install(NS_CPP, sym); 396 sym->flags |= SDECLARED|SSTRING; 397 } 398 399 namespace = NS_IDEN; /* Avoid polution in NS_CPP */ 400 if ((n = getpars(args)) == NR_MACROARG) 401 goto delete; 402 if (n > 0 && !args[n-1]) /* it is a variadic function */ 403 --n; 404 sprintf(buff, "%02d#", n); 405 if (!getdefs(args, n, buff+3, LINESIZ-3)) 406 goto delete; 407 sym->u.s = xstrdup(buff); 408 DBG("MACRO '%s' defined as '%s'", sym->name, buff); 409 return; 410 411 delete: 412 killsym(sym); 413 } 414 415 void 416 incdir(char *dir) 417 { 418 if (!dir || *dir == '\0') 419 die("incorrect -I flag"); 420 newitem(&dirinclude, dir); 421 } 422 423 static int 424 includefile(char *dir, char *file, size_t filelen) 425 { 426 size_t dirlen; 427 char path[FILENAME_MAX]; 428 429 if (!dir) { 430 dirlen = 0; 431 if (filelen > FILENAME_MAX-1) 432 return 0; 433 } else { 434 dirlen = strlen(dir); 435 if (dirlen + filelen > FILENAME_MAX-2) 436 return 0; 437 memcpy(path, dir, dirlen); 438 if (dir[dirlen-1] != '/') 439 path[dirlen++] = '/'; 440 } 441 memcpy(path+dirlen, file, filelen); 442 path[dirlen + filelen] = '\0'; 443 444 return addinput(path, NULL, NULL); 445 } 446 447 static char * 448 cwd(char *buf) 449 { 450 char *p, *s = filenam; 451 size_t len; 452 453 if ((p = strrchr(s, '/')) == NULL) 454 return NULL; 455 if ((len = p - s) >= FILENAME_MAX) 456 die("current work directory too long"); 457 memcpy(buf, s, len); 458 buf[len] = '\0'; 459 return buf; 460 } 461 462 static void 463 include(void) 464 { 465 char dir[FILENAME_MAX], file[FILENAME_MAX], *p, **bp; 466 size_t filelen; 467 int n; 468 469 if (cppoff) 470 return; 471 472 namespace = NS_IDEN; 473 next(); 474 475 switch (*yytext) { 476 case '<': 477 if ((p = strchr(input->begin, '>')) == NULL || p[-1] == '<') 478 goto bad_include; 479 filelen = p - input->begin; 480 if (filelen >= FILENAME_MAX) 481 goto too_long; 482 memcpy(file, input->begin, filelen); 483 file[filelen] = '\0'; 484 485 input->begin = input->p = p+1; 486 if (next() != '\n') 487 goto trailing_characters; 488 489 break; 490 case '"': 491 if (yylen < 3) 492 goto bad_include; 493 filelen = yylen-2; 494 if (filelen >= FILENAME_MAX) 495 goto too_long; 496 memcpy(file, yytext+1, filelen); 497 file[filelen] = '\0'; 498 499 if (next() != '\n') 500 goto trailing_characters; 501 502 if (includefile(cwd(dir), file, filelen)) 503 goto its_done; 504 break; 505 default: 506 goto bad_include; 507 } 508 509 n = dirinclude.n; 510 for (bp = dirinclude.s; n--; ++bp) { 511 if (includefile(*bp, file, filelen)) 512 goto its_done; 513 } 514 cpperror("included file '%s' not found", file); 515 516 its_done: 517 return; 518 519 trailing_characters: 520 cpperror("trailing characters after preprocessor directive"); 521 return; 522 523 too_long: 524 cpperror("too long file name in #include"); 525 return; 526 527 bad_include: 528 cpperror("#include expects \"FILENAME\" or <FILENAME>"); 529 return; 530 } 531 532 static void 533 line(void) 534 { 535 long n; 536 char *endp, *fname; 537 538 if (cppoff) 539 return; 540 541 disexpand = 0; 542 next(); 543 n = strtol(yytext, &endp, 10); 544 if (n <= 0 || n > USHRT_MAX || *endp != '\0') { 545 cpperror("first parameter of #line is not a positive integer"); 546 return; 547 } 548 549 next(); 550 if (yytoken == '\n') { 551 fname = NULL; 552 } else { 553 if (*yytext != '\"' || yylen == 1) { 554 cpperror("second parameter of #line is not a valid filename"); 555 return; 556 } 557 fname = yylval.sym->u.s; 558 } 559 setloc(fname, n - 1); 560 if (yytoken != '\n') 561 next(); 562 } 563 564 static void 565 pragma(void) 566 { 567 if (cppoff) 568 return; 569 next(); 570 warn("ignoring pragma '%s'", yytext); 571 *input->p = '\0'; 572 next(); 573 } 574 575 static void 576 usererr(void) 577 { 578 if (cppoff) 579 return; 580 cpperror("#error %s", input->p); 581 *input->p = '\0'; 582 next(); 583 } 584 585 static void 586 ifclause(int negate, int isifdef) 587 { 588 Symbol *sym; 589 unsigned n; 590 int status; 591 Node *expr; 592 593 if (cppctx == NR_COND-1) 594 error("too many nesting levels of conditional inclusion"); 595 596 n = cppctx++; 597 namespace = NS_CPP; 598 next(); 599 600 if (isifdef) { 601 if (yytoken != IDEN) { 602 cpperror("no macro name given in #%s directive", 603 (negate) ? "ifndef" : "ifdef"); 604 return; 605 } 606 sym = yylval.sym; 607 next(); 608 status = (sym->flags & SDECLARED) != 0; 609 if (!status) 610 killsym(sym); 611 } else { 612 /* TODO: catch recovery here */ 613 if ((expr = constexpr()) == NULL) { 614 cpperror("parameter of #if is not an integer constant expression"); 615 return; 616 } 617 status = expr->sym->u.i != 0; 618 freetree(expr); 619 } 620 621 if (negate) 622 status = !status; 623 if ((ifstatus[n] = status) == 0) 624 ++cppoff; 625 } 626 627 static void 628 cppif(void) 629 { 630 disexpand = 0; 631 ifclause(0, 0); 632 } 633 634 static void 635 ifdef(void) 636 { 637 ifclause(0, 1); 638 } 639 640 static void 641 ifndef(void) 642 { 643 ifclause(1, 1); 644 } 645 646 static void 647 elseclause(void) 648 { 649 int status; 650 651 if (cppctx == 0) { 652 cpperror("#else without #ifdef/ifndef"); 653 return; 654 } 655 656 status = ifstatus[cppctx-1]; 657 ifstatus[cppctx-1] = !status; 658 cppoff += (status) ? 1 : -1; 659 } 660 661 static void 662 cppelse(void) 663 { 664 elseclause(); 665 next(); 666 } 667 668 static void 669 elif(void) 670 { 671 elseclause(); 672 if (ifstatus[cppctx-1]) { 673 --cppctx; 674 cppif(); 675 } 676 } 677 678 static void 679 endif(void) 680 { 681 if (cppctx == 0) 682 error("#endif without #if"); 683 if (!ifstatus[--cppctx]) 684 --cppoff; 685 next(); 686 } 687 688 static void 689 undef(void) 690 { 691 if (cppoff) 692 return; 693 694 namespace = NS_CPP; 695 next(); 696 if (yytoken != IDEN) { 697 error("no macro name given in #undef directive"); 698 return; 699 } 700 killsym(yylval.sym); 701 next(); 702 } 703 704 int 705 cpp(void) 706 { 707 static struct { 708 unsigned char token; 709 void (*fun)(void); 710 } *bp, clauses [] = { 711 {DEFINE, define}, 712 {INCLUDE, include}, 713 {LINE, line}, 714 {IFDEF, ifdef}, 715 {IF, cppif}, 716 {ELIF, elif}, 717 {IFNDEF, ifndef}, 718 {ELSE, cppelse}, 719 {ENDIF, endif}, 720 {UNDEF, undef}, 721 {PRAGMA, pragma}, 722 {ERROR, usererr}, 723 {0, NULL} 724 }; 725 int ns; 726 char *p; 727 728 for (p = input->p; isspace(*p); ++p) 729 /* nothing */; 730 731 if (*p != '#') 732 return cppoff; 733 input->p = p+1; 734 735 disexpand = 1; 736 lexmode = CPPMODE; 737 ns = namespace; 738 namespace = NS_CPPCLAUSES; 739 next(); 740 namespace = NS_IDEN; 741 742 for (bp = clauses; bp->token && bp->token != yytoken; ++bp) 743 /* nothing */; 744 if (!bp->token) { 745 errorp("incorrect preprocessor directive '%s'", yytext); 746 goto error; 747 } 748 749 DBG("CPP %s", yytext); 750 751 pushctx(); /* create a new context to avoid polish */ 752 (*bp->fun)(); /* the current context, and to get all */ 753 popctx(); /* the symbols freed at the end */ 754 755 /* 756 * #include changes the content of input->line, so the correctness 757 * of the line must be checked in the own include(), and we have 758 * to skip this tests. For the same reason include() is the only 759 * function which does not prepare the next token 760 */ 761 if (yytoken != '\n' && !cppoff && bp->token != INCLUDE) 762 errorp("trailing characters after preprocessor directive"); 763 764 error: 765 disexpand = 0; 766 lexmode = CCMODE; 767 namespace = ns; 768 769 return 1; 770 } 771 772 void 773 ppragmaln(void) 774 { 775 static char file[FILENAME_MAX]; 776 static unsigned nline; 777 char *s; 778 779 putchar('\n'); 780 if (strcmp(file, filenam)) { 781 strcpy(file, filenam); 782 s = "#line %u \"%s\"\n"; 783 } else if (nline+1 != lineno) { 784 s = "#line %u\n"; 785 } else { 786 s = ""; 787 } 788 nline = lineno; 789 printf(s, nline, file); 790 } 791 792 void 793 outcpp(void) 794 { 795 int c; 796 char *s, *t; 797 798 for (next(); yytoken != EOFTOK; next()) { 799 if (onlyheader) 800 continue; 801 if (yytoken != STRING) { 802 printf("%s ", yytext); 803 continue; 804 } 805 for (s = yytext; c = *s; ++s) { 806 switch (c) { 807 case '\n': 808 t = "\\n"; 809 goto print_str; 810 case '\v': 811 t = "\\v"; 812 goto print_str; 813 case '\b': 814 t = "\\b"; 815 goto print_str; 816 case '\t': 817 t = "\\t"; 818 goto print_str; 819 case '\a': 820 t = "\\a"; 821 print_str: 822 fputs(t, stdout); 823 break; 824 case '\\': 825 putchar('\\'); 826 default: 827 if (!isprint(c)) 828 printf("\\x%x", c); 829 else 830 putchar(c); 831 break; 832 } 833 } 834 putchar(' '); 835 } 836 putchar('\n'); 837 } 838