1 /* 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1989 by Berkeley Softworks 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * %sccs.include.redist.c% 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)cond.c 8.1 (Berkeley) 06/06/93"; 15 #endif /* not lint */ 16 17 /*- 18 * cond.c -- 19 * Functions to handle conditionals in a makefile. 20 * 21 * Interface: 22 * Cond_Eval Evaluate the conditional in the passed line. 23 * 24 */ 25 26 #include <ctype.h> 27 #include <math.h> 28 #include "make.h" 29 #include "hash.h" 30 #include "dir.h" 31 #include "buf.h" 32 33 /* 34 * The parsing of conditional expressions is based on this grammar: 35 * E -> F || E 36 * E -> F 37 * F -> T && F 38 * F -> T 39 * T -> defined(variable) 40 * T -> make(target) 41 * T -> exists(file) 42 * T -> empty(varspec) 43 * T -> target(name) 44 * T -> symbol 45 * T -> $(varspec) op value 46 * T -> $(varspec) == "string" 47 * T -> $(varspec) != "string" 48 * T -> ( E ) 49 * T -> ! T 50 * op -> == | != | > | < | >= | <= 51 * 52 * 'symbol' is some other symbol to which the default function (condDefProc) 53 * is applied. 54 * 55 * Tokens are scanned from the 'condExpr' string. The scanner (CondToken) 56 * will return And for '&' and '&&', Or for '|' and '||', Not for '!', 57 * LParen for '(', RParen for ')' and will evaluate the other terminal 58 * symbols, using either the default function or the function given in the 59 * terminal, and return the result as either True or False. 60 * 61 * All Non-Terminal functions (CondE, CondF and CondT) return Err on error. 62 */ 63 typedef enum { 64 And, Or, Not, True, False, LParen, RParen, EndOfFile, None, Err 65 } Token; 66 67 /*- 68 * Structures to handle elegantly the different forms of #if's. The 69 * last two fields are stored in condInvert and condDefProc, respectively. 70 */ 71 static int CondGetArg __P((char **, char **, char *, Boolean)); 72 static Boolean CondDoDefined __P((int, char *)); 73 static int CondStrMatch __P((char *, char *)); 74 static Boolean CondDoMake __P((int, char *)); 75 static Boolean CondDoExists __P((int, char *)); 76 static Boolean CondDoTarget __P((int, char *)); 77 static Boolean CondCvtArg __P((char *, double *)); 78 static Token CondToken __P((Boolean)); 79 static Token CondT __P((Boolean)); 80 static Token CondF __P((Boolean)); 81 static Token CondE __P((Boolean)); 82 83 static struct If { 84 char *form; /* Form of if */ 85 int formlen; /* Length of form */ 86 Boolean doNot; /* TRUE if default function should be negated */ 87 Boolean (*defProc)(); /* Default function to apply */ 88 } ifs[] = { 89 { "ifdef", 5, FALSE, CondDoDefined }, 90 { "ifndef", 6, TRUE, CondDoDefined }, 91 { "ifmake", 6, FALSE, CondDoMake }, 92 { "ifnmake", 7, TRUE, CondDoMake }, 93 { "if", 2, FALSE, CondDoDefined }, 94 { (char *)0, 0, FALSE, (Boolean (*)())0 } 95 }; 96 97 static Boolean condInvert; /* Invert the default function */ 98 static Boolean (*condDefProc)(); /* Default function to apply */ 99 static char *condExpr; /* The expression to parse */ 100 static Token condPushBack=None; /* Single push-back token used in 101 * parsing */ 102 103 #define MAXIF 30 /* greatest depth of #if'ing */ 104 105 static Boolean condStack[MAXIF]; /* Stack of conditionals's values */ 106 static int condTop = MAXIF; /* Top-most conditional */ 107 static int skipIfLevel=0; /* Depth of skipped conditionals */ 108 static Boolean skipLine = FALSE; /* Whether the parse module is skipping 109 * lines */ 110 111 /*- 112 *----------------------------------------------------------------------- 113 * CondPushBack -- 114 * Push back the most recent token read. We only need one level of 115 * this, so the thing is just stored in 'condPushback'. 116 * 117 * Results: 118 * None. 119 * 120 * Side Effects: 121 * condPushback is overwritten. 122 * 123 *----------------------------------------------------------------------- 124 */ 125 static void 126 CondPushBack (t) 127 Token t; /* Token to push back into the "stream" */ 128 { 129 condPushBack = t; 130 } 131 132 /*- 133 *----------------------------------------------------------------------- 134 * CondGetArg -- 135 * Find the argument of a built-in function. 136 * 137 * Results: 138 * The length of the argument and the address of the argument. 139 * 140 * Side Effects: 141 * The pointer is set to point to the closing parenthesis of the 142 * function call. 143 * 144 *----------------------------------------------------------------------- 145 */ 146 static int 147 CondGetArg (linePtr, argPtr, func, parens) 148 char **linePtr; 149 char **argPtr; 150 char *func; 151 Boolean parens; /* TRUE if arg should be bounded by parens */ 152 { 153 register char *cp; 154 int argLen; 155 register Buffer buf; 156 157 cp = *linePtr; 158 if (parens) { 159 while (*cp != '(' && *cp != '\0') { 160 cp++; 161 } 162 if (*cp == '(') { 163 cp++; 164 } 165 } 166 167 if (*cp == '\0') { 168 /* 169 * No arguments whatsoever. Because 'make' and 'defined' aren't really 170 * "reserved words", we don't print a message. I think this is better 171 * than hitting the user with a warning message every time s/he uses 172 * the word 'make' or 'defined' at the beginning of a symbol... 173 */ 174 *argPtr = cp; 175 return (0); 176 } 177 178 while (*cp == ' ' || *cp == '\t') { 179 cp++; 180 } 181 182 /* 183 * Create a buffer for the argument and start it out at 16 characters 184 * long. Why 16? Why not? 185 */ 186 buf = Buf_Init(16); 187 188 while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) { 189 if (*cp == '$') { 190 /* 191 * Parse the variable spec and install it as part of the argument 192 * if it's valid. We tell Var_Parse to complain on an undefined 193 * variable, so we don't do it too. Nor do we return an error, 194 * though perhaps we should... 195 */ 196 char *cp2; 197 int len; 198 Boolean doFree; 199 200 cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree); 201 202 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 203 if (doFree) { 204 free(cp2); 205 } 206 cp += len; 207 } else { 208 Buf_AddByte(buf, (Byte)*cp); 209 cp++; 210 } 211 } 212 213 Buf_AddByte(buf, (Byte)'\0'); 214 *argPtr = (char *)Buf_GetAll(buf, &argLen); 215 Buf_Destroy(buf, FALSE); 216 217 while (*cp == ' ' || *cp == '\t') { 218 cp++; 219 } 220 if (parens && *cp != ')') { 221 Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()", 222 func); 223 return (0); 224 } else if (parens) { 225 /* 226 * Advance pointer past close parenthesis. 227 */ 228 cp++; 229 } 230 231 *linePtr = cp; 232 return (argLen); 233 } 234 235 /*- 236 *----------------------------------------------------------------------- 237 * CondDoDefined -- 238 * Handle the 'defined' function for conditionals. 239 * 240 * Results: 241 * TRUE if the given variable is defined. 242 * 243 * Side Effects: 244 * None. 245 * 246 *----------------------------------------------------------------------- 247 */ 248 static Boolean 249 CondDoDefined (argLen, arg) 250 int argLen; 251 char *arg; 252 { 253 char savec = arg[argLen]; 254 Boolean result; 255 256 arg[argLen] = '\0'; 257 if (Var_Value (arg, VAR_CMD) != (char *)NULL) { 258 result = TRUE; 259 } else { 260 result = FALSE; 261 } 262 arg[argLen] = savec; 263 return (result); 264 } 265 266 /*- 267 *----------------------------------------------------------------------- 268 * CondStrMatch -- 269 * Front-end for Str_Match so it returns 0 on match and non-zero 270 * on mismatch. Callback function for CondDoMake via Lst_Find 271 * 272 * Results: 273 * 0 if string matches pattern 274 * 275 * Side Effects: 276 * None 277 * 278 *----------------------------------------------------------------------- 279 */ 280 static int 281 CondStrMatch(string, pattern) 282 char *string; 283 char *pattern; 284 { 285 return(!Str_Match(string,pattern)); 286 } 287 288 /*- 289 *----------------------------------------------------------------------- 290 * CondDoMake -- 291 * Handle the 'make' function for conditionals. 292 * 293 * Results: 294 * TRUE if the given target is being made. 295 * 296 * Side Effects: 297 * None. 298 * 299 *----------------------------------------------------------------------- 300 */ 301 static Boolean 302 CondDoMake (argLen, arg) 303 int argLen; 304 char *arg; 305 { 306 char savec = arg[argLen]; 307 Boolean result; 308 309 arg[argLen] = '\0'; 310 if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) { 311 result = FALSE; 312 } else { 313 result = TRUE; 314 } 315 arg[argLen] = savec; 316 return (result); 317 } 318 319 /*- 320 *----------------------------------------------------------------------- 321 * CondDoExists -- 322 * See if the given file exists. 323 * 324 * Results: 325 * TRUE if the file exists and FALSE if it does not. 326 * 327 * Side Effects: 328 * None. 329 * 330 *----------------------------------------------------------------------- 331 */ 332 static Boolean 333 CondDoExists (argLen, arg) 334 int argLen; 335 char *arg; 336 { 337 char savec = arg[argLen]; 338 Boolean result; 339 char *path; 340 341 arg[argLen] = '\0'; 342 path = Dir_FindFile(arg, dirSearchPath); 343 if (path != (char *)NULL) { 344 result = TRUE; 345 free(path); 346 } else { 347 result = FALSE; 348 } 349 arg[argLen] = savec; 350 return (result); 351 } 352 353 /*- 354 *----------------------------------------------------------------------- 355 * CondDoTarget -- 356 * See if the given node exists and is an actual target. 357 * 358 * Results: 359 * TRUE if the node exists as a target and FALSE if it does not. 360 * 361 * Side Effects: 362 * None. 363 * 364 *----------------------------------------------------------------------- 365 */ 366 static Boolean 367 CondDoTarget (argLen, arg) 368 int argLen; 369 char *arg; 370 { 371 char savec = arg[argLen]; 372 Boolean result; 373 GNode *gn; 374 375 arg[argLen] = '\0'; 376 gn = Targ_FindNode(arg, TARG_NOCREATE); 377 if ((gn != NILGNODE) && !OP_NOP(gn->type)) { 378 result = TRUE; 379 } else { 380 result = FALSE; 381 } 382 arg[argLen] = savec; 383 return (result); 384 } 385 386 387 /*- 388 *----------------------------------------------------------------------- 389 * CondCvtArg -- 390 * Convert the given number into a double. If the number begins 391 * with 0x, it is interpreted as a hexadecimal integer 392 * and converted to a double from there. All other strings just have 393 * strtod called on them. 394 * 395 * Results: 396 * Sets 'value' to double value of string. 397 * Returns true if the string was a valid number, false o.w. 398 * 399 * Side Effects: 400 * Can change 'value' even if string is not a valid number. 401 * 402 * 403 *----------------------------------------------------------------------- 404 */ 405 static Boolean 406 CondCvtArg(str, value) 407 register char *str; 408 double *value; 409 { 410 if ((*str == '0') && (str[1] == 'x')) { 411 register long i; 412 413 for (str += 2, i = 0; *str; str++) { 414 int x; 415 if (isdigit((unsigned char) *str)) 416 x = *str - '0'; 417 else if (isxdigit((unsigned char) *str)) 418 x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a'; 419 else 420 return FALSE; 421 i = (i << 4) + x; 422 } 423 *value = (double) i; 424 return TRUE; 425 } 426 else { 427 char *eptr; 428 *value = strtod(str, &eptr); 429 return *eptr == '\0'; 430 } 431 } 432 433 /*- 434 *----------------------------------------------------------------------- 435 * CondToken -- 436 * Return the next token from the input. 437 * 438 * Results: 439 * A Token for the next lexical token in the stream. 440 * 441 * Side Effects: 442 * condPushback will be set back to None if it is used. 443 * 444 *----------------------------------------------------------------------- 445 */ 446 static Token 447 CondToken(doEval) 448 Boolean doEval; 449 { 450 Token t; 451 452 if (condPushBack == None) { 453 while (*condExpr == ' ' || *condExpr == '\t') { 454 condExpr++; 455 } 456 switch (*condExpr) { 457 case '(': 458 t = LParen; 459 condExpr++; 460 break; 461 case ')': 462 t = RParen; 463 condExpr++; 464 break; 465 case '|': 466 if (condExpr[1] == '|') { 467 condExpr++; 468 } 469 condExpr++; 470 t = Or; 471 break; 472 case '&': 473 if (condExpr[1] == '&') { 474 condExpr++; 475 } 476 condExpr++; 477 t = And; 478 break; 479 case '!': 480 t = Not; 481 condExpr++; 482 break; 483 case '\n': 484 case '\0': 485 t = EndOfFile; 486 break; 487 case '$': { 488 char *lhs; 489 char *rhs; 490 char *op; 491 int varSpecLen; 492 Boolean doFree; 493 494 /* 495 * Parse the variable spec and skip over it, saving its 496 * value in lhs. 497 */ 498 t = Err; 499 lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree); 500 if (lhs == var_Error) { 501 /* 502 * Even if !doEval, we still report syntax errors, which 503 * is what getting var_Error back with !doEval means. 504 */ 505 return(Err); 506 } 507 condExpr += varSpecLen; 508 509 if (!isspace(*condExpr) && strchr("!=><", *condExpr) == NULL) { 510 Buffer buf; 511 char *cp; 512 513 buf = Buf_Init(0); 514 515 for (cp = lhs; *cp; cp++) 516 Buf_AddByte(buf, (Byte)*cp); 517 518 if (doFree) 519 free(lhs); 520 521 for (;*condExpr && !isspace(*condExpr); condExpr++) 522 Buf_AddByte(buf, (Byte)*condExpr); 523 524 Buf_AddByte(buf, (Byte)'\0'); 525 lhs = (char *)Buf_GetAll(buf, &varSpecLen); 526 Buf_Destroy(buf, FALSE); 527 528 doFree = TRUE; 529 } 530 531 /* 532 * Skip whitespace to get to the operator 533 */ 534 while (isspace(*condExpr)) 535 condExpr++; 536 537 /* 538 * Make sure the operator is a valid one. If it isn't a 539 * known relational operator, pretend we got a 540 * != 0 comparison. 541 */ 542 op = condExpr; 543 switch (*condExpr) { 544 case '!': 545 case '=': 546 case '<': 547 case '>': 548 if (condExpr[1] == '=') { 549 condExpr += 2; 550 } else { 551 condExpr += 1; 552 } 553 break; 554 default: 555 op = "!="; 556 rhs = "0"; 557 558 goto do_compare; 559 } 560 while (isspace(*condExpr)) { 561 condExpr++; 562 } 563 if (*condExpr == '\0') { 564 Parse_Error(PARSE_WARNING, 565 "Missing right-hand-side of operator"); 566 goto error; 567 } 568 rhs = condExpr; 569 do_compare: 570 if (*rhs == '"') { 571 /* 572 * Doing a string comparison. Only allow == and != for 573 * operators. 574 */ 575 char *string; 576 char *cp, *cp2; 577 Buffer buf; 578 579 do_string_compare: 580 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { 581 Parse_Error(PARSE_WARNING, 582 "String comparison operator should be either == or !="); 583 goto error; 584 } 585 586 buf = Buf_Init(0); 587 588 for (cp = &rhs[*rhs == '"' ? 1 : 0]; 589 (*cp != '"') && (*cp != '\0'); cp++) { 590 if ((*cp == '\\') && (cp[1] != '\0')) { 591 /* 592 * Backslash escapes things -- skip over next 593 * character, if it exists. 594 */ 595 cp++; 596 Buf_AddByte(buf, (Byte)*cp); 597 } else if (*cp == '$') { 598 int len; 599 Boolean freeIt; 600 601 cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt); 602 if (cp2 != var_Error) { 603 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 604 if (freeIt) { 605 free(cp2); 606 } 607 cp += len - 1; 608 } else { 609 Buf_AddByte(buf, (Byte)*cp); 610 } 611 } else { 612 Buf_AddByte(buf, (Byte)*cp); 613 } 614 } 615 616 Buf_AddByte(buf, (Byte)0); 617 618 string = (char *)Buf_GetAll(buf, (int *)0); 619 Buf_Destroy(buf, FALSE); 620 621 if (DEBUG(COND)) { 622 printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", 623 lhs, string, op); 624 } 625 /* 626 * Null-terminate rhs and perform the comparison. 627 * t is set to the result. 628 */ 629 if (*op == '=') { 630 t = strcmp(lhs, string) ? False : True; 631 } else { 632 t = strcmp(lhs, string) ? True : False; 633 } 634 free(string); 635 if (rhs == condExpr) { 636 condExpr = cp + 1; 637 } 638 } else { 639 /* 640 * rhs is either a float or an integer. Convert both the 641 * lhs and the rhs to a double and compare the two. 642 */ 643 double left, right; 644 char *string; 645 646 if (!CondCvtArg(lhs, &left)) 647 goto do_string_compare; 648 if (*rhs == '$') { 649 int len; 650 Boolean freeIt; 651 652 string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt); 653 if (string == var_Error) { 654 right = 0.0; 655 } else { 656 if (!CondCvtArg(string, &right)) { 657 if (freeIt) 658 free(string); 659 goto do_string_compare; 660 } 661 if (freeIt) 662 free(string); 663 if (rhs == condExpr) 664 condExpr += len; 665 } 666 } else { 667 if (!CondCvtArg(rhs, &right)) 668 goto do_string_compare; 669 if (rhs == condExpr) { 670 /* 671 * Skip over the right-hand side 672 */ 673 while(!isspace(*condExpr) && (*condExpr != '\0')) { 674 condExpr++; 675 } 676 } 677 } 678 679 if (DEBUG(COND)) { 680 printf("left = %f, right = %f, op = %.2s\n", left, 681 right, op); 682 } 683 switch(op[0]) { 684 case '!': 685 if (op[1] != '=') { 686 Parse_Error(PARSE_WARNING, 687 "Unknown operator"); 688 goto error; 689 } 690 t = (left != right ? True : False); 691 break; 692 case '=': 693 if (op[1] != '=') { 694 Parse_Error(PARSE_WARNING, 695 "Unknown operator"); 696 goto error; 697 } 698 t = (left == right ? True : False); 699 break; 700 case '<': 701 if (op[1] == '=') { 702 t = (left <= right ? True : False); 703 } else { 704 t = (left < right ? True : False); 705 } 706 break; 707 case '>': 708 if (op[1] == '=') { 709 t = (left >= right ? True : False); 710 } else { 711 t = (left > right ? True : False); 712 } 713 break; 714 } 715 } 716 error: 717 if (doFree) 718 free(lhs); 719 break; 720 } 721 default: { 722 Boolean (*evalProc)(); 723 Boolean invert = FALSE; 724 char *arg; 725 int arglen; 726 727 if (strncmp (condExpr, "defined", 7) == 0) { 728 /* 729 * Use CondDoDefined to evaluate the argument and 730 * CondGetArg to extract the argument from the 'function 731 * call'. 732 */ 733 evalProc = CondDoDefined; 734 condExpr += 7; 735 arglen = CondGetArg (&condExpr, &arg, "defined", TRUE); 736 if (arglen == 0) { 737 condExpr -= 7; 738 goto use_default; 739 } 740 } else if (strncmp (condExpr, "make", 4) == 0) { 741 /* 742 * Use CondDoMake to evaluate the argument and 743 * CondGetArg to extract the argument from the 'function 744 * call'. 745 */ 746 evalProc = CondDoMake; 747 condExpr += 4; 748 arglen = CondGetArg (&condExpr, &arg, "make", TRUE); 749 if (arglen == 0) { 750 condExpr -= 4; 751 goto use_default; 752 } 753 } else if (strncmp (condExpr, "exists", 6) == 0) { 754 /* 755 * Use CondDoExists to evaluate the argument and 756 * CondGetArg to extract the argument from the 757 * 'function call'. 758 */ 759 evalProc = CondDoExists; 760 condExpr += 6; 761 arglen = CondGetArg(&condExpr, &arg, "exists", TRUE); 762 if (arglen == 0) { 763 condExpr -= 6; 764 goto use_default; 765 } 766 } else if (strncmp(condExpr, "empty", 5) == 0) { 767 /* 768 * Use Var_Parse to parse the spec in parens and return 769 * True if the resulting string is empty. 770 */ 771 int length; 772 Boolean doFree; 773 char *val; 774 775 condExpr += 5; 776 777 for (arglen = 0; 778 condExpr[arglen] != '(' && condExpr[arglen] != '\0'; 779 arglen += 1) 780 { 781 /* void */ ; 782 } 783 if (condExpr[arglen] != '\0') { 784 val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, 785 doEval, &length, &doFree); 786 if (val == var_Error) { 787 t = Err; 788 } else { 789 /* 790 * A variable is empty when it just contains 791 * spaces... 4/15/92, christos 792 */ 793 char *p; 794 for (p = val; *p && isspace(*p); p++) 795 continue; 796 t = (*p == '\0') ? True : False; 797 } 798 if (doFree) { 799 free(val); 800 } 801 /* 802 * Advance condExpr to beyond the closing ). Note that 803 * we subtract one from arglen + length b/c length 804 * is calculated from condExpr[arglen - 1]. 805 */ 806 condExpr += arglen + length - 1; 807 } else { 808 condExpr -= 5; 809 goto use_default; 810 } 811 break; 812 } else if (strncmp (condExpr, "target", 6) == 0) { 813 /* 814 * Use CondDoTarget to evaluate the argument and 815 * CondGetArg to extract the argument from the 816 * 'function call'. 817 */ 818 evalProc = CondDoTarget; 819 condExpr += 6; 820 arglen = CondGetArg(&condExpr, &arg, "target", TRUE); 821 if (arglen == 0) { 822 condExpr -= 6; 823 goto use_default; 824 } 825 } else { 826 /* 827 * The symbol is itself the argument to the default 828 * function. We advance condExpr to the end of the symbol 829 * by hand (the next whitespace, closing paren or 830 * binary operator) and set to invert the evaluation 831 * function if condInvert is TRUE. 832 */ 833 use_default: 834 invert = condInvert; 835 evalProc = condDefProc; 836 arglen = CondGetArg(&condExpr, &arg, "", FALSE); 837 } 838 839 /* 840 * Evaluate the argument using the set function. If invert 841 * is TRUE, we invert the sense of the function. 842 */ 843 t = (!doEval || (* evalProc) (arglen, arg) ? 844 (invert ? False : True) : 845 (invert ? True : False)); 846 free(arg); 847 break; 848 } 849 } 850 } else { 851 t = condPushBack; 852 condPushBack = None; 853 } 854 return (t); 855 } 856 857 /*- 858 *----------------------------------------------------------------------- 859 * CondT -- 860 * Parse a single term in the expression. This consists of a terminal 861 * symbol or Not and a terminal symbol (not including the binary 862 * operators): 863 * T -> defined(variable) | make(target) | exists(file) | symbol 864 * T -> ! T | ( E ) 865 * 866 * Results: 867 * True, False or Err. 868 * 869 * Side Effects: 870 * Tokens are consumed. 871 * 872 *----------------------------------------------------------------------- 873 */ 874 static Token 875 CondT(doEval) 876 Boolean doEval; 877 { 878 Token t; 879 880 t = CondToken(doEval); 881 882 if (t == EndOfFile) { 883 /* 884 * If we reached the end of the expression, the expression 885 * is malformed... 886 */ 887 t = Err; 888 } else if (t == LParen) { 889 /* 890 * T -> ( E ) 891 */ 892 t = CondE(doEval); 893 if (t != Err) { 894 if (CondToken(doEval) != RParen) { 895 t = Err; 896 } 897 } 898 } else if (t == Not) { 899 t = CondT(doEval); 900 if (t == True) { 901 t = False; 902 } else if (t == False) { 903 t = True; 904 } 905 } 906 return (t); 907 } 908 909 /*- 910 *----------------------------------------------------------------------- 911 * CondF -- 912 * Parse a conjunctive factor (nice name, wot?) 913 * F -> T && F | T 914 * 915 * Results: 916 * True, False or Err 917 * 918 * Side Effects: 919 * Tokens are consumed. 920 * 921 *----------------------------------------------------------------------- 922 */ 923 static Token 924 CondF(doEval) 925 Boolean doEval; 926 { 927 Token l, o; 928 929 l = CondT(doEval); 930 if (l != Err) { 931 o = CondToken(doEval); 932 933 if (o == And) { 934 /* 935 * F -> T && F 936 * 937 * If T is False, the whole thing will be False, but we have to 938 * parse the r.h.s. anyway (to throw it away). 939 * If T is True, the result is the r.h.s., be it an Err or no. 940 */ 941 if (l == True) { 942 l = CondF(doEval); 943 } else { 944 (void) CondF(FALSE); 945 } 946 } else { 947 /* 948 * F -> T 949 */ 950 CondPushBack (o); 951 } 952 } 953 return (l); 954 } 955 956 /*- 957 *----------------------------------------------------------------------- 958 * CondE -- 959 * Main expression production. 960 * E -> F || E | F 961 * 962 * Results: 963 * True, False or Err. 964 * 965 * Side Effects: 966 * Tokens are, of course, consumed. 967 * 968 *----------------------------------------------------------------------- 969 */ 970 static Token 971 CondE(doEval) 972 Boolean doEval; 973 { 974 Token l, o; 975 976 l = CondF(doEval); 977 if (l != Err) { 978 o = CondToken(doEval); 979 980 if (o == Or) { 981 /* 982 * E -> F || E 983 * 984 * A similar thing occurs for ||, except that here we make sure 985 * the l.h.s. is False before we bother to evaluate the r.h.s. 986 * Once again, if l is False, the result is the r.h.s. and once 987 * again if l is True, we parse the r.h.s. to throw it away. 988 */ 989 if (l == False) { 990 l = CondE(doEval); 991 } else { 992 (void) CondE(FALSE); 993 } 994 } else { 995 /* 996 * E -> F 997 */ 998 CondPushBack (o); 999 } 1000 } 1001 return (l); 1002 } 1003 1004 /*- 1005 *----------------------------------------------------------------------- 1006 * Cond_Eval -- 1007 * Evaluate the conditional in the passed line. The line 1008 * looks like this: 1009 * #<cond-type> <expr> 1010 * where <cond-type> is any of if, ifmake, ifnmake, ifdef, 1011 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef 1012 * and <expr> consists of &&, ||, !, make(target), defined(variable) 1013 * and parenthetical groupings thereof. 1014 * 1015 * Results: 1016 * COND_PARSE if should parse lines after the conditional 1017 * COND_SKIP if should skip lines after the conditional 1018 * COND_INVALID if not a valid conditional. 1019 * 1020 * Side Effects: 1021 * None. 1022 * 1023 *----------------------------------------------------------------------- 1024 */ 1025 int 1026 Cond_Eval (line) 1027 char *line; /* Line to parse */ 1028 { 1029 struct If *ifp; 1030 Boolean isElse; 1031 Boolean value = FALSE; 1032 int level; /* Level at which to report errors. */ 1033 1034 level = PARSE_FATAL; 1035 1036 for (line++; *line == ' ' || *line == '\t'; line++) { 1037 continue; 1038 } 1039 1040 /* 1041 * Find what type of if we're dealing with. The result is left 1042 * in ifp and isElse is set TRUE if it's an elif line. 1043 */ 1044 if (line[0] == 'e' && line[1] == 'l') { 1045 line += 2; 1046 isElse = TRUE; 1047 } else if (strncmp (line, "endif", 5) == 0) { 1048 /* 1049 * End of a conditional section. If skipIfLevel is non-zero, that 1050 * conditional was skipped, so lines following it should also be 1051 * skipped. Hence, we return COND_SKIP. Otherwise, the conditional 1052 * was read so succeeding lines should be parsed (think about it...) 1053 * so we return COND_PARSE, unless this endif isn't paired with 1054 * a decent if. 1055 */ 1056 if (skipIfLevel != 0) { 1057 skipIfLevel -= 1; 1058 return (COND_SKIP); 1059 } else { 1060 if (condTop == MAXIF) { 1061 Parse_Error (level, "if-less endif"); 1062 return (COND_INVALID); 1063 } else { 1064 skipLine = FALSE; 1065 condTop += 1; 1066 return (COND_PARSE); 1067 } 1068 } 1069 } else { 1070 isElse = FALSE; 1071 } 1072 1073 /* 1074 * Figure out what sort of conditional it is -- what its default 1075 * function is, etc. -- by looking in the table of valid "ifs" 1076 */ 1077 for (ifp = ifs; ifp->form != (char *)0; ifp++) { 1078 if (strncmp (ifp->form, line, ifp->formlen) == 0) { 1079 break; 1080 } 1081 } 1082 1083 if (ifp->form == (char *) 0) { 1084 /* 1085 * Nothing fit. If the first word on the line is actually 1086 * "else", it's a valid conditional whose value is the inverse 1087 * of the previous if we parsed. 1088 */ 1089 if (isElse && (line[0] == 's') && (line[1] == 'e')) { 1090 if (condTop == MAXIF) { 1091 Parse_Error (level, "if-less else"); 1092 return (COND_INVALID); 1093 } else if (skipIfLevel == 0) { 1094 value = !condStack[condTop]; 1095 } else { 1096 return (COND_SKIP); 1097 } 1098 } else { 1099 /* 1100 * Not a valid conditional type. No error... 1101 */ 1102 return (COND_INVALID); 1103 } 1104 } else { 1105 if (isElse) { 1106 if (condTop == MAXIF) { 1107 Parse_Error (level, "if-less elif"); 1108 return (COND_INVALID); 1109 } else if (skipIfLevel != 0) { 1110 /* 1111 * If skipping this conditional, just ignore the whole thing. 1112 * If we don't, the user might be employing a variable that's 1113 * undefined, for which there's an enclosing ifdef that 1114 * we're skipping... 1115 */ 1116 return(COND_SKIP); 1117 } 1118 } else if (skipLine) { 1119 /* 1120 * Don't even try to evaluate a conditional that's not an else if 1121 * we're skipping things... 1122 */ 1123 skipIfLevel += 1; 1124 return(COND_SKIP); 1125 } 1126 1127 /* 1128 * Initialize file-global variables for parsing 1129 */ 1130 condDefProc = ifp->defProc; 1131 condInvert = ifp->doNot; 1132 1133 line += ifp->formlen; 1134 1135 while (*line == ' ' || *line == '\t') { 1136 line++; 1137 } 1138 1139 condExpr = line; 1140 condPushBack = None; 1141 1142 switch (CondE(TRUE)) { 1143 case True: 1144 if (CondToken(TRUE) == EndOfFile) { 1145 value = TRUE; 1146 break; 1147 } 1148 goto err; 1149 /*FALLTHRU*/ 1150 case False: 1151 if (CondToken(TRUE) == EndOfFile) { 1152 value = FALSE; 1153 break; 1154 } 1155 /*FALLTHRU*/ 1156 case Err: 1157 err: 1158 Parse_Error (level, "Malformed conditional (%s)", 1159 line); 1160 return (COND_INVALID); 1161 default: 1162 break; 1163 } 1164 } 1165 if (!isElse) { 1166 condTop -= 1; 1167 } else if ((skipIfLevel != 0) || condStack[condTop]) { 1168 /* 1169 * If this is an else-type conditional, it should only take effect 1170 * if its corresponding if was evaluated and FALSE. If its if was 1171 * TRUE or skipped, we return COND_SKIP (and start skipping in case 1172 * we weren't already), leaving the stack unmolested so later elif's 1173 * don't screw up... 1174 */ 1175 skipLine = TRUE; 1176 return (COND_SKIP); 1177 } 1178 1179 if (condTop < 0) { 1180 /* 1181 * This is the one case where we can definitely proclaim a fatal 1182 * error. If we don't, we're hosed. 1183 */ 1184 Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); 1185 return (COND_INVALID); 1186 } else { 1187 condStack[condTop] = value; 1188 skipLine = !value; 1189 return (value ? COND_PARSE : COND_SKIP); 1190 } 1191 } 1192 1193 /*- 1194 *----------------------------------------------------------------------- 1195 * Cond_End -- 1196 * Make sure everything's clean at the end of a makefile. 1197 * 1198 * Results: 1199 * None. 1200 * 1201 * Side Effects: 1202 * Parse_Error will be called if open conditionals are around. 1203 * 1204 *----------------------------------------------------------------------- 1205 */ 1206 void 1207 Cond_End() 1208 { 1209 if (condTop != MAXIF) { 1210 Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop, 1211 MAXIF-condTop == 1 ? "" : "s"); 1212 } 1213 condTop = MAXIF; 1214 } 1215