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
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|