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.2 (Berkeley) 01/02/94"; 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 int qt; 578 Buffer buf; 579 580 do_string_compare: 581 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { 582 Parse_Error(PARSE_WARNING, 583 "String comparison operator should be either == or !="); 584 goto error; 585 } 586 587 buf = Buf_Init(0); 588 qt = *rhs == '"' ? 1 : 0; 589 590 for (cp = &rhs[qt]; 591 ((qt && (*cp != '"')) || 592 (!qt && strchr(" \t)", *cp) == NULL)) && 593 (*cp != '\0'); cp++) { 594 if ((*cp == '\\') && (cp[1] != '\0')) { 595 /* 596 * Backslash escapes things -- skip over next 597 * character, if it exists. 598 */ 599 cp++; 600 Buf_AddByte(buf, (Byte)*cp); 601 } else if (*cp == '$') { 602 int len; 603 Boolean freeIt; 604 605 cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt); 606 if (cp2 != var_Error) { 607 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 608 if (freeIt) { 609 free(cp2); 610 } 611 cp += len - 1; 612 } else { 613 Buf_AddByte(buf, (Byte)*cp); 614 } 615 } else { 616 Buf_AddByte(buf, (Byte)*cp); 617 } 618 } 619 620 Buf_AddByte(buf, (Byte)0); 621 622 string = (char *)Buf_GetAll(buf, (int *)0); 623 Buf_Destroy(buf, FALSE); 624 625 if (DEBUG(COND)) { 626 printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", 627 lhs, string, op); 628 } 629 /* 630 * Null-terminate rhs and perform the comparison. 631 * t is set to the result. 632 */ 633 if (*op == '=') { 634 t = strcmp(lhs, string) ? False : True; 635 } else { 636 t = strcmp(lhs, string) ? True : False; 637 } 638 free(string); 639 if (rhs == condExpr) { 640 if (!qt && *cp == ')') 641 condExpr = cp; 642 else 643 condExpr = cp + 1; 644 } 645 } else { 646 /* 647 * rhs is either a float or an integer. Convert both the 648 * lhs and the rhs to a double and compare the two. 649 */ 650 double left, right; 651 char *string; 652 653 if (!CondCvtArg(lhs, &left)) 654 goto do_string_compare; 655 if (*rhs == '$') { 656 int len; 657 Boolean freeIt; 658 659 string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt); 660 if (string == var_Error) { 661 right = 0.0; 662 } else { 663 if (!CondCvtArg(string, &right)) { 664 if (freeIt) 665 free(string); 666 goto do_string_compare; 667 } 668 if (freeIt) 669 free(string); 670 if (rhs == condExpr) 671 condExpr += len; 672 } 673 } else { 674 if (!CondCvtArg(rhs, &right)) 675 goto do_string_compare; 676 if (rhs == condExpr) { 677 /* 678 * Skip over the right-hand side 679 */ 680 while(!isspace(*condExpr) && (*condExpr != '\0')) { 681 condExpr++; 682 } 683 } 684 } 685 686 if (DEBUG(COND)) { 687 printf("left = %f, right = %f, op = %.2s\n", left, 688 right, op); 689 } 690 switch(op[0]) { 691 case '!': 692 if (op[1] != '=') { 693 Parse_Error(PARSE_WARNING, 694 "Unknown operator"); 695 goto error; 696 } 697 t = (left != right ? True : False); 698 break; 699 case '=': 700 if (op[1] != '=') { 701 Parse_Error(PARSE_WARNING, 702 "Unknown operator"); 703 goto error; 704 } 705 t = (left == right ? True : False); 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 case '>': 715 if (op[1] == '=') { 716 t = (left >= right ? True : False); 717 } else { 718 t = (left > right ? True : False); 719 } 720 break; 721 } 722 } 723 error: 724 if (doFree) 725 free(lhs); 726 break; 727 } 728 default: { 729 Boolean (*evalProc)(); 730 Boolean invert = FALSE; 731 char *arg; 732 int arglen; 733 734 if (strncmp (condExpr, "defined", 7) == 0) { 735 /* 736 * Use CondDoDefined to evaluate the argument and 737 * CondGetArg to extract the argument from the 'function 738 * call'. 739 */ 740 evalProc = CondDoDefined; 741 condExpr += 7; 742 arglen = CondGetArg (&condExpr, &arg, "defined", TRUE); 743 if (arglen == 0) { 744 condExpr -= 7; 745 goto use_default; 746 } 747 } else if (strncmp (condExpr, "make", 4) == 0) { 748 /* 749 * Use CondDoMake to evaluate the argument and 750 * CondGetArg to extract the argument from the 'function 751 * call'. 752 */ 753 evalProc = CondDoMake; 754 condExpr += 4; 755 arglen = CondGetArg (&condExpr, &arg, "make", TRUE); 756 if (arglen == 0) { 757 condExpr -= 4; 758 goto use_default; 759 } 760 } else if (strncmp (condExpr, "exists", 6) == 0) { 761 /* 762 * Use CondDoExists to evaluate the argument and 763 * CondGetArg to extract the argument from the 764 * 'function call'. 765 */ 766 evalProc = CondDoExists; 767 condExpr += 6; 768 arglen = CondGetArg(&condExpr, &arg, "exists", TRUE); 769 if (arglen == 0) { 770 condExpr -= 6; 771 goto use_default; 772 } 773 } else if (strncmp(condExpr, "empty", 5) == 0) { 774 /* 775 * Use Var_Parse to parse the spec in parens and return 776 * True if the resulting string is empty. 777 */ 778 int length; 779 Boolean doFree; 780 char *val; 781 782 condExpr += 5; 783 784 for (arglen = 0; 785 condExpr[arglen] != '(' && condExpr[arglen] != '\0'; 786 arglen += 1) 787 { 788 /* void */ ; 789 } 790 if (condExpr[arglen] != '\0') { 791 val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, 792 doEval, &length, &doFree); 793 if (val == var_Error) { 794 t = Err; 795 } else { 796 /* 797 * A variable is empty when it just contains 798 * spaces... 4/15/92, christos 799 */ 800 char *p; 801 for (p = val; *p && isspace(*p); p++) 802 continue; 803 t = (*p == '\0') ? True : False; 804 } 805 if (doFree) { 806 free(val); 807 } 808 /* 809 * Advance condExpr to beyond the closing ). Note that 810 * we subtract one from arglen + length b/c length 811 * is calculated from condExpr[arglen - 1]. 812 */ 813 condExpr += arglen + length - 1; 814 } else { 815 condExpr -= 5; 816 goto use_default; 817 } 818 break; 819 } else if (strncmp (condExpr, "target", 6) == 0) { 820 /* 821 * Use CondDoTarget to evaluate the argument and 822 * CondGetArg to extract the argument from the 823 * 'function call'. 824 */ 825 evalProc = CondDoTarget; 826 condExpr += 6; 827 arglen = CondGetArg(&condExpr, &arg, "target", TRUE); 828 if (arglen == 0) { 829 condExpr -= 6; 830 goto use_default; 831 } 832 } else { 833 /* 834 * The symbol is itself the argument to the default 835 * function. We advance condExpr to the end of the symbol 836 * by hand (the next whitespace, closing paren or 837 * binary operator) and set to invert the evaluation 838 * function if condInvert is TRUE. 839 */ 840 use_default: 841 invert = condInvert; 842 evalProc = condDefProc; 843 arglen = CondGetArg(&condExpr, &arg, "", FALSE); 844 } 845 846 /* 847 * Evaluate the argument using the set function. If invert 848 * is TRUE, we invert the sense of the function. 849 */ 850 t = (!doEval || (* evalProc) (arglen, arg) ? 851 (invert ? False : True) : 852 (invert ? True : False)); 853 free(arg); 854 break; 855 } 856 } 857 } else { 858 t = condPushBack; 859 condPushBack = None; 860 } 861 return (t); 862 } 863 864 /*- 865 *----------------------------------------------------------------------- 866 * CondT -- 867 * Parse a single term in the expression. This consists of a terminal 868 * symbol or Not and a terminal symbol (not including the binary 869 * operators): 870 * T -> defined(variable) | make(target) | exists(file) | symbol 871 * T -> ! T | ( E ) 872 * 873 * Results: 874 * True, False or Err. 875 * 876 * Side Effects: 877 * Tokens are consumed. 878 * 879 *----------------------------------------------------------------------- 880 */ 881 static Token 882 CondT(doEval) 883 Boolean doEval; 884 { 885 Token t; 886 887 t = CondToken(doEval); 888 889 if (t == EndOfFile) { 890 /* 891 * If we reached the end of the expression, the expression 892 * is malformed... 893 */ 894 t = Err; 895 } else if (t == LParen) { 896 /* 897 * T -> ( E ) 898 */ 899 t = CondE(doEval); 900 if (t != Err) { 901 if (CondToken(doEval) != RParen) { 902 t = Err; 903 } 904 } 905 } else if (t == Not) { 906 t = CondT(doEval); 907 if (t == True) { 908 t = False; 909 } else if (t == False) { 910 t = True; 911 } 912 } 913 return (t); 914 } 915 916 /*- 917 *----------------------------------------------------------------------- 918 * CondF -- 919 * Parse a conjunctive factor (nice name, wot?) 920 * F -> T && F | T 921 * 922 * Results: 923 * True, False or Err 924 * 925 * Side Effects: 926 * Tokens are consumed. 927 * 928 *----------------------------------------------------------------------- 929 */ 930 static Token 931 CondF(doEval) 932 Boolean doEval; 933 { 934 Token l, o; 935 936 l = CondT(doEval); 937 if (l != Err) { 938 o = CondToken(doEval); 939 940 if (o == And) { 941 /* 942 * F -> T && F 943 * 944 * If T is False, the whole thing will be False, but we have to 945 * parse the r.h.s. anyway (to throw it away). 946 * If T is True, the result is the r.h.s., be it an Err or no. 947 */ 948 if (l == True) { 949 l = CondF(doEval); 950 } else { 951 (void) CondF(FALSE); 952 } 953 } else { 954 /* 955 * F -> T 956 */ 957 CondPushBack (o); 958 } 959 } 960 return (l); 961 } 962 963 /*- 964 *----------------------------------------------------------------------- 965 * CondE -- 966 * Main expression production. 967 * E -> F || E | F 968 * 969 * Results: 970 * True, False or Err. 971 * 972 * Side Effects: 973 * Tokens are, of course, consumed. 974 * 975 *----------------------------------------------------------------------- 976 */ 977 static Token 978 CondE(doEval) 979 Boolean doEval; 980 { 981 Token l, o; 982 983 l = CondF(doEval); 984 if (l != Err) { 985 o = CondToken(doEval); 986 987 if (o == Or) { 988 /* 989 * E -> F || E 990 * 991 * A similar thing occurs for ||, except that here we make sure 992 * the l.h.s. is False before we bother to evaluate the r.h.s. 993 * Once again, if l is False, the result is the r.h.s. and once 994 * again if l is True, we parse the r.h.s. to throw it away. 995 */ 996 if (l == False) { 997 l = CondE(doEval); 998 } else { 999 (void) CondE(FALSE); 1000 } 1001 } else { 1002 /* 1003 * E -> F 1004 */ 1005 CondPushBack (o); 1006 } 1007 } 1008 return (l); 1009 } 1010 1011 /*- 1012 *----------------------------------------------------------------------- 1013 * Cond_Eval -- 1014 * Evaluate the conditional in the passed line. The line 1015 * looks like this: 1016 * #<cond-type> <expr> 1017 * where <cond-type> is any of if, ifmake, ifnmake, ifdef, 1018 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef 1019 * and <expr> consists of &&, ||, !, make(target), defined(variable) 1020 * and parenthetical groupings thereof. 1021 * 1022 * Results: 1023 * COND_PARSE if should parse lines after the conditional 1024 * COND_SKIP if should skip lines after the conditional 1025 * COND_INVALID if not a valid conditional. 1026 * 1027 * Side Effects: 1028 * None. 1029 * 1030 *----------------------------------------------------------------------- 1031 */ 1032 int 1033 Cond_Eval (line) 1034 char *line; /* Line to parse */ 1035 { 1036 struct If *ifp; 1037 Boolean isElse; 1038 Boolean value = FALSE; 1039 int level; /* Level at which to report errors. */ 1040 1041 level = PARSE_FATAL; 1042 1043 for (line++; *line == ' ' || *line == '\t'; line++) { 1044 continue; 1045 } 1046 1047 /* 1048 * Find what type of if we're dealing with. The result is left 1049 * in ifp and isElse is set TRUE if it's an elif line. 1050 */ 1051 if (line[0] == 'e' && line[1] == 'l') { 1052 line += 2; 1053 isElse = TRUE; 1054 } else if (strncmp (line, "endif", 5) == 0) { 1055 /* 1056 * End of a conditional section. If skipIfLevel is non-zero, that 1057 * conditional was skipped, so lines following it should also be 1058 * skipped. Hence, we return COND_SKIP. Otherwise, the conditional 1059 * was read so succeeding lines should be parsed (think about it...) 1060 * so we return COND_PARSE, unless this endif isn't paired with 1061 * a decent if. 1062 */ 1063 if (skipIfLevel != 0) { 1064 skipIfLevel -= 1; 1065 return (COND_SKIP); 1066 } else { 1067 if (condTop == MAXIF) { 1068 Parse_Error (level, "if-less endif"); 1069 return (COND_INVALID); 1070 } else { 1071 skipLine = FALSE; 1072 condTop += 1; 1073 return (COND_PARSE); 1074 } 1075 } 1076 } else { 1077 isElse = FALSE; 1078 } 1079 1080 /* 1081 * Figure out what sort of conditional it is -- what its default 1082 * function is, etc. -- by looking in the table of valid "ifs" 1083 */ 1084 for (ifp = ifs; ifp->form != (char *)0; ifp++) { 1085 if (strncmp (ifp->form, line, ifp->formlen) == 0) { 1086 break; 1087 } 1088 } 1089 1090 if (ifp->form == (char *) 0) { 1091 /* 1092 * Nothing fit. If the first word on the line is actually 1093 * "else", it's a valid conditional whose value is the inverse 1094 * of the previous if we parsed. 1095 */ 1096 if (isElse && (line[0] == 's') && (line[1] == 'e')) { 1097 if (condTop == MAXIF) { 1098 Parse_Error (level, "if-less else"); 1099 return (COND_INVALID); 1100 } else if (skipIfLevel == 0) { 1101 value = !condStack[condTop]; 1102 } else { 1103 return (COND_SKIP); 1104 } 1105 } else { 1106 /* 1107 * Not a valid conditional type. No error... 1108 */ 1109 return (COND_INVALID); 1110 } 1111 } else { 1112 if (isElse) { 1113 if (condTop == MAXIF) { 1114 Parse_Error (level, "if-less elif"); 1115 return (COND_INVALID); 1116 } else if (skipIfLevel != 0) { 1117 /* 1118 * If skipping this conditional, just ignore the whole thing. 1119 * If we don't, the user might be employing a variable that's 1120 * undefined, for which there's an enclosing ifdef that 1121 * we're skipping... 1122 */ 1123 return(COND_SKIP); 1124 } 1125 } else if (skipLine) { 1126 /* 1127 * Don't even try to evaluate a conditional that's not an else if 1128 * we're skipping things... 1129 */ 1130 skipIfLevel += 1; 1131 return(COND_SKIP); 1132 } 1133 1134 /* 1135 * Initialize file-global variables for parsing 1136 */ 1137 condDefProc = ifp->defProc; 1138 condInvert = ifp->doNot; 1139 1140 line += ifp->formlen; 1141 1142 while (*line == ' ' || *line == '\t') { 1143 line++; 1144 } 1145 1146 condExpr = line; 1147 condPushBack = None; 1148 1149 switch (CondE(TRUE)) { 1150 case True: 1151 if (CondToken(TRUE) == EndOfFile) { 1152 value = TRUE; 1153 break; 1154 } 1155 goto err; 1156 /*FALLTHRU*/ 1157 case False: 1158 if (CondToken(TRUE) == EndOfFile) { 1159 value = FALSE; 1160 break; 1161 } 1162 /*FALLTHRU*/ 1163 case Err: 1164 err: 1165 Parse_Error (level, "Malformed conditional (%s)", 1166 line); 1167 return (COND_INVALID); 1168 default: 1169 break; 1170 } 1171 } 1172 if (!isElse) { 1173 condTop -= 1; 1174 } else if ((skipIfLevel != 0) || condStack[condTop]) { 1175 /* 1176 * If this is an else-type conditional, it should only take effect 1177 * if its corresponding if was evaluated and FALSE. If its if was 1178 * TRUE or skipped, we return COND_SKIP (and start skipping in case 1179 * we weren't already), leaving the stack unmolested so later elif's 1180 * don't screw up... 1181 */ 1182 skipLine = TRUE; 1183 return (COND_SKIP); 1184 } 1185 1186 if (condTop < 0) { 1187 /* 1188 * This is the one case where we can definitely proclaim a fatal 1189 * error. If we don't, we're hosed. 1190 */ 1191 Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); 1192 return (COND_INVALID); 1193 } else { 1194 condStack[condTop] = value; 1195 skipLine = !value; 1196 return (value ? COND_PARSE : COND_SKIP); 1197 } 1198 } 1199 1200 /*- 1201 *----------------------------------------------------------------------- 1202 * Cond_End -- 1203 * Make sure everything's clean at the end of a makefile. 1204 * 1205 * Results: 1206 * None. 1207 * 1208 * Side Effects: 1209 * Parse_Error will be called if open conditionals are around. 1210 * 1211 *----------------------------------------------------------------------- 1212 */ 1213 void 1214 Cond_End() 1215 { 1216 if (condTop != MAXIF) { 1217 Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop, 1218 MAXIF-condTop == 1 ? "" : "s"); 1219 } 1220 condTop = MAXIF; 1221 } 1222