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.

500 lines
11 KiB

  1. //===== Copyright � 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). Evaluates C style infix parenthetic logical
  5. // expressions. Supports !, ||, &&, (). Symbols are resolved via callback.
  6. // Syntax is $<name>. $0 evaluates to false. $<number> evaluates to true.
  7. // e.g: ( $1 || ( $FOO || $WHATEVER ) && !$BAR )
  8. //===========================================================================//
  9. #include <ctype.h>
  10. #include <vstdlib/ikeyvaluessystem.h>
  11. #include "tier1/exprevaluator.h"
  12. #include "tier1/convar.h"
  13. #include "tier1/fmtstr.h"
  14. #include "tier0/dbg.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. //-----------------------------------------------------------------------------
  18. // Default conditional symbol handler callback. Symbols are the form $<name>.
  19. // Return true or false for the value of the symbol.
  20. //-----------------------------------------------------------------------------
  21. bool DefaultConditionalSymbolProc( const char *pKey )
  22. {
  23. if ( pKey[0] == '$' )
  24. {
  25. pKey++;
  26. }
  27. if ( !V_stricmp( pKey, "WIN32" ) )
  28. {
  29. return IsPC();
  30. }
  31. if ( !V_stricmp( pKey, "WINDOWS" ) )
  32. {
  33. return IsPlatformWindowsPC();
  34. }
  35. if ( !V_stricmp( pKey, "X360" ) )
  36. {
  37. return IsX360();
  38. }
  39. if ( !V_stricmp( pKey, "PS3" ) )
  40. {
  41. return IsPS3();
  42. }
  43. if ( !V_stricmp( pKey, "OSX" ) )
  44. {
  45. return IsPlatformOSX();
  46. }
  47. if ( !V_stricmp( pKey, "LINUX" ) )
  48. {
  49. return IsPlatformLinux();
  50. }
  51. if ( !V_stricmp( pKey, "POSIX" ) )
  52. {
  53. return IsPlatformPosix();
  54. }
  55. if ( !V_stricmp( pKey, "GAMECONSOLE" ) )
  56. {
  57. return IsGameConsole();
  58. }
  59. if ( !V_stricmp( pKey, "DEMO" ) )
  60. {
  61. #if defined( _DEMO )
  62. return true;
  63. #else
  64. return false;
  65. #endif
  66. }
  67. if ( !V_stricmp( pKey, "LOWVIOLENCE" ) )
  68. {
  69. #if defined( _LOWVIOLENCE )
  70. return true;
  71. #endif
  72. // If it is not a LOWVIOLENCE binary build, then fall through
  73. // and check if there was a run-time symbol installed for it
  74. }
  75. // don't know it at compile time, so fall through to installed symbol values
  76. return KeyValuesSystem()->GetKeyValuesExpressionSymbol( pKey );
  77. }
  78. void DefaultConditionalErrorProc( const char *pReason )
  79. {
  80. Warning( "Conditional Error: %s\n", pReason );
  81. }
  82. CExpressionEvaluator::CExpressionEvaluator()
  83. {
  84. m_ExprTree = NULL;
  85. }
  86. CExpressionEvaluator::~CExpressionEvaluator()
  87. {
  88. FreeTree( m_ExprTree );
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Sets mCurToken to the next token in the input string. Skips all whitespace.
  92. //-----------------------------------------------------------------------------
  93. char CExpressionEvaluator::GetNextToken( void )
  94. {
  95. // while whitespace, Increment CurrentPosition
  96. while ( m_pExpression[m_CurPosition] == ' ' )
  97. ++m_CurPosition;
  98. // CurrentToken = Expression[CurrentPosition]
  99. m_CurToken = m_pExpression[m_CurPosition++];
  100. return m_CurToken;
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Utility funcs
  104. //-----------------------------------------------------------------------------
  105. void CExpressionEvaluator::FreeNode( ExprNode *pNode )
  106. {
  107. delete pNode;
  108. }
  109. ExprNode *CExpressionEvaluator::AllocateNode( void )
  110. {
  111. return new ExprNode;
  112. }
  113. void CExpressionEvaluator::FreeTree( ExprTree& node )
  114. {
  115. if ( !node )
  116. return;
  117. FreeTree( node->left );
  118. FreeTree( node->right );
  119. FreeNode( node );
  120. node = 0;
  121. }
  122. bool CExpressionEvaluator::IsConditional( bool &bConditional, const char token )
  123. {
  124. char nextchar = ' ';
  125. if ( token == OR_OP || token == AND_OP )
  126. {
  127. // expect || or &&
  128. nextchar = m_pExpression[m_CurPosition++];
  129. if ( (token & nextchar) == token )
  130. {
  131. bConditional = true;
  132. }
  133. else if ( m_pSyntaxErrorProc )
  134. {
  135. m_pSyntaxErrorProc( CFmtStr( "Bad expression operator: '%c%c', expected C style operator", token, nextchar ) );
  136. return false;
  137. }
  138. }
  139. else
  140. {
  141. bConditional = false;
  142. }
  143. // valid
  144. return true;
  145. }
  146. bool CExpressionEvaluator::IsNotOp( const char token )
  147. {
  148. if ( token == NOT_OP )
  149. return true;
  150. else
  151. return false;
  152. }
  153. bool CExpressionEvaluator::IsIdentifierOrConstant( const char token )
  154. {
  155. bool success = false;
  156. if ( token == '$' )
  157. {
  158. // store the entire identifier
  159. int i = 0;
  160. m_Identifier[i++] = token;
  161. while( (V_isalnum( m_pExpression[m_CurPosition] ) || m_pExpression[m_CurPosition] == '_') && i < MAX_IDENTIFIER_LEN )
  162. {
  163. m_Identifier[i] = m_pExpression[m_CurPosition];
  164. ++m_CurPosition;
  165. ++i;
  166. }
  167. if ( i < MAX_IDENTIFIER_LEN - 1 )
  168. {
  169. m_Identifier[i] = '\0';
  170. success = true;
  171. }
  172. }
  173. else
  174. {
  175. if ( V_isdigit( token ) )
  176. {
  177. int i = 0;
  178. m_Identifier[i++] = token;
  179. while( V_isdigit( m_pExpression[m_CurPosition] ) && ( i < MAX_IDENTIFIER_LEN ) )
  180. {
  181. m_Identifier[i] = m_pExpression[m_CurPosition];
  182. ++m_CurPosition;
  183. ++i;
  184. }
  185. if ( i < MAX_IDENTIFIER_LEN - 1 )
  186. {
  187. m_Identifier[i] = '\0';
  188. success = true;
  189. }
  190. }
  191. }
  192. return success;
  193. }
  194. bool CExpressionEvaluator::MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right )
  195. {
  196. tree = AllocateNode();
  197. tree->left = left;
  198. tree->right = right;
  199. tree->kind = kind;
  200. switch ( kind )
  201. {
  202. case CONDITIONAL:
  203. tree->data.cond = token;
  204. break;
  205. case LITERAL:
  206. if ( V_isdigit( m_Identifier[0] ) )
  207. {
  208. tree->data.value = ( atoi( m_Identifier ) != 0 );
  209. }
  210. else
  211. {
  212. tree->data.value = m_pGetSymbolProc( m_Identifier );
  213. }
  214. break;
  215. case NOT:
  216. break;
  217. default:
  218. if ( m_pSyntaxErrorProc )
  219. {
  220. Assert( 0 );
  221. m_pSyntaxErrorProc( CFmtStr( "Logic Error in CExpressionEvaluator" ) );
  222. }
  223. return false;
  224. }
  225. return true;
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Makes a factor :: { <expression> } | <identifier>.
  229. //-----------------------------------------------------------------------------
  230. bool CExpressionEvaluator::MakeFactor( ExprTree &tree )
  231. {
  232. if ( m_CurToken == '(' )
  233. {
  234. // Get the next token
  235. GetNextToken();
  236. // Make an expression, setting Tree to point to it
  237. if ( !MakeExpression( tree ) )
  238. {
  239. return false;
  240. }
  241. }
  242. else if ( IsIdentifierOrConstant( m_CurToken ) )
  243. {
  244. // Make a literal node, set Tree to point to it, set left/right children to NULL.
  245. if ( !MakeExprNode( tree, m_CurToken, LITERAL, NULL, NULL ) )
  246. {
  247. return false;
  248. }
  249. }
  250. else if ( IsNotOp( m_CurToken ) )
  251. {
  252. // do nothing
  253. return true;
  254. }
  255. else
  256. {
  257. // This must be a bad token
  258. if ( m_pSyntaxErrorProc )
  259. {
  260. m_pSyntaxErrorProc( CFmtStr( "Bad expression token: %c", m_CurToken ) );
  261. }
  262. return false;
  263. }
  264. // Get the next token
  265. GetNextToken();
  266. return true;
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Makes a term :: <factor> { <not> }.
  270. //-----------------------------------------------------------------------------
  271. bool CExpressionEvaluator::MakeTerm( ExprTree &tree )
  272. {
  273. // Make a factor, setting Tree to point to it
  274. if ( !MakeFactor( tree ) )
  275. {
  276. return false;
  277. }
  278. // while the next token is !
  279. while ( IsNotOp( m_CurToken ) )
  280. {
  281. // Make an operator node, setting left child to Tree and right to NULL. (Tree points to new node)
  282. if ( !MakeExprNode( tree, m_CurToken, NOT, tree, NULL ) )
  283. {
  284. return false;
  285. }
  286. // Get the next token.
  287. GetNextToken();
  288. // Make a factor, setting the right child of Tree to point to it.
  289. if ( !MakeFactor( tree->right ) )
  290. {
  291. return false;
  292. }
  293. }
  294. return true;
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Makes a complete expression :: <term> { <cond> <term> }.
  298. //-----------------------------------------------------------------------------
  299. bool CExpressionEvaluator::MakeExpression( ExprTree &tree )
  300. {
  301. // Make a term, setting Tree to point to it
  302. if ( !MakeTerm( tree ) )
  303. {
  304. return false;
  305. }
  306. // while the next token is a conditional
  307. while ( 1 )
  308. {
  309. bool bConditional = false;
  310. bool bValid = IsConditional( bConditional, m_CurToken );
  311. if ( !bValid )
  312. {
  313. return false;
  314. }
  315. if ( !bConditional )
  316. {
  317. break;
  318. }
  319. // Make a conditional node, setting left child to Tree and right to NULL. (Tree points to new node)
  320. if ( !MakeExprNode( tree, m_CurToken, CONDITIONAL, tree, NULL ) )
  321. {
  322. return false;
  323. }
  324. // Get the next token.
  325. GetNextToken();
  326. // Make a term, setting the right child of Tree to point to it.
  327. if ( !MakeTerm( tree->right ) )
  328. {
  329. return false;
  330. }
  331. }
  332. return true;
  333. }
  334. //-----------------------------------------------------------------------------
  335. // returns true for success, false for failure
  336. //-----------------------------------------------------------------------------
  337. bool CExpressionEvaluator::BuildExpression( void )
  338. {
  339. // Get the first token, and build the tree.
  340. GetNextToken();
  341. return ( MakeExpression( m_ExprTree ) );
  342. }
  343. //-----------------------------------------------------------------------------
  344. // returns the value of the node after resolving all children
  345. //-----------------------------------------------------------------------------
  346. bool CExpressionEvaluator::SimplifyNode( ExprTree& node )
  347. {
  348. if ( !node )
  349. return false;
  350. // Simplify the left and right children of this node
  351. bool leftVal = SimplifyNode(node->left);
  352. bool rightVal = SimplifyNode(node->right);
  353. // Simplify this node
  354. switch( node->kind )
  355. {
  356. case NOT:
  357. // the child of '!' is always to the right
  358. node->data.value = !rightVal;
  359. break;
  360. case CONDITIONAL:
  361. if ( node->data.cond == AND_OP )
  362. {
  363. node->data.value = leftVal && rightVal;
  364. }
  365. else // OR_OP
  366. {
  367. node->data.value = leftVal || rightVal;
  368. }
  369. break;
  370. default: // LITERAL
  371. break;
  372. }
  373. // This node has beed resolved
  374. node->kind = LITERAL;
  375. return node->data.value;
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Interface to solve a conditional expression. Returns false on failure, Result is undefined.
  379. //-----------------------------------------------------------------------------
  380. bool CExpressionEvaluator::Evaluate( bool &bResult, const char *pInfixExpression, GetSymbolProc_t pGetSymbolProc, SyntaxErrorProc_t pSyntaxErrorProc )
  381. {
  382. if ( !pInfixExpression )
  383. {
  384. return false;
  385. }
  386. // for caller simplicity, we strip of any enclosing braces
  387. // strip the bracketing [] if present
  388. char szCleanToken[512];
  389. if ( pInfixExpression[0] == '[' )
  390. {
  391. int len = V_strlen( pInfixExpression );
  392. // SECURITY: Bail on input buffers that are too large, they're used for RCEs and we don't
  393. // need to support them.
  394. if ( len + 1 > ARRAYSIZE( szCleanToken ) )
  395. {
  396. return false;
  397. }
  398. V_strncpy( szCleanToken, pInfixExpression + 1, len );
  399. len--;
  400. if ( szCleanToken[len-1] == ']' )
  401. {
  402. szCleanToken[len-1] = '\0';
  403. }
  404. pInfixExpression = szCleanToken;
  405. }
  406. // reset state
  407. m_pExpression = pInfixExpression;
  408. m_pGetSymbolProc = pGetSymbolProc ? pGetSymbolProc : DefaultConditionalSymbolProc;
  409. m_pSyntaxErrorProc = pSyntaxErrorProc ? pSyntaxErrorProc : DefaultConditionalErrorProc;
  410. m_ExprTree = 0;
  411. m_CurPosition = 0;
  412. m_CurToken = 0;
  413. // Building the expression tree will fail on bad syntax
  414. bool bValid = BuildExpression();
  415. if ( bValid )
  416. {
  417. bResult = SimplifyNode( m_ExprTree );
  418. }
  419. // don't leak
  420. FreeTree( m_ExprTree );
  421. m_ExprTree = NULL;
  422. return bValid;
  423. }