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