儲存庫 kBuild 的更動 1719
- 時間撮記:
- 2008-9-4 上午02:49:36 (16 年 以前)
- 位置:
- trunk/src/kmk
- 檔案:
-
- 修改 5 筆資料
圖例:
- 未更動
- 新增
- 刪除
-
trunk/src/kmk/Makefile.kmk
r1716 r1719 159 159 CONFIG_WITH_NANOTS \ 160 160 CONFIG_WITH_SET_CONDITIONALS \ 161 CONFIG_WITH_IF_CONDITIONALS \162 161 CONFIG_WITH_DATE \ 163 162 CONFIG_WITH_FILE_SIZE \ -
trunk/src/kmk/ifcond.c
r1715 r1719 1 1 #ifdef CONFIG_WITH_IF_CONDITIONALS 2 2 /* $Id$ */ 3 /** @file 4 * ifcond - C like if expressions. 5 */ 6 7 /* 8 * Copyright (c) 2008 knut st. osmundsen <[email protected]> 9 * 10 * This file is part of kBuild. 11 * 12 * kBuild is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * kBuild is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with kBuild; if not, write to the Free Software 24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 25 * 26 */ 27 28 /******************************************************************************* 29 * Header Files * 30 *******************************************************************************/ 3 31 #include "make.h" 4 32 #include <assert.h> … … 14 42 #include "debug.h" 15 43 #include "hash.h" 16 17 18 19 20 int ifcond_eval(char *line, const struct floc *flocp) 21 { 22 error (flocp, _("if conditionals are not implemented yet")); 23 24 return -1; 44 #include <ctype.h> 45 #ifdef _MSC_VER 46 # include <stdint.h> 47 #endif 48 #include <stdarg.h> 49 50 51 /******************************************************************************* 52 * Defined Constants And Macros * 53 *******************************************************************************/ 54 /** The max length of a string representation of a number. */ 55 #define IFCOND_NUM_LEN ((sizeof("-9223372036854775802") + 4) & ~3) 56 57 /** The max operator stack depth. */ 58 #define IFCOND_MAX_OPERATORS 72 59 /** The max operand depth. */ 60 #define IFCOND_MAX_OPERANDS 128 61 62 63 /******************************************************************************* 64 * Structures and Typedefs * 65 *******************************************************************************/ 66 /** The 64-bit signed integer type we're using. */ 67 #ifdef _MSC_VER 68 typedef __int64 IFCONDINT64; 69 #else 70 # include <stdint.h> 71 typedef int64_t IFCONDINT64; 72 #endif 73 74 /** Pointer to a evaluator instance. */ 75 typedef struct IFCOND *PIFCOND; 76 77 78 /** 79 * Operand variable type. 80 */ 81 typedef enum 82 { 83 /** Invalid zero entry. */ 84 kIfCondVar_Invalid = 0, 85 /** A number. */ 86 kIfCondVar_Num, 87 /** A string in need of expanding (perhaps). */ 88 kIfCondVar_String, 89 /** A simple string that doesn't need expanding. */ 90 kIfCondVar_SimpleString, 91 /** The end of the valid variable types. */ 92 kIfCondVar_End 93 } IFCONDVARTYPE; 94 95 /** 96 * Operand variable. 97 */ 98 typedef struct 99 { 100 /** The variable type. */ 101 IFCONDVARTYPE enmType; 102 /** The variable. */ 103 union 104 { 105 /** Pointer to the string. */ 106 char *psz; 107 /** The variable. */ 108 IFCONDINT64 i; 109 } uVal; 110 } IFCONDVAR; 111 /** Pointer to a operand variable. */ 112 typedef IFCONDVAR *PIFCONDVAR; 113 /** Pointer to a const operand variable. */ 114 typedef IFCONDVAR const *PCIFCONDVAR; 115 116 /** 117 * Operator return statuses. 118 */ 119 typedef enum 120 { 121 kIfCondRet_Error = -1, 122 kIfCondRet_Ok = 0, 123 kIfCondRet_Operator, 124 kIfCondRet_Operand, 125 kIfCondRet_EndOfExpr, 126 kIfCondRet_End 127 } IFCONDRET; 128 129 /** 130 * Operator. 131 */ 132 typedef struct 133 { 134 /** The operator. */ 135 char szOp[11]; 136 /** The length of the operator string. */ 137 char cchOp; 138 /** The pair operator. 139 * This is used with '(' and '?'. */ 140 char chPair; 141 /** The precedence. Higher means higher. */ 142 char iPrecedence; 143 /** The number of arguments it takes. */ 144 signed char cArgs; 145 /** Pointer to the method implementing the operator. */ 146 IFCONDRET (*pfn)(PIFCOND pThis); 147 } IFCONDOP; 148 /** Pointer to a const operator. */ 149 typedef IFCONDOP const *PCIFCONDOP; 150 151 /** 152 * Expression evaluator instance. 153 */ 154 typedef struct IFCOND 155 { 156 /** The full expression. */ 157 const char *pszExpr; 158 /** The current location. */ 159 const char *psz; 160 /** The current file location, used for errors. */ 161 const struct floc *pFileLoc; 162 /** Pending binary operator. */ 163 PCIFCONDOP pPending; 164 /** Top of the operator stack. */ 165 int iOp; 166 /** Top of the operand stack. */ 167 int iVar; 168 /** The operator stack. */ 169 PCIFCONDOP apOps[IFCOND_MAX_OPERATORS]; 170 /** The operand stack. */ 171 IFCONDVAR aVars[IFCOND_MAX_OPERANDS]; 172 } IFCOND; 173 174 175 /******************************************************************************* 176 * Global Variables * 177 *******************************************************************************/ 178 /** Operator start character map. 179 * This indicates which characters that are starting operators and which aren't. */ 180 static char g_auchOpStartCharMap[256]; 181 /** Whether we've initialized the map. */ 182 static int g_fIfCondInitializedMap = 0; 183 184 185 /******************************************************************************* 186 * Internal Functions * 187 *******************************************************************************/ 188 static void ifcond_unget_op(PIFCOND pThis); 189 static IFCONDRET ifcond_get_binary_or_eoe_or_rparen(PIFCOND pThis); 190 191 192 193 194 /** 195 * Displays an error message. 196 * 197 * The total string length must not exceed 256 bytes. 198 * 199 * @param pThis The evaluator instance. 200 * @param pszError The message format string. 201 * @param ... The message format args. 202 */ 203 static void ifcond_error(PIFCOND pThis, const char *pszError, ...) 204 { 205 char szTmp[256]; 206 va_list va; 207 208 va_start(va, pszError); 209 vsprintf(szTmp, pszError, va); 210 va_end(va); 211 212 fatal(pThis->pFileLoc, "%s", szTmp); 213 } 214 215 216 /** 217 * Converts a number to a string. 218 * 219 * @returns pszDst. 220 * @param pszDst The string buffer to write into. Assumes length of IFCOND_NUM_LEN. 221 * @param iSrc The number to convert. 222 */ 223 static char *ifcond_num_to_string(char *pszDst, IFCONDINT64 iSrc) 224 { 225 static const char s_szDigits[17] = "0123456789abcdef"; 226 char szTmp[IFCOND_NUM_LEN]; 227 char *psz = &szTmp[IFCOND_NUM_LEN - 1]; 228 int fNegative; 229 230 fNegative = iSrc < 0; 231 if (fNegative) 232 { 233 /** @todo this isn't right for INT64_MIN. */ 234 iSrc = -iSrc; 235 } 236 237 *psz = '\0'; 238 do 239 { 240 #if 0 241 *--psz = s_szDigits[iSrc & 0xf]; 242 iSrc >>= 4; 243 #else 244 *--psz = s_szDigits[iSrc % 10]; 245 iSrc /= 10; 246 #endif 247 } while (iSrc); 248 249 #if 0 250 *--psz = 'x'; 251 *--psz = '0'; 252 #endif 253 254 if (fNegative) 255 *--psz = '-'; 256 257 /* copy it into the output buffer. */ 258 psz++; 259 return (char *)memcpy(pszDst, psz, &szTmp[IFCOND_NUM_LEN] - psz); 260 } 261 262 263 /** 264 * Attempts to convert a (simple) string into a number. 265 * 266 * @returns status code. 267 * @param pThis The evaluator instance. This is optional when fQuiet is true. 268 * @param piSrc Where to store the numeric value on success. 269 * @param pszSrc The string to try convert. 270 * @param fQuiet Whether we should be quiet or grumpy on failure. 271 */ 272 static IFCONDRET ifcond_string_to_num(PIFCOND pThis, IFCONDINT64 *piDst, const char *pszSrc, int fQuiet) 273 { 274 IFCONDRET rc = kIfCondRet_Ok; 275 char const *psz = pszSrc; 276 IFCONDINT64 i; 277 unsigned uBase; 278 int fNegative; 279 280 281 /* 282 * Skip blanks. 283 */ 284 while (isblank(*psz)) 285 psz++; 286 287 /* 288 * Check for '-'. 289 * 290 * At this point we will not need to deal with operators, this is 291 * just an indicator of negative numbers. If some operator ends up 292 * here it's because it came from a string expansion and thus shall 293 * not be interpreted. If this turns out to be an stupid restriction 294 * it can be fixed, but for now it stays like this. 295 */ 296 fNegative = *psz == '-'; 297 if (fNegative) 298 psz++; 299 300 /* 301 * Determin base . 302 * . 303 * Recognize some exsotic prefixes here in addition to the two standard ones. 304 */ 305 if (*psz != '0' || psz[1] == '\0' || isblank((unsigned int)psz[1])) 306 uBase = 10; 307 else if (psz[1] == 'x' || psz[1] == 'X') 308 { 309 uBase = 16; 310 psz += 2; 311 } 312 else if (psz[1] == 'b' || psz[1] == 'B') 313 { 314 uBase = 2; 315 psz += 2; 316 } 317 else if (psz[1] == 'd' || psz[1] == 'D') 318 { 319 uBase = 10; 320 psz += 2; 321 } 322 else if (psz[1] == 'o' || psz[1] == 'O') 323 { 324 uBase = 8; 325 psz += 2; 326 } 327 else if (isdigit(psz[1]) && psz[1] != '9' && psz[1] != '8') 328 { 329 uBase = 8; 330 psz++; 331 } 332 else 333 uBase = 10; 334 335 /* 336 * Convert until we hit a non-digit. 337 */ 338 i = 0; 339 for (;;) 340 { 341 int iDigit; 342 int ch = *psz; 343 switch (ch) 344 { 345 case '0': iDigit = 0; break; 346 case '1': iDigit = 1; break; 347 case '2': iDigit = 2; break; 348 case '3': iDigit = 3; break; 349 case '4': iDigit = 4; break; 350 case '5': iDigit = 5; break; 351 case '6': iDigit = 6; break; 352 case '7': iDigit = 7; break; 353 case '8': iDigit = 8; break; 354 case '9': iDigit = 9; break; 355 case 'a': 356 case 'A': iDigit = 10; break; 357 case 'b': 358 case 'B': iDigit = 11; break; 359 case 'c': 360 case 'C': iDigit = 12; break; 361 case 'd': 362 case 'D': iDigit = 13; break; 363 case 'e': 364 case 'E': iDigit = 14; break; 365 case 'f': 366 case 'F': iDigit = 15; break; 367 368 default: 369 /* is the rest white space? */ 370 while (isspace((unsigned int)*psz)) 371 psz++; 372 if (*psz != '\0') 373 { 374 iDigit = uBase; 375 break; 376 } 377 /* fall thru */ 378 379 case '\0': 380 if (fNegative) 381 i = -i; 382 *piDst = i; 383 return rc; 384 } 385 if (iDigit >= uBase) 386 { 387 if (fNegative) 388 i = -i; 389 *piDst = i; 390 if (!fQuiet) 391 ifcond_error(pThis, "Invalid a number \"%.80s\"", pszSrc); 392 return kIfCondRet_Error; 393 } 394 395 /* add the digit and advance */ 396 i *= uBase; 397 i += iDigit; 398 psz++; 399 } 400 /* not reached */ 401 } 402 403 404 /** 405 * Checks if the variable is a string or not. 406 * 407 * @returns 1 if it's a string, 0 otherwise. 408 * @param pVar The variable. 409 */ 410 static int ifcond_var_is_string(PCIFCONDVAR pVar) 411 { 412 return pVar->enmType >= kIfCondVar_String; 413 } 414 415 416 /** 417 * Deletes a variable. 418 * 419 * @param pVar The variable. 420 */ 421 static void ifcond_var_delete(PIFCONDVAR pVar) 422 { 423 if (ifcond_var_is_string(pVar)) 424 { 425 free(pVar->uVal.psz); 426 pVar->uVal.psz = NULL; 427 } 428 pVar->enmType = kIfCondVar_Invalid; 429 } 430 431 432 /** 433 * Initializes a new variables with a sub-string value. 434 * 435 * @param pVar The new variable. 436 * @param psz The start of the string value. 437 * @param cch The number of chars to copy. 438 * @param enmType The string type. 439 */ 440 static void ifcond_var_init_substring(PIFCONDVAR pVar, const char *psz, size_t cch, IFCONDVARTYPE enmType) 441 { 442 if ( enmType != kIfCondVar_SimpleString 443 && memchr(psz, '$', cch)) 444 pVar->enmType = kIfCondVar_String; 445 else 446 pVar->enmType = kIfCondVar_SimpleString; 447 pVar->uVal.psz = xmalloc(cch + 1); 448 memcpy(pVar->uVal.psz, psz, cch); 449 pVar->uVal.psz[cch] = '\0'; 450 } 451 452 453 #if 0 /* unused */ 454 /** 455 * Initializes a new variables with a string value. 456 * 457 * @param pVar The new variable. 458 * @param psz The string value. 459 * @param enmType The string type. 460 */ 461 static void ifcond_var_init_string(PIFCONDVAR pVar, const char *psz, IFCONDVARTYPE enmType) 462 { 463 ifcond_var_init_substring(pVar, psz, strlen(psz), enmType); 464 } 465 466 467 /** 468 * Assigns a sub-string value to a variable. 469 * 470 * @param pVar The new variable. 471 * @param psz The start of the string value. 472 * @param cch The number of chars to copy. 473 * @param enmType The string type. 474 */ 475 static void ifcond_var_assign_substring(PIFCONDVAR pVar, const char *psz, size_t cch, IFCONDVARTYPE enmType) 476 { 477 ifcond_var_delete(pVar); 478 ifcond_var_init_substring(pVar, psz, cch, enmType); 479 } 480 481 482 /** 483 * Assignes a string value to a variable. 484 * 485 * @param pVar The variable. 486 * @param psz The string value. 487 * @param enmType The string type. 488 */ 489 static void ifcond_var_assign_string(PIFCONDVAR pVar, const char *psz, IFCONDVARTYPE enmType) 490 { 491 ifcond_var_delete(pVar); 492 ifcond_var_init_string(pVar, psz, enmType); 493 } 494 #endif /* unused */ 495 496 497 /** 498 * Simplifies a string variable. 499 * 500 * @param pVar The variable. 501 */ 502 static void ifcond_var_make_simple_string(PIFCONDVAR pVar) 503 { 504 switch (pVar->enmType) 505 { 506 case kIfCondVar_Num: 507 { 508 char *psz = (char *)xmalloc(IFCOND_NUM_LEN); 509 ifcond_num_to_string(psz, pVar->uVal.i); 510 pVar->uVal.psz = psz; 511 pVar->enmType = kIfCondVar_SimpleString; 512 break; 513 } 514 515 case kIfCondVar_String: 516 { 517 char *psz; 518 assert(strchr(pVar->uVal.psz, '$')); 519 520 psz = allocated_variable_expand(pVar->uVal.psz); 521 free(pVar->uVal.psz); 522 pVar->uVal.psz = psz; 523 524 pVar->enmType = kIfCondVar_SimpleString; 525 break; 526 } 527 528 case kIfCondVar_SimpleString: 529 /* nothing to do. */ 530 break; 531 532 default: 533 assert(0); 534 } 535 } 536 537 538 #if 0 /* unused */ 539 /** 540 * Turns a variable into a string value. 541 * 542 * @param pVar The variable. 543 */ 544 static void ifcond_var_make_string(PIFCONDVAR pVar) 545 { 546 switch (pVar->enmType) 547 { 548 case kIfCondVar_Num: 549 ifcond_var_make_simple_string(pVar); 550 551 case kIfCondVar_String: 552 case kIfCondVar_SimpleString: 553 /* nothing to do. */ 554 break; 555 556 default: 557 assert(0); 558 } 559 } 560 #endif /* unused */ 561 562 563 /** 564 * Initializes a new variables with a integer value. 565 * 566 * @param pVar The new variable. 567 * @param i The integer value. 568 */ 569 static void ifcond_var_init_num(PIFCONDVAR pVar, IFCONDINT64 i) 570 { 571 pVar->enmType = kIfCondVar_Num; 572 pVar->uVal.i = i; 573 } 574 575 576 /** 577 * Assigns a integer value to a variable. 578 * 579 * @param pVar The variable. 580 * @param i The integer value. 581 */ 582 static void ifcond_var_assign_num(PIFCONDVAR pVar, IFCONDINT64 i) 583 { 584 ifcond_var_delete(pVar); 585 ifcond_var_init_num(pVar, i); 586 } 587 588 589 /** 590 * Turns the variable into a number. 591 * 592 * @returns status code. 593 * @param pThis The evaluator instance. 594 * @param pVar The variable. 595 */ 596 static IFCONDRET ifcond_var_make_num(PIFCOND pThis, PIFCONDVAR pVar) 597 { 598 switch (pVar->enmType) 599 { 600 case kIfCondVar_Num: 601 /* nothing to do. */ 602 break; 603 604 case kIfCondVar_String: 605 ifcond_var_make_simple_string(pVar); 606 /* fall thru */ 607 case kIfCondVar_SimpleString: 608 { 609 IFCONDINT64 i; 610 IFCONDRET rc = ifcond_string_to_num(pThis, &i, pVar->uVal.psz, 0 /* fQuiet */); 611 if (rc < kIfCondRet_Ok) 612 return rc; 613 ifcond_var_assign_num(pVar, i); 614 break; 615 } 616 617 default: 618 assert(0); 619 return kIfCondRet_Error; 620 } 621 622 return kIfCondRet_Ok; 623 } 624 625 626 /** 627 * Initializes a new variables with a boolean value. 628 * 629 * @param pVar The new variable. 630 * @param f The boolean value. 631 */ 632 static void ifcond_var_init_bool(PIFCONDVAR pVar, int f) 633 { 634 pVar->enmType = kIfCondVar_Num; 635 pVar->uVal.i = !!f; 636 } 637 638 639 /** 640 * Assigns a boolean value to a variable. 641 * 642 * @param pVar The variable. 643 * @param f The boolean value. 644 */ 645 static void ifcond_var_assign_bool(PIFCONDVAR pVar, int f) 646 { 647 ifcond_var_delete(pVar); 648 ifcond_var_init_bool(pVar, f); 649 } 650 651 652 /** 653 * Turns the variable into an boolean. 654 * 655 * @returns the boolean interpretation. 656 * @param pVar The variable. 657 */ 658 static int ifcond_var_make_bool(PIFCONDVAR pVar) 659 { 660 switch (pVar->enmType) 661 { 662 case kIfCondVar_Num: 663 pVar->uVal.i = !!pVar->uVal.i; 664 break; 665 666 case kIfCondVar_String: 667 ifcond_var_make_simple_string(pVar); 668 /* fall thru */ 669 case kIfCondVar_SimpleString: 670 { 671 /* 672 * Try convert it to a number. If that fails, use the 673 * GNU make boolean logic - not empty string means true. 674 */ 675 IFCONDINT64 iVal; 676 char const *psz = pVar->uVal.psz; 677 while (isblank((unsigned char)*psz)) 678 psz++; 679 if ( *psz 680 && ifcond_string_to_num(NULL, &iVal, psz, 1 /* fQuiet */) >= kIfCondRet_Ok) 681 ifcond_var_assign_bool(pVar, iVal != 0); 682 else 683 ifcond_var_assign_bool(pVar, *psz != '\0'); 684 break; 685 } 686 687 default: 688 assert(0); 689 break; 690 } 691 692 return pVar->uVal.i; 693 } 694 695 696 /** 697 * Pops a varable off the stack and deletes it. 698 * @param pThis The evaluator instance. 699 */ 700 static void ifcond_pop_and_delete_var(PIFCOND pThis) 701 { 702 ifcond_var_delete(&pThis->aVars[pThis->iVar]); 703 pThis->iVar--; 704 } 705 706 707 /** 708 * Bitwise OR. 709 * 710 * @returns Status code. 711 * @param pThis The instance. 712 */ 713 static IFCONDRET ifcond_op_bitwise_or(PIFCOND pThis) 714 { 715 IFCONDRET rc; 716 assert(pThis->iVar >= 1); 717 718 rc = ifcond_var_make_num(pThis, &pThis->aVars[pThis->iVar - 1]); 719 if (rc >= kIfCondRet_Ok) 720 { 721 rc = ifcond_var_make_num(pThis, &pThis->aVars[pThis->iVar]); 722 if (rc >= kIfCondRet_Ok) 723 pThis->aVars[pThis->iVar - 1].uVal.i |= pThis->aVars[pThis->iVar].uVal.i; 724 } 725 726 ifcond_pop_and_delete_var(pThis); 727 return kIfCondRet_Ok; 728 } 729 730 731 /** 732 * Logical AND. 733 * 734 * @returns Status code. 735 * @param pThis The instance. 736 */ 737 static IFCONDRET ifcond_op_logical_and(PIFCOND pThis) 738 { 739 assert(pThis->iVar >= 1); 740 if ( ifcond_var_make_bool(&pThis->aVars[pThis->iVar - 1]) 741 && ifcond_var_make_bool(&pThis->aVars[pThis->iVar])) 742 ifcond_var_assign_bool(&pThis->aVars[pThis->iVar - 1], 1); 743 else 744 ifcond_var_assign_bool(&pThis->aVars[pThis->iVar - 1], 0); 745 746 ifcond_pop_and_delete_var(pThis); 747 return kIfCondRet_Ok; 748 } 749 750 751 /** 752 * Logical OR. 753 * 754 * @returns Status code. 755 * @param pThis The instance. 756 */ 757 static IFCONDRET ifcond_op_logical_or(PIFCOND pThis) 758 { 759 assert(pThis->iVar >= 1); 760 if ( ifcond_var_make_bool(&pThis->aVars[pThis->iVar - 1]) 761 || ifcond_var_make_bool(&pThis->aVars[pThis->iVar])) 762 ifcond_var_assign_bool(&pThis->aVars[pThis->iVar - 1], 1); 763 else 764 ifcond_var_assign_bool(&pThis->aVars[pThis->iVar - 1], 0); 765 766 ifcond_pop_and_delete_var(pThis); 767 return kIfCondRet_Ok; 768 } 769 770 771 /** 772 * Left parenthesis. 773 * 774 * @returns Status code. 775 * @param pThis The instance. 776 */ 777 static IFCONDRET ifcond_op_left_parenthesis(PIFCOND pThis) 778 { 779 /* 780 * There should be a right parenthesis operator lined up for us now, 781 * eat it. If not found there is an inbalance. 782 */ 783 IFCONDRET rc = ifcond_get_binary_or_eoe_or_rparen(pThis); 784 if ( rc == kIfCondRet_Operator 785 && pThis->apOps[pThis->iOp]->szOp[0] == ')') 786 { 787 /* pop it and get another one which we can leave pending. */ 788 pThis->iOp--; 789 rc = ifcond_get_binary_or_eoe_or_rparen(pThis); 790 if (rc >= kIfCondRet_Ok) 791 ifcond_unget_op(pThis); 792 } 793 else 794 { 795 ifcond_error(pThis, "Missing ')'"); 796 rc = kIfCondRet_Error; 797 } 798 799 return rc; 800 } 801 802 803 /** 804 * Right parenthesis, dummy that's never actually called. 805 * 806 * @returns Status code. 807 * @param pThis The instance. 808 */ 809 static IFCONDRET ifcond_op_right_parenthesis(PIFCOND pThis) 810 { 811 return kIfCondRet_Ok; 812 } 813 814 815 816 817 818 /** 819 * The operator table. 820 * 821 * This table is NOT ordered by precedence, but for linear search 822 * allowing for first match to return the correct operator. This 823 * means that || must come before |, or else | will match all. 824 */ 825 static const IFCONDOP g_aIfCondOps[] = 826 { 827 #define IFCOND_OP(szOp, iPrecedence, cArgs, pfn) { szOp, sizeof(szOp) - 1, '\0', iPrecedence, cArgs, pfn } 828 /* Name, iPrecedence, cArgs, pfn */ 829 #if 0 830 IFCOND_OP("defined", 90, 1, ifcond_op_defined), 831 IFCOND_OP("+", 80, 1, ifcond_op_pluss), 832 IFCOND_OP("-", 80, 1, ifcond_op_minus), 833 IFCOND_OP("~", 80, 1, ifcond_op_bitwise_not), 834 IFCOND_OP("*", 75, 2, ifcond_op_multiply), 835 IFCOND_OP("/", 75, 2, ifcond_op_divide), 836 IFCOND_OP("%", 75, 2, ifcond_op_mod), 837 IFCOND_OP("+", 70, 2, ifcond_op_add), 838 IFCOND_OP("-", 70, 2, ifcond_op_sub), 839 IFCOND_OP("<<", 65, 2, ifcond_op_shift_left), 840 IFCOND_OP(">>", 65, 2, ifcond_op_shift_right), 841 IFCOND_OP("<=", 60, 2, ifcond_op_less_or_equal_than), 842 IFCOND_OP("<", 60, 2, ifcond_op_less_than), 843 IFCOND_OP(">=", 60, 2, ifcond_op_greater_or_equal_than), 844 IFCOND_OP(">", 60, 2, ifcond_op_greater_than), 845 IFCOND_OP("==", 55, 2, ifcond_op_equal), 846 IFCOND_OP("!=", 55, 2, ifcond_op_not_equal), 847 IFCOND_OP("!", 80, 1, ifcond_op_logical_not), 848 IFCOND_OP("^", 45, 2, ifcond_op_bitwise_xor), 849 #endif 850 IFCOND_OP("&&", 35, 2, ifcond_op_logical_and), 851 /*IFCOND_OP("&", 50, 2, ifcond_op_bitwise_and),*/ 852 IFCOND_OP("||", 30, 2, ifcond_op_logical_or), 853 IFCOND_OP("|", 40, 2, ifcond_op_bitwise_or), 854 { "(", 1, ')', 10, 1, ifcond_op_left_parenthesis }, 855 { ")", 1, '(', 10, 0, ifcond_op_right_parenthesis }, 856 /* { "?", 1, ':', 5, 2, ifcond_op_question }, 857 { ":", 1, '?', 5, 2, ifcond_op_colon }, -- too weird for now. */ 858 #undef IFCOND_OP 859 }; 860 861 /** Dummy end of expression fake. */ 862 static const IFCONDOP g_IfCondEndOfExpOp = 863 { 864 "", 0, '\0', 0, 0, NULL 865 }; 866 867 868 /** 869 * Initializes the opcode character map if necessary. 870 */ 871 static void ifcond_map_init(void) 872 { 873 int i; 874 if (g_fIfCondInitializedMap) 875 return; 876 877 /* 878 * Initialize it. 879 */ 880 memset(&g_auchOpStartCharMap, 0, sizeof(g_auchOpStartCharMap)); 881 for (i = 0; i < sizeof(g_aIfCondOps) / sizeof(g_aIfCondOps[0]); i++) 882 { 883 unsigned int ch = (unsigned int)g_aIfCondOps[i].szOp[0]; 884 if (!g_auchOpStartCharMap[ch]) 885 g_auchOpStartCharMap[ch] = (i << 1) | 1; 886 } 887 888 g_fIfCondInitializedMap = 1; 889 } 890 891 892 /** 893 * Looks up a character in the map. 894 * 895 * @returns the value for that char. 896 * @retval 0 if not a potential opcode start char. 897 * @retval non-zero if it's a potential operator. The low bit is always set 898 * while the remaining 7 bits is the index into the operator table 899 * of the first match. 900 * 901 * @param ch The character. 902 */ 903 static unsigned char ifcond_map_get(char ch) 904 { 905 return g_auchOpStartCharMap[(unsigned int)ch]; 906 } 907 908 909 /** 910 * Searches the operator table given a potential operator start char. 911 * 912 * @returns Pointer to the matching operator. NULL if not found. 913 * @param psz Pointer to what can be an operator. 914 * @param uchVal The ifcond_map_get value. 915 * @param fUnary Whether it must be an unary operator or not. 916 */ 917 static PCIFCONDOP ifcond_lookup_op(char const *psz, unsigned char uchVal, int fUnary) 918 { 919 char ch = *psz; 920 int i; 921 922 for (i = uchVal >> 1; i < sizeof(g_aIfCondOps) / sizeof(g_aIfCondOps[0]); i++) 923 { 924 /* compare the string... */ 925 switch (g_aIfCondOps[i].cchOp) 926 { 927 case 1: 928 if (g_aIfCondOps[i].szOp[0] != ch) 929 continue; 930 break; 931 case 2: 932 if ( g_aIfCondOps[i].szOp[0] != ch 933 || g_aIfCondOps[i].szOp[1] != psz[1]) 934 continue; 935 break; 936 default: 937 if ( g_aIfCondOps[i].szOp[0] != ch 938 || strncmp(&g_aIfCondOps[i].szOp[1], psz + 1, g_aIfCondOps[i].cchOp - 1)) 939 continue; 940 break; 941 } 942 943 /* ... and the operator type. */ 944 if (fUnary == (g_aIfCondOps[i].cArgs == 1)) 945 { 946 /* got a match! */ 947 return &g_aIfCondOps[i]; 948 } 949 } 950 951 return NULL; 952 } 953 954 955 /** 956 * Ungets a binary operator. 957 * 958 * The operator is poped from the stack and put in the pending position. 959 * 960 * @param pThis The evaluator instance. 961 */ 962 static void ifcond_unget_op(PIFCOND pThis) 963 { 964 assert(pThis->pPending == NULL); 965 assert(pThis->iOp >= 0); 966 967 pThis->pPending = pThis->apOps[pThis->iOp]; 968 pThis->apOps[pThis->iOp] = NULL; 969 pThis->iOp--; 970 } 971 972 973 974 /** 975 * Get the next token, it should be a binary operator, or the end of 976 * the expression, or a right parenthesis. 977 * 978 * The operator is pushed onto the stack and the status code indicates 979 * which of the two we found. 980 * 981 * @returns status code. Will grumble on failure. 982 * @retval kIfCondRet_EndOfExpr if we encountered the end of the expression. 983 * @retval kIfCondRet_Operator if we encountered a binary operator or right 984 * parenthesis. It's on the operator stack. 985 * 986 * @param pThis The evaluator instance. 987 */ 988 static IFCONDRET ifcond_get_binary_or_eoe_or_rparen(PIFCOND pThis) 989 { 990 /* 991 * See if there is anything pending first. 992 */ 993 PCIFCONDOP pOp = pThis->pPending; 994 if (pOp) 995 pThis->pPending = NULL; 996 else 997 { 998 /* 999 * Eat more of the expression. 1000 */ 1001 char const *psz = pThis->psz; 1002 1003 /* spaces */ 1004 while (isspace((unsigned int)*psz)) 1005 psz++; 1006 /* see what we've got. */ 1007 if (*psz) 1008 { 1009 unsigned char uchVal = ifcond_map_get(*psz); 1010 if (uchVal) 1011 pOp = ifcond_lookup_op(psz, uchVal, 0 /* fUnary */); 1012 if (!pOp) 1013 { 1014 ifcond_error(pThis, "Expected binary operator, found \"%.42s\"...", psz); 1015 return kIfCondRet_Error; 1016 } 1017 psz += pOp->cchOp; 1018 } 1019 else 1020 pOp = &g_IfCondEndOfExpOp; 1021 pThis->psz = psz; 1022 } 1023 1024 /* 1025 * Push it. 1026 */ 1027 if (pThis->iOp >= IFCOND_MAX_OPERATORS - 1) 1028 { 1029 ifcond_error(pThis, "Operator stack overflow"); 1030 return kIfCondRet_Error; 1031 } 1032 pThis->apOps[++pThis->iOp] = pOp; 1033 1034 return pOp->iPrecedence 1035 ? kIfCondRet_Operator 1036 : kIfCondRet_EndOfExpr; 1037 } 1038 1039 1040 1041 /** 1042 * Get the next token, it should be an unary operator or an operand. 1043 * 1044 * This will fail if encountering the end of the expression since 1045 * it is implied that there should be something more. 1046 * 1047 * The token is pushed onto the respective stack and the status code 1048 * indicates which it is. 1049 * 1050 * @returns status code. On failure we'll be done bitching already. 1051 * @retval kIfCondRet_Operator if we encountered an unary operator. 1052 * It's on the operator stack. 1053 * @retval kIfCondRet_Operand if we encountered an operand operator. 1054 * It's on the operand stack. 1055 * 1056 * @param This The evaluator instance. 1057 */ 1058 static IFCONDRET ifcond_get_unary_or_operand(PIFCOND pThis) 1059 { 1060 IFCONDRET rc; 1061 unsigned char uchVal; 1062 PCIFCONDOP pOp; 1063 char const *psz = pThis->psz; 1064 1065 /* 1066 * Eat white space and make sure there is something after it. 1067 */ 1068 while (isspace((unsigned int)*psz)) 1069 psz++; 1070 if (!*psz) 1071 { 1072 ifcond_error(pThis, "Unexpected end of expression"); 1073 return kIfCondRet_Error; 1074 } 1075 1076 /* 1077 * Is it an operator? 1078 */ 1079 pOp = NULL; 1080 uchVal = ifcond_map_get(*psz); 1081 if (uchVal) 1082 pOp = ifcond_lookup_op(psz, uchVal, 1 /* fUnary */); 1083 if (pOp) 1084 { 1085 /* 1086 * Push the operator onto the stack. 1087 */ 1088 if (pThis->iVar < IFCOND_MAX_OPERANDS - 1) 1089 { 1090 pThis->apOps[++pThis->iOp] = pOp; 1091 rc = kIfCondRet_Operator; 1092 } 1093 else 1094 { 1095 ifcond_error(pThis, "Operator stack overflow"); 1096 rc = kIfCondRet_Error; 1097 } 1098 psz += pOp->cchOp; 1099 } 1100 else if (pThis->iVar < IFCOND_MAX_OPERANDS - 1) 1101 { 1102 /* 1103 * It's an operand. Figure out where it ends and 1104 * push it onto the stack. 1105 */ 1106 const char *pszStart = psz; 1107 1108 rc = kIfCondRet_Ok; 1109 if (*psz == '"') 1110 { 1111 pszStart++; 1112 while (*psz && *psz != '"') 1113 psz++; 1114 ifcond_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kIfCondVar_String); 1115 } 1116 else if (*psz == '\'') 1117 { 1118 pszStart++; 1119 while (*psz && *psz != '\'') 1120 psz++; 1121 ifcond_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kIfCondVar_SimpleString); 1122 } 1123 else 1124 { 1125 char achPars[20]; 1126 int iPar = -1; 1127 char chEndPar = '\0'; 1128 char ch; 1129 1130 while ((ch = *psz) != '\0') 1131 { 1132 /* $(adsf) or ${asdf} needs special handling. */ 1133 if ( ch == '$' 1134 && ( psz[1] == '(' 1135 || psz[1] == '{')) 1136 { 1137 psz++; 1138 if (iPar > sizeof(achPars) / sizeof(achPars[0])) 1139 { 1140 ifcond_error(pThis, "Too deep nesting of variable expansions"); 1141 rc = kIfCondRet_Error; 1142 break; 1143 } 1144 achPars[++iPar] = chEndPar = ch == '(' ? ')' : '}'; 1145 } 1146 else if (ch == chEndPar) 1147 { 1148 iPar--; 1149 chEndPar = iPar >= 0 ? achPars[iPar] : '\0'; 1150 } 1151 else if (!chEndPar) 1152 { 1153 /** @todo combine isspace and ifcond_map_get! */ 1154 unsigned chVal = ifcond_map_get(ch); 1155 if (chVal) 1156 { 1157 PCIFCONDOP pOp = ifcond_lookup_op(psz, uchVal, 0 /* fUnary */); 1158 if (pOp) 1159 break; 1160 } 1161 if (isspace((unsigned char)ch)) 1162 break; 1163 } 1164 1165 /* next */ 1166 psz++; 1167 } 1168 1169 if (rc == kIfCondRet_Ok) 1170 ifcond_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kIfCondVar_String); 1171 } 1172 } 1173 else 1174 { 1175 ifcond_error(pThis, "Operand stack overflow"); 1176 rc = kIfCondRet_Error; 1177 } 1178 pThis->psz = psz; 1179 1180 return rc; 1181 } 1182 1183 1184 /** 1185 * Evaluates the current expression. 1186 * 1187 * @returns status code. 1188 * 1189 * @param pThis The instance. 1190 */ 1191 static IFCONDRET ifcond_eval(PIFCOND pThis) 1192 { 1193 IFCONDRET rc; 1194 PCIFCONDOP pOp; 1195 1196 /* 1197 * The main loop. 1198 */ 1199 for (;;) 1200 { 1201 /* 1202 * Eat unary operators until we hit an operand. 1203 */ 1204 do rc = ifcond_get_unary_or_operand(pThis); 1205 while (rc == kIfCondRet_Operator); 1206 if (rc < kIfCondRet_Error) 1207 break; 1208 1209 /* 1210 * Look for a binary operator, right parenthesis or end of expression. 1211 */ 1212 rc = ifcond_get_binary_or_eoe_or_rparen(pThis); 1213 if (rc < kIfCondRet_Error) 1214 break; 1215 ifcond_unget_op(pThis); 1216 1217 /* 1218 * Pop operators and apply them. 1219 * 1220 * Parenthesis will be handed via precedence, where the left parenthesis 1221 * will go pop the right one and make another operator pending. 1222 */ 1223 while ( pThis->iOp >= 0 1224 && pThis->apOps[pThis->iOp]->iPrecedence >= pThis->pPending->iPrecedence) 1225 { 1226 pOp = pThis->apOps[pThis->iOp--]; 1227 rc = pOp->pfn(pThis); 1228 if (rc < kIfCondRet_Error) 1229 break; 1230 } 1231 if (rc < kIfCondRet_Error) 1232 break; 1233 1234 /* 1235 * Get the next binary operator or end of expression. 1236 * There should be no right parenthesis here. 1237 */ 1238 rc = ifcond_get_binary_or_eoe_or_rparen(pThis); 1239 if (rc < kIfCondRet_Error) 1240 break; 1241 pOp = pThis->apOps[pThis->iOp]; 1242 if (!pOp->iPrecedence) 1243 break; /* end of expression */ 1244 if (!pOp->cArgs) 1245 { 1246 ifcond_error(pThis, "Unexpected \"%s\"", pOp->szOp); 1247 rc = kIfCondRet_Error; 1248 break; 1249 } 1250 } 1251 1252 return rc; 1253 } 1254 1255 1256 /** 1257 * Destroys the given instance. 1258 * 1259 * @param pThis The instance to destroy. 1260 */ 1261 static void ifcond_destroy(PIFCOND pThis) 1262 { 1263 while (pThis->iVar >= 0) 1264 { 1265 ifcond_var_delete(pThis->aVars); 1266 pThis->iVar--; 1267 } 1268 free(pThis); 1269 } 1270 1271 1272 /** 1273 * Instantiates an expression evaluator. 1274 * 1275 * @returns The instance. 1276 * 1277 * @param pszExpr What to parse. 1278 * This must stick around until ifcond_destroy. 1279 */ 1280 static PIFCOND ifcond_create(char const *pszExpr) 1281 { 1282 PIFCOND pThis = (PIFCOND)xmalloc(sizeof(*pThis)); 1283 pThis->pszExpr = pszExpr; 1284 pThis->psz = pszExpr; 1285 pThis->pFileLoc = NULL; 1286 pThis->pPending = NULL; 1287 pThis->iVar = -1; 1288 pThis->iOp = -1; 1289 1290 ifcond_map_init(); 1291 return pThis; 1292 } 1293 1294 1295 /** 1296 * Evaluates the given if expression. 1297 * 1298 * @returns -1, 0 or 1. 1299 * @retval -1 if the expression is invalid. 1300 * @retval 0 if the expression is true 1301 * @retval 1 if the expression is false. 1302 * 1303 * @param line The expression. Can modify this as we like. 1304 * @param flocp The file location, used for errors. 1305 */ 1306 int ifcond(char *line, const struct floc *flocp) 1307 { 1308 /* 1309 * Instantiate the expression evaluator and let 1310 * it have a go at it. 1311 */ 1312 int rc = -1; 1313 PIFCOND pIfCond = ifcond_create(line); 1314 pIfCond->pFileLoc = flocp; 1315 if (ifcond_eval(pIfCond) >= kIfCondRet_Ok) 1316 { 1317 /* 1318 * Convert the result (on top of the stack) to boolean and 1319 * set our return value accordingly. 1320 */ 1321 if (ifcond_var_make_bool(&pIfCond->aVars[0])) 1322 rc = 0; 1323 else 1324 rc = 1; 1325 } 1326 ifcond_destroy(pIfCond); 1327 1328 return rc; 25 1329 } 26 1330 -
trunk/src/kmk/make.h
r1715 r1719 729 729 730 730 #ifdef CONFIG_WITH_IF_CONDITIONALS 731 extern int ifcond _eval(char *line, const struct floc *flocp);732 #endif 733 731 extern int ifcond(char *line, const struct floc *flocp); 732 #endif 733 -
trunk/src/kmk/read.c
r1715 r1719 2173 2173 else if (cmdtype == c_ifcond) 2174 2174 { 2175 int rval = ifcond _eval(line, flocp);2175 int rval = ifcond (line, flocp); 2176 2176 if (rval == -1) 2177 2177 return rval; -
trunk/src/kmk/testcase-if1of.kmk
r1109 r1719 78 78 79 79 all_recursive: 80 $(ECHO) "if1of and ifn1of work sfine"80 $(ECHO) "if1of and ifn1of work fine"
注意:
瀏覽 TracChangeset
來幫助您使用更動檢視器