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

//===== Copyright (c) 1996-2006, Valve Corporation, All rights reserved. ======//
//
// Purpose: ExprSimplifier builds a binary tree from an infix expression (in the
// form of a character array).
//
//===========================================================================//
#include "vpc.h"
static ExprTree mExprTree; // Tree representation of the expression
static char mCurToken; // Current token read from the input expression
static const char *mExpression; // Array of the expression characters
static int mCurPosition; // Current position in the input expression
static char mIdentifier[MAX_IDENTIFIER_LEN]; // Stores the identifier string
static GetSymbolProc_t g_pGetSymbolProc;
//-----------------------------------------------------------------------------
// Sets mCurToken to the next token in the input string. Skips all whitespace.
//-----------------------------------------------------------------------------
static char GetNextToken( void )
{
// while whitespace, Increment CurrentPosition
while( mExpression[mCurPosition] == ' ' )
++mCurPosition;
// CurrentToken = Expression[CurrentPosition]
mCurToken = mExpression[mCurPosition++];
return mCurToken;
}
//-----------------------------------------------------------------------------
// Utility funcs
//-----------------------------------------------------------------------------
static void FreeNode( ExprNode *node )
{
delete node;
}
static ExprNode *AllocateNode( void )
{
return new ExprNode;
}
static void FreeTree( ExprTree& node )
{
if(!node)
return;
FreeTree(node->left);
FreeTree(node->right);
FreeNode(node);
node = 0;
}
static bool IsConditional( const char token )
{
char nextchar = ' ';
if ( token == OR_OP || token == AND_OP )
{
nextchar = mExpression[mCurPosition++];
if ( (token & nextchar) == token )
{
return true;
}
else
g_pVPC->VPCSyntaxError( "Bad expression token: %c %c", token, nextchar );
}
return false;
}
static bool IsNotOp( const char token )
{
if ( token == NOT_OP )
return true;
else
return false;
}
static bool IsIdentifierOrConstant( const char token )
{
bool success = false;
if ( token == '$' )
{
// store the entire identifier
int i = 0;
mIdentifier[i++] = token;
while( (V_isalnum( mExpression[mCurPosition] ) || mExpression[mCurPosition] == '_') && i < MAX_IDENTIFIER_LEN )
{
mIdentifier[i] = mExpression[mCurPosition];
++mCurPosition;
++i;
}
if ( i < MAX_IDENTIFIER_LEN - 1 )
{
mIdentifier[i] = '\0';
success = true;
}
}
else
{
if ( V_isdigit( token ) )
{
int i = 0;
mIdentifier[i++] = token;
while( V_isdigit( mExpression[mCurPosition] ) && ( i < MAX_IDENTIFIER_LEN ) )
{
mIdentifier[i] = mExpression[mCurPosition];
++mCurPosition;
++i;
}
if ( i < MAX_IDENTIFIER_LEN - 1 )
{
mIdentifier[i] = '\0';
success = true;
}
}
}
return success;
}
static void MakeExprNode( ExprTree &tree, char token, Kind kind, ExprTree left, ExprTree right )
{
tree = AllocateNode();
tree->left = left;
tree->right = right;
tree->kind = kind;
switch ( kind )
{
case CONDITIONAL:
tree->data.cond = token;
break;
case LITERAL:
if ( V_isdigit( mIdentifier[0] ) )
{
tree->data.value = atoi( mIdentifier ) != 0;
}
else
{
tree->data.value = g_pGetSymbolProc( mIdentifier );
}
break;
case NOT:
break;
default:
g_pVPC->VPCError( "Error in ExpTree" );
}
}
static void MakeExpression( ExprTree& tree );
//-----------------------------------------------------------------------------
// Makes a factor :: { <expression> } | <identifier>.
//-----------------------------------------------------------------------------
static void MakeFactor( ExprTree& tree )
{
if ( mCurToken == '(' )
{
// Get the next token
GetNextToken();
// Make an expression, setting Tree to point to it
MakeExpression( tree );
}
else if ( IsIdentifierOrConstant( mCurToken ) )
{
// Make a literal node, set Tree to point to it, set left/right children to NULL.
MakeExprNode( tree, mCurToken, LITERAL, NULL, NULL );
}
else if ( IsNotOp( mCurToken ) )
{
// do nothing
return;
}
else
{
// This must be a bad token
g_pVPC->VPCSyntaxError( "Bad expression token: %c", mCurToken );
}
// Get the next token
GetNextToken();
}
//-----------------------------------------------------------------------------
// Makes a term :: <factor> { <not> }.
//-----------------------------------------------------------------------------
static void MakeTerm( ExprTree& tree )
{
// Make a factor, setting Tree to point to it
MakeFactor( tree );
// while the next token is !
while( IsNotOp( mCurToken ) )
{
// Make an operator node, setting left child to Tree and right to NULL. (Tree points to new node)
MakeExprNode( tree, mCurToken, NOT, tree, NULL );
// Get the next token.
GetNextToken();
// Make a factor, setting the right child of Tree to point to it.
MakeFactor(tree->right);
}
}
//-----------------------------------------------------------------------------
// Makes a complete expression :: <term> { <cond> <term> }.
//-----------------------------------------------------------------------------
static void MakeExpression( ExprTree& tree )
{
// Make a term, setting Tree to point to it
MakeTerm( tree );
// while the next token is a conditional
while ( IsConditional( mCurToken ) )
{
// Make a conditional node, setting left child to Tree and right to NULL. (Tree points to new node)
MakeExprNode( tree, mCurToken, CONDITIONAL, tree, NULL );
// Get the next token.
GetNextToken();
// Make a term, setting the right child of Tree to point to it.
MakeTerm( tree->right );
}
}
//-----------------------------------------------------------------------------
// returns true for success, false for failure
//-----------------------------------------------------------------------------
static bool BuildExpression( void )
{
// Get the first token, and build the tree.
GetNextToken();
MakeExpression( mExprTree );
return true;
}
//-----------------------------------------------------------------------------
// returns the value of the node after resolving all children
//-----------------------------------------------------------------------------
static bool SimplifyNode( ExprTree& node )
{
if( !node )
return false;
// Simplify the left and right children of this node
bool leftVal = SimplifyNode(node->left);
bool rightVal = SimplifyNode(node->right);
// Simplify this node
switch( node->kind )
{
case NOT:
// the child of '!' is always to the right
node->data.value = !rightVal;
break;
case CONDITIONAL:
if ( node->data.cond == AND_OP )
{
node->data.value = leftVal && rightVal;
}
else // OR_OP
{
node->data.value = leftVal || rightVal;
}
break;
default: // LITERAL
break;
}
// This node has beed resolved
node->kind = LITERAL;
return node->data.value;
}
//-----------------------------------------------------------------------------
// Interface to solve a conditional expression. Returns false on failure.
//-----------------------------------------------------------------------------
bool EvaluateExpression( bool &result, const char *InfixExpression, GetSymbolProc_t pGetSymbolProc )
{
if ( !InfixExpression )
return false;
g_pGetSymbolProc = pGetSymbolProc;
bool success = false;
mExpression = InfixExpression;
mExprTree = 0;
mCurPosition = 0;
// Building the expression tree will fail on bad syntax
if ( BuildExpression() )
{
success = true;
result = SimplifyNode( mExprTree );
}
FreeTree( mExprTree );
return success;
}