diff options
Diffstat (limited to 'src/core/xbexp.cpp')
-rwxr-xr-x | src/core/xbexp.cpp | 2661 |
1 files changed, 0 insertions, 2661 deletions
diff --git a/src/core/xbexp.cpp b/src/core/xbexp.cpp deleted file mode 100755 index deea53d..0000000 --- a/src/core/xbexp.cpp +++ /dev/null @@ -1,2661 +0,0 @@ -/* xbexp.cpp - -XBase64 Software Library - -Copyright (c) 1997,2003,2014,2017,2021,2022 Gary A Kunkel - -The xb64 software library is covered under -the terms of the GPL Version 3, 2007 license. - -Email Contact: - - XDB-devel@lists.sourceforge.net - XDB-users@lists.sourceforge.net - - -This module is part of the expression logic and has the code -for parsing various tokens out of an expression - -*/ - -#include "xbase.h" - -#ifdef XB_EXPRESSION_SUPPORT - -namespace xb{ - -/*************************************************************************/ -//! Constructor -/*! - \param x Pointer to xbXBase instance. -*/ - -xbExp::xbExp( xbXBase *x ){ - xbase = x; - dbf = NULL; - nTree = NULL; -} - -/*************************************************************************/ -//! Constructor -/*! - \param x Pointer to xbXBase instance. - \param d Pointer to xbDbf instance. -*/ -xbExp::xbExp( xbXBase *x, xbDbf *d ){ - xbase = x; - dbf = d; - nTree = NULL; -} - -/*************************************************************************/ -//! Deconstrucor. - -xbExp::~xbExp() { - - if( nTree ) - delete nTree; -} - -/*************************************************************************/ -//! Calulate expression return length -/*! - - This function returns the maximum possible length of an expression - The create index functions use this for determining the fixed length keys - It sets the return length field in the node. - - \param n Start node - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::CalcFunctionResultLen( xbExpNode * n ) const{ - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - xbInt16 iReturnLenCalc = 0;; - xbInt32 lReturnLenVal = 0; - xbString sNodeText; - - - try{ - - n->GetNodeText( sNodeText ); - char cReturnType = 0; - if(( iRc = xbase->GetFunctionInfo( sNodeText, cReturnType, iReturnLenCalc, lReturnLenVal )) != XB_NO_ERROR ){ - iErrorStop = 100; - throw iRc; - } - - if( iReturnLenCalc == 1 ){ - // use the value from iReturnLenVal - n->SetResultLen( (xbUInt32) lReturnLenVal ); - } - else if( iReturnLenCalc == 2 ){ - // use the length from the child node identified in lReturnLenVal - xbExpNode *nChild = n->GetChild( (xbUInt32) lReturnLenVal - 1 ); - if( !nChild ){ - iErrorStop = 110; - iRc = XB_PARSE_ERROR; - throw iRc; - } - n->SetResultLen( nChild->GetResultLen()); - } - - else if( iReturnLenCalc == 3 ){ - // use the length from the child node identified in lReturnLenVal - xbExpNode *nChild = n->GetChild( (xbUInt32) lReturnLenVal - 1 ); - if( !nChild ){ - iErrorStop = 120; - iRc = XB_PARSE_ERROR; - throw iRc; - } - n->SetResultLen( (xbUInt32) nChild->GetNumericResult()); - } - else if( iReturnLenCalc == 4 ){ - // use the value from the length in parm 1 multiplied by the value in parm 2 (REPLICATE) - xbExpNode *nChild1 = n->GetChild( 0 ); - xbExpNode *nChild2 = n->GetChild( 1 ); - if( !nChild1 || !nChild2 ){ - iErrorStop = 130; - iRc = XB_PARSE_ERROR; - throw iRc; - } - n->SetResultLen( nChild1->GetResultLen() * (xbUInt32) nChild2->GetNumericResult()); - } - else if( iReturnLenCalc == 5 ){ - // use the larger of the length of the value in parm2 or parm 3 (IIF statement) - xbExpNode *nChild2 = n->GetChild( 1 ); - xbExpNode *nChild3 = n->GetChild( 2 ); - if( !nChild2 || !nChild3 ){ - iErrorStop = 140; - iRc = XB_PARSE_ERROR; - throw iRc; - } - if( nChild2->GetResultLen() >= nChild3->GetResultLen()) - n->SetResultLen( nChild2->GetResultLen()); - else - n->SetResultLen( nChild3->GetResultLen()); - } - - else if( iReturnLenCalc == 6 ){ - - if( n->GetChildCnt() >= 2 ){ - xbExpNode *nChild2 = n->GetChild( 1 ); - n->SetResultLen( (xbUInt32) nChild2->GetNumericResult()); - } else { - n->SetResultLen( (xbUInt32) lReturnLenVal ); - } - - } else { - iErrorStop = 150; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::GetFunctionResultLen() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} - -/*************************************************************************/ -//! Check parens and quotes -/*! - This routine looks for unbalanced parens and quotes - - \param sExpression Expression to examine. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - - -xbInt16 xbExp::CheckParensAndQuotes( const xbString &sExpression ){ - - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - - xbBool bInQuotes = xbFalse; - xbInt16 iLparenCtr = 0; - xbInt16 iRparenCtr = 0; - xbInt16 iQuoteType = 0; - const char *s = sExpression; - - try{ - - while( *s ){ - if( !bInQuotes ){ - if( *s == '(' ){ - iLparenCtr++; - } else if( *s == ')' ){ - iRparenCtr++; - } else if( *s == '\'' ){ - bInQuotes++; - iQuoteType = 0; - } else if( *s == '"' ){ - bInQuotes++; - iQuoteType = 1; - } - } else { - if(( *s == '\'' && iQuoteType == 0 ) || (*s == '"' && iQuoteType == 1 )) - bInQuotes--; - } - s++; - } - if( iLparenCtr != iRparenCtr ){ - iErrorStop = 100; - iRc = XB_UNBALANCED_PARENS; - throw iRc; - } - if( bInQuotes ){ - iErrorStop = 110; - iRc = XB_UNBALANCED_QUOTES; - throw iRc; - } - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::CheckParensAndQuots() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - xbase->WriteLogMessage( sExpression ); - } - return iRc; -} -/*************************************************************************/ -//! Clear tree handle. -/*! - This routine clears the expression tree and frees any associated memory. - \returns void. -*/ - -void xbExp::ClearTreeHandle(){ - if( nTree ){ - nTree = NULL; - } -} - -/*************************************************************************/ -#ifdef XB_DEBUG_SUPPORT -//! Dump the tree. -/*! - \param iOption - Output opton. - \returns void. -*/ - -void xbExp::DumpTree( xbInt16 iOption ){ - nTree->DumpNode( iOption ); -} - -//! Dump token -/*! - \param iOption - Output opton. - \returns void. -*/ - - -void xbExp::DumpToken( xbExpToken &t, xbInt16 iOption ){ - - xbString sMsg; - sMsg = "Processing Token"; - xbase->WriteLogMessage( sMsg.Str(), iOption ); - - sMsg.Sprintf( "Expression = [%s]", t.sExpression.Str()); - xbase->WriteLogMessage( sMsg.Str(), iOption ); - - sMsg.Sprintf( "Token = [%s]", t.sToken.Str()); - xbase->WriteLogMessage( sMsg.Str(), iOption ); - - sMsg.Sprintf( "NodeType = [%c]", t.cNodeType ); - xbase->WriteLogMessage( sMsg.Str(), iOption ); - - sMsg.Sprintf( "ReturnType = [%c]", t.cReturnType ); - xbase->WriteLogMessage( sMsg.Str(), iOption ); - - sMsg.Sprintf( "Sts = [%d]", t.iSts ); - xbase->WriteLogMessage( sMsg.Str(), iOption ); - - sMsg.Sprintf( "PrevNodeType = [%c]", t.cPrevNodeType ); - xbase->WriteLogMessage( sMsg.Str(), iOption ); - - sMsg.Sprintf( "PrevReturnType = [%c]", t.cPrevReturnType ); - xbase->WriteLogMessage( sMsg.Str(), iOption ); -} - -#endif - -/*************************************************************************/ -//! Get date result. -/*! - If the expression generates a date return type, this method retrieves the date value. - \param dtResult - Output date value. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::GetDateResult( xbDate &dtResult ){ - if( nTree ){ - dtResult.JulToDate8( (xbInt32) nTree->GetNumericResult() ); - return XB_NO_ERROR; - } - else{ - //dtResult = ?; - return XB_PARSE_ERROR; - } -} -/*************************************************************************/ -//! Get bool result. -/*! - If the expression generates a boolean return type, this method retrieves the boolean value. - \param bResult - Output boolean value. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ -xbInt16 xbExp::GetBoolResult( xbBool &bResult){ - if( nTree ){ - bResult = nTree->GetBoolResult(); - return XB_NO_ERROR; - } - else{ - return XB_PARSE_ERROR; - } -} - -/*************************************************************************/ -//! Get the next node in the tree. -/*! - \param n Node to starting point. To get the first node of the entire tree, set n = NULL - \returns Pointer to next node. -*/ - -xbExpNode *xbExp::GetNextNode( xbExpNode * n ) const { - - // to get the first node of the entire tree, set n = NULL - // std::cout << "In GetNextNode\n"; - - if( n == nTree ) - return NULL; - - else if( !n ){ - if( !nTree ) - return NULL; - else - return nTree->GetFirstNode(); - } - return n->GetNextNode(); -} - -/*************************************************************************/ -//! GetNextToken -/*! This method returns the next token in an expression of one or more tokens - \param t Token - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::GetNextToken( xbExpToken &t ){ - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - - try{ - t.iSts = XB_NO_ERROR; - t.sExpression.Ltrim(); - - if( t.sExpression.Len() == 0 ){ - t.iSts = XB_END_OF_EXPRESSION; - return XB_NO_ERROR; - } - - // Check for date constant - if((t.sExpression.Len() >= 10 && t.sExpression[1] == '{' && t.sExpression[4] == '/' && t.sExpression[7] == '/') && - (t.sExpression[10] == '}' || (t.sExpression.Len() >= 12 && t.sExpression[12] == '}'))){ - if(( iRc = GetTokenDateConstant( t )) != XB_NO_ERROR ){ - iErrorStop = 100; - throw iRc; - } - } - // Check for parens - else if( t.sExpression[1] == '(' || t.sExpression[1] == '{' ){ - if(( iRc = GetTokenParen( t )) != XB_NO_ERROR ){ - iErrorStop = 110; - throw iRc; - } - } - // Check for a char constant - else if( t.sExpression[1] == '"' || t.sExpression[1] == '\'' ){ - if(( iRc = GetTokenCharConstant( t )) != XB_NO_ERROR ){ - iErrorStop = 120; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - // Check for logical constant - else if( IsLogicalConstant( t.sExpression )){ - if(( iRc = GetTokenLogicalConstant( t )) != XB_NO_ERROR ){ - iErrorStop = 130; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - // check for numeric constant - else if( IsNumericConstant( t.sExpression, t.cPrevNodeType )){ - if(( iRc = GetTokenNumericConstant( t )) != XB_NO_ERROR ){ - iErrorStop = 140; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - // check for operator - else if( IsOperator( t.sExpression )){ - if(( iRc = GetTokenOperator( t )) != XB_NO_ERROR ){ - iErrorStop = 150; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - // check for function - else if( IsFunction( t.sExpression, t.cReturnType )){ - if(( iRc = GetTokenFunction( t )) != XB_NO_ERROR ){ - iErrorStop = 160; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - else if(( iRc = GetTokenDatabaseField( t )) != XB_NO_ERROR ){ - iErrorStop = 170; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::GetNextToken() Exception Caught. Error Stop = [%d] iRc = [%d] Expression = [%s]", iErrorStop, iRc, t.sExpression.Str() );sMsg.Sprintf( "xbexp::GetNextToken() Exception Caught. Error Stop = [%d] iRc = [%d] Expression = [%s]", iErrorStop, iRc, t.sExpression.Str() );sMsg.Sprintf( "xbexp::GetNextToken() Exception Caught. Error Stop = [%d] iRc = [%d] Expression = [%s]", iErrorStop, iRc, t.sExpression.Str() );sMsg.Sprintf( "xbexp::GetNextToken() Exception Caught. Error Stop = [%d] iRc = [%d] Expression = [%s]", iErrorStop, iRc, t.sExpression.Str() ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} - -/*************************************************************************/ -//! Get numeric result. -/*! - If the expression generates a numeric return type, this method retrieves the numeric value. - \param dResult - Output numeric value. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::GetNumericResult( xbDouble &dResult){ - if( nTree ){ - dResult = nTree->GetNumericResult(); - return XB_NO_ERROR; - } - else{ - dResult = 0; - return XB_PARSE_ERROR; - } -} -/*************************************************************************/ -//! Get result length. -/*! - This routine returns the result length. - \returns Result length. -*/ - -xbInt16 xbExp::GetResultLen() const{ - if( nTree ) - return nTree->GetResultLen(); - else - return 0; -} - -/*************************************************************************/ -//! Get return type. -/*! - \returns Expression return type. -*/ - -char xbExp::GetReturnType() const{ - if( nTree ) - return nTree->GetReturnType(); - else - return ' '; -} - -/*************************************************************************/ -//! Get string result. -/*! - If the expression generates a string return type, this method retrieves the string value. - \param sResult - Output string value. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::GetStringResult( xbString &sResult){ - if( nTree ){ - sResult = nTree->GetStringResult(); - return XB_NO_ERROR; - } - else{ - sResult = ""; - return XB_PARSE_ERROR; - } -} - -/*************************************************************************/ -//! Get string result. -/*! - If the expression generates a string return type, this method retrieves the string value. - \param vpResult - Pointer to user supplied buffer for result. - \param ulLen - Max size of buffer. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - - -xbInt16 xbExp::GetStringResult( char * vpResult, xbUInt32 ulLen ){ - if( nTree ){ - nTree->GetStringResult().strncpy((char *) vpResult, ulLen ); - return XB_NO_ERROR; - } - else{ - return XB_PARSE_ERROR; - } -} - - - -/*************************************************************************/ -//! GetTokenCharConstant -/*! This method returns the character constant in a pair of quotes - - This routine returns the tokens inside a set of matching quotes in sOutToken - If there is nothing between the quotes then sOutToken is returned empty - sOutRemainder contains whatever remains to the right of the right quote - - \param t Token - \returns <a href="xbretcod_8h.html">Return Codes</a> - -*/ - -xbInt16 xbExp::GetTokenCharConstant( xbExpToken &t ){ - - const char *s = t.sExpression; - const char *sToken; // pointer to beginning of token - xbInt16 iQuoteType; - xbUInt32 ulTokenLen = 0; - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - xbBool bDone = xbFalse; - - try{ - if( *s == '"' ) - iQuoteType = 0; - else - iQuoteType = 1; - s++; - sToken = s; - while( *s && !bDone ){ - if(( *s == '"' && iQuoteType == 0 ) || (*s == '\'' && iQuoteType == 1 )) - bDone = xbTrue; - s++; - ulTokenLen++; - } - if( bDone ){ // found matching paren - t.cNodeType = XB_EXP_CONSTANT; - t.cReturnType = XB_EXP_CHAR; - t.sToken.Set( sToken, ulTokenLen - 1 ); - t.sExpression.Ltrunc( ulTokenLen + 1 ); - } else { - iRc = XB_PARSE_ERROR; - t.iSts = XB_UNBALANCED_QUOTES; - iErrorStop = 100; - throw iRc; - } - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::GetTokenCharConstant() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} - - -/*************************************************************************/ -//! GetTokenDateConstant -/*! This method returns the date constant in a pair of {} - - Date format is one of {mm/dd/yy} or {mm/dd/yyyy} - \param t Token. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::GetTokenDateConstant( xbExpToken &t ){ - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - char wBuf[13]; - xbDate dt; - - try{ - memset( wBuf, 0x00, 13 ); - t.cNodeType = XB_EXP_CONSTANT; - t.cReturnType = XB_EXP_DATE; - - if( t.sExpression[10] == '}' ){ - for( xbInt16 i = 0; i < 8; i++ ) - wBuf[i] = t.sExpression[i+2]; - - if(( iRc = dt.CTOD( wBuf )) != XB_NO_ERROR ){ - iErrorStop = 100; - throw iRc; - } - t.sToken.Set( dt.Str() ); - t.sExpression.Ltrunc( 10 ); - - } else if( t.sExpression[12] == '}' ){ - - wBuf[0] = t.sExpression[8]; - wBuf[1] = t.sExpression[9]; - wBuf[2] = t.sExpression[10]; - wBuf[3] = t.sExpression[11]; - wBuf[4] = t.sExpression[2]; - wBuf[5] = t.sExpression[3]; - wBuf[6] = t.sExpression[5]; - wBuf[7] = t.sExpression[6]; - - t.sToken.Set( wBuf ); - t.sExpression.Ltrunc( 12 ); - } else { - iRc = XB_PARSE_ERROR; - t.iSts = XB_INVALID_DATE; - iErrorStop = 110; - throw iRc; - } - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::GetTokenDateConstant() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} -/*************************************************************************/ -//! GetTokenField -/*! This method gets a database field token - - Looks for a xbase field in one of the following formats - - FIELDNAME - or - TABLENAME->FIELDNAME - - \param t Token. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::GetTokenDatabaseField( xbExpToken &t ){ - - const char *s = t.sExpression; - xbUInt32 ulTokenLen = 0; - xbUInt32 ulTokenLen2 = 0; - - while( *s && !IsTokenSeparator( *s ) && !IsWhiteSpace( *s )) { - ulTokenLen++; - s++; - } - - // go past any white space - while( *s && !IsTokenSeparator( *s ) && IsWhiteSpace( *s )) { - ulTokenLen2++; - s++; - } - - // look for -> - // remove the table name from before the -> - if( strncmp( s, "->", 2 ) == 0 ){ - ulTokenLen2+=2; - s+=2; - -/* - if( strncmp( s, "->", 2 ) == 0 || strncmp( s, ".", 1 ) == 0){ - if( *s == '.' ){ - ulTokenLen2+=1; - s+=1; - } else { - ulTokenLen2+=2; - s+=2; - } -*/ - - // go past white space - while( *s && !IsTokenSeparator( *s ) && IsWhiteSpace( *s )) { - ulTokenLen2++; - s++; - } - // go to the end - while( *s && !IsTokenSeparator( *s ) && !IsWhiteSpace( *s )) { - ulTokenLen2++; - s++; - } - ulTokenLen += ulTokenLen2; - } - t.cNodeType = XB_EXP_FIELD; - t.cReturnType = XB_EXP_UNKNOWN; - t.sToken.Set( t.sExpression, ulTokenLen ); - t.sExpression.Ltrunc( ulTokenLen ); - - return XB_NO_ERROR; -} - -/*************************************************************************/ -//! GetTokenFunction -/*! - This method gets a function and everything between the following quotes - \param t Token - \returns <a href="xbretcod_8h.html">Return Codes</a> - -*/ - -xbInt16 xbExp::GetTokenFunction( xbExpToken &t ){ - - xbUInt32 lPos = t.sExpression.Pos( '(' ); - if( lPos == 0 ) - return XB_PARSE_ERROR; - - xbBool bDone = xbFalse; - xbUInt32 lLen = t.sExpression.Len(); - xbInt16 iDepthCtr = 1; - - while( ++lPos <= lLen && !bDone ){ - if( t.sExpression[lPos] == ')' ){ - iDepthCtr--; - if( iDepthCtr == 0 ) - bDone = xbTrue; - } else if( t.sExpression[lPos] == '(' ){ - iDepthCtr++; - } - } - - t.cNodeType = XB_EXP_FUNCTION; - t.sToken.Set( t.sExpression, lPos-1 ); - t.sExpression.Ltrunc( lPos-1 ); - -// std::cout << "lPos = [" << lPos << "] done= [" << bDone << "][" << t.sExpression << "] len=[" << lLen << "] return type = [" << t.cReturnType << "]\n"; - - return XB_NO_ERROR; -} - -/*************************************************************************/ -//! GetTokenCharConstant -/*! This method returns the character constant in a pair of quotes - - This routine returns the tokens inside a set of matching quotes in sOutToken - If there is nothing between the quotes then sOutToken is returned empty - sOutRemainder contains whatever remains to the right of the right quote - - \param t Token - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::GetTokenLogicalConstant( xbExpToken &t ){ - - t.cNodeType = XB_EXP_CONSTANT; - t.cReturnType = XB_EXP_LOGICAL; - t.sToken = t.sExpression[2]; - - if( t.sExpression[3] == '.' ) - t.sExpression.Ltrunc( 3 ); - else if( t.sExpression[6] == '.' ) - t.sExpression.Ltrunc( 6 ); - else if( t.sExpression[7] == '.' ) - t.sExpression.Ltrunc( 7 ); - - return XB_NO_ERROR; -} - - -/*************************************************************************/ -//! GetTokenNumericConstant -/*! This method returns a numeric constant in - - This routine returns a numeric constant token - sOutRemainder contains whatever remains to the right of the right quote - - \param t Token - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::GetTokenNumericConstant( xbExpToken &t ){ - - const char * s = t.sExpression; - xbUInt32 ulTokenLen = 0; - t.sToken = ""; - - t.cNodeType = XB_EXP_CONSTANT; - t.cReturnType = XB_EXP_NUMERIC; - - // capture the leading sign - if( *s == '-' || *s == '+' || *s == '.' ){ - t.sToken = *s; - ulTokenLen++; - s++; - - // go past any white space between sign and number - while( *s && IsWhiteSpace( *s )){ - s++; - ulTokenLen++; - } - } - - // add the number to the token - while( *s && (isdigit( *s ) || *s == '.' )){ - t.sToken += *s; - s++; - ulTokenLen++; - } - t.sExpression.Ltrunc( ulTokenLen ); - return XB_NO_ERROR; -} - -/*************************************************************************/ -//! GetTokenOperator -/*! This method returns the operator - - \param t Token - \returns <a href="xbretcod_8h.html">Return Codes</a> - -*/ - -xbInt16 xbExp::GetTokenOperator( xbExpToken &t ){ - - const char *s = t.sExpression; - - // Logical operators - if((strncmp( s, "<>", 2 ) == 0 ) || (strncmp( s, "!=", 2 ) == 0 ) || - (strncmp( s, "<=", 2 ) == 0 ) || (strncmp( s, ">=", 2 ) == 0 )){ - t.cReturnType = XB_EXP_LOGICAL; - t.sToken.Assign( s, 1, 2 ); - t.sExpression.Ltrunc( 2 ); - t.cNodeType = XB_EXP_OPERATOR; - return XB_NO_ERROR; - } - - if( *s == '=' || *s == '<' || *s == '>' || *s == '$' || *s == '#' ){ - t.cReturnType = XB_EXP_LOGICAL; - t.sToken.Assign( s, 1, 1 ); - t.sExpression.Ltrunc( 1 ); - t.cNodeType = XB_EXP_OPERATOR; - return XB_NO_ERROR; - } - - if( (strncmp( s, ".NOT.", 5 ) == 0 ) || (strncmp( s, ".AND.", 5 ) == 0 )){ - t.cReturnType = XB_EXP_LOGICAL; - t.sToken.Assign( s, 1, 5 ); - t.sExpression.Ltrunc( 5 ); - t.cNodeType = XB_EXP_OPERATOR; - return XB_NO_ERROR; - } - - if( (strncmp( s, "NOT ", 4 ) == 0 ) || (strncmp( s, "AND ", 4 ) == 0 )){ - t.cReturnType = XB_EXP_LOGICAL; - t.sToken.Assign( s, 1, 3 ); - t.sExpression.Ltrunc( 3 ); - t.cNodeType = XB_EXP_OPERATOR; - return XB_NO_ERROR; - } - - if( strncmp( s, ".OR.", 4 ) == 0 ) { - t.cReturnType = XB_EXP_LOGICAL; - t.sToken.Assign( s, 1, 4 ); - t.sExpression.Ltrunc( 4 ); - t.cNodeType = XB_EXP_OPERATOR; - return XB_NO_ERROR; - } - - if( strncmp( s, "OR ", 3 ) == 0 ) { - t.cReturnType = XB_EXP_LOGICAL; - t.sToken.Assign( s, 1, 2 ); - t.sExpression.Ltrunc( 2 ); - t.cNodeType = XB_EXP_OPERATOR; - return XB_NO_ERROR; - } - - // Numeric operators - if(( strncmp( s, "**", 2 ) == 0 ) || ( strncmp( s, "+=", 2 ) == 0 ) || - ( strncmp( s, "-=", 2 ) == 0 ) || ( strncmp( s, "*=", 2 ) == 0 ) || ( strncmp( s, "/=", 2 ) == 0 )){ - t.cReturnType = XB_EXP_NUMERIC; - t.sToken.Assign( s, 1, 2 ); - t.sExpression.Ltrunc( 2 ); - t.cNodeType = XB_EXP_OPERATOR; - return XB_NO_ERROR; - } - - // Pre/post increment/decrement operators ++ or -- - if(( strncmp( s, "--", 2 ) == 0 ) || ( strncmp( s, "++", 2 ) == 0 )){ - t.cReturnType = XB_EXP_NUMERIC; - t.sToken.Assign( s, 1, 2 ); - t.sExpression.Ltrunc( 2 ); - if( t.sExpression.Len() > 0 && (isdigit( t.sExpression[1] ) || isalpha( t.sExpression[1] ))) - t.cNodeType = XB_EXP_PRE_OPERATOR; - else - t.cNodeType = XB_EXP_POST_OPERATOR; - - return XB_NO_ERROR; - } - - if( *s == '*' || *s == '/' || *s == '%' || *s == '^' ){ - t.cReturnType = XB_EXP_NUMERIC; - t.sToken.Assign( s, 1, 1 ); - t.sExpression.Ltrunc( 1 ); - t.cNodeType = XB_EXP_OPERATOR; - return XB_NO_ERROR; - } - - // multi return type operators - t.cReturnType = XB_EXP_UNKNOWN; - if( *s == '+' || *s == '-' ){ - t.sToken.Assign( s, 1, 1 ); - t.sExpression.Ltrunc( 1 ); - t.cNodeType = XB_EXP_OPERATOR; - return XB_NO_ERROR; - } - return XB_PARSE_ERROR; -} - -/*************************************************************************/ -//! GetTokenParen -/*! This method returns the tokens in a pair of enclosed parens - - This routine returns the tokens inside a set of matching parens in sOutToken - If there is nothing between the parens then sOutToken is returned empty - sOutRemainder contains whatever remains to the right of the right paren - - \param t Token - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - - -xbInt16 xbExp::GetTokenParen( xbExpToken &t ){ - - const char * s = t.sExpression; - const char * sToken; // pointer to beginning of token - xbInt16 iParenType = 0; - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - xbInt16 iDepthCtr = 0; // depth inside of nested parens - xbUInt32 ulTokenLen = 0; - xbBool bDone = xbFalse; - - try{ - if( *s == '{' ) - iParenType = 0; - else - iParenType = 1; - iDepthCtr = 1; - s++; - sToken = s; - - while( *s && !bDone ){ - if(( *s == ')' && iParenType == 1 ) || (*s == '}' && iParenType == 0 )){ - iDepthCtr--; - if( iDepthCtr == 0 ) - bDone = xbTrue; - } else if(( *s == '(' && iParenType == 1 ) || (*s == '{' && iParenType == 0 )){ - iDepthCtr++; - } - s++; - ulTokenLen++; - } - - if( bDone ){ // found matching paren - t.cNodeType = XB_EXP_NOTROOT; - t.cReturnType = XB_EXP_UNKNOWN; - t.sToken.Set( sToken, ulTokenLen - 1 ); - t.sExpression.Ltrunc( ulTokenLen + 1 ); - } else { - t.sToken = ""; - t.cNodeType = XB_EXP_NOTROOT; - t.cReturnType = XB_EXP_UNKNOWN; - t.iSts = XB_UNBALANCED_PARENS; - iRc = XB_PARSE_ERROR; - iErrorStop = 100; - throw iRc; - } - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::GetTokenParen() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg ); - } - return iRc; -} - -/*************************************************************************/ -//! Get the expression tree handle. -/*! - \returns Pointer to the top most node in the expression tree. -*/ -xbExpNode *xbExp::GetTreeHandle(){ - return nTree; -} - -/*************************************************************************/ -//! Is Function -/*! This method determines if the next token is a function. - - \param sExpression - String expression to be evaluated. - \param cReturnType Output - Return type. - \returns xbTrue - Is a function.<br> - xbFalse - Is not a function. -*/ - -xbBool xbExp::IsFunction( const xbString & sExpression, char &cReturnType ){ - - xbInt16 i = 0; - xbInt32 l = 0; - if( sExpression.Pos( '(' ) > 0 ){ - if( xbase->GetFunctionInfo( sExpression, cReturnType, i, l ) == XB_NO_ERROR ) - return xbTrue; - } - return xbFalse; -} - -/*************************************************************************/ -//! Is Logical constant -/*! This method determines if the next token is a logical constant (T/F, etc). - - \param sExpression - String expression to be evaluated. - \returns xbTrue - Is a logical constant.<br> - xbFalse - Is not a logical constant. -*/ - -xbBool xbExp::IsLogicalConstant( const xbString & sExpression ){ - - const char *s = sExpression; - if(( strncmp( s, ".T.", 3 ) == 0 ) || ( strncmp( s, ".F.", 3 ) == 0 )) - return xbTrue; - else if( strncmp( s, ".TRUE.", 6 ) == 0 ) - return xbTrue; - else if( strncmp( s, ".FALSE.", 7 ) == 0 ) - return xbTrue; - - return xbFalse; -} - -/*************************************************************************/ -//! Is Numeric constant -/*! This method determines if the next token is a numeric constant. - - \param sExpression - String expression to be evaluated. - \param cPrevNodeType - Type of previous node. - \returns xbTrue - Is a numeric constant.<br> - xbFalse - Is not a numeric constant. -*/ -xbBool xbExp::IsNumericConstant( const xbString & sExpression, char cPrevNodeType ){ - - // check for positive, negative or decimal number constants - - const char *s = sExpression; - if(( *s == '-' && ( cPrevNodeType == 'O' || cPrevNodeType == 0 )) || - ( *s == '+' && ( cPrevNodeType == 'O' || cPrevNodeType == 0 ))){ - s++; - while( *s && IsWhiteSpace( *s )) - s++; - } - if( *s == '.' ) - s++; - - if( isdigit( *s )) - return xbTrue; - else - return xbFalse; -} - -/*************************************************************************/ -//! Is Operator. -/*! This method determines if the next token is an operator. - - \param sExpression - String expression to be evaluated. - \returns xbTrue - Is an operator.<br> - xbFalse - Is not an operator. -*/ -xbBool xbExp::IsOperator( const xbString & sExpression ){ - - const char *s = sExpression; - if( *s == '+' || *s == '-' || *s == '/' || *s == '^' || *s == '=' || *s == '$' || - *s == '#' || *s == '*' || *s == '<' || *s == '>' || *s == '%' ) - return xbTrue; - - if( strncmp( s, "!=", 2 ) == 0 ) - return xbTrue; - - if((strncmp( s, ".NOT.", 5 ) == 0 ) || (strncmp( s, ".OR.", 4 ) == 0 ) || (strncmp( s, ".AND.", 5 ) == 0 )) - return xbTrue; - - if((strncmp( s, "NOT ", 4 ) == 0 ) || (strncmp( s, "OR ", 3 ) == 0 ) || (strncmp( s, "AND ", 4 ) == 0 )) - return xbTrue; - - return xbFalse; -} - -/*************************************************************************/ -//! Is Token seperator -/*! This method determines if the next token is a seperator. - - \param sExpression - String expression to be evaluated. - \returns xbTrue - Is a token seperator.<br> - xbFalse - Is not a token seperator. -*/ -char xbExp::IsTokenSeparator( char c ){ - if( c == '-' || c == '+' || c == '*' || c == '/' || c == '$' || c == '#' || - c == '<' || c == '>' || c == '^' || c == '=' || c == '.' || c == '!' ) - return c; - else - return 0; -} -/*************************************************************************/ -//! Is White space -/*! This method determines if a given character is white space. - - \param c - Character to be evaluated. - \returns xbTrue - Is white space.<br> - xbFalse - Is not white space. -*/ -xbBool xbExp::IsWhiteSpace( char c ){ - return(( c == 0x20 )? 1 : 0 ); -} - -/*************************************************************************/ -//! Get operator weight. -/*! - This method determines the priority of an operator - - Operator precendence - 10 .AND. .OR. .NOT. (not really an operator) - 9 > or < (includes <= or >=) - 6 unary plus or minus (+,-) -- not passed this routine - 5 prefix increment and/or decrement (++,--) - 4 exponentiation ** or ^ - 3 multiplication,division or modulus (*,/,%) - 2 Addition, subtraction (+,-) - 1 Postfix increment and/or decrement (++,--) - - \param sOper - Operator. - \returns Operator weight - -*/ - -xbInt16 xbExp::OperatorWeight( const xbString &sOper ){ - - if( sOper == "" || sOper.Len() > 5 ) - return 0; - - else if( sOper == "--0" || sOper == "++0" ) // 0 is prefix - return 9; - else if( sOper == "**" || sOper == "^" ) - return 8; - else if( sOper == "*" || sOper == "/" || sOper == "%" || sOper == "*=" || sOper == "/=" ) - return 7; - else if( sOper == "+" || sOper == "-" || sOper == "+=" || sOper == "-=" ) - return 6; - else if( sOper == "--1" || sOper == "++1" ) // 1 is post fix - return 5; - else if( sOper == ">" || sOper == ">=" || sOper == "<" || sOper == "<=" || - sOper == "<>" || sOper == "!=" || sOper == "#" || sOper == "$" || sOper == "=" ) - return 4; - else if( sOper == ".NOT." || sOper == "NOT" ) - return 3; - else if( sOper == ".AND." || sOper == "AND" ) - return 2; - else if( sOper == ".OR." || sOper == "OR" ) - return 1; - - return 0; -} - - -/*************************************************************************/ -//! Parse expression. -/*! - \param sExpression - Expression to parse. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::ParseExpression( const xbString &sExpression ){ - return ParseExpression( sExpression, (xbInt16) 0 ); -} - -/*************************************************************************/ -//! Parse expression. -/*! - \param dbf - Pointer to xbDbf instance. - \param sExpression - Expression to parse. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::ParseExpression( xbDbf *dbf, const xbString &sExpression ){ - this->dbf = dbf; - return ParseExpression( sExpression, (xbInt16) 0 ); -} - -/*************************************************************************/ -//! Parse expression. -/*! - \param sExpression - Expression to parse. - \param iWeight. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ -xbInt16 xbExp::ParseExpression( const xbString &sExpression, xbInt16 iWeight ){ - - xbExpNode *n; - xbExpNode *nLastNode = NULL; // pointer to the last node processed - xbExpToken t; - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - xbString s; - - try { - - if( nTree ) - delete nTree; - - if(( iRc = CheckParensAndQuotes( sExpression )) != XB_NO_ERROR ){ - iErrorStop = 100; - throw iRc; - } - - t.sExpression = sExpression; - - xbString sOriginalExp; - while( t.iSts == XB_NO_ERROR && iRc == XB_NO_ERROR ){ - - sOriginalExp = t.sExpression; // test code - iRc = GetNextToken( t ); - if( !iRc && !t.iSts ){ - - // comment / uncomment debug / live - // DumpToken( t, 0 ); - - if( t.cNodeType == XB_EXP_NOTROOT ){ - xbExp enr( xbase, dbf ); - if(( iRc = enr.ParseExpression( t.sToken, iWeight + 10 )) != XB_NO_ERROR ){ - iErrorStop = 110; - throw iRc; - } - n = enr.GetTreeHandle(); - enr.ClearTreeHandle(); - - } else { - - switch( t.cNodeType ) { - - case XB_EXP_CONSTANT: - n = new xbExpNode( t.sToken, t.cNodeType ); - if(( iRc = ParseExpressionConstant( t, n )) != XB_NO_ERROR ){ - iErrorStop = 120; - throw iRc; - } - break; - - case XB_EXP_FUNCTION: - n = new xbExpNode( t.cNodeType ); - if(( iRc = ParseExpressionFunction( t, n, iWeight )) != XB_NO_ERROR ){ - iErrorStop = 130; - throw iRc; - } - break; - - case XB_EXP_FIELD: - n = new xbExpNode( t.cNodeType ); - if(( iRc = ParseExpressionField( t, n )) != XB_NO_ERROR ){ - iErrorStop = 140; - throw iRc; - } - break; - - case XB_EXP_OPERATOR: - case XB_EXP_PRE_OPERATOR: - case XB_EXP_POST_OPERATOR: - n = new xbExpNode( t.sToken, t.cNodeType ); - if(( iRc = ParseExpressionOperator( t, n, iWeight )) != XB_NO_ERROR ){ - iErrorStop = 150; - throw iRc; - } - break; - - default: - iErrorStop = 160; - iRc = XB_PARSE_ERROR; - throw iRc; - // break; - } - } - t.cPrevNodeType = t.cNodeType; - t.cPrevReturnType = t.cReturnType; - - // determine where in the expression tree to insert the latest node "n" - // Is this the first node to be added to the tree? - if( !nTree ){ - nTree = n; - } - - // else if last node was XB_EXB_PRE_OPERATOR then append this as child to last node - else if( nLastNode && nLastNode->GetNodeType() == XB_EXP_PRE_OPERATOR ){ - n->SetParent( nLastNode ); - nLastNode->AddChild( n ); - } - - // else if last node was XB_EXB_POST_OPERATOR then append this as child to last node - else if( nLastNode && n->GetNodeType() == XB_EXP_POST_OPERATOR ){ - n->AddChild( nLastNode ); - nLastNode->SetParent( n ); - if( nLastNode == nTree ){ - nTree = n; - } else { - nLastNode->GetParent()->RemoveLastChild(); - nLastNode->GetParent()->AddChild( n ); - n->SetParent( nLastNode->GetParent() ); - } - } - - else if( n->GetNodeType() == XB_EXP_OPERATOR ){ - xbExpNode * nWorkNode = nLastNode; - while( nWorkNode && ( nWorkNode->GetNodeType() != XB_EXP_OPERATOR || n->GetWeight() <= nWorkNode->GetWeight())){ - nWorkNode = nWorkNode->GetParent(); - } - - if( !nWorkNode ){ // we are at the top - nTree->SetParent( n ); - n->AddChild( nTree ); - nTree = n; - - } else if( nWorkNode->GetChildCnt() == 1 ){ - nWorkNode->AddChild( n ); - n->SetParent( nWorkNode ); - - } else if( nWorkNode->GetChildCnt() == 2 ){ - xbExpNode * nChild2 = nWorkNode->GetChild(1); - n->AddChild( nChild2 ); - nWorkNode->RemoveLastChild(); - nWorkNode->AddChild( n ); - n->SetParent( nWorkNode ); - - } else{ - // should not be stopping on anything but an operator node with one or two children - iErrorStop = 170; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } else { - n->SetParent( nLastNode ); - nLastNode->AddChild( n ); - } - nLastNode = n; - n = NULL; - } - } - - // for each node in the tree, calculate the length if it's not already set - xbExpNode * nWork = GetNextNode( NULL ); - xbExpNode * nChild1; - xbExpNode * nChild2; - - while( nWork ){ - if( nWork->GetReturnType() == XB_EXP_UNKNOWN ){ - nWork->GetNodeText( s ); - - // std::cout << "XB_EXP_UNKNOWN logic [" << s << "][" << nWork->GetChildCnt() << "]\n"; - // if this is "-" and child 1 and child 2 are both dates, set this result type to numeric - if( s == "-" && nWork->GetChildCnt() == 2 && - nWork->GetChild(0)->GetReturnType() == XB_EXP_DATE && nWork->GetChild(1)->GetReturnType() == XB_EXP_DATE ) - nWork->SetReturnType( XB_EXP_NUMERIC ); - else if( nWork->GetChildCnt() > 0 ) - nWork->SetReturnType( nWork->GetChild(0)->GetReturnType()); - else{ - iErrorStop = 180; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - if( nWork->GetResultLen() == 0 ){ - - switch( nWork->GetReturnType() ){ - - case XB_EXP_NUMERIC: - nWork->SetResultLen( 4 ); - break; - - case XB_EXP_CHAR: - if( nWork->GetNodeType() != XB_EXP_OPERATOR ){ - iErrorStop = 190; - iRc = XB_PARSE_ERROR; - throw iRc; - } - if( nWork->GetChildCnt() < 2 ){ - iErrorStop = 200; - iRc = XB_PARSE_ERROR; - throw iRc; - } - nChild1 = nWork->GetChild( 0 ); - nChild2 = nWork->GetChild( 1 ); - nWork->SetResultLen( nChild1->GetResultLen() + nChild2->GetResultLen()); - break; - - case XB_EXP_DATE: - nWork->SetResultLen( 8 ); - break; - - case XB_EXP_LOGICAL: - nWork->SetResultLen( 1 ); - break; - - default: - iErrorStop = 210; - iRc = XB_PARSE_ERROR; - throw iRc; - // break; - } - } - if( nWork->IsUnaryOperator() ){ - if( nWork->GetChildCnt() != 1 ){ - iErrorStop = 220; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } else if( nWork->IsOperator() && nWork->GetChildCnt() != 2 ){ - iErrorStop = 230; - iRc = XB_PARSE_ERROR; - throw iRc; - } - nWork = GetNextNode( nWork ); - } - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::ParseExpression() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} -/*************************************************************************/ -//! Parse expression constant. -/*! - \param t - Token. - \param n - Node. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ -xbInt16 xbExp::ParseExpressionConstant( xbExpToken &t, xbExpNode *n ){ - - xbDate dtWork; - n->SetReturnType( t.cReturnType ); - - // std::cout << "parse expression constant[" << t.sToken << "]\n"; - - switch( t.cReturnType ){ - case XB_EXP_CHAR: - n->SetResultLen( t.sToken.Len() ); - n->SetResult( t.sToken ); - break; - - case XB_EXP_DATE: - n->SetResultLen( 8 ); - dtWork.Set( t.sToken ); - n->SetResult( dtWork ); - break; - - case XB_EXP_LOGICAL: - n->SetResultLen( 1 ); - if( strncmp( t.sToken, "T", 1 ) == 0 ) - n->SetResult( (xbBool) xbTrue ); - else - n->SetResult( (xbBool) xbFalse ); - break; - - case XB_EXP_NUMERIC: - n->SetResultLen( 4 ); - n->SetResult( strtod( t.sToken, 0 )); - n->SetResult( t.sToken ); - break; - - default: - return XB_PARSE_ERROR; - // break; - } - return XB_NO_ERROR; -} - -/*************************************************************************/ -//! Parse expression field. -/*! - \param t - Token. - \param n - Node. - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ -xbInt16 xbExp::ParseExpressionField( xbExpToken &t, xbExpNode *n ){ - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - xbDbf * pDbf; - xbString sFieldName; - - // do the db lookup and set the field number for the field - - try{ - - xbUInt32 lPos; - - if(( lPos = t.sToken.Pos( "->" )) > 0 ){ - // table name is part of the token - xbString sTableName = t.sToken; - sTableName.Left( lPos-1 ); - sFieldName = t.sToken; - sFieldName.Mid( lPos + 2, t.sToken.Len() - lPos - 1 ); - pDbf = (xbDbf *) xbase->GetDbfPtr( sTableName ); - - -/* - // updated 1/2/23 to support either table.field or table->field - if((( lPos = t.sToken.Pos( "->" )) > 0) || (( lPos = t.sToken.Pos( "." )) > 0) ){ - // table name is part of the token - xbString sTableName = t.sToken; - sTableName.Left( lPos-1 ); - sFieldName = t.sToken; - if( t.sToken[lPos] == '.' ) - sFieldName.Mid( lPos + 1, t.sToken.Len() - lPos ); - else // -> - sFieldName.Mid( lPos + 2, t.sToken.Len() - lPos - 1 ); - pDbf = (xbDbf *) xbase->GetDbfPtr( sTableName ); -*/ - - } else { - // table name is not part of the token - pDbf = dbf; - sFieldName = t.sToken; - } - if( !pDbf ){ - iErrorStop = 100; - iRc = XB_INVALID_FIELD; - throw iRc; - } - xbInt16 iFieldNo = 0; - - if(( iRc = pDbf->GetFieldNo( sFieldName, iFieldNo )) != XB_NO_ERROR ){ - iErrorStop = 110; - throw iRc; - } - char cFieldType; - if(( iRc = pDbf->GetFieldType( iFieldNo, cFieldType )) != XB_NO_ERROR ){ - iErrorStop = 120; - throw iRc; - } - n->SetDbfInfo( pDbf, iFieldNo ); - switch( cFieldType ){ - case XB_CHAR_FLD: - n->SetReturnType( XB_EXP_CHAR ); - break; - - case XB_LOGICAL_FLD: - n->SetReturnType( XB_EXP_LOGICAL ); - break; - - case XB_NUMERIC_FLD: - case XB_FLOAT_FLD: - n->SetReturnType( XB_EXP_NUMERIC ); - break; - - case XB_DATE_FLD: - n->SetReturnType( XB_EXP_DATE ); - break; - - case XB_MEMO_FLD: - default: - iErrorStop = 130; - iRc = XB_PARSE_ERROR; - throw iRc; - // break; - } - n->SetNodeText( sFieldName ); - xbInt16 iResultLen = 0; - if(( iRc = pDbf->GetFieldLen( iFieldNo, iResultLen )) != XB_NO_ERROR ){ - iErrorStop = 140; - throw iRc; - } - n->SetResultLen( (xbUInt32) iResultLen ); - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::ParseExpressionField() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} - -/*************************************************************************/ -//! Parse expression function. -/*! - \param t - Token. - \param n - Node. - \param iWeight - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ -xbInt16 xbExp::ParseExpressionFunction( xbExpToken &t, xbExpNode *n, xbInt16 iWeight ){ - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - - try{ - // find the first "(" - xbUInt32 lPos = t.sToken.Pos( '(' ); - if( lPos == 0 ){ - iErrorStop = 100; - iRc = XB_INVALID_FUNCTION; - throw iRc; - } - // Get the function name and look it up in the table - - - xbString sFunc = t.sToken; - sFunc.Left( lPos - 1 ).Trim(); - char cReturnType; - xbInt16 i = 0; - xbInt32 l = 0; - if(( iRc = xbase->GetFunctionInfo( sFunc, cReturnType, i, l )) != XB_NO_ERROR ){ - iErrorStop = 110; - throw iRc; - } - n->SetNodeText( sFunc ); - - - // Get the function parms - xbString sParms = t.sToken; - sParms.Mid( lPos+1, t.sToken.Len() - lPos ); - lPos = sParms.GetLastPos( ')' ); - if( lPos == 0 ){ - iErrorStop = 120; - iRc = XB_INVALID_FUNCTION; - throw iRc; - } - - // remove the trailing ")" paren - sParms.Left( lPos - 1 ).Trim(); - - // if this function has parms, put them in the tree - if( sParms.Len() > 0 ){ - xbExp enr( xbase, dbf ); - - // create a linked list of parms - xbLinkList<xbString> llParms; - if(( iRc = ParseExpressionFunctionParms( sParms, llParms )) != XB_NO_ERROR ){ - iErrorStop = 130; - throw iRc; - } - - // for each function parm, recursively process it - xbLinkListNode<xbString> * llN = llParms.GetHeadNode(); - xbString sParm; - while( llN ){ - sParm = llN->GetKey(); - if(( iRc = enr.ParseExpression( sParm, iWeight + 10 )) != XB_NO_ERROR ){ - iErrorStop = 140; - throw iRc; - } - n->AddChild( enr.GetTreeHandle()); - enr.ClearTreeHandle(); - llN = llN->GetNextNode(); - } - llParms.Clear(); - } - - if( cReturnType == '1' ){ - if( n->GetChildCnt() > 0 ){ - xbExpNode *n1 = n->GetChild( 0 ); - n->SetReturnType( n1->GetReturnType()); - } - - } else { - n->SetReturnType( cReturnType ); - } - - if(( iRc = CalcFunctionResultLen( n )) != XB_NO_ERROR ){ - iErrorStop = 150; - throw iRc; - } - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::ParseExpressionFunction() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} - -/*************************************************************************/ -//! Parse expression function. -/*! - - Creates a linked list of function parms as xbStrings - This function pulls out the parms and addresses embedded parens and quotes within the parms - - \param sParms - \param lParms - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::ParseExpressionFunctionParms( const xbString &sParms, xbLinkList<xbString> & llParms ){ - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - xbInt16 iParenCtr = 0; - xbInt16 iInQuotes = 0; - xbInt16 iDoubleQuotes = 0; - xbInt16 iSingleQuotes = 0; - xbInt32 lStartPos = 0; - xbInt32 lParmLen = 0; - - xbString sParm; - - try{ - const char *sp = sParms; - - while( *sp ){ - if( *sp == '(') - iParenCtr++; - else if( *sp == ')' ) - iParenCtr--; - else if( !iInQuotes && *sp == '"' ){ - iInQuotes++; - iDoubleQuotes++; - } else if( iInQuotes && *sp == '"' ){ - iInQuotes--; - iDoubleQuotes--; - } - else if( !iInQuotes && *sp == '\'' ){ - iInQuotes++; - iSingleQuotes++; - } else if( iInQuotes && *sp == '\'' ){ - iInQuotes--; - iSingleQuotes--; - - } else if( !iInQuotes && !iParenCtr && *sp == ',' ){ - // found a valid comma - at the end of a parm - // add it to the end of the linked list - sParm = sParms; - sParm.Mid( (xbUInt32) lStartPos + 1, (xbUInt32) lParmLen ).Trim(); // mid is one based - llParms.InsertAtEnd( sParm ); - - // set the start pos for the next one on the list - lStartPos += lParmLen + 1; - lParmLen = -1; - // lParmLen = 0; - } - lParmLen++; - sp++; - } - if( lParmLen > 0 ){ - // get the last parm, it didn't end with a comma - sParm = sParms; - sParm.Mid( (xbUInt32) lStartPos + 1, (xbUInt32) lParmLen ).Trim(); - llParms.InsertAtEnd( sParm ); - } - - } - // try / catch not used in this method, structure added for potential future use - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::ParseExpressionFunctionParms() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} -/*************************************************************************/ -//! Parse expression operator. -/*! - \param t - Token. - \param n - Node. - \param iWeight - \returns <a href="xbretcod_8h.html">Return Codes</a> -*/ - -xbInt16 xbExp::ParseExpressionOperator( xbExpToken &t, xbExpNode *n, xbInt16 iWeight ){ - - n->SetResult( t.sToken ); - n->SetWeight( iWeight + OperatorWeight( t.sToken) ); - -// std::cout << "ParseExpressionOperator [" << t.cPrevNodeType << "][" << t.sToken << "] Weight = [" << iWeight; -// std::cout << "] PrevReturnType [" << t.cPrevReturnType; -// std::cout << "] Operator weight [" << OperatorWeight( t.sToken ) << "] getweight [" << n->GetWeight() << "]\n"; - - if( t.sToken == "**" || t.sToken == "^" || - t.sToken == "*" || t.sToken == "/" || t.sToken == "%" || t.sToken == "*=" || t.sToken == "/=" ) - n->SetReturnType( XB_EXP_NUMERIC ); - - else if( t.sToken == "--" || t.sToken == "++" || t.sToken == "+=" || t.sToken == "-=" ) // could be date or numeric - n->SetReturnType( XB_EXP_UNKNOWN ); - - else if( t.cPrevReturnType == XB_EXP_CHAR && ( t.sToken == "+" || t.sToken == "-" )) - n->SetReturnType( XB_EXP_CHAR ); - - else if( t.sToken == ".AND." || t.sToken == ".OR." || t.sToken == ".NOT." || - t.sToken == "AND" || t.sToken == "OR" || t.sToken == "NOT" || - t.sToken == ">" || t.sToken == ">=" || t.sToken == "<" || - t.sToken == "<=" || t.sToken == "<>" || t.sToken == "!=" || - t.sToken == "$" || t.sToken == "#" || t.sToken == "=" ) - n->SetReturnType( XB_EXP_LOGICAL ); - - - else if( t.cPrevReturnType == XB_EXP_UNKNOWN ) - n->SetReturnType( XB_EXP_UNKNOWN ); - - // added for date constant logic 10/28/17 - else if(( t.sToken == "+" || t.sToken == "-" ) && t.cPrevReturnType == XB_EXP_DATE ) - n->SetReturnType( XB_EXP_DATE ); - - else if( t.sToken == "+" || t.sToken == "-" ) - n->SetReturnType( XB_EXP_NUMERIC ); - - return XB_NO_ERROR; -} - - -/************************************************************************/ -//! ProcessExpression -/*! This method processes an expression tree leaving the result in the - root node of the tree -*/ -xbInt16 xbExp::ProcessExpression(){ - return ProcessExpression( 0 ); -} -/************************************************************************/ -//! ProcessExpression -/*! This method processes a parsed expression tree leaving the result in the - root node of the tree - \param iRecBufSw Record buffer to use when evaluating expression.<br> - 0 - Current record buffer.<br> - 1 - Original record buffer. -*/ - -xbInt16 xbExp::ProcessExpression( xbInt16 iRecBufSw ){ - -// iRecBufSw 0 - Record Buffer -// 1 - Original Record Buffer - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - - try{ - - xbExpNode * nWork = GetNextNode( NULL ); - xbExpNode * nChild1; - xbDbf * dbf; - xbString sWork1; - xbString sWork2; - xbString sOperator; - xbDate dtWork1; - - xbBool bWork; - xbDouble dWork; - - while( nWork ){ - switch( nWork->GetNodeType() ){ - - case XB_EXP_CONSTANT: - break; - - case XB_EXP_PRE_OPERATOR: // increment value before setting in head node - if( nWork->GetChildCnt() != 1 ){ - iErrorStop = 100; - iRc = XB_PARSE_ERROR; - throw iRc; - } - nChild1 = nWork->GetChild( 0 ); - //if( nChild1->GetReturnType() == XB_EXP_DATE ) - // nChild1->SetResult( (xbDouble) nChild1->GetDateResult().JulianDays()); - - nWork->GetNodeText( sWork1 ); - if( sWork1 == "++" ) - nChild1->SetResult( nChild1->GetNumericResult() + 1 ); - else - nChild1->SetResult( nChild1->GetNumericResult() - 1 ); - - nWork->SetResult( nChild1->GetNumericResult()); - - //if( nChild1->GetReturnType() == XB_EXP_DATE ){ - // dtWork1.JulToDate8( (xbInt32) nChild1->GetNumericResult()); - // nChild1->SetResult( dtWork1 ); - // nWork->SetResult( dtWork1 ); - // } - break; - - case XB_EXP_POST_OPERATOR: // increment value after setting in head node - if( nWork->GetChildCnt() != 1 ){ - iErrorStop = 110; - iRc = XB_PARSE_ERROR; - throw iRc; - } - nChild1 = nWork->GetChild( 0 ); - //if( nChild1->GetReturnType() == XB_EXP_DATE ){ - // nWork->SetResult( nChild1->GetDateResult()); - // nChild1->SetResult( (xbDouble) nChild1->GetDateResult().JulianDays()); - //} - //else - nWork->SetResult( nChild1->GetNumericResult()); - - nWork->GetNodeText( sWork1 ); - if( sWork1 == "++" ) - nChild1->SetResult( nChild1->GetNumericResult() + 1 ); - else - nChild1->SetResult( nChild1->GetNumericResult() - 1 ); - - //if( nChild1->GetReturnType() == XB_EXP_DATE ){ - // dtWork1.JulToDate8( (xbInt32) nChild1->GetNumericResult()); - // nChild1->SetResult( dtWork1 ); - // } - break; - - case XB_EXP_FIELD: - - if(( dbf = nWork->GetDbf()) == NULL ){ - iErrorStop = 120; - iRc = XB_PARSE_ERROR; - throw iRc; - } - switch( nWork->GetReturnType()){ - case XB_EXP_CHAR: - if(( iRc = dbf->GetField( nWork->GetFieldNo(), sWork1, iRecBufSw )) < XB_NO_ERROR ){ - iErrorStop = 130; - throw iRc; - } - nWork->SetResult( sWork1 ); - break; - - case XB_EXP_DATE: - - if(( iRc = dbf->GetField( nWork->GetFieldNo(), sWork1, iRecBufSw )) < XB_NO_ERROR ){ - iErrorStop = 140; - throw iRc; - } - if( sWork1 == " " ){ - nWork->SetResult( (xbDouble) 21474835648 ); // dbase sets a date value in ndx to this if spaces on dbf record - } else { - dtWork1.Set( sWork1 ); - nWork->SetResult( (xbDouble) dtWork1.JulianDays() ); - } - break; - - case XB_EXP_LOGICAL: - if(( iRc = dbf->GetLogicalField( nWork->GetFieldNo(), bWork, iRecBufSw )) != XB_NO_ERROR ){ - iErrorStop = 150; - throw iRc; - } - nWork->SetResult( bWork ); - break; - - case XB_EXP_NUMERIC: - if(( iRc = dbf->GetDoubleField( nWork->GetFieldNo(), dWork, iRecBufSw )) != XB_NO_ERROR ){ - iErrorStop = 160; - throw iRc; - } - nWork->SetResult( dWork ); - break; - - default: - iErrorStop = 170; - iRc = XB_PARSE_ERROR; - throw iRc; - // break; - } - break; - - - case XB_EXP_OPERATOR: - if(( iRc = ProcessExpressionOperator( nWork )) != XB_NO_ERROR ){ - iErrorStop = 180; - throw iRc; - } - - break; - - case XB_EXP_FUNCTION: - if(( iRc = ProcessExpressionFunction( nWork, iRecBufSw )) != XB_NO_ERROR ){ - iErrorStop = 190; - throw iRc; - } - break; - - default: - iErrorStop = 200; - iRc = XB_PARSE_ERROR; - throw iRc; - // break; - } - nWork = GetNextNode( nWork ); - } - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::ProcessExpression() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} -/*************************************************************************/ -//! ProcessExpression -/*! This method processes an expression tree for a given node. -*/ - -xbInt16 xbExp::ProcessExpressionFunction( xbExpNode * n, xbInt16 iRecBufSw ){ - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - - try{ - - xbString sFunction; - xbString sResult; - xbDouble dResult; - xbDate dtResult; - xbBool bResult; - - n->GetNodeText( sFunction ); - - // process functions with no children first - xbExpNode * nChild1; - if( n->GetChildCnt() == 0 ){ - if( sFunction == "DATE" ){ - if(( iRc = xbase->DATE( dtResult )) != XB_NO_ERROR ){ - iErrorStop = 100; - throw iRc; - } - n->SetResult( dtResult ); - } else if( sFunction == "DEL" ){ - if(( iRc = xbase->DEL( dbf, sResult, iRecBufSw )) != XB_NO_ERROR ){ - iErrorStop = 110; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "DELETED" ){ - if(( iRc = xbase->DELETED( dbf, bResult, iRecBufSw )) != XB_NO_ERROR ){ - iErrorStop = 120; - throw iRc; - } - n->SetResult( bResult ); - } else if( sFunction == "RECCOUNT" ){ - if(( iRc = xbase->RECCOUNT( dbf, dResult )) != XB_NO_ERROR ){ - iErrorStop = 130; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "RECNO" ){ - if(( iRc = xbase->RECNO( dbf, dResult )) != XB_NO_ERROR ){ - iErrorStop = 140; - throw iRc; - } - n->SetResult( dResult ); - } - // process functions with one child - } else if( n->GetChildCnt() == 1 ){ - - nChild1 = n->GetChild( 0 ); - - if( sFunction == "ABS" ){ - if(( iRc = xbase->ABS( nChild1->GetNumericResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 200; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "ALLTRIM" ){ - if(( iRc = xbase->ALLTRIM( nChild1->GetStringResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 210; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "ASC" ){ - if(( iRc = xbase->ASC( nChild1->GetStringResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 220; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "CDOW" ){ - xbDate d( (xbInt32) nChild1->GetNumericResult()); - if(( iRc = xbase->CDOW( d, sResult )) != XB_NO_ERROR ){ - iErrorStop = 230; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "CHR" ){ - if(( iRc = xbase->CHR( nChild1->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 240; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "CMONTH" ){ - xbDate d( (xbInt32) nChild1->GetNumericResult()); - if(( iRc = xbase->CMONTH( d, sResult )) != XB_NO_ERROR ){ - iErrorStop = 250; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "CTOD" ){ - if(( iRc = xbase->CTOD( nChild1->GetStringResult(), dtResult )) != XB_NO_ERROR ){ - iErrorStop = 260; - throw iRc; - } - n->SetResult( dtResult ); - } else if( sFunction == "DAY" ){ - xbDate d( (xbInt32) nChild1->GetNumericResult()); - if(( iRc = xbase->DAY( d, dResult )) != XB_NO_ERROR ){ - iErrorStop = 270; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "DESCEND" ){ - - if( n->GetReturnType() == XB_EXP_CHAR ){ - if(( iRc = xbase->DESCEND( nChild1->GetStringResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 280; - throw iRc; - } - n->SetResult( sResult ); - - } else if( n->GetReturnType() == XB_EXP_DATE ){ - xbDate d( (xbInt32) nChild1->GetNumericResult()); - if(( iRc = xbase->DESCEND( d, dtResult )) != XB_NO_ERROR ){ - iErrorStop = 290; - throw iRc; - } - n->SetResult( dtResult ); - - } else if( n->GetReturnType() == XB_EXP_NUMERIC ){ - if(( iRc = xbase->DESCEND( nChild1->GetNumericResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 300; - throw iRc; - } - n->SetResult( dResult ); - - } else { - iErrorStop = 310; - iRc = XB_PARSE_ERROR; - throw iRc; - } - - } else if( sFunction == "DOW" ){ - xbDate d( (xbInt32) nChild1->GetNumericResult()); - if(( iRc = xbase->DOW( d, dResult )) != XB_NO_ERROR ){ - iErrorStop = 320; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "DTOC" ){ - xbDate d( (xbInt32) nChild1->GetNumericResult()); - if(( iRc = xbase->DTOC( d, sResult )) != XB_NO_ERROR ){ - iErrorStop = 330; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "DTOS" ){ - xbDate d( (xbInt32) nChild1->GetNumericResult()); - if(( iRc = xbase->DTOS( d, sResult )) != XB_NO_ERROR ){ - iErrorStop = 340; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "EXP" ){ - if(( iRc = xbase->EXP( nChild1->GetNumericResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 350; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "INT" ){ - if(( iRc = xbase->INT( nChild1->GetNumericResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 360; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "ISALPHA" ){ - if(( iRc = xbase->ISALPHA( nChild1->GetStringResult(), bResult )) != XB_NO_ERROR ){ - iErrorStop = 370; - throw iRc; - } - n->SetResult( bResult ); - } else if( sFunction == "ISLOWER" ){ - if(( iRc = xbase->ISLOWER( nChild1->GetStringResult(), bResult )) != XB_NO_ERROR ){ - iErrorStop = 380; - throw iRc; - } - n->SetResult( bResult ); - } else if( sFunction == "ISUPPER" ){ - if(( iRc = xbase->ISUPPER( nChild1->GetStringResult(), bResult )) != XB_NO_ERROR ){ - iErrorStop = 390; - throw iRc; - } - n->SetResult( bResult ); - } else if( sFunction == "LEN" ){ - if(( iRc = xbase->LEN( nChild1->GetStringResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 400; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "LOG" ){ - if(( iRc = xbase->LOG( nChild1->GetNumericResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 410; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "LTRIM" ){ - if(( iRc = xbase->LTRIM( nChild1->GetStringResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 420; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "LOWER" ){ - if(( iRc = xbase->LOWER( nChild1->GetStringResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 430; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "MONTH" ){ - xbDate d( (xbInt32) nChild1->GetNumericResult()); - if(( iRc = xbase->MONTH( d, dResult )) != XB_NO_ERROR ){ - iErrorStop = 440; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "RTRIM" ){ - if(( iRc = xbase->RTRIM( nChild1->GetStringResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 450; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "STOD" ){ - if(( iRc = xbase->STOD( nChild1->GetStringResult(), dtResult )) != XB_NO_ERROR ){ - iErrorStop = 460; - throw iRc; - } - n->SetResult( dtResult ); - } else if( sFunction == "SPACE" ){ - if(( iRc = xbase->SPACE( (xbInt32) nChild1->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 470; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "SQRT" ){ - if(( iRc = xbase->SQRT( nChild1->GetNumericResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 480; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "STR" ){ - if(( iRc = xbase->STR( nChild1->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 490; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "TRIM" ){ - if(( iRc = xbase->TRIM( nChild1->GetStringResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 500; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "UPPER" ){ - if(( iRc = xbase->UPPER( nChild1->GetStringResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 510; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "VAL" ){ - if(( iRc = xbase->VAL( nChild1->GetStringResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 520; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "YEAR" ){ - xbDate d( (xbInt32) nChild1->GetNumericResult()); - if(( iRc = xbase->YEAR( d, dResult )) != XB_NO_ERROR ){ - iErrorStop = 530; - throw iRc; - } - n->SetResult( dResult ); - } else { - iErrorStop = 540; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } else if( n->GetChildCnt() == 2 ){ - xbExpNode * nChild2; - nChild1 = n->GetChild( 0 ); - nChild2 = n->GetChild( 1 ); - - if( sFunction == "AT" ){ - if(( iRc = xbase->AT( nChild1->GetStringResult(), nChild2->GetStringResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 700; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "LEFT" ){ - if(( iRc = xbase->LEFT( nChild1->GetStringResult(), (xbUInt32) nChild2->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 710; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "MAX" ){ - if(( iRc = xbase->MAX( nChild1->GetNumericResult(), nChild2->GetNumericResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 720; - throw iRc; - } - n->SetResult( dResult ); - } else if( sFunction == "MIN" ){ - if(( iRc = xbase->MIN( nChild1->GetNumericResult(), nChild2->GetNumericResult(), dResult )) != XB_NO_ERROR ){ - iErrorStop = 730; - throw iRc; - } - n->SetResult( dResult ); - } - else if( sFunction == "REPLICATE" ){ - if(( iRc = xbase->REPLICATE( nChild1->GetStringResult(), (xbUInt32) nChild2->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 800; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "RIGHT" ){ - if(( iRc = xbase->RIGHT( nChild1->GetStringResult(), (xbUInt32) nChild2->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 810; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "STR" ){ - if(( iRc = xbase->STR( nChild1->GetNumericResult(), (xbUInt32) nChild2->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 820; - throw iRc; - } - n->SetResult( sResult ); - } else { - iErrorStop = 830; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } else if( n->GetChildCnt() == 3 ){ - xbExpNode * nChild2; - xbExpNode * nChild3; - nChild1 = n->GetChild( 0 ); - nChild2 = n->GetChild( 1 ); - nChild3 = n->GetChild( 2 ); - - if( sFunction == "IIF" ){ - if(( iRc = xbase->IIF( nChild1->GetBoolResult(), nChild2->GetStringResult(), nChild3->GetStringResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 900; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "STR" ){ - if(( iRc = xbase->STR( nChild1->GetNumericResult(), (xbUInt32) nChild2->GetNumericResult(), (xbUInt32) nChild3->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 910; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "STRZERO" ){ - if(( iRc = xbase->STRZERO( nChild1->GetNumericResult(), (xbUInt32) nChild2->GetNumericResult(), (xbUInt32) nChild3->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 920; - throw iRc; - } - n->SetResult( sResult ); - } else if( sFunction == "SUBSTR" ){ - if(( iRc = xbase->SUBSTR( nChild1->GetStringResult(), (xbUInt32) nChild2->GetNumericResult(), (xbUInt32) nChild3->GetNumericResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 930; - throw iRc; - } - n->SetResult( sResult ); - } else { - iErrorStop = 950; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } else if( n->GetChildCnt() == 4 ){ - xbExpNode * nChild2; - xbExpNode * nChild3; - xbExpNode * nChild4; - nChild1 = n->GetChild( 0 ); - nChild2 = n->GetChild( 1 ); - nChild3 = n->GetChild( 2 ); - nChild4 = n->GetChild( 3 ); - - if( sFunction == "STR" ){ - if(( iRc = xbase->STR( nChild1->GetNumericResult(), (xbUInt32) nChild2->GetNumericResult(), - (xbUInt32) nChild3->GetNumericResult(), nChild4->GetStringResult(), sResult )) != XB_NO_ERROR ){ - iErrorStop = 1000; - throw iRc; - } - n->SetResult( sResult ); - } else { - iErrorStop = 1010; - iRc = XB_PARSE_ERROR; - throw iRc; - } - - } else { - iErrorStop = 2000; - iRc = XB_PARSE_ERROR; - throw iRc; - } - - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::ProcessExpressionFunction() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} -/*************************************************************************/ -//! Process Expression Operator -/*! This method processes an expression operator for a given node. -*/ - -xbInt16 xbExp::ProcessExpressionOperator( xbExpNode * n ){ - - xbInt16 iRc = XB_NO_ERROR; - xbInt16 iErrorStop = 0; - - xbExpNode * nChild1 = NULL; - xbExpNode * nChild2 = NULL; - xbString sOperator; - xbString sWork1; - xbString sWork2; - xbDate dtWork1; - - xbString sMsg; - - try{ - - n->GetNodeText( sOperator ); - nChild1 = n->GetChild( 0 ); - if( !n->IsUnaryOperator()) - nChild2 = n->GetChild( 1 ); - - switch( n->GetReturnType()){ - case XB_EXP_CHAR: - if( sOperator == "+" ){ - sWork1 = nChild1->GetStringResult(); - sWork1 += nChild2->GetStringResult(); - n->SetResult( sWork1 ); - } else if( sOperator == "-" ){ - sWork1 = nChild1->GetStringResult(); - sWork1.Rtrim(); - sWork1 += nChild2->GetStringResult(); - sWork1.PadRight( ' ', n->GetResultLen()); - n->SetResult( sWork1 ); - } else { - iErrorStop = 100; - iRc = XB_PARSE_ERROR; - throw iRc; - } - break; - - case XB_EXP_NUMERIC: - if( sOperator == "+" ) - n->SetResult( nChild1->GetNumericResult() + nChild2->GetNumericResult()); - else if( sOperator == "-" ){ - n->SetResult( nChild1->GetNumericResult() - nChild2->GetNumericResult()); - - } - else if( sOperator == "*" ) - n->SetResult( nChild1->GetNumericResult() * nChild2->GetNumericResult()); - else if( sOperator == "/" ) - n->SetResult( nChild1->GetNumericResult() / nChild2->GetNumericResult()); - else if( sOperator == "^" || sOperator == "**" ) - n->SetResult( pow( nChild1->GetNumericResult(), nChild2->GetNumericResult())); - else if( sOperator == "+=" ){ - n->SetResult( nChild1->GetNumericResult() + nChild2->GetNumericResult()); - nChild1->SetResult( n->GetNumericResult() ); - } - else if( sOperator == "-=" ){ - n->SetResult( nChild1->GetNumericResult() - nChild2->GetNumericResult()); - nChild1->SetResult( n->GetNumericResult() ); - } - else if( sOperator == "*=" ){ - n->SetResult( nChild1->GetNumericResult() * nChild2->GetNumericResult()); - nChild1->SetResult( n->GetNumericResult() ); - } - else if( sOperator == "/=" ){ - n->SetResult( nChild1->GetNumericResult() / nChild2->GetNumericResult()); - nChild1->SetResult( n->GetNumericResult() ); - } else { - iErrorStop = 200; - iRc = XB_PARSE_ERROR; - throw iRc; - } - break; - - - case XB_EXP_DATE: - // if date values in the leaf nodes, convert to numeric for operator logic - - if( sOperator == "+" ) - n->SetResult( nChild1->GetNumericResult() + nChild2->GetNumericResult()); - else if( sOperator == "-" ){ - n->SetResult( nChild1->GetNumericResult() - nChild2->GetNumericResult()); - xbDate d( (xbInt32) n->GetNumericResult()); - } - else if( sOperator == "+=" ){ - n->SetResult( nChild1->GetNumericResult() + nChild2->GetNumericResult()); - nChild1->SetResult( n->GetNumericResult() ); - } - else if( sOperator == "-=" ){ - n->SetResult( nChild1->GetNumericResult() - nChild2->GetNumericResult()); - nChild1->SetResult( n->GetNumericResult() ); - } else { - iErrorStop = 300; - iRc = XB_PARSE_ERROR; - throw iRc; - } - break; - - case XB_EXP_LOGICAL: - - if( !n->IsUnaryOperator() && (nChild1->GetReturnType() != nChild2->GetReturnType())){ - iErrorStop = 400; - iRc = XB_INCOMPATIBLE_OPERANDS; - throw iRc; - } - - if( sOperator == ".AND." || sOperator == "AND" ) - n->SetResult((xbBool) (nChild1->GetBoolResult() && nChild2->GetBoolResult()) ); - - else if( sOperator == ".OR." || sOperator == "OR" ) - n->SetResult((xbBool) (nChild1->GetBoolResult() || nChild2->GetBoolResult()) ); - - else if( sOperator == ".NOT." || sOperator == "NOT" ){ - if( nChild1->GetBoolResult()) - n->SetResult((xbBool) xbFalse ); - else - n->SetResult((xbBool) xbTrue ); - } - - else if( sOperator == ">" ){ - - if( nChild1->GetReturnType() == XB_EXP_CHAR ) - n->SetResult((xbBool)(nChild1->GetStringResult() > nChild2->GetStringResult())); - else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE ) - n->SetResult((xbBool)(nChild1->GetNumericResult() > nChild2->GetNumericResult())); - - else { - iErrorStop = 410; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - - else if( sOperator == ">=" ){ - if( nChild1->GetReturnType() == XB_EXP_CHAR ) - n->SetResult((xbBool)(nChild1->GetStringResult() >= nChild2->GetStringResult())); - - else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE ) - n->SetResult((xbBool)(nChild1->GetNumericResult() >= nChild2->GetNumericResult())); - - else { - iErrorStop = 420; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - - else if( sOperator == "<" ){ - - if( nChild1->GetReturnType() == XB_EXP_CHAR ) - n->SetResult((xbBool)( nChild1->GetStringResult() < nChild2->GetStringResult())); - - else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE ) - n->SetResult((xbBool)( nChild1->GetNumericResult() < nChild2->GetNumericResult())); - - else { - iErrorStop = 430; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - - else if( sOperator == "<=" ){ - - if( nChild1->GetReturnType() == XB_EXP_CHAR ) - n->SetResult((xbBool)( nChild1->GetStringResult() <= nChild2->GetStringResult())); - - else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE ) - n->SetResult((xbBool)( nChild1->GetNumericResult() <= nChild2->GetNumericResult())); - - else { - iErrorStop = 440; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - - else if( sOperator == "<>" || sOperator == "#" || sOperator == "!=" ){ - - if( nChild1->GetReturnType() == XB_EXP_CHAR ) - n->SetResult((xbBool)( nChild1->GetStringResult() != nChild2->GetStringResult())); - - else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE ) - n->SetResult((xbBool)( nChild1->GetNumericResult() != nChild2->GetNumericResult())); - - else { - iErrorStop = 450; - iRc = XB_PARSE_ERROR; - throw iRc; - } - } - - else if( sOperator == "$" ){ - if( nChild1->GetReturnType() == XB_EXP_CHAR ) - if( nChild2->GetStringResult().Pos( nChild1->GetStringResult()) > 0 ) - n->SetResult((xbBool) xbTrue ); - else - n->SetResult((xbBool) xbFalse ); - else { - iErrorStop = 460; - iRc = XB_INCOMPATIBLE_OPERANDS; - throw iRc; - } - } - - else if( sOperator == "=" ){ - - if( nChild1->GetReturnType() == XB_EXP_CHAR ){ - xbString sChld1 = nChild1->GetStringResult(); - xbString sChld2 = nChild2->GetStringResult(); - sChld1.Rtrim(); - sChld2.Rtrim(); - n->SetResult((xbBool)( sChld1 == sChld2 )); - - } else if( nChild1->GetReturnType() == XB_EXP_NUMERIC || nChild1->GetReturnType() == XB_EXP_DATE ) - n->SetResult((xbBool)( nChild1->GetNumericResult() == nChild2->GetNumericResult())); - - else { - iErrorStop = 470; - iRc = XB_PARSE_ERROR; - throw iRc; - } - - } else { - iErrorStop = 500; - iRc = XB_PARSE_ERROR; - throw iRc; - } - - break; - - default: - iErrorStop = 600; - iRc = XB_PARSE_ERROR; - throw iRc; - // break; - } - } - catch (xbInt16 iRc ){ - xbString sMsg; - sMsg.Sprintf( "xbexp::ProcessExpressionOperator() Exception Caught. Error Stop = [%d] iRc = [%d]", iErrorStop, iRc ); - xbase->WriteLogMessage( sMsg.Str() ); - } - return iRc; -} - -/*************************************************************************/ -}; // namespace -#endif // XB_EXPRESSION_SUPPORT -/*************************************************************************/ |