parser.c (12747B)
1 #include <assert.h> 2 #include <ctype.h> 3 #include <errno.h> 4 #include <limits.h> 5 #include <stdarg.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include "make.h" 11 12 #define MAXREPL 30 13 #define TABSIZ 64 14 #define MAXTOKEN 256 15 #define ITEM 128 16 17 typedef struct macro Macro; 18 19 enum inputype { 20 FTFILE, 21 FTEXPAN, 22 }; 23 24 struct loc { 25 char *fname; 26 int lineno; 27 }; 28 29 struct input { 30 int siz; 31 int type; 32 33 FILE *fp; 34 struct loc loc; 35 36 int pos; 37 char *buf; 38 39 struct input *prev; 40 }; 41 42 struct macro { 43 char *name; 44 char *value; 45 46 struct macro *next; 47 }; 48 49 static struct input *input; 50 static char token[MAXTOKEN]; 51 static int tok; 52 static Macro *htab[TABSIZ]; 53 54 void 55 dumpmacros(void) 56 { 57 Macro **pp, *p; 58 59 for (pp = htab; pp < &htab[TABSIZ]; ++pp) { 60 for (p = *pp; p; p = p->next) 61 printf("%s = %s\n", p->name, getmacro(p->name)); 62 } 63 } 64 65 static Macro * 66 lookup(char *name) 67 { 68 Macro *mp; 69 int h = hash(name) & TABSIZ-1; 70 71 for (mp = htab[h]; mp && strcmp(mp->name, name); mp = mp->next) 72 ; 73 74 if (mp) 75 return mp; 76 77 mp = emalloc(sizeof(*mp)); 78 mp->name = estrdup(name); 79 mp->value = NULL; 80 mp->next = htab[h]; 81 htab[h] = mp; 82 83 return mp; 84 } 85 86 void 87 setmacro(char *name, char *val, int export) 88 { 89 int n; 90 char *buf; 91 Macro *mp; 92 93 mp = lookup(name); 94 free(mp->value); 95 mp->value = estrdup(val); 96 97 if (export && strcmp(name, "SHELL") != 0) { 98 n = snprintf(NULL, 0, "%s=%s", name, val); 99 buf = emalloc(n+1); 100 snprintf(buf, n+1, "%s=%s", name, val); 101 putenv(buf); 102 } 103 } 104 105 char * 106 getmacro(char *name) 107 { 108 int hide; 109 char *s, *t; 110 Macro *mp = lookup(name); 111 112 hide = 0; 113 if (!strcmp(name, "SHELL") || !strcmp(name, "MAKEFLAGS")) 114 hide = 1; 115 116 s = mp->value; 117 if (!s && !hide) 118 s = getenv(name); 119 if (!s) 120 s = ""; 121 122 if (eflag && !hide) { 123 t = getenv(name); 124 if (t) 125 s = t; 126 } 127 128 return s; 129 } 130 131 static struct loc * 132 getloc(void) 133 { 134 struct input *ip; 135 136 for (ip = input; ip && ip->type != FTFILE; ip = ip->prev) 137 ; 138 if (!ip) 139 return NULL; 140 141 return &ip->loc; 142 } 143 144 145 void 146 error(char *fmt, ...) 147 { 148 va_list va; 149 struct loc *loc; 150 151 fprintf(stderr, "make: error: "); 152 if ((loc = getloc()) != NULL) 153 fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno); 154 155 va_start(va, fmt); 156 vfprintf(stderr, fmt, va); 157 va_end(va); 158 putc('\n', stderr); 159 160 exit(EXIT_FAILURE); 161 } 162 163 void 164 warning(char *fmt, ...) 165 { 166 va_list va; 167 struct loc *loc; 168 169 fprintf(stderr, "make: warning: "); 170 if ((loc = getloc()) != NULL) 171 fprintf(stderr, "%s:%d: ", loc->fname, loc->lineno); 172 173 va_start(va, fmt); 174 vfprintf(stderr, fmt, va); 175 va_end(va); 176 putc('\n', stderr); 177 } 178 179 static void 180 pop(void) 181 { 182 struct input *ip = input->prev; 183 184 if (input->type == FTFILE) { 185 fclose(input->fp); 186 free(input->loc.fname); 187 } 188 free(input->buf); 189 free(input); 190 191 input = ip; 192 } 193 194 static void 195 push(int type, ...) 196 { 197 int len, pos; 198 FILE *fp = NULL; 199 char *buf, *s, *fname = NULL; 200 va_list va; 201 struct input *ip; 202 203 va_start(va, type); 204 switch (type) { 205 case FTFILE: 206 s = va_arg(va, char *); 207 fp = va_arg(va, FILE *); 208 fname = estrdup(s); 209 buf = emalloc(BUFSIZ); 210 pos = len = BUFSIZ; 211 break; 212 case FTEXPAN: 213 s = va_arg(va, char *); 214 buf = estrdup(s); 215 pos = 0; 216 len = strlen(s); 217 break; 218 } 219 va_end(va); 220 221 ip = emalloc(sizeof(*ip)); 222 ip->siz = len; 223 ip->buf = buf; 224 ip->type = type; 225 ip->fp = fp; 226 ip->loc.fname = fname; 227 ip->loc.lineno = 1; 228 ip->pos = pos; 229 ip->prev = input; 230 231 input = ip; 232 } 233 234 static char * 235 trim(char *s) 236 { 237 size_t len; 238 239 while (isspace(*s)) 240 s++; 241 242 for (len = strlen(s); len > 0 && isspace(s[len-1]); --len) 243 s[len-1] = '\0'; 244 245 return s; 246 } 247 248 static void 249 include(char *s) 250 { 251 int len; 252 FILE *fp; 253 char *fil, *t; 254 255 s = trim(s); 256 fil = expandstring(s, NULL); 257 258 t = trim(fil); 259 if (strlen(t) != 0) { 260 debug("including '%s'", t); 261 if ((fp = fopen(t, "r")) == NULL) 262 error("opening %s:%s", t, strerror(errno)); 263 push(FTFILE, t, fp); 264 } 265 266 end: 267 free(fil); 268 } 269 270 static char * 271 nextline(void) 272 { 273 int c; 274 FILE *fp; 275 char *s, *lim; 276 277 assert(input->type == FTFILE); 278 279 repeat: 280 fp = input->fp; 281 if (feof(fp)) 282 return NULL; 283 284 lim = &input->buf[input->siz]; 285 for (s = input->buf; s < lim; *s++ = c) { 286 c = getc(fp); 287 if (c == '\n' || c == EOF) { 288 input->loc.lineno++; 289 *s++ = '\n'; 290 break; 291 } 292 if (c > UCHAR_MAX || c < 0) 293 error("invalid character '%c' (%d)", c, c); 294 } 295 296 297 if (s == lim) 298 error("too long line"); 299 if (ferror(fp)) 300 error(strerror(errno)); 301 *s = '\0'; 302 303 if (!strcmp(input->buf, "")) 304 goto repeat; 305 306 if (strncmp(input->buf, "include", 7) == 0) { 307 input->pos = input->siz; 308 include(input->buf+7); 309 goto repeat; 310 } 311 312 input->pos = 0; 313 314 315 return input->buf; 316 } 317 318 static int 319 empty(struct input *ip) 320 { 321 return ip->pos == ip->siz || ip->buf[ip->pos] == '\0'; 322 } 323 324 static int 325 moreinput(void) 326 { 327 while (input) { 328 if (!empty(input)) 329 break; 330 331 switch (input->type) { 332 case FTEXPAN: 333 pop(); 334 break; 335 case FTFILE: 336 if (!nextline()) 337 pop(); 338 break; 339 } 340 } 341 342 return input != NULL; 343 } 344 345 static int 346 nextc(void) 347 { 348 if (!moreinput()) 349 return EOF; 350 351 return input->buf[input->pos++]; 352 } 353 354 static int 355 back(int c) 356 { 357 if (c == EOF) 358 return c; 359 assert(input->pos > 0); 360 return input->buf[--input->pos] = c; 361 } 362 363 static void 364 comment(void) 365 { 366 int c; 367 368 while ((c = nextc()) != EOF && c != '\n') { 369 if (c == '\\' && nextc() == EOF) 370 break; 371 } 372 } 373 374 static void 375 skipspaces(void) 376 { 377 int c; 378 379 for (c = nextc(); c == ' ' || c == '\t'; c = nextc()) 380 ; 381 back(c); 382 } 383 384 static int 385 validchar(int c) 386 { 387 if (c == EOF) 388 return 0; 389 return c == '.' || c == '/' || c == '_' || c == '-' || isalnum(c); 390 } 391 392 static int 393 item(void) 394 { 395 int c; 396 char *s; 397 398 for (s = token; s < &token[MAXTOKEN] - 1; *s++ = c) { 399 c = nextc(); 400 if (!validchar(c)) 401 break; 402 } 403 404 if (s >= &token[MAXTOKEN] - 1) 405 error("token too long"); 406 if (s == token) 407 error("invalid empty token"); 408 *s = '\0'; 409 back(c); 410 411 return ITEM; 412 } 413 414 static void 415 expandmacro(char *name, char *repl, char *to) 416 { 417 int pos, siz, replsiz, tosiz; 418 char *s, *t, *p, *buf; 419 420 s = expandstring(getmacro(name), NULL); 421 422 pos = 0; 423 buf = NULL; 424 tosiz = strlen(to); 425 replsiz = strlen(repl); 426 427 t = s; 428 for (pos = 0; *t; pos += siz) { 429 if (replsiz > 0 && strncmp(t, repl, replsiz) == 0) { 430 siz = tosiz; 431 p = to; 432 t += replsiz; 433 } else { 434 siz = 1; 435 p = t; 436 t++; 437 } 438 439 buf = erealloc(buf, pos + siz + 1); 440 memcpy(buf+pos, p, siz); 441 } 442 443 if (pos > 0) { 444 buf[pos] = '\0'; 445 push(FTEXPAN, buf); 446 free(buf); 447 } 448 free(s); 449 } 450 451 static void 452 expandsimple(Target *tp) 453 { 454 char *s; 455 Target **p; 456 int len, c; 457 458 switch (c = nextc()) { 459 case '@': 460 if (!tp || !tp->target) 461 return; 462 push(FTEXPAN, tp->target); 463 break; 464 case '<': 465 if (!tp || !tp->req) 466 return; 467 push(FTEXPAN, tp->req); 468 break; 469 case '*': 470 if (!tp || !tp->target) 471 return; 472 s = strrchr(tp->target, '.'); 473 if (!s) { 474 push(FTEXPAN, tp->target); 475 return; 476 } 477 478 len = s - tp->target; 479 s = emalloc(len+1); 480 memcpy(s, tp->target, len); 481 s[len] = '\0'; 482 push(FTEXPAN, s); 483 free(s); 484 break; 485 case '?': 486 if (!tp) 487 return; 488 489 if (tp->req && stamp(tp->req) > tp->stamp) { 490 push(FTEXPAN, " "); 491 push(FTEXPAN, tp->req); 492 } 493 494 for (p = tp->deps; p && *p; ++p) { 495 if (stamp((*p)->name) > tp->stamp) { 496 push(FTEXPAN, " "); 497 push(FTEXPAN, (*p)->name); 498 } 499 } 500 break; 501 default: 502 token[0] = c; 503 token[1] = '\0'; 504 expandmacro(token, "", ""); 505 break; 506 } 507 } 508 509 static void 510 expansion(Target *tp) 511 { 512 int delim, c, repli, toi, namei, st; 513 char name[MAXTOKEN], repl[MAXREPL], to[MAXREPL]; 514 515 c = nextc(); 516 if (c == '(') 517 delim = ')'; 518 else if (c == '{') 519 delim = '}'; 520 else 521 delim = 0; 522 523 if (!delim) { 524 back(c); 525 expandsimple(tp); 526 } else { 527 st = namei = repli = toi = 0; 528 while ((c = nextc()) != EOF) { 529 if (c == delim) 530 break; 531 532 switch (st) { 533 case 0: 534 if (c == ':') { 535 st = 1; 536 continue; 537 } 538 if (!validchar(c)) 539 error("invalid macro name in expansion"); 540 if (namei == MAXTOKEN-1) 541 error("expansion text too long"); 542 name[namei++] = c; 543 break; 544 case 1: 545 if (c == '=') { 546 st = 2; 547 continue; 548 } 549 if (repli == MAXREPL-1) 550 error("macro replacement too big"); 551 repl[repli++] = c; 552 break; 553 case 2: 554 if (toi == MAXREPL-1) 555 error("macro substiturion too big"); 556 to[toi++] = c; 557 break; 558 } 559 } 560 561 if (c == EOF) 562 error("found eof while parsing expansion"); 563 if (st > 0 && (namei == 0 || repli == 0 || to == 0)) 564 error("invalid macro expansion"); 565 566 name[namei] = '\0'; 567 repl[repli] = '\0'; 568 to[toi] = '\0'; 569 expandmacro(name, repl, to); 570 } 571 } 572 573 /* 574 * Horrible hack to do string expansion. 575 * We cannot use normal push and nextc because that 576 * would consume characters of the current file too. 577 * For that reason it cleans the input and it recovers 578 * it later. 579 */ 580 char * 581 expandstring(char *line, Target *tp) 582 { 583 int c, n; 584 char *s; 585 struct input *ip = input; 586 587 input = NULL; 588 push(FTEXPAN, line); 589 590 n = 0; 591 s = NULL; 592 while ((c = nextc()) != EOF) { 593 if (c == '$') { 594 if ((c = nextc()) != '$') { 595 back(c); 596 expansion(tp); 597 continue; 598 } 599 } 600 601 s = erealloc(s, ++n); 602 s[n-1] = c; 603 } 604 605 s = erealloc(s, n+1); 606 s[n] = '\0'; 607 input = ip; 608 609 return s; 610 } 611 612 static int 613 readchar(void) 614 { 615 int c; 616 617 while ((c = nextc()) != EOF) { 618 if (c == ' ' || c == '\t') 619 continue; 620 if (c == '\\') { 621 if ((c = nextc()) == '\n') 622 continue; 623 back(c); 624 c = '\\'; 625 } 626 break; 627 } 628 629 return c; 630 } 631 632 static int 633 next(void) 634 { 635 int c; 636 637 repeat: 638 c = readchar(); 639 640 switch (c) { 641 case EOF: 642 strcpy(token, "<EOF>"); 643 tok = EOF; 644 break; 645 case '$': 646 if ((c = nextc()) == '$') 647 goto single; 648 back(c); 649 expansion(NULL); 650 goto repeat; 651 case '#': 652 comment(); 653 c = '\n'; 654 case ';': 655 case ':': 656 case '=': 657 case '\n': 658 single: 659 token[0] = c; 660 token[1] = '\0'; 661 tok = c; 662 break; 663 default: 664 if (!validchar(c)) 665 error("unexpected character '%c'", c); 666 back(c); 667 tok = item(); 668 break; 669 } 670 671 return tok; 672 } 673 674 static char * 675 readmacrodef(void) 676 { 677 int n, c; 678 char *line; 679 680 n = 0; 681 line = NULL; 682 while ((c = nextc()) != EOF) { 683 line = erealloc(line, n+1); 684 if (c == '\n') 685 break; 686 if (c == '#') { 687 comment(); 688 break; 689 } 690 if (c == '\\') { 691 if ((c = nextc()) != '\n') { 692 back(c); 693 c = '\\'; 694 } else { 695 skipspaces(); 696 c = ' '; 697 } 698 } 699 700 line[n++] = c; 701 } 702 if (c == EOF) 703 error("EOF while looking for end of line"); 704 line[n] = '\0'; 705 706 return line; 707 } 708 709 static char * 710 readcmd(void) 711 { 712 int n, c; 713 char *line; 714 715 skipspaces(); 716 717 n = 0; 718 line = NULL; 719 while ((c = nextc()) != EOF) { 720 line = erealloc(line, n+1); 721 if (c == '\n') 722 break; 723 if (c == '\\') { 724 if ((c = nextc()) == '\n') { 725 if ((c = nextc()) != '\t') 726 back(c); 727 continue; 728 } 729 back(c); 730 c = '\\'; 731 } 732 line[n++] = c; 733 } 734 if (c == EOF) 735 error("EOF while looking for end of command"); 736 line[n] = '\0'; 737 738 return line; 739 } 740 741 static void 742 rule(char *targets[], int ntargets) 743 { 744 int c, i, j, ndeps, nactions; 745 char **actions, **deps = NULL; 746 747 if (ntargets == 0) 748 error("missing target"); 749 750 for (ndeps = 0; next() == ITEM; ++ndeps) { 751 deps = erealloc(deps, (ndeps+1) * sizeof(char *)); 752 deps[ndeps] = estrdup(token); 753 } 754 755 if (tok != '\n' && tok != ';') 756 error("garbage at the end of the line"); 757 758 nactions = 0; 759 actions = NULL; 760 if (tok == ';') { 761 nactions++; 762 actions = erealloc(actions, nactions * sizeof(char *)); 763 actions[nactions-1] = readcmd(); 764 } 765 766 for (;;) { 767 if ((c = nextc()) == '#') { 768 comment(); 769 continue; 770 } 771 if (c != '\t') 772 break; 773 nactions++; 774 actions = erealloc(actions, nactions * sizeof(char *)); 775 actions[nactions-1] = readcmd(); 776 } 777 back(c); 778 779 for (i = 0; i < ntargets; i++) { 780 addtarget(targets[i], ndeps); 781 for (j = 0; j < ndeps; j++) 782 adddep(targets[i], deps[j]); 783 if (nactions > 0) 784 addrule(targets[i], actions, nactions); 785 } 786 787 for (i = 0; i < ndeps; i++) 788 free(deps[i]); 789 free(deps); 790 791 for (i = 0; i < nactions; i++) 792 free(actions[i]); 793 free(actions); 794 } 795 796 static void 797 assign(char *macros[], int n) 798 { 799 int len, c; 800 char *defs; 801 802 if (n != 1) 803 error("invalid macro definition"); 804 805 skipspaces(); 806 defs = readmacrodef(); 807 setmacro(*macros, defs, NOEXPORT); 808 free(defs); 809 } 810 811 void 812 parseinput(void) 813 { 814 int i, n; 815 char **targets; 816 817 while (moreinput()) { 818 n = 0; 819 targets = NULL; 820 821 next(); 822 if (tok == '\n') 823 continue; 824 825 while (tok == ITEM) { 826 n++; 827 targets = erealloc(targets, n * sizeof(char *)); 828 targets[n-1] = estrdup(token); 829 next(); 830 } 831 832 switch (tok) { 833 case ':': 834 rule(targets, n); 835 break; 836 case '=': 837 assign(targets, n); 838 break; 839 default: 840 error("unexpected token '%s'(%d)", token, tok); 841 } 842 843 for (i = 0; i < n; i++) 844 free(targets[i]); 845 free(targets); 846 } 847 } 848 849 int 850 parse(char *fname) 851 { 852 FILE *fp; 853 854 if (!fname) { 855 fp = stdin; 856 fname = "<stdin>"; 857 } else if ((fp = fopen(fname, "r")) == NULL) { 858 return 0; 859 } 860 861 debug("parsing %s", fname); 862 push(FTFILE, fname, fp); 863 parseinput(); 864 865 return 1; 866 } 867 868 void 869 inject(char *s) 870 { 871 push(FTEXPAN, s); 872 parseinput(); 873 }