//===== 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 :: { } | . //----------------------------------------------------------------------------- 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 :: { }. //----------------------------------------------------------------------------- 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 :: { }. //----------------------------------------------------------------------------- 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; }