Leaked source code of windows server 2003
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.

164 lines
4.2 KiB

  1. // Copyright (c) 1999 Microsoft Corporation. All rights reserved.
  2. //
  3. // Implementation of ExprBlock.
  4. //
  5. #include "stdinc.h"
  6. #include "engexpr.h"
  7. HRESULT
  8. Expression::Generate()
  9. {
  10. HRESULT hr = InfixToPostfix();
  11. if (FAILED(hr))
  12. {
  13. // clean up the working stack
  14. while (!m_stack.empty())
  15. m_stack.pop();
  16. return hr;
  17. }
  18. return S_OK;
  19. }
  20. int Precedence(Token t)
  21. {
  22. switch(t)
  23. {
  24. case TOKEN_op_pow: return 10;
  25. case TOKEN_sub: return 9; // unary - (negation)
  26. case TOKEN_op_mult: return 8;
  27. case TOKEN_op_div: return 7;
  28. case TOKEN_op_mod: return 6;
  29. case TOKEN_op_plus:
  30. case TOKEN_op_minus: return 5;
  31. case TOKEN_op_lt:
  32. case TOKEN_op_leq:
  33. case TOKEN_op_gt:
  34. case TOKEN_op_geq:
  35. case TOKEN_op_eq:
  36. case TOKEN_op_neq:
  37. case TOKEN_is: return 4;
  38. case TOKEN_op_not: return 3;
  39. case TOKEN_and: return 2;
  40. case TOKEN_or: return 1;
  41. case TOKEN_lparen: return 0;
  42. default:
  43. assert(false);
  44. return 12;
  45. }
  46. }
  47. // Infix to postfix conversion is performed by a single scan of the infix expression blocks.
  48. // A stack is used to hold some of the blocks before they eventually are appended to the postfix expression.
  49. //
  50. // The algorithm follows the following rules:
  51. // * If the current item is an value it is immediately appended.
  52. // * If the current item is an operator, pop and append each operator on the stack until one is encountered that:
  53. // - has lower precedence than the current operator OR
  54. // - is a left paren OR
  55. // - is a unary operator and the current item is also unary
  56. // Once done with this popping, push the current item onto the stack.
  57. // * If the current item is a left paren, push it onto the stack.
  58. // * If the current item is a right paren, pop and append all the operators until the matching left paren is found.
  59. // Discard the left and right paren as parens are not needed in postfix.
  60. // * After scanning all items of the input, pop and append any operators that remain on the stack.
  61. //
  62. // Before working with this code, try out a few expressions on paper to see how this works.
  63. HRESULT
  64. Expression::InfixToPostfix()
  65. {
  66. assert(m_stack.empty());
  67. HRESULT hr = S_OK;
  68. ExprBlocks::index iLast = m_e.Next();
  69. assert(iLast > 0);
  70. for (ExprBlocks::index i = 0; i < iLast; ++i)
  71. {
  72. const ExprBlock &b = m_e[i];
  73. if (b.k == ExprBlock::_val || b.k == ExprBlock::_call)
  74. {
  75. // this is an operand -- send it directly to the postfix output
  76. hr = m_eblocks.Add(b);
  77. if (FAILED(hr))
  78. return hr;
  79. }
  80. else
  81. {
  82. if (b.op == TOKEN_rparen)
  83. {
  84. // pop whatever's left until the matching lparen
  85. for (;;)
  86. {
  87. if (m_stack.empty())
  88. {
  89. assert(false);
  90. return E_FAIL;
  91. }
  92. ExprBlock bPop = m_stack.top();
  93. if (bPop.op == TOKEN_lparen)
  94. {
  95. m_stack.pop();
  96. break;
  97. }
  98. hr = m_eblocks.Add(bPop);
  99. if (FAILED(hr))
  100. return hr;
  101. m_stack.pop();
  102. }
  103. continue;
  104. }
  105. else if (b.op != TOKEN_lparen)
  106. {
  107. // Pop all operators of lower precedence off the stack. (This won't pass a left paren because its precedence is set to 0.)
  108. // Exception: don't pop a unary operator if the new one is also unary.
  109. int iNewPrecidence = Precedence(b.op);
  110. bool fNewUnary = b.op == TOKEN_sub || b.op == TOKEN_op_not;
  111. while (!m_stack.empty()) // note that there's a break inside the loop as well
  112. {
  113. ExprBlock bPop = m_stack.top();
  114. if (Precedence(bPop.op) < iNewPrecidence)
  115. break;
  116. if (fNewUnary && (bPop.op == TOKEN_sub || bPop.op == TOKEN_op_not))
  117. break;
  118. hr = m_eblocks.Add(bPop);
  119. if (FAILED(hr))
  120. return hr;
  121. m_stack.pop();
  122. }
  123. }
  124. // now push the new operator onto the stack
  125. hr = m_stack.push(b);
  126. if (FAILED(hr))
  127. return hr;
  128. }
  129. }
  130. while (!m_stack.empty())
  131. {
  132. ExprBlock bPop = m_stack.top();
  133. if (bPop.op == TOKEN_lparen)
  134. {
  135. assert(false);
  136. return E_FAIL;
  137. }
  138. hr = m_eblocks.Add(bPop);
  139. if (FAILED(hr))
  140. return hr;
  141. m_stack.pop();
  142. }
  143. // Add the teminating (_end) block
  144. hr = m_eblocks.Add(ExprBlock(ExprBlock::cons_end()));
  145. if (FAILED(hr))
  146. return hr;
  147. return S_OK;
  148. }