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.3 (Berkeley) 04/28/95"; 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((ClientData, ClientData)); 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 char *p1; 255 Boolean result; 256 257 arg[argLen] = '\0'; 258 if (Var_Value (arg, VAR_CMD, &p1) != (char *)NULL) { 259 result = TRUE; 260 } else { 261 result = FALSE; 262 } 263 if (p1) 264 free(p1); 265 arg[argLen] = savec; 266 return (result); 267 } 268 269 /*- 270 *----------------------------------------------------------------------- 271 * CondStrMatch -- 272 * Front-end for Str_Match so it returns 0 on match and non-zero 273 * on mismatch. Callback function for CondDoMake via Lst_Find 274 * 275 * Results: 276 * 0 if string matches pattern 277 * 278 * Side Effects: 279 * None 280 * 281 *----------------------------------------------------------------------- 282 */ 283 static int 284 CondStrMatch(string, pattern) 285 ClientData string; 286 ClientData pattern; 287 { 288 return(!Str_Match((char *) string,(char *) pattern)); 289 } 290 291 /*- 292 *----------------------------------------------------------------------- 293 * CondDoMake -- 294 * Handle the 'make' function for conditionals. 295 * 296 * Results: 297 * TRUE if the given target is being made. 298 * 299 * Side Effects: 300 * None. 301 * 302 *----------------------------------------------------------------------- 303 */ 304 static Boolean 305 CondDoMake (argLen, arg) 306 int argLen; 307 char *arg; 308 { 309 char savec = arg[argLen]; 310 Boolean result; 311 312 arg[argLen] = '\0'; 313 if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) { 314 result = FALSE; 315 } else { 316 result = TRUE; 317 } 318 arg[argLen] = savec; 319 return (result); 320 } 321 322 /*- 323 *----------------------------------------------------------------------- 324 * CondDoExists -- 325 * See if the given file exists. 326 * 327 * Results: 328 * TRUE if the file exists and FALSE if it does not. 329 * 330 * Side Effects: 331 * None. 332 * 333 *----------------------------------------------------------------------- 334 */ 335 static Boolean 336 CondDoExists (argLen, arg) 337 int argLen; 338 char *arg; 339 { 340 char savec = arg[argLen]; 341 Boolean result; 342 char *path; 343 344 arg[argLen] = '\0'; 345 path = Dir_FindFile(arg, dirSearchPath); 346 if (path != (char *)NULL) { 347 result = TRUE; 348 free(path); 349 } else { 350 result = FALSE; 351 } 352 arg[argLen] = savec; 353 return (result); 354 } 355 356 /*- 357 *----------------------------------------------------------------------- 358 * CondDoTarget -- 359 * See if the given node exists and is an actual target. 360 * 361 * Results: 362 * TRUE if the node exists as a target and FALSE if it does not. 363 * 364 * Side Effects: 365 * None. 366 * 367 *----------------------------------------------------------------------- 368 */ 369 static Boolean 370 CondDoTarget (argLen, arg) 371 int argLen; 372 char *arg; 373 { 374 char savec = arg[argLen]; 375 Boolean result; 376 GNode *gn; 377 378 arg[argLen] = '\0'; 379 gn = Targ_FindNode(arg, TARG_NOCREATE); 380 if ((gn != NILGNODE) && !OP_NOP(gn->type)) { 381 result = TRUE; 382 } else { 383 result = FALSE; 384 } 385 arg[argLen] = savec; 386 return (result); 387 } 388 389 390 /*- 391 *----------------------------------------------------------------------- 392 * CondCvtArg -- 393 * Convert the given number into a double. If the number begins 394 * with 0x, it is interpreted as a hexadecimal integer 395 * and converted to a double from there. All other strings just have 396 * strtod called on them. 397 * 398 * Results: 399 * Sets 'value' to double value of string. 400 * Returns true if the string was a valid number, false o.w. 401 * 402 * Side Effects: 403 * Can change 'value' even if string is not a valid number. 404 * 405 * 406 *----------------------------------------------------------------------- 407 */ 408 static Boolean 409 CondCvtArg(str, value) 410 register char *str; 411 double *value; 412 { 413 if ((*str == '0') && (str[1] == 'x')) { 414 register long i; 415 416 for (str += 2, i = 0; *str; str++) { 417 int x; 418 if (isdigit((unsigned char) *str)) 419 x = *str - '0'; 420 else if (isxdigit((unsigned char) *str)) 421 x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a'; 422 else 423 return FALSE; 424 i = (i << 4) + x; 425 } 426 *value = (double) i; 427 return TRUE; 428 } 429 else { 430 char *eptr; 431 *value = strtod(str, &eptr); 432 return *eptr == '\0'; 433 } 434 } 435 436 /*- 437 *----------------------------------------------------------------------- 438 * CondToken -- 439 * Return the next token from the input. 440 * 441 * Results: 442 * A Token for the next lexical token in the stream. 443 * 444 * Side Effects: 445 * condPushback will be set back to None if it is used. 446 * 447 *----------------------------------------------------------------------- 448 */ 449 static Token 450 CondToken(doEval) 451 Boolean doEval; 452 { 453 Token t; 454 455 if (condPushBack == None) { 456 while (*condExpr == ' ' || *condExpr == '\t') { 457 condExpr++; 458 } 459 switch (*condExpr) { 460 case '(': 461 t = LParen; 462 condExpr++; 463 break; 464 case ')': 465 t = RParen; 466 condExpr++; 467 break; 468 case '|': 469 if (condExpr[1] == '|') { 470 condExpr++; 471 } 472 condExpr++; 473 t = Or; 474 break; 475 case '&': 476 if (condExpr[1] == '&') { 477 condExpr++; 478 } 479 condExpr++; 480 t = And; 481 break; 482 case '!': 483 t = Not; 484 condExpr++; 485 break; 486 case '\n': 487 case '\0': 488 t = EndOfFile; 489 break; 490 case '$': { 491 char *lhs; 492 char *rhs; 493 char *op; 494 int varSpecLen; 495 Boolean doFree; 496 497 /* 498 * Parse the variable spec and skip over it, saving its 499 * value in lhs. 500 */ 501 t = Err; 502 lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree); 503 if (lhs == var_Error) { 504 /* 505 * Even if !doEval, we still report syntax errors, which 506 * is what getting var_Error back with !doEval means. 507 */ 508 return(Err); 509 } 510 condExpr += varSpecLen; 511 512 if (!isspace((unsigned char) *condExpr) && 513 strchr("!=><", *condExpr) == NULL) { 514 Buffer buf; 515 char *cp; 516 517 buf = Buf_Init(0); 518 519 for (cp = lhs; *cp; cp++) 520 Buf_AddByte(buf, (Byte)*cp); 521 522 if (doFree) 523 free(lhs); 524 525 for (;*condExpr && !isspace((unsigned char) *condExpr); 526 condExpr++) 527 Buf_AddByte(buf, (Byte)*condExpr); 528 529 Buf_AddByte(buf, (Byte)'\0'); 530 lhs = (char *)Buf_GetAll(buf, &varSpecLen); 531 Buf_Destroy(buf, FALSE); 532 533 doFree = TRUE; 534 } 535 536 /* 537 * Skip whitespace to get to the operator 538 */ 539 while (isspace((unsigned char) *condExpr)) 540 condExpr++; 541 542 /* 543 * Make sure the operator is a valid one. If it isn't a 544 * known relational operator, pretend we got a 545 * != 0 comparison. 546 */ 547 op = condExpr; 548 switch (*condExpr) { 549 case '!': 550 case '=': 551 case '<': 552 case '>': 553 if (condExpr[1] == '=') { 554 condExpr += 2; 555 } else { 556 condExpr += 1; 557 } 558 break; 559 default: 560 op = "!="; 561 rhs = "0"; 562 563 goto do_compare; 564 } 565 while (isspace((unsigned char) *condExpr)) { 566 condExpr++; 567 } 568 if (*condExpr == '\0') { 569 Parse_Error(PARSE_WARNING, 570 "Missing right-hand-side of operator"); 571 goto error; 572 } 573 rhs = condExpr; 574 do_compare: 575 if (*rhs == '"') { 576 /* 577 * Doing a string comparison. Only allow == and != for 578 * operators. 579 */ 580 char *string; 581 char *cp, *cp2; 582 int qt; 583 Buffer buf; 584 585 do_string_compare: 586 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { 587 Parse_Error(PARSE_WARNING, 588 "String comparison operator should be either == or !="); 589 goto error; 590 } 591 592 buf = Buf_Init(0); 593 qt = *rhs == '"' ? 1 : 0; 594 595 for (cp = &rhs[qt]; 596 ((qt && (*cp != '"')) || 597 (!qt && strchr(" \t)", *cp) == NULL)) && 598 (*cp != '\0'); cp++) { 599 if ((*cp == '\\') && (cp[1] != '\0')) { 600 /* 601 * Backslash escapes things -- skip over next 602 * character, if it exists. 603 */ 604 cp++; 605 Buf_AddByte(buf, (Byte)*cp); 606 } else if (*cp == '$') { 607 int len; 608 Boolean freeIt; 609 610 cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt); 611 if (cp2 != var_Error) { 612 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 613 if (freeIt) { 614 free(cp2); 615 } 616 cp += len - 1; 617 } else { 618 Buf_AddByte(buf, (Byte)*cp); 619 } 620 } else { 621 Buf_AddByte(buf, (Byte)*cp); 622 } 623 } 624 625 Buf_AddByte(buf, (Byte)0); 626 627 string = (char *)Buf_GetAll(buf, (int *)0); 628 Buf_Destroy(buf, FALSE); 629 630 if (DEBUG(COND)) { 631 printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", 632 lhs, string, op); 633 } 634 /* 635 * Null-terminate rhs and perform the comparison. 636 * t is set to the result. 637 */ 638 if (*op == '=') { 639 t = strcmp(lhs, string) ? False : True; 640 } else { 641 t = strcmp(lhs, string) ? True : False; 642 } 643 free(string); 644 if (rhs == condExpr) { 645 if (!qt && *cp == ')') 646 condExpr = cp; 647 else 648 condExpr = cp + 1; 649 } 650 } else { 651 /* 652 * rhs is either a float or an integer. Convert both the 653 * lhs and the rhs to a double and compare the two. 654 */ 655 double left, right; 656 char *string; 657 658 if (!CondCvtArg(lhs, &left)) 659 goto do_string_compare; 660 if (*rhs == '$') { 661 int len; 662 Boolean freeIt; 663 664 string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt); 665 if (string == var_Error) { 666 right = 0.0; 667 } else { 668 if (!CondCvtArg(string, &right)) { 669 if (freeIt) 670 free(string); 671 goto do_string_compare; 672 } 673 if (freeIt) 674 free(string); 675 if (rhs == condExpr) 676 condExpr += len; 677 } 678 } else { 679 if (!CondCvtArg(rhs, &right)) 680 goto do_string_compare; 681 if (rhs == condExpr) { 682 /* 683 * Skip over the right-hand side 684 */ 685 while(!isspace((unsigned char) *condExpr) && 686 (*condExpr != '\0')) { 687 condExpr++; 688 } 689 } 690 } 691 692 if (DEBUG(COND)) { 693 printf("left = %f, right = %f, op = %.2s\n", left, 694 right, op); 695 } 696 switch(op[0]) { 697 case '!': 698 if (op[1] != '=') { 699 Parse_Error(PARSE_WARNING, 700 "Unknown operator"); 701 goto error; 702 } 703 t = (left != right ? True : False); 704 break; 705 case '=': 706 if (op[1] != '=') { 707 Parse_Error(PARSE_WARNING, 708 "Unknown operator"); 709 goto error; 710 } 711 t = (left == right ? True : False); 712 break; 713 case '<': 714 if (op[1] == '=') { 715 t = (left <= right ? True : False); 716 } else { 717 t = (left < right ? True : False); 718 } 719 break; 720 case '>': 721 if (op[1] == '=') { 722 t = (left >= right ? True : False); 723 } else { 724 t = (left > right ? True : False); 725 } 726 break; 727 } 728 } 729 error: 730 if (doFree) 731 free(lhs); 732 break; 733 } 734 default: { 735 Boolean (*evalProc)(); 736 Boolean invert = FALSE; 737 char *arg; 738 int arglen; 739 740 if (strncmp (condExpr, "defined", 7) == 0) { 741 /* 742 * Use CondDoDefined to evaluate the argument and 743 * CondGetArg to extract the argument from the 'function 744 * call'. 745 */ 746 evalProc = CondDoDefined; 747 condExpr += 7; 748 arglen = CondGetArg (&condExpr, &arg, "defined", TRUE); 749 if (arglen == 0) { 750 condExpr -= 7; 751 goto use_default; 752 } 753 } else if (strncmp (condExpr, "make", 4) == 0) { 754 /* 755 * Use CondDoMake to evaluate the argument and 756 * CondGetArg to extract the argument from the 'function 757 * call'. 758 */ 759 evalProc = CondDoMake; 760 condExpr += 4; 761 arglen = CondGetArg (&condExpr, &arg, "make", TRUE); 762 if (arglen == 0) { 763 condExpr -= 4; 764 goto use_default; 765 } 766 } else if (strncmp (condExpr, "exists", 6) == 0) { 767 /* 768 * Use CondDoExists to evaluate the argument and 769 * CondGetArg to extract the argument from the 770 * 'function call'. 771 */ 772 evalProc = CondDoExists; 773 condExpr += 6; 774 arglen = CondGetArg(&condExpr, &arg, "exists", TRUE); 775 if (arglen == 0) { 776 condExpr -= 6; 777 goto use_default; 778 } 779 } else if (strncmp(condExpr, "empty", 5) == 0) { 780 /* 781 * Use Var_Parse to parse the spec in parens and return 782 * True if the resulting string is empty. 783 */ 784 int length; 785 Boolean doFree; 786 char *val; 787 788 condExpr += 5; 789 790 for (arglen = 0; 791 condExpr[arglen] != '(' && condExpr[arglen] != '\0'; 792 arglen += 1) 793 continue; 794 795 if (condExpr[arglen] != '\0') { 796 val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, 797 doEval, &length, &doFree); 798 if (val == var_Error) { 799 t = Err; 800 } else { 801 /* 802 * A variable is empty when it just contains 803 * spaces... 4/15/92, christos 804 */ 805 char *p; 806 for (p = val; *p && isspace((unsigned char)*p); p++) 807 continue; 808 t = (*p == '\0') ? True : False; 809 } 810 if (doFree) { 811 free(val); 812 } 813 /* 814 * Advance condExpr to beyond the closing ). Note that 815 * we subtract one from arglen + length b/c length 816 * is calculated from condExpr[arglen - 1]. 817 */ 818 condExpr += arglen + length - 1; 819 } else { 820 condExpr -= 5; 821 goto use_default; 822 } 823 break; 824 } else if (strncmp (condExpr, "target", 6) == 0) { 825 /* 826 * Use CondDoTarget to evaluate the argument and 827 * CondGetArg to extract the argument from the 828 * 'function call'. 829 */ 830 evalProc = CondDoTarget; 831 condExpr += 6; 832 arglen = CondGetArg(&condExpr, &arg, "target", TRUE); 833 if (arglen == 0) { 834 condExpr -= 6; 835 goto use_default; 836 } 837 } else { 838 /* 839 * The symbol is itself the argument to the default 840 * function. We advance condExpr to the end of the symbol 841 * by hand (the next whitespace, closing paren or 842 * binary operator) and set to invert the evaluation 843 * function if condInvert is TRUE. 844 */ 845 use_default: 846 invert = condInvert; 847 evalProc = condDefProc; 848 arglen = CondGetArg(&condExpr, &arg, "", FALSE); 849 } 850 851 /* 852 * Evaluate the argument using the set function. If invert 853 * is TRUE, we invert the sense of the function. 854 */ 855 t = (!doEval || (* evalProc) (arglen, arg) ? 856 (invert ? False : True) : 857 (invert ? True : False)); 858 free(arg); 859 break; 860 } 861 } 862 } else { 863 t = condPushBack; 864 condPushBack = None; 865 } 866 return (t); 867 } 868 869 /*- 870 *----------------------------------------------------------------------- 871 * CondT -- 872 * Parse a single term in the expression. This consists of a terminal 873 * symbol or Not and a terminal symbol (not including the binary 874 * operators): 875 * T -> defined(variable) | make(target) | exists(file) | symbol 876 * T -> ! T | ( E ) 877 * 878 * Results: 879 * True, False or Err. 880 * 881 * Side Effects: 882 * Tokens are consumed. 883 * 884 *----------------------------------------------------------------------- 885 */ 886 static Token 887 CondT(doEval) 888 Boolean doEval; 889 { 890 Token t; 891 892 t = CondToken(doEval); 893 894 if (t == EndOfFile) { 895 /* 896 * If we reached the end of the expression, the expression 897 * is malformed... 898 */ 899 t = Err; 900 } else if (t == LParen) { 901 /* 902 * T -> ( E ) 903 */ 904 t = CondE(doEval); 905 if (t != Err) { 906 if (CondToken(doEval) != RParen) { 907 t = Err; 908 } 909 } 910 } else if (t == Not) { 911 t = CondT(doEval); 912 if (t == True) { 913 t = False; 914 } else if (t == False) { 915 t = True; 916 } 917 } 918 return (t); 919 } 920 921 /*- 922 *----------------------------------------------------------------------- 923 * CondF -- 924 * Parse a conjunctive factor (nice name, wot?) 925 * F -> T && F | T 926 * 927 * Results: 928 * True, False or Err 929 * 930 * Side Effects: 931 * Tokens are consumed. 932 * 933 *----------------------------------------------------------------------- 934 */ 935 static Token 936 CondF(doEval) 937 Boolean doEval; 938 { 939 Token l, o; 940 941 l = CondT(doEval); 942 if (l != Err) { 943 o = CondToken(doEval); 944 945 if (o == And) { 946 /* 947 * F -> T && F 948 * 949 * If T is False, the whole thing will be False, but we have to 950 * parse the r.h.s. anyway (to throw it away). 951 * If T is True, the result is the r.h.s., be it an Err or no. 952 */ 953 if (l == True) { 954 l = CondF(doEval); 955 } else { 956 (void) CondF(FALSE); 957 } 958 } else { 959 /* 960 * F -> T 961 */ 962 CondPushBack (o); 963 } 964 } 965 return (l); 966 } 967 968 /*- 969 *----------------------------------------------------------------------- 970 * CondE -- 971 * Main expression production. 972 * E -> F || E | F 973 * 974 * Results: 975 * True, False or Err. 976 * 977 * Side Effects: 978 * Tokens are, of course, consumed. 979 * 980 *----------------------------------------------------------------------- 981 */ 982 static Token 983 CondE(doEval) 984 Boolean doEval; 985 { 986 Token l, o; 987 988 l = CondF(doEval); 989 if (l != Err) { 990 o = CondToken(doEval); 991 992 if (o == Or) { 993 /* 994 * E -> F || E 995 * 996 * A similar thing occurs for ||, except that here we make sure 997 * the l.h.s. is False before we bother to evaluate the r.h.s. 998 * Once again, if l is False, the result is the r.h.s. and once 999 * again if l is True, we parse the r.h.s. to throw it away. 1000 */ 1001 if (l == False) { 1002 l = CondE(doEval); 1003 } else { 1004 (void) CondE(FALSE); 1005 } 1006 } else { 1007 /* 1008 * E -> F 1009 */ 1010 CondPushBack (o); 1011 } 1012 } 1013 return (l); 1014 } 1015 1016 /*- 1017 *----------------------------------------------------------------------- 1018 * Cond_Eval -- 1019 * Evaluate the conditional in the passed line. The line 1020 * looks like this: 1021 * #<cond-type> <expr> 1022 * where <cond-type> is any of if, ifmake, ifnmake, ifdef, 1023 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef 1024 * and <expr> consists of &&, ||, !, make(target), defined(variable) 1025 * and parenthetical groupings thereof. 1026 * 1027 * Results: 1028 * COND_PARSE if should parse lines after the conditional 1029 * COND_SKIP if should skip lines after the conditional 1030 * COND_INVALID if not a valid conditional. 1031 * 1032 * Side Effects: 1033 * None. 1034 * 1035 *----------------------------------------------------------------------- 1036 */ 1037 int 1038 Cond_Eval (line) 1039 char *line; /* Line to parse */ 1040 { 1041 struct If *ifp; 1042 Boolean isElse; 1043 Boolean value = FALSE; 1044 int level; /* Level at which to report errors. */ 1045 1046 level = PARSE_FATAL; 1047 1048 for (line++; *line == ' ' || *line == '\t'; line++) { 1049 continue; 1050 } 1051 1052 /* 1053 * Find what type of if we're dealing with. The result is left 1054 * in ifp and isElse is set TRUE if it's an elif line. 1055 */ 1056 if (line[0] == 'e' && line[1] == 'l') { 1057 line += 2; 1058 isElse = TRUE; 1059 } else if (strncmp (line, "endif", 5) == 0) { 1060 /* 1061 * End of a conditional section. If skipIfLevel is non-zero, that 1062 * conditional was skipped, so lines following it should also be 1063 * skipped. Hence, we return COND_SKIP. Otherwise, the conditional 1064 * was read so succeeding lines should be parsed (think about it...) 1065 * so we return COND_PARSE, unless this endif isn't paired with 1066 * a decent if. 1067 */ 1068 if (skipIfLevel != 0) { 1069 skipIfLevel -= 1; 1070 return (COND_SKIP); 1071 } else { 1072 if (condTop == MAXIF) { 1073 Parse_Error (level, "if-less endif"); 1074 return (COND_INVALID); 1075 } else { 1076 skipLine = FALSE; 1077 condTop += 1; 1078 return (COND_PARSE); 1079 } 1080 } 1081 } else { 1082 isElse = FALSE; 1083 } 1084 1085 /* 1086 * Figure out what sort of conditional it is -- what its default 1087 * function is, etc. -- by looking in the table of valid "ifs" 1088 */ 1089 for (ifp = ifs; ifp->form != (char *)0; ifp++) { 1090 if (strncmp (ifp->form, line, ifp->formlen) == 0) { 1091 break; 1092 } 1093 } 1094 1095 if (ifp->form == (char *) 0) { 1096 /* 1097 * Nothing fit. If the first word on the line is actually 1098 * "else", it's a valid conditional whose value is the inverse 1099 * of the previous if we parsed. 1100 */ 1101 if (isElse && (line[0] == 's') && (line[1] == 'e')) { 1102 if (condTop == MAXIF) { 1103 Parse_Error (level, "if-less else"); 1104 return (COND_INVALID); 1105 } else if (skipIfLevel == 0) { 1106 value = !condStack[condTop]; 1107 } else { 1108 return (COND_SKIP); 1109 } 1110 } else { 1111 /* 1112 * Not a valid conditional type. No error... 1113 */ 1114 return (COND_INVALID); 1115 } 1116 } else { 1117 if (isElse) { 1118 if (condTop == MAXIF) { 1119 Parse_Error (level, "if-less elif"); 1120 return (COND_INVALID); 1121 } else if (skipIfLevel != 0) { 1122 /* 1123 * If skipping this conditional, just ignore the whole thing. 1124 * If we don't, the user might be employing a variable that's 1125 * undefined, for which there's an enclosing ifdef that 1126 * we're skipping... 1127 */ 1128 return(COND_SKIP); 1129 } 1130 } else if (skipLine) { 1131 /* 1132 * Don't even try to evaluate a conditional that's not an else if 1133 * we're skipping things... 1134 */ 1135 skipIfLevel += 1; 1136 return(COND_SKIP); 1137 } 1138 1139 /* 1140 * Initialize file-global variables for parsing 1141 */ 1142 condDefProc = ifp->defProc; 1143 condInvert = ifp->doNot; 1144 1145 line += ifp->formlen; 1146 1147 while (*line == ' ' || *line == '\t') { 1148 line++; 1149 } 1150 1151 condExpr = line; 1152 condPushBack = None; 1153 1154 switch (CondE(TRUE)) { 1155 case True: 1156 if (CondToken(TRUE) == EndOfFile) { 1157 value = TRUE; 1158 break; 1159 } 1160 goto err; 1161 /*FALLTHRU*/ 1162 case False: 1163 if (CondToken(TRUE) == EndOfFile) { 1164 value = FALSE; 1165 break; 1166 } 1167 /*FALLTHRU*/ 1168 case Err: 1169 err: 1170 Parse_Error (level, "Malformed conditional (%s)", 1171 line); 1172 return (COND_INVALID); 1173 default: 1174 break; 1175 } 1176 } 1177 if (!isElse) { 1178 condTop -= 1; 1179 } else if ((skipIfLevel != 0) || condStack[condTop]) { 1180 /* 1181 * If this is an else-type conditional, it should only take effect 1182 * if its corresponding if was evaluated and FALSE. If its if was 1183 * TRUE or skipped, we return COND_SKIP (and start skipping in case 1184 * we weren't already), leaving the stack unmolested so later elif's 1185 * don't screw up... 1186 */ 1187 skipLine = TRUE; 1188 return (COND_SKIP); 1189 } 1190 1191 if (condTop < 0) { 1192 /* 1193 * This is the one case where we can definitely proclaim a fatal 1194 * error. If we don't, we're hosed. 1195 */ 1196 Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); 1197 return (COND_INVALID); 1198 } else { 1199 condStack[condTop] = value; 1200 skipLine = !value; 1201 return (value ? COND_PARSE : COND_SKIP); 1202 } 1203 } 1204 1205 /*- 1206 *----------------------------------------------------------------------- 1207 * Cond_End -- 1208 * Make sure everything's clean at the end of a makefile. 1209 * 1210 * Results: 1211 * None. 1212 * 1213 * Side Effects: 1214 * Parse_Error will be called if open conditionals are around. 1215 * 1216 *----------------------------------------------------------------------- 1217 */ 1218 void 1219 Cond_End() 1220 { 1221 if (condTop != MAXIF) { 1222 Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop, 1223 MAXIF-condTop == 1 ? "" : "s"); 1224 } 1225 condTop = MAXIF; 1226 } 1227