Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

837 lines
23 KiB

  1. // RPN.C -- expression evaluator
  2. //
  3. // Copyright (c) 1988-1990, Microsoft Corporation. All rights reserved.
  4. //
  5. // Purpose:
  6. // This module contains NMAKE's expression evaluator routines.
  7. //
  8. // Revision History:
  9. // 15-Nov-1993 JdR Major speed improvements
  10. // 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
  11. // 10-May-1993 HV Add include file mbstring.h
  12. // Change the str* functions to STR*
  13. // 04-Dec-1989 SB Add prototype for match() and chkInvokeAndPush()
  14. // 09-Oct-1989 SB Added HACK to handle pointer arithmetic quirks; Done to
  15. // avoid rewriting entire module
  16. // 08-Oct-1989 SB '!if' expressions can be decimal, octal or hex now
  17. // 05-Apr-1989 SB made all funcs NEAR; Reqd to make all function calls NEAR
  18. // 19-Sep-1988 RB Split ptr_to_string(). Process ESCH in program invocations.
  19. // 17-Aug-1988 RB Clean up.
  20. // 28-Jun-1988 rj Added doCmd parameter to execLine.
  21. // 23-Jun-1988 rj Add parameter to execLine (no echo of command).
  22. // 25-May-1988 rb Change isspace to _istspace, isdigit to _istdigit.
  23. #include "precomp.h"
  24. #pragma hdrstop
  25. #include "rpn.h"
  26. char * GetEndQuote(void);
  27. char * GetEndBracket(void);
  28. void check_syntax_error(UCHAR);
  29. void type_and_val(UCHAR, INT_PTR);
  30. void pushIntoList(void);
  31. void printList(void);
  32. BOOL handleExpr(void);
  33. BOOL handleExists(char*);
  34. BOOL handleDefines(char*);
  35. void getTok(void);
  36. BOOL do_binary_op(UCHAR);
  37. BOOL do_unary_op(UCHAR);
  38. UCHAR match(char *tokPtr);
  39. void chkInvocAndPush(RPNINFO *pListPtr);
  40. #define TEMPSTACKSIZE 512 // size of temporary stack
  41. #define LISTSIZE 1024 // size of list of rpn-form items
  42. RPNINFO tempStack[TEMPSTACKSIZE]; // temporary/operand stack
  43. RPNINFO rpnList[LISTSIZE]; // list of items in rpn order
  44. char * text; // pointer to expr text in lbufPtr
  45. UCHAR prevTok; // initial token put on tempstack
  46. BOOL done; // true if there are no more tokens
  47. UCHAR errRow; // first token is '(' so error table
  48. // row val is 3. See check_syntax....
  49. RPNINFO * pTop; // top item on tempStack
  50. RPNINFO * pList; // next free slot in list
  51. RPNINFO * pEnd = &(tempStack[TEMPSTACKSIZE-1]);
  52. RPNINFO * pListEnd = &(rpnList[LISTSIZE-1]);
  53. RPNINFO tokRec;
  54. // do_binary_op() - do operation on two stack operands
  55. //
  56. // arguments: type - operator type code
  57. //
  58. // actions : pops first operand from the stack (tempStack).
  59. // checks the types of the two operands (the operand
  60. // that was popped as well as the operand currently
  61. // on top of the stack).
  62. // if both operands are integers then do the operation
  63. // else if both operands are strings and operation is
  64. // the equality operation then do it.
  65. // else return FALSE ( illegal operation )
  66. //
  67. // modifies : tempStack - top element will now be the result of
  68. // the operation.
  69. BOOL
  70. do_binary_op(
  71. UCHAR type
  72. )
  73. {
  74. INT_PTR *left;
  75. INT_PTR *right;
  76. RPNINFO *pOldTop;
  77. pOldTop = pTop--; // pop one item off stack, with a ptr to it
  78. right = &pOldTop->valPtr;
  79. left = &pTop->valPtr;
  80. if ((pOldTop->type == INTEGER) && (pTop->type == INTEGER)) {
  81. switch (type) {
  82. case LOGICAL_OR:
  83. *left = *left || *right;
  84. break;
  85. case LOGICAL_AND:
  86. *left = *left && *right;
  87. break;
  88. case BIT_OR:
  89. *left |= *right;
  90. break;
  91. case BIT_XOR:
  92. *left ^= *right;
  93. break;
  94. case BIT_AND:
  95. *left &= *right;
  96. break;
  97. case NOT_EQUAL:
  98. *left = *right != *left;
  99. break;
  100. case EQUAL:
  101. *left = *right == *left;
  102. break;
  103. case GREATER_THAN:
  104. *left = *left > *right;
  105. break;
  106. case LESS_THAN:
  107. *left = *left < *right;
  108. break;
  109. case GREATER_EQ:
  110. *left = *left >= *right;
  111. break;
  112. case LESS_EQ:
  113. *left = *left <= *right;
  114. break;
  115. case SHFT_RIGHT:
  116. *left >>= *right;
  117. break;
  118. case SHFT_LEFT:
  119. *left <<= *right;
  120. break;
  121. case BINARY_MINUS:
  122. *left -= *right;
  123. break;
  124. case ADD:
  125. *left += *right;
  126. break;
  127. case MODULUS:
  128. if (!*right)
  129. makeError(line, DIVIDE_BY_ZERO);
  130. *left %= *right;
  131. break;
  132. case DIVIDE:
  133. if (!*right)
  134. makeError(line, DIVIDE_BY_ZERO);
  135. *left /= *right;
  136. break;
  137. case MULTIPLY:
  138. *left *= *right;
  139. break;
  140. default:
  141. return(FALSE);
  142. break;
  143. }
  144. } else if ((pOldTop->type == STR) &&
  145. (pTop->type == STR) &&
  146. ((type == EQUAL) || (type == NOT_EQUAL))) {
  147. pTop->type = INTEGER;
  148. *left = !_tcscmp((char *) *left, (char *) *right);
  149. if (type == NOT_EQUAL) {
  150. if (!do_unary_op(LOGICAL_NOT)) {
  151. return(FALSE);
  152. }
  153. }
  154. } else {
  155. return(FALSE);
  156. }
  157. return(TRUE);
  158. }
  159. // do_unary_op() - do operation on top stack operand
  160. //
  161. // arguments: type - operator type code
  162. //
  163. // actions : checks the type of the top operand on the stack
  164. // if operand is an integer then do the operation
  165. // else return FALSE ( illegal operation )
  166. //
  167. // modifies : tempStack - top element will now be the result of
  168. // the operation.
  169. BOOL
  170. do_unary_op(
  171. UCHAR type
  172. )
  173. {
  174. INT_PTR *top;
  175. top = &pTop->valPtr;
  176. if (pTop->type == INTEGER) {
  177. switch (type) {
  178. case UNARY_MINUS:
  179. *top = -*top;
  180. break;
  181. case COMPLEMENT:
  182. *top = ~*top;
  183. break;
  184. case LOGICAL_NOT:
  185. *top = !*top;
  186. break;
  187. default:
  188. return(FALSE);
  189. break;
  190. }
  191. } else {
  192. return(FALSE);
  193. }
  194. return(TRUE);
  195. }
  196. // GetEndQuote
  197. //
  198. // Return the pointer to the next double-quote character in text. A
  199. // double-quote followed immediately by a double-quote is skipped.
  200. //
  201. // text : the global ptr to the buffer is moved up beyond this string.
  202. char *
  203. GetEndQuote()
  204. {
  205. char *pStart;
  206. for (pStart = ++text; *text; ++text)
  207. if (*text == '\"') {
  208. if (text[1] == '\"')
  209. ++text;
  210. else
  211. break;
  212. }
  213. if (!*text)
  214. makeError(line, SYNTAX_MISSING_END_CHAR, '\"');
  215. *text++ = '\0'; // null byte over closing quote
  216. return(pStart);
  217. }
  218. // GetEndBracket
  219. //
  220. // Lexes a program invocation.
  221. //
  222. // Program invocation is of the form: [ prog <arglist> ].
  223. // Process escaped ']' here because this is where we do the lexing.
  224. //
  225. // text : the global ptr to the buffer is moved up beyond this string.
  226. char *
  227. GetEndBracket()
  228. {
  229. char *pStart;
  230. for (pStart = ++text; *text; text = _tcsinc (text)) {
  231. if (*text == ESCH && text[1] == ']')
  232. memmove(text, text + 1, 1 + _tcslen(text + 1));
  233. else if (*text == ']')
  234. break;
  235. }
  236. if (!*text)
  237. makeError(line, SYNTAX_MISSING_END_CHAR, ']');
  238. *text++ = '\0'; // null byte over closing bracket
  239. return(pStart);
  240. }
  241. // check_syntax_error() - check if there is a syntax error in expr
  242. //
  243. // arguments: type - type of the current token
  244. //
  245. // actions: checks the type of the current token against the type
  246. // of the previous token.
  247. //
  248. // ERROR_TABLE :
  249. // 2nd tok
  250. //
  251. // alpha op unary_op ( )
  252. // ------------------------------------------------
  253. // alpha | 0 | 1 | 0 | 0 | 1 |
  254. // -------------------------------------------------
  255. // op | 1 | 0 | 1 | 1 | 0 |
  256. // -------------------------------------------------
  257. // unary_op | 1 | 0 | 0 | 1 | 0 |
  258. // -------------------------------------------------
  259. // ( | 1 | 0 | 1 | 1 | 0 |
  260. // -------------------------------------------------
  261. // ) | 0 | 1 | 0 | 0 | 1 |
  262. // -------------------------------------------------
  263. // 1st tok.
  264. //
  265. // alpha : a primary ( integer, str, prog. invoc. )
  266. // op : a binary operator
  267. // unary_op : a unary operator ( ~, !, - ). A ZERO in the slot => error
  268. //
  269. // NOTE: ANY CHANGES TO THE TYPE VALUES WILL AFFECT THIS ROUTINE.
  270. void
  271. check_syntax_error(
  272. UCHAR newTok
  273. )
  274. {
  275. extern UCHAR errTable[5][5];
  276. extern UCHAR errRow;
  277. UCHAR errCol;
  278. if (newTok == LEFT_PAREN)
  279. errCol = 3;
  280. else if (newTok == RIGHT_PAREN)
  281. errCol = 4;
  282. else if (newTok > LOGICAL_NOT)
  283. errCol = 0;
  284. else if (newTok > MULTIPLY)
  285. errCol = 2;
  286. else
  287. errCol = 1;
  288. if (!errTable[errRow][errCol])
  289. makeError(line, SYNTAX_INVALID_EXPR);
  290. errRow = errCol; // this becomes the first token the next time
  291. }
  292. // type_and_val()
  293. //
  294. // arguments: type - the type code of the present operator.
  295. // val - ptr to a str/or integer
  296. //
  297. // initialises a record with the type code, after checking for any
  298. // syntax errors. The new token is checked against the previous token
  299. // for illegal combinations of tokens.
  300. // initialises the record with the integer value/string ptr.
  301. void
  302. type_and_val(
  303. UCHAR type,
  304. INT_PTR val
  305. )
  306. {
  307. extern RPNINFO tokRec; // returned to handleExpr
  308. extern UCHAR prevTok; // token last seen
  309. check_syntax_error(type);
  310. prevTok = type;
  311. tokRec.type = type;
  312. tokRec.valPtr = val;
  313. }
  314. // match()
  315. //
  316. // arguments: tokPtr - ptr to a token string ( in tokTable )
  317. //
  318. // actions : looks for a substring in the expression buffer
  319. // pointed to by 'text', that matches the given token.
  320. // if substring found, returns TRUE, else returns FALSE.
  321. UCHAR
  322. match(
  323. char *tokPtr
  324. )
  325. {
  326. extern char *text;
  327. char *t = text;
  328. while (*tokPtr && (*t == *tokPtr)) {
  329. t++;
  330. tokPtr++;
  331. }
  332. if (!*tokPtr) {
  333. text = t;
  334. return(TRUE);
  335. }
  336. return(FALSE);
  337. }
  338. // getTok()
  339. //
  340. // arguments: none
  341. //
  342. // gets a token from the expression buffer.
  343. // if the current char from the buffer is a space/tab, skip space/tabs
  344. // until we get a non-space char ( could be NULL char ).
  345. // Check if we are now at the beginning of one of the tokens in the
  346. // tokenTable. This covers most tokens.
  347. // Check if we have a minus. If a minus and the previous token was an
  348. // integer, this is a binary minus, else a unary minus.
  349. // If the current char is a double-quote, we are at the start of a
  350. // string-token.
  351. // If the current char is a '[', we are at the start of a program
  352. // invocation. In both cases, the escape character is '\\'.
  353. // If current char is a digit, we have a constant ( integer ).
  354. // Else we have defined(ID).
  355. // If none of the above, if current char is NULL, break out, else
  356. // report error ( illegal character string has been found ).
  357. //
  358. // If we came to the NULL char at the end of the buffer, set global
  359. // flag 'done' to TRUE, return a RIGHT_PAREN to match the opening
  360. // LEFT_PAREN.
  361. //
  362. //
  363. // modifies: text : ptr to expression buffer.
  364. // prevTok: thru' calls to type_and_val().
  365. // done : at end of buffer
  366. // errRow : index into error table, thru calls to
  367. // type_and_val()
  368. // returns : token in tokRec(global, static to the module). The
  369. // token has the new type/integer/ptr values.
  370. void
  371. getTok()
  372. {
  373. extern UCHAR prevTok;
  374. extern BOOL done;
  375. char c;
  376. TOKTABREC *p;
  377. char *ptr;
  378. long constant;
  379. c = *text;
  380. if (c == ' ' || c == '\t') {
  381. while(_istspace(c))
  382. c = *++text; // skip white spaces
  383. }
  384. if (IS_OPERATORCHAR(c)) {
  385. for (p = tokTable; p->op_str && !match(p->op_str); p++)
  386. ;
  387. } else {
  388. // make p point to last entry in table
  389. p = &tokTable[(sizeof(tokTable) / sizeof(TOKTABREC)) - 1];
  390. }
  391. if (p->op_str) {
  392. type_and_val(p->op, 0);
  393. } else
  394. if (c == '-') { // now check if binary or unary minus to be returned
  395. text++;
  396. if (prevTok == INTEGER)
  397. type_and_val(BINARY_MINUS, 0);
  398. else
  399. type_and_val(UNARY_MINUS, 0);
  400. } else
  401. if (c == '\"') {
  402. type_and_val(STR, (INT_PTR) GetEndQuote());
  403. } else
  404. if (c == '[') {
  405. type_and_val(PROG_INVOC_STR, (INT_PTR) GetEndBracket());
  406. } else { // integers and IDs handled here
  407. if (_istdigit(c)) {
  408. char *pNumber = text;
  409. errno = 0; // Accept decimal, octal or hex no (richgi)
  410. constant = strtol(text, &text, 0);
  411. if (errno == ERANGE) {
  412. *text = '\0';
  413. makeError(line, CONST_TOO_BIG, pNumber);
  414. }
  415. if (_totupper(*text) == 'L')
  416. text++;
  417. type_and_val(INTEGER, constant);
  418. } else { // defined(ID) comes here
  419. if (c) {
  420. if (!_tcsnicmp(text, "DEFINED", 7)) {
  421. if (!(ptr = _tcschr(text, '(')))
  422. makeError(line, SYNTAX_INVALID_EXPR);
  423. ptr++;
  424. text = ptr + _tcscspn(ptr, ")");
  425. *text++ = '\0';
  426. type_and_val(INTEGER, handleDefines(ptr));
  427. }
  428. else if (!_tcsnicmp(text, "EXIST", 5)) {
  429. if (!(ptr = _tcschr(text, '(')))
  430. makeError(line, SYNTAX_INVALID_EXPR);
  431. ptr++;
  432. text = ptr + _tcscspn(ptr, ")");
  433. *text++ = '\0';
  434. type_and_val(INTEGER, handleExists(ptr));
  435. }
  436. else
  437. makeError(line, SYNTAX_INVALID_EXPR);
  438. } else { // we are now at the end of the string (c is null)
  439. done = TRUE;
  440. type_and_val(RIGHT_PAREN, 0); // this is the last token
  441. }
  442. }
  443. }
  444. }
  445. // chkInvocAndPush() - check if program invocation required
  446. //
  447. // arguments: pListPtr - might have a program invocation string
  448. // present.
  449. //
  450. // actions : if this is a program invocation string, make the
  451. // program invocation.
  452. // the return value is got and placed on the stack.
  453. // the type of the new stack element is now INTEGER.
  454. // else place list item on stack.
  455. //
  456. // in either case it moves one item from list to stack.
  457. void
  458. chkInvocAndPush(
  459. RPNINFO *pListPtr
  460. )
  461. {
  462. ++pTop;
  463. if (pListPtr->type == PROG_INVOC_STR) {
  464. pTop->valPtr = execLine((char *) pListPtr->valPtr, FALSE, TRUE, FALSE, NULL);
  465. pTop->type = INTEGER;
  466. } else {
  467. *pTop = *pListPtr;
  468. }
  469. }
  470. // processList()
  471. //
  472. // arguments: none
  473. //
  474. // actions : remove an item from the list.
  475. // if the item is an operand, place it on the operand
  476. // stack (tempStack).
  477. // if the operand is a program invocation string, make
  478. // the invocation, place the return code on stack.
  479. // if the item is an operator, call the function to
  480. // do the operation on one/two elements on tempStack.
  481. //
  482. // finally, check if there is exactly one item on stack.
  483. // if this item has a value of zero, return FALSE.
  484. // else return TRUE.
  485. // if more than one item on stack, abort with error.
  486. //
  487. // modifies: pTop - ptr to top of tempStack.
  488. // pList - ptr to next position in list.
  489. BOOL
  490. processList()
  491. {
  492. extern RPNINFO *pList;
  493. extern RPNINFO *pTop;
  494. RPNINFO *pTemp;
  495. BOOL (* func)(UCHAR);
  496. for (pTemp = rpnList; pTemp < pList; pTemp++) {
  497. if (pTemp->type > LOGICAL_NOT) { // operand
  498. chkInvocAndPush(pTemp);
  499. } else {
  500. if (pTemp->type > MULTIPLY)
  501. func = do_unary_op;
  502. else
  503. func = do_binary_op;
  504. if (!(*func)(pTemp->type))
  505. makeError(line, BAD_OP_TYPES);
  506. }
  507. }
  508. if ((pTop == tempStack) && (pTop->type == INTEGER))
  509. if (!pTop->valPtr)
  510. return(FALSE);
  511. else
  512. return(TRUE);
  513. else
  514. makeError(line, SYNTAX_INVALID_EXPR);
  515. return(FALSE);
  516. }
  517. // pushIntoList()
  518. //
  519. // arguments: none
  520. //
  521. // actions : pops an item from the tempStack and pushes it onto
  522. // the list. checks list for overflow ( internal error )
  523. // and tempStack for underflow ( syntax error in expr ).
  524. //
  525. // modifies: tempTop - index of top of tempStack.
  526. // nextInList - index to next position in list.
  527. void
  528. pushIntoList()
  529. {
  530. if (pTop < tempStack)
  531. makeError(line, SYNTAX_INVALID_EXPR);
  532. if (pList > pListEnd)
  533. makeError(line, EXPR_TOO_LONG_INTERNAL);
  534. #if !defined(NDEBUG)
  535. // Keep track of the high water mark on the stack just for grins
  536. {
  537. static int iStackMax = 0;
  538. if ( pList - rpnList > iStackMax )
  539. iStackMax = (int) (pList - rpnList);
  540. }
  541. #endif
  542. *pList++ = *pTop--;
  543. }
  544. // handleExpr()
  545. //
  546. // arguments: text - pointer to the buffer that has the expression.
  547. //
  548. // actions : calls getTok() to get tokens from the buffer. Places
  549. // tokens in a tempStack, and moves them into a list in
  550. // reverse-polish order.
  551. //
  552. // We need the list so that ALL syntax errors are caught
  553. // BEFORE processing of the expression begins (especially
  554. // program invocations that have side effects)
  555. //
  556. // Once the list is available, an operand stack is used
  557. // Items are popped and pushed from this stack by the
  558. // evaluation routines (add, mult, negate etc.)
  559. //
  560. // we don't really need a separate operand stack. the
  561. // tempStack has served its purpose when the list is
  562. // formed and so it may be used for operand processing.
  563. BOOL
  564. handleExpr()
  565. {
  566. extern RPNINFO tokRec;
  567. BOOL fRParen; // was the token got a right paren?
  568. extern BOOL done;
  569. extern RPNINFO *pTop, *pList;
  570. extern UCHAR errRow;
  571. extern UCHAR prevTok;
  572. pTop = tempStack;
  573. pList = rpnList;
  574. done = FALSE;
  575. errRow = 3; // row for the first token put in,left paren
  576. prevTok = LEFT_PAREN;
  577. type_and_val(LEFT_PAREN, 0);
  578. *pTop = tokRec;
  579. while (!done) { // while there are more tokens in buffer
  580. getTok();
  581. fRParen = FALSE;
  582. if (tokRec.type != LEFT_PAREN) {
  583. while (precVector[tokRec.type] <= precVector[pTop->type]) {
  584. if (!precVector[tokRec.type]) { // if RIGHT_PAREN pop till a
  585. // left paren is seen
  586. while (pTop->type != LEFT_PAREN)
  587. pushIntoList();
  588. fRParen = TRUE;
  589. if (pTop < tempStack) {
  590. makeError(line, SYNTAX_INVALID_EXPR);
  591. } else {
  592. pTop--; // pop the left paren
  593. break;
  594. }
  595. } else {
  596. pushIntoList();
  597. }
  598. }
  599. }
  600. // if token is a left paren, it has to go on the stack
  601. if (!fRParen) {
  602. if (pTop == pEnd)
  603. makeError(line, EXPR_TOO_LONG_INTERNAL);
  604. else
  605. *++pTop = tokRec;
  606. }
  607. }
  608. // check the stack here for not empty state
  609. if (pTop != tempStack - 1)
  610. makeError(line, SYNTAX_INVALID_EXPR);
  611. return(processList());
  612. }
  613. // handleDefines()
  614. //
  615. // arguments: t pointer to buffer that has the identifier
  616. //
  617. // actions: Checks if one of 'ID' is present.
  618. // Aborts with error if more IDs present.
  619. // Is called for ifdef/ifndef/defined(ID).
  620. //
  621. // returns : TRUE if ID found in table. FALSE otherwise.
  622. BOOL
  623. handleDefines(
  624. char *t
  625. )
  626. {
  627. char *s;
  628. s = _tcstok(t, " \t");
  629. if (_tcstok(NULL, " \t")) {
  630. makeError(line, SYNTAX_UNEXPECTED_TOKEN, s);
  631. }
  632. if (!s) {
  633. makeError(line, MISSING_ARG_BEFORE_PAREN);
  634. }
  635. if (findMacro(s)) {
  636. return(TRUE);
  637. }
  638. return(FALSE);
  639. }
  640. // handleExists()
  641. //
  642. // arguments: t pointer to buffer that has the identifier
  643. //
  644. // actions: Checks if 'name' is a valid file/directory
  645. // Aborts with error if more names present.
  646. // Is called for exist(name).
  647. //
  648. // returns : TRUE if ID found in table. FALSE otherwise.
  649. BOOL
  650. handleExists(
  651. char *_t
  652. )
  653. {
  654. char *s;
  655. char *szUnQuoted;
  656. BOOL fResult = FALSE;
  657. char *szDelim;
  658. char *t;
  659. // make local copy, strip blank space before and after string
  660. char *tSav = t = makeString(_t);
  661. while (*t && WHITESPACE (*t)) {
  662. t++;
  663. }
  664. s = t + _tcslen(t);
  665. while (s > t) {
  666. s = _tcsdec(t, s);
  667. if (WHITESPACE (*s)) {
  668. *s = '\0';
  669. }
  670. else {
  671. break;
  672. }
  673. }
  674. szDelim = ('\"' == *t) ? "\t" : " \t";
  675. // DS 15360: if id starts with a quote,
  676. // use "\t" instead of " \t" in _tcstok
  677. // (handle paths with embedded spaces)
  678. s = _tcstok(t, szDelim);
  679. if (_tcstok(NULL, szDelim)) {
  680. makeError(line, SYNTAX_UNEXPECTED_TOKEN, s);
  681. }
  682. if (NULL == s || NULL == (szUnQuoted = unQuote(s))) { // handle quoted names
  683. makeError(line, MISSING_ARG_BEFORE_PAREN);
  684. }
  685. if (!_access(szUnQuoted, 0x00)) { // existence check
  686. fResult = TRUE;
  687. }
  688. FREE(szUnQuoted);
  689. FREE(tSav);
  690. return(fResult);
  691. }
  692. // evalExpr()
  693. //
  694. // arguments: t pointer to buffer that has the expression
  695. // kind specifies if it is if/ifdef/ifndef etc.
  696. //
  697. //
  698. //
  699. // returns : TRUE if expression evaluates to true.
  700. // FALSE otherwise.
  701. BOOL
  702. evalExpr(
  703. char *t,
  704. UCHAR kind
  705. )
  706. {
  707. if (!*t) {
  708. makeError(line, SYNTAX_MISSING_DIRECTIVE);
  709. }
  710. switch (kind) {
  711. case IFDEF_TYPE:
  712. case ELSE_IFDEF_TYPE:
  713. return(handleDefines(t));
  714. case IFNDEF_TYPE:
  715. case ELSE_IFNDEF_TYPE:
  716. return((BOOL)!handleDefines(t));
  717. default:
  718. text = t;
  719. return(handleExpr());
  720. }
  721. }