Counter Strike : Global Offensive Source Code
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.

324 lines
7.5 KiB

  1. //===== Copyright (c) 1996-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: ExprSimplifier builds a binary tree from an infix expression (in the
  4. // form of a character array).
  5. //
  6. //===========================================================================//
  7. #include "vpc.h"
  8. static ExprTree mExprTree; // Tree representation of the expression
  9. static char mCurToken; // Current token read from the input expression
  10. static const char *mExpression; // Array of the expression characters
  11. static int mCurPosition; // Current position in the input expression
  12. static char mIdentifier[MAX_IDENTIFIER_LEN]; // Stores the identifier string
  13. static GetSymbolProc_t g_pGetSymbolProc;
  14. //-----------------------------------------------------------------------------
  15. // Sets mCurToken to the next token in the input string. Skips all whitespace.
  16. //-----------------------------------------------------------------------------
  17. static char GetNextToken( void )
  18. {
  19. // while whitespace, Increment CurrentPosition
  20. while( mExpression[mCurPosition] == ' ' )
  21. ++mCurPosition;
  22. // CurrentToken = Expression[CurrentPosition]
  23. mCurToken = mExpression[mCurPosition++];
  24. return mCurToken;
  25. }
  26. //-----------------------------------------------------------------------------
  27. // Utility funcs
  28. //-----------------------------------------------------------------------------
  29. static void FreeNode( ExprNode *node )
  30. {
  31. delete node;
  32. }
  33. static ExprNode *AllocateNode( void )
  34. {
  35. return new ExprNode;
  36. }
  37. static void FreeTree( ExprTree& node )
  38. {
  39. if(!node)
  40. return;
  41. FreeTree(node->left);
  42. FreeTree(node->right);
  43. FreeNode(node);
  44. node = 0;
  45. }
  46. static bool IsConditional( const char token )
  47. {
  48. char nextchar = ' ';
  49. if ( token == OR_OP || token == AND_OP )
  50. {
  51. nextchar = mExpression[mCurPosition++];
  52. if ( (token & nextchar) == token )
  53. {
  54. return true;
  55. }
  56. else
  57. g_pVPC->VPCSyntaxError( "Bad expression token: %c %c", token, nextchar );
  58. }
  59. return false;
  60. }
  61. static bool IsNotOp( const char token )
  62. {
  63. if ( token == NOT_OP )
  64. return true;
  65. else
  66. return false;
  67. }
  68. static bool IsIdentifierOrConstant( const char token )
  69. {
  70. bool success = false;
  71. if ( token == '$' )
  72. {
  73. // store the entire identifier
  74. int i = 0;
  75. mIdentifier[i++] = token;
  76. while( (V_isalnum( mExpression[mCurPosition] ) || mExpression[mCurPosition] == '_') && i < MAX_IDENTIFIER_LEN )
  77. {
  78. mIdentifier[i] = mExpression[mCurPosition];
  79. ++mCurPosition;
  80. ++i;
  81. }
  82. if ( i < MAX_IDENTIFIER_LEN - 1 )
  83. {
  84. mIdentifier[i] = '\0';
  85. success = true;
  86. }
  87. }
  88. else
  89. {
  90. if ( V_isdigit( token ) )
  91. {
  92. int i = 0;
  93. mIdentifier[i++] = token;
  94. while( V_isdigit( mExpression[mCurPosition] ) && ( i < MAX_IDENTIFIER_LEN ) )
  95. {
  96. mIdentifier[i] = mExpression[mCurPosition];
  97. ++mCurPosition;
  98. ++i;
  99. }
  100. if ( i < MAX_IDENTIFIER_LEN - 1 )
  101. {
  102. mIdentifier[i] = '\0';
  103. success = true;
  104. }
  105. }
  106. }
  107. return success;
  108. }
  109. static void MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right )
  110. {
  111. tree = AllocateNode();
  112. tree->left = left;
  113. tree->right = right;
  114. tree->kind = kind;
  115. switch ( kind )
  116. {
  117. case CONDITIONAL:
  118. tree->data.cond = token;
  119. break;
  120. case LITERAL:
  121. if ( V_isdigit( mIdentifier[0] ) )
  122. {
  123. tree->data.value = atoi( mIdentifier ) != 0;
  124. }
  125. else
  126. {
  127. tree->data.value = g_pGetSymbolProc( mIdentifier );
  128. }
  129. break;
  130. case NOT:
  131. break;
  132. default:
  133. g_pVPC->VPCError( "Error in ExpTree" );
  134. }
  135. }
  136. static void MakeExpression( ExprTree& tree );
  137. //-----------------------------------------------------------------------------
  138. // Makes a factor :: { <expression> } | <identifier>.
  139. //-----------------------------------------------------------------------------
  140. static void MakeFactor( ExprTree& tree )
  141. {
  142. if ( mCurToken == '(' )
  143. {
  144. // Get the next token
  145. GetNextToken();
  146. // Make an expression, setting Tree to point to it
  147. MakeExpression( tree );
  148. }
  149. else if ( IsIdentifierOrConstant( mCurToken ) )
  150. {
  151. // Make a literal node, set Tree to point to it, set left/right children to NULL.
  152. MakeExprNode( tree, mCurToken, LITERAL, NULL, NULL );
  153. }
  154. else if ( IsNotOp( mCurToken ) )
  155. {
  156. // do nothing
  157. return;
  158. }
  159. else
  160. {
  161. // This must be a bad token
  162. g_pVPC->VPCSyntaxError( "Bad expression token: %c", mCurToken );
  163. }
  164. // Get the next token
  165. GetNextToken();
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Makes a term :: <factor> { <not> }.
  169. //-----------------------------------------------------------------------------
  170. static void MakeTerm( ExprTree& tree )
  171. {
  172. // Make a factor, setting Tree to point to it
  173. MakeFactor( tree );
  174. // while the next token is !
  175. while( IsNotOp( mCurToken ) )
  176. {
  177. // Make an operator node, setting left child to Tree and right to NULL. (Tree points to new node)
  178. MakeExprNode( tree, mCurToken, NOT, tree, NULL );
  179. // Get the next token.
  180. GetNextToken();
  181. // Make a factor, setting the right child of Tree to point to it.
  182. MakeFactor(tree->right);
  183. }
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Makes a complete expression :: <term> { <cond> <term> }.
  187. //-----------------------------------------------------------------------------
  188. static void MakeExpression( ExprTree& tree )
  189. {
  190. // Make a term, setting Tree to point to it
  191. MakeTerm( tree );
  192. // while the next token is a conditional
  193. while ( IsConditional( mCurToken ) )
  194. {
  195. // Make a conditional node, setting left child to Tree and right to NULL. (Tree points to new node)
  196. MakeExprNode( tree, mCurToken, CONDITIONAL, tree, NULL );
  197. // Get the next token.
  198. GetNextToken();
  199. // Make a term, setting the right child of Tree to point to it.
  200. MakeTerm( tree->right );
  201. }
  202. }
  203. //-----------------------------------------------------------------------------
  204. // returns true for success, false for failure
  205. //-----------------------------------------------------------------------------
  206. static bool BuildExpression( void )
  207. {
  208. // Get the first token, and build the tree.
  209. GetNextToken();
  210. MakeExpression( mExprTree );
  211. return true;
  212. }
  213. //-----------------------------------------------------------------------------
  214. // returns the value of the node after resolving all children
  215. //-----------------------------------------------------------------------------
  216. static bool SimplifyNode( ExprTree& node )
  217. {
  218. if( !node )
  219. return false;
  220. // Simplify the left and right children of this node
  221. bool leftVal = SimplifyNode(node->left);
  222. bool rightVal = SimplifyNode(node->right);
  223. // Simplify this node
  224. switch( node->kind )
  225. {
  226. case NOT:
  227. // the child of '!' is always to the right
  228. node->data.value = !rightVal;
  229. break;
  230. case CONDITIONAL:
  231. if ( node->data.cond == AND_OP )
  232. {
  233. node->data.value = leftVal && rightVal;
  234. }
  235. else // OR_OP
  236. {
  237. node->data.value = leftVal || rightVal;
  238. }
  239. break;
  240. default: // LITERAL
  241. break;
  242. }
  243. // This node has beed resolved
  244. node->kind = LITERAL;
  245. return node->data.value;
  246. }
  247. //-----------------------------------------------------------------------------
  248. // Interface to solve a conditional expression. Returns false on failure.
  249. //-----------------------------------------------------------------------------
  250. bool EvaluateExpression( bool &result, const char *InfixExpression, GetSymbolProc_t pGetSymbolProc )
  251. {
  252. if ( !InfixExpression )
  253. return false;
  254. g_pGetSymbolProc = pGetSymbolProc;
  255. bool success = false;
  256. mExpression = InfixExpression;
  257. mExprTree = 0;
  258. mCurPosition = 0;
  259. // Building the expression tree will fail on bad syntax
  260. if ( BuildExpression() )
  261. {
  262. success = true;
  263. result = SimplifyNode( mExprTree );
  264. }
  265. FreeTree( mExprTree );
  266. return success;
  267. }