summaryrefslogtreecommitdiff
path: root/xbase64/xbexp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbase64/xbexp.cpp')
-rwxr-xr-xxbase64/xbexp.cpp1323
1 files changed, 1323 insertions, 0 deletions
diff --git a/xbase64/xbexp.cpp b/xbase64/xbexp.cpp
new file mode 100755
index 0000000..a3e1fa5
--- /dev/null
+++ b/xbase64/xbexp.cpp
@@ -0,0 +1,1323 @@
+/* xbexp.cpp
+
+ Xbase64 project source code
+
+ This file contains logic for handling Xbase expressions.
+
+ Copyright (C) 1997,2003,2004 Gary A Kunkel
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+ Contact:
+
+ Email:
+
+ xdb-devel@lists.sourceforge.net
+ xdb-users@lists.sourceforge.net
+
+
+ Regular Mail:
+
+ XBase Support
+ 149C South Main St
+ Keller Texas, 76248
+ USA
+
+*/
+
+#ifdef __GNU LesserG__
+ #pragma implementation "xbexp.h"
+#endif
+
+#ifdef __WIN32__
+#include <xbase64/xbwincfg.h>
+#else
+#include <xbase64/xbconfig.h>
+#endif
+
+#include <xbase64/xbase64.h>
+#ifdef XB_EXPRESSIONS
+#include <ctype.h>
+#include <string.h>
+
+//#include <xbase64/xbexcept.h>
+
+
+/*! \file xbexp.cpp
+*/
+
+// set the default date format
+//xbString xbExpn::DefaultDateFormat = "MM/DD/YY";
+
+/************************************************************************/
+/* putting this part in EXP did not work */
+
+/* No of parms
+
+ value meaning
+
+ 0 0
+ 1 1
+ 2 2
+ 100 0 or more
+ 101 1 or more
+ 102 2 or more
+
+
+ Return Type
+ N Numeric
+ C Char or string
+ 1 Varies, if sibling 1 is C, set to C, otherwise N
+
+
+*/
+
+
+
+
+
+
+static xbFuncDtl FuncList[] =
+{
+ /* Func # of Return
+ Name parms Type */
+ { "ABS", 1, 'N' },
+ { "ASC", 1, 'N' },
+ { "AT", 2, 'N' },
+ { "CDOW", 1, 'C' },
+ { "CHR", 1, 'C' },
+ { "CMONTH", 1, 'C' },
+ { "CTOD", 1, 'C' },
+ { "DATE", 0, 'C' },
+ { "DAY", 1, 'N' },
+ { "DESCEND", 1, '1' },
+ { "DOW", 1, 'N' },
+ { "DTOC", 1, 'C' },
+ { "DTOS", 1, 'C' },
+ { "EXP", 1, 'N' },
+ { "IIF", 3, 'C' },
+ { "INT", 1, 'N' },
+ { "ISALPHA", 1, 'L' },
+ { "ISLOWER", 1, 'L' },
+ { "ISUPPER", 1, 'L' },
+ { "LEFT", 2, 'C' },
+ { "LEN", 1, 'N' },
+ { "LOG", 1, 'N' },
+ { "LOWER", 1, 'C' },
+ { "LTRIM", 1, 'C' },
+ { "MAX", 2, 'N' },
+ { "MIN", 2, 'N' },
+ { "MONTH", 1, 'N' },
+ { "RECNO", 0, 'N' },
+ { "REPLICATE", 2, 'C' },
+ { "RIGHT", 2, 'C' },
+ { "RTRIM", 1, 'C' },
+ { "SPACE", 1, 'C' },
+ { "SQRT", 1, 'N' },
+ { "STR", 101, 'C' },
+ { "STRZERO", 1, 'C' },
+ { "SUBSTR", 3, 'C' },
+ { "TRIM", 1, 'C' },
+ { "UPPER", 1, 'C' },
+ { "VAL", 1, 'N' },
+ { "YEAR", 1, 'N' },
+ { 0, 0, 0 },
+};
+
+/*************************************************************************/
+//! xbExpn Constructor
+/*!
+*/
+xbExpn::xbExpn( xbXBase * x )
+{
+ xbase = x;
+ TokenType = 0;
+ Tree = 0;
+ TokenLen = 0;
+ OpLen1 = 0;
+ OpLen2 = 0;
+ OpDataLen1 = 0;
+ OpDataLen2 = 0;
+ Op1 = 0;
+ Op2 = 0;
+ First = 0;
+ Last = 0;
+ StackDepth = 0;
+ XbaseFuncList = FuncList;
+ memset( WorkBuf, 0x00, WorkBufMaxLen+1 );
+}
+/*************************************************************************/
+//! xbExpn Destructor
+/*!
+*/
+xbExpn::~xbExpn()
+{
+ InitStack();
+
+ delete Tree;
+
+ if(Op1)
+ free(Op1);
+
+ if(Op2)
+ free(Op2);
+
+}
+
+/*************************************************************************/
+//! Get information on a function.
+/*!
+ Returns the information specifed (Option) for the specified function.
+
+ \param Function name of function to get information about
+ \param Option One of the following:
+ \htmlonly
+ <p>
+ <table border=2><tr><th>Option</th><th>Description</th></tr>
+ <tr><td>1</td><td>Return minimum number of parms</td></tr>
+ <tr><td>2</td><td>Return function result type</td></tr>
+ <tr><td>?</td><td>Return 0 if valid function</td></tr>
+ </table>
+ \endhtmlonly
+ \latexonly
+ \\
+ \\
+ \begin{tabular}{|l|l|} \hline
+ \textbf{Option} & \textbf{Description} \\ \hline \hline
+ 1 & Return minimum number of parms \\ \hline
+ 2 & Return function result type \\ \hline
+ ? & Return 0 if valid function \\ \hline
+ \end{tabular}
+ \endlatexonly
+
+ \returns requested information or -1 on failure.
+*/
+xbShort xbExpn::GetFuncInfo( const char * Function, xbShort Option )
+{
+/* Option =
+ 1 - return minimum number of needed parms
+ 2 - return function result type
+ ? - return 0 if valid function
+*/
+ xbFuncDtl * f;
+ xbShort i, len;
+ const char *s;
+
+ if(( Option<1 )||( Option>2 ))
+ return XB_INVALID_OPTION;
+
+ s = Function;
+ len = 0;
+ while( *s && *s != '(' ) { s++; len++; }
+
+ f = XbaseFuncList;
+ i = 0;
+ while( f[i].FuncName ){
+ if( strncmp( f[i].FuncName, Function, len ) == 0 )
+ return( (Option==1) ? f[i].ParmCnt : f[i].ReturnType );
+ i++;
+ }
+ return -1;
+}
+
+/*************************************************************************/
+//! IsWhiteSpace
+/*!
+*/
+xbShort xbExpn::IsWhiteSpace( char c )
+{
+ return(( c == 0x20 )? 1 : 0 );
+}
+
+/*************************************************************************/
+//! GetNextToken
+/*!
+*/
+xbShort xbExpn::GetNextToken( const char * s, xbShort MaxLen )
+{
+ /* TreeResultType Settings
+ Token Action/
+ Was Type Result
+ Unv N N
+ Unv C C
+ Unv Function Table Lookup
+ Unv Field Field Type
+ Not L Any Logical L
+ */
+
+ xbShort Wctr, Wtype, Wsw, EmptyCtr, MaxCtr, MaxCtrSave;
+ const char *sp, *np, *pp; /* save, next and previous pointer */
+
+ LogicalType = 0;
+ TokenType = 0;
+ TokenLen = 0;
+ EmptyCtr = 0;
+ MaxCtr = 0;
+
+ if( !s || ! *s )
+ return XB_NO_DATA;
+
+ /* go past any initial white space */
+ while( s && *s && IsWhiteSpace( *s )){
+ s++;
+ MaxCtr++;
+ if (MaxCtr >= MaxLen)
+ return XB_NO_ERROR;
+ }
+
+/* 1 - check for parens */
+/* '(', if found go to corresponding ')', if no ')', return -1 */
+ if( *s == '(' || *s == '{' ){
+ if( *s == '{' ) Wtype = 0; else Wtype = 1;
+ Wctr = 1;
+ s++;
+
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_PARSE_ERROR;
+
+ while( s && *s ){
+ if(( *s == ')' && Wtype == 1 ) || (*s == '}' && Wtype == 0 )){
+ Wctr--;
+ if( Wctr == 0 ){
+ if( EmptyCtr != 0 ) {
+ TokenType = 'E';
+ PreviousType = 'E';
+ } else
+ return XB_PARSE_ERROR;
+
+ TokenLen += 2;
+ return XB_NO_ERROR;
+ }
+ }
+ else if(( *s == '(' && Wtype == 1 ) || (*s == '{' && Wtype == 0 )){
+ Wctr++;
+ EmptyCtr++;
+ } else if( *s != ' ' )
+ EmptyCtr++;
+
+ s++;
+ TokenLen++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_PARSE_ERROR;
+ }
+ return XB_PARSE_ERROR;
+ }
+
+
+/* 2 - Check for Constants */
+/* check for "'" or """, if no corresponding quote return -1 */
+ if( *s == '"' || *s == '\'' ){
+ if( *s == '"' ) Wtype = 0; else Wtype = 1;
+ TokenType = 'C'; /* set to constant */
+ PreviousType = 'C';
+ s++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_NO_ERROR;
+ while( s && *s ){
+ if(( *s == '"' && Wtype == 0 ) || (*s == '\'' && Wtype == 1 ))
+ return XB_NO_ERROR;
+ s++;
+ TokenLen++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_NO_ERROR;
+ }
+ return XB_PARSE_ERROR;
+ }
+
+
+/* 3 - check for .T. .F. .TRUE. or .FALSE. */
+ if( s && *s && *s == '.' ){
+ if(( strncmp( s, ".T.", 3 ) == 0 ) || ( strncmp( s, ".F.", 3 ) == 0 )){
+ TokenLen = 3;
+ TokenType = 'C'; /* constant */
+ PreviousType = 'C';
+ LogicalType = 1;
+ return XB_NO_ERROR;
+ } else if( strncmp( s, ".TRUE.", 6 ) == 0 ){
+ TokenLen = 6;
+ TokenType = 'C'; /* constant */
+ PreviousType = 'C';
+ LogicalType = 1;
+ return XB_NO_ERROR;
+ } else if( strncmp( s, ".FALSE.", 7 ) == 0 ){
+ TokenLen = 7;
+ TokenType = 'C'; /* constant */
+ PreviousType = 'C';
+ LogicalType = 1;
+ return XB_NO_ERROR;
+ }
+ }
+
+/* 4 - check for positive, negative or decimal number constants */
+ if(( *s == '-' && ( PreviousType == 'O' || PreviousType == 0 )) ||
+ ( *s == '+' && ( PreviousType == 'O' || PreviousType == 0 )) ||
+ *s == '.' || isdigit( *s )){
+ sp = s;
+ MaxCtrSave = MaxCtr;
+ Wsw = Wctr = 0;
+ if( *s == '.' ){
+ Wctr++;
+ s++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_PARSE_ERROR;
+
+ if( s && *s && isdigit( *s ))
+ TokenLen++;
+ else
+ Wsw++;
+ } else if( *s == '-' ){
+ s++;
+ TokenLen++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_PARSE_ERROR;
+
+ /* go past any white space between sign and number */
+ while( s && *s && IsWhiteSpace( *s )){
+ s++;
+ TokenLen++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_PARSE_ERROR;
+ }
+ }
+
+ if( isdigit( *s ) || (*s == '.' && !Wsw )){
+ while(s && *s && ((*s == '.' && Wctr < 2 ) || isdigit(*s)) && !Wsw ){
+ if( *s == '.' ) {
+ Wctr++;
+ if( Wctr > 1 ) break;
+ s++;
+
+ MaxCtr++;
+ if( MaxCtr >= MaxLen ){
+ TokenType = 'N';
+ PreviousType = 'N';
+ return XB_NO_ERROR;
+ }
+
+ if( s && *s && isdigit( *s ))
+ TokenLen++;
+ else
+ Wsw++;
+ } else {
+ s++;
+ TokenLen++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen ) {
+ TokenType = 'N';
+ PreviousType = 'N';
+ return XB_NO_ERROR;
+ }
+ }
+ }
+ TokenType = 'N'; /* constant */
+ PreviousType = 'N';
+ return XB_NO_ERROR;
+ } else {
+ s = sp;
+ MaxCtr = MaxCtrSave;
+ }
+ }
+
+/* 5 - Check for operators */
+ if( *s == '+' || *s == '-' || *s == '/' || *s == '^'){
+ TokenLen = 1;
+ TokenType = 'O';
+ PreviousType = 'O';
+ return XB_NO_ERROR;
+ }
+ if(*s == '=' || *s == '$' || *s == '#' ){
+ LogicalType = 1;
+ TokenLen = 1;
+ TokenType = 'O';
+ PreviousType = 'O';
+ return XB_NO_ERROR;
+ }
+ if( strncmp( s, "!=", 2 ) == 0 ){
+ LogicalType = 1;
+ TokenLen = 2;
+ TokenType = 'O';
+ PreviousType = 'O';
+ return XB_NO_ERROR;
+ }
+ if( *s == '*' ){
+ s++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_PARSE_ERROR;
+
+ TokenType = 'O';
+ PreviousType = 'O';
+ if( *s == '*' ){
+ TokenLen = 2;
+ return XB_NO_ERROR;
+ } else {
+ TokenLen = 1;
+ return XB_NO_ERROR;
+ }
+ }
+ if( *s == '<' || *s == '>' ) {
+ s++;
+
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_PARSE_ERROR;
+
+ LogicalType = 1; // added 3/25/00 dtb
+ TokenType = 'O';
+ PreviousType = 'O';
+ if( *s == '<' || *s == '>' || *s == '=' ){
+ TokenLen = 2;
+ return XB_NO_ERROR;
+ } else {
+ TokenLen = 1;
+ return XB_NO_ERROR;
+ }
+ }
+
+/* check for .NOT. .OR. .AND. */
+
+ if( s && *s && *s == '.' ){
+ if( strncmp( s, ".NOT.", 5 ) == 0 ){
+ TokenLen = 5;
+ TokenType = 'O'; /* constant */
+ PreviousType = 'O';
+ LogicalType = 1;
+ return XB_NO_ERROR;
+ } else if( strncmp( s, ".AND.", 5 ) == 0 ){
+ TokenLen = 5;
+ TokenType = 'O'; /* constant */
+ PreviousType = 'O';
+ LogicalType = 1;
+ return XB_NO_ERROR;
+ } else if( strncmp( s, ".OR.", 4 ) == 0 ){
+ TokenLen = 4;
+ TokenType = 'O'; /* constant */
+ PreviousType = 'O';
+ LogicalType = 1;
+ return XB_NO_ERROR;
+ }
+ }
+
+ /* If get this far, must be function or database field */
+ while( s && *s ){
+ s++;
+ TokenLen++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen ) {
+ TokenType = 'D';
+ PreviousType = 'D';
+ return XB_NO_ERROR;
+ }
+
+ if( s && *s && *s == '(' ) {
+ /* look for corresponding ) */
+ Wctr = 1;
+ s++;
+ TokenLen++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_PARSE_ERROR;
+
+ while( s && *s ) {
+ if( *s == ')' ) {
+ Wctr--;
+ if( !Wctr ) {
+ TokenType = 'F'; /* function */
+ PreviousType = 'F';
+ TokenLen++;
+ return XB_NO_ERROR;
+ }
+ }
+ if( *s == '(' ) Wctr++;
+ s++;
+ TokenLen++;
+ MaxCtr++;
+ if( MaxCtr >= MaxLen )
+ return XB_PARSE_ERROR;
+ }
+ return XB_PARSE_ERROR;
+ } else {
+ np = s + 1;
+ pp = s - 1;
+ if( !s || !*s || (IsSeparator( *s ) &&
+ !(*s == '-' && *np == '>' ) && !(*s == '>' && *pp == '-' ))) {
+ if( TokenLen > 0 ){
+ TokenType = 'D'; /* database field */
+ PreviousType = 'D';
+ return XB_NO_ERROR;
+ }
+ }
+ }
+ }
+ return XB_NO_ERROR;
+}
+/*************************************************************************/
+//! IsSeparator
+/*!
+*/
+char xbExpn::IsSeparator( char c )
+{
+ if( c == '-' || c == '+' || c == '*' || c == '/' || c == '$' ||
+ c == ' ' || c == '#' || c == '<' || c == '>' || c == '^' ||
+ c == '=' || c == '.' || c == '!' /* || c == ')' */ )
+ return c;
+ else
+ return 0;
+}
+
+/*************************************************************************/
+//! GetExpNode
+/*!
+*/
+/*
+xbExpNode * xbExpn::GetExpNode(xbShort Len) {
+ xbExpNode * Temp;
+
+ Temp = new xbExpNode;
+ if( Temp && Len > 0 )
+ Temp->ResultLen = Len;
+ return Temp;
+}
+*/
+/*************************************************************************/
+//! LoadExpNode
+/*!
+*/
+xbExpNode * xbExpn::LoadExpNode(
+ const char *ENodeText, /* pointer to text data */
+ const char EType, /* Operand type */
+ const xbShort ELen, /* length of node text data */
+ const xbShort BufLen ) /* length needed in the buffer*/
+{
+// xbExpNode * CurNode;
+// if(( CurNode = GetExpNode(BufLen)) == NULL ) return NULL;
+
+ xbExpNode * CurNode = new xbExpNode;
+ if( !CurNode )
+ return NULL;
+ CurNode->ResultLen = BufLen;
+
+ CurNode->NodeText = strdup( ENodeText );
+ CurNode->Type = EType;
+ CurNode->Len = ELen;
+ CurNode->InTree = 1;
+ CurNode->ResultLen = BufLen;
+ return CurNode;
+}
+
+/*************************************************************************/
+//! BuildExpressionTree
+/*!
+*/
+xbShort xbExpn::BuildExpressionTree( const char * Expression,
+ xbShort MaxTokenLen, xbDbf * d )
+{
+ /* previous node is the node to insert under */
+ xbExpNode * CurNode = 0;
+ xbExpNode * PreviousNode;
+ xbShort rc, FieldNo=0, BufLen;
+ xbShort TokenLenCtr;
+ char c;
+ const char *p;
+ char TempField[11];
+ char TableName[31];
+ xbDbf * TempDbf=0;
+ int LocTokenLen;
+
+ if( Tree ) {
+ delete Tree;
+ Tree = NULL;
+ }
+
+ p = Expression;
+ PreviousNode = NULL;
+ PreviousType = TokenLenCtr = 0;
+
+ while( IsWhiteSpace( *p )) {
+ p++;
+ TokenLenCtr++;
+ if(TokenLenCtr >= MaxTokenLen)
+ return XB_NO_ERROR;
+ }
+
+ rc = GetNextToken( p, MaxTokenLen-TokenLenCtr );
+ LocTokenLen = TokenLen;
+ if( rc != XB_NO_DATA && rc != XB_NO_ERROR )
+ return rc;
+
+ while( rc == 0 ){
+ if( TokenType == 'D' && d ){
+ if( TokenLen > 30 )
+ strncpy( TableName, p, 30 );
+ else
+ strncpy( TableName, p, TokenLen );
+
+ memset( TempField, 0x00, 11 );
+
+ if( strstr( p, "->" ) != NULL ) {
+ if(( TempDbf = d->xbase->GetDbfPtr( TableName )) == NULL )
+ return XB_INVALID_FIELD;
+ xbShort tlen = 0;
+ while( TableName[tlen] != '-' && TableName[tlen+1] != '>' )
+ tlen++;
+ tlen = TokenLen - tlen - 2; // length of field name
+ const char * fp = strstr( p, "->" );
+ fp += 2; // ptr to beginning of field name
+ strncpy( TempField, fp, tlen );
+ } else {
+ TempDbf = d;
+ if( TokenLen > 10 )
+ return XB_INVALID_FIELD;
+ strncpy( TempField, p, TokenLen );
+ }
+ if(( FieldNo = TempDbf->GetFieldNo( TempField )) == -1 )
+ return XB_INVALID_FIELD;
+ BufLen = TempDbf->GetFieldLen( FieldNo ) + 1;
+ }
+ else if( TokenType == 'C' || TokenType == 'N' )
+ BufLen = TokenLen + 1;
+ else
+ BufLen = 0;
+
+ if( TokenType == 'C' ) p++; /* go past first ' */
+
+ if( TokenType != 'O' ){
+ if( !Tree ) { /* create root node with this token */
+ CurNode = LoadExpNode( p, TokenType, TokenLen, BufLen );
+ Tree = CurNode;
+ } else { /* put as child 2 of previous node */
+ CurNode = LoadExpNode( p, TokenType, TokenLen, BufLen );
+ PreviousNode->Sibling2 = CurNode;
+ CurNode->Node = PreviousNode;
+ }
+
+ if( TokenType == 'E' ){
+ if((rc=ReduceComplexExpression(p,TokenLen,CurNode,d))!=0)
+ return rc;
+ if(PreviousNode)
+ CurNode = PreviousNode->Sibling2;
+ else
+ CurNode = Tree;
+ } else if( TokenType == 'F' ){
+ if(( rc = ReduceFunction( p, CurNode, d)) != 0 )
+ return rc;
+
+ xbShort parmCnt = GetFuncInfo( p, 1 );
+ if( (parmCnt == 1 || parmCnt == 101 ) && !CurNode->Sibling1 ||
+ (parmCnt == 2 || parmCnt == 201 ) && !CurNode->Sibling2 ||
+ (parmCnt == 3 ) && !CurNode->Sibling3 )
+ return XB_INSUFFICIENT_PARMS;
+ else if( parmCnt == 0 && CurNode->Sibling1 )
+ return XB_TOO_MANY_PARMS;
+ else if( parmCnt == 1 && CurNode->Sibling2 )
+ return XB_TOO_MANY_PARMS;
+ else if( parmCnt == 2 && CurNode->Sibling3 )
+ return XB_TOO_MANY_PARMS;
+
+ CurNode->ExpressionType = GetFuncInfo( p, 2 );
+ if( CurNode->ExpressionType == '1' ){
+ if( CurNode->Sibling1 )
+ if( CurNode->Sibling1->ExpressionType == 'C' )
+ CurNode->ExpressionType = 'C';
+ else
+ CurNode->ExpressionType = 'N';
+ else
+ return XB_INSUFFICIENT_PARMS;
+ }
+
+ CurNode->dbf = d;
+ }
+ else if( TokenType == 'D' && d ) {
+ CurNode->DataLen = BufLen - 1;
+ CurNode->FieldNo = FieldNo;
+ CurNode->dbf = TempDbf;
+ c = TempDbf->GetFieldType( FieldNo );
+ if( c == 'C' || c == 'M' ) CurNode->ExpressionType = 'C';
+ else if( c == 'L' ) CurNode->ExpressionType = 'L';
+ else if( c == 'N' || c == 'F' ) CurNode->ExpressionType = 'N';
+ else if( c == 'D' ) CurNode->ExpressionType = 'D';
+ } else if( TokenType == 'C' || TokenType == 'N' ) {
+ CurNode->DataLen = CurNode->Len;
+ CurNode->StringResult = CurNode->NodeText;
+ CurNode->StringResult.resize( CurNode->DataLen+1 );
+ if( TokenType == 'N' ) {
+ CurNode->DoubResult = strtod( CurNode->StringResult, 0 );
+ CurNode->ExpressionType = 'N';
+ } else
+ CurNode->ExpressionType = 'C';
+ }
+ }
+ else /* it is an operator */
+ {
+ if(!Tree){
+ if(*p == '-'){
+ CurNode = LoadExpNode( p, TokenType, TokenLen, 0 );
+ CurNode->ExpressionType = 'C';
+ } else
+ return XB_EXP_SYNTAX_ERROR;
+ } else {
+ if( Tree->Type != 'O' ){
+ CurNode = LoadExpNode( p, TokenType, TokenLen, 0 );
+ Tree->Node = CurNode; /* link the new parent to old tree */
+ CurNode->Sibling1 = Tree; /* connect the sibling */
+ Tree = CurNode; /* root in tree */
+ } else {
+ PreviousNode = CurNode->Node;
+ CurNode = LoadExpNode( p, TokenType, TokenLen, 0 );
+ while( PreviousNode &&
+ (( OperatorWeight( PreviousNode->NodeText, TokenLen ) == 0 ) ||
+ ( OperatorWeight( CurNode->NodeText, TokenLen ) <=
+ OperatorWeight( PreviousNode->NodeText, TokenLen ))))
+ PreviousNode = PreviousNode->Node;
+
+ if( PreviousNode ) {
+ CurNode->Node = PreviousNode;
+ CurNode->Sibling1 = PreviousNode->Sibling2;
+ PreviousNode->Sibling2 = CurNode;
+ CurNode->Sibling1->Node = CurNode;
+ } else { /* insert at root */
+ CurNode->Sibling1 = Tree;
+ Tree = CurNode;
+ CurNode->Sibling1->Node = CurNode;
+ }
+ }
+ if( LogicalType )
+ CurNode->ExpressionType = 'L';
+ }
+ }
+ PreviousNode = CurNode;
+// p += CurNode->Len; // 2/20/04 - not sure when this was updated - gk
+ p += LocTokenLen;
+
+// if( TokenType == 'C' ) { gk - 2/20/04 func("fff") + 4 didn't work
+ if( TokenType == 'C' && CurNode->Type != 'F' ){
+ p++; /* go past last ' */
+ TokenLenCtr+=2; /* add the quotes */
+ }
+
+// TokenLenCtr += CurNode->Len; // 2/20/04 - not sure when this was updated - gk
+ TokenLenCtr += LocTokenLen;
+ if( TokenLenCtr >= MaxTokenLen )
+ return XB_NO_ERROR;
+ if( p && *p && TokenType == 'E' ) {
+ p++;
+ TokenLenCtr++;
+ }
+
+ while( IsWhiteSpace( *p )) {
+ p++;
+ TokenLenCtr++;
+ if( TokenLenCtr >= MaxTokenLen )
+ return XB_NO_ERROR;
+ }
+ rc = GetNextToken( p, MaxTokenLen-TokenLenCtr );
+ LocTokenLen = TokenLen;
+ if( rc != XB_NO_DATA && rc != XB_NO_ERROR )
+ return rc;
+ }
+ return XB_NO_ERROR;
+}
+/*************************************************************************/
+//! GetExpressionResultType
+/*!
+*/
+char xbExpn::GetExpressionResultType( xbExpNode * e ) {
+ xbExpNode * Temp = 0;
+ if( e )
+ Temp = e;
+ else if( !Temp )
+ Temp = Tree;
+ else
+ return 0;
+
+ if( e->Type == 'O' &&
+ ( *e->NodeText == '<' || *e->NodeText == '>' || *e->NodeText == '=' ||
+ *e->NodeText == '#' || *e->NodeText == '$' ||
+ strncmp( e->NodeText, "!=", 2 ) == 0 ))
+ return 'L';
+
+ /* go down to second lowest level */
+ while( Temp && Temp->Sibling1 && Temp->Sibling1->Sibling1 )
+ Temp = Temp->Sibling1;
+
+ /* if subtracting dates, return numeric type */
+ if( Temp->Type == 'O' && *Temp->NodeText == '-' &&
+ Temp->Sibling1 && Temp->Sibling2 &&
+ Temp->Sibling1->ExpressionType == 'D' &&
+ Temp->Sibling2->ExpressionType == 'D' )
+ return 'N';
+
+ /* else return the type of the lowest left node */
+ while( Temp && !Temp->ExpressionType && Temp->Sibling1 )
+ Temp = Temp->Sibling1;
+ return Temp->ExpressionType;
+}
+/*************************************************************************/
+//! GetExpressionHandle
+/*!
+*/
+xbExpNode * xbExpn::GetExpressionHandle() {
+ xbExpNode * e;
+ e = Tree;
+ Tree = NULL;
+ return e;
+}
+/*************************************************************************/
+//! OperatorWeight
+/*! This function determines the priority of an operator
+*/
+xbShort xbExpn::OperatorWeight( const char * Oper, xbShort len )
+{
+ /* operator precendence
+
+ not all are implemented yet, but the structure is here
+
+ 10 .AND. .OR. .NOT. (not really an operator)
+ 9 > or < (includes <= or >=)
+ 6 unary plus or minus (+,-)
+ 5 prefix increment and/or decrement (++,--)
+ 4 exponentiation ** or ^
+ 3 multiplication,division or modulus (*,/,%)
+ 2 Addition, subtraction (+,-)
+ 1 Postfix increment and/or decrement (++,--)
+ */
+
+ if( len < 1 || len > 5 ) return 0;
+
+
+ if( Oper[0] == '>' || Oper[0] == '<' )
+ return 13;
+
+ if( strncmp( Oper, ".AND.", 5 ) == 0 ||
+ strncmp( Oper, ".OR.", 4 ) == 0 ||
+ strncmp( Oper, ".NOT.", 5 ))
+ return 10;
+
+ if( strncmp( Oper, "**", 2 ) == 0 || Oper[0] == '^' )
+ return 4;
+
+ if( Oper[0] == '*' || Oper[0] == '/' || Oper[0] == '%' )
+ return 3;
+
+ if( Oper[0] == '+' || Oper[0] == '-' )
+ return 1;
+
+ return 0;
+}
+/*************************************************************************/
+//! ReduceComplexExpression
+/*!
+*/
+xbShort xbExpn::ReduceComplexExpression(const char *NextToken, xbShort Len,
+ xbExpNode *cn, xbDbf *d) {
+ const char *p;
+ xbShort rc;
+ xbExpNode * SaveTree;
+
+ SaveTree = Tree;
+ Tree = NULL;
+
+ p = NextToken;
+ p++;
+
+ if(( rc = BuildExpressionTree( p, Len-2, d )) != XB_NO_ERROR )
+ return rc;
+
+ if(cn->Node) { /* then this is the base tree */
+ cn->Node->Sibling2 = Tree;
+ Tree->Node = cn->Node;
+ delete cn;
+ Tree = SaveTree;
+ } else
+ delete cn;
+
+ return XB_NO_ERROR;
+}
+/*************************************************************************/
+//! GetFunctionTokenLen
+/*!
+*/
+xbShort xbExpn::GetFunctionTokenLen( const char * s )
+{
+ xbShort cnt, LeftParenCtr;
+ const char *p;
+
+ cnt = LeftParenCtr = 0;
+ p = s;
+
+ while( p && ( *p != ',' || ( *p == ',' && LeftParenCtr > 0 )) &&
+ !( LeftParenCtr == 0 && *p == ')')) {
+ if( *p == '(' )
+ LeftParenCtr++;
+ else if( *p == ')' )
+ LeftParenCtr--;
+ p++;
+ cnt++;
+ }
+ return cnt;
+}
+/*************************************************************************/
+//! ReduceFunction
+/*!
+*/
+xbShort xbExpn::ReduceFunction(const char *NextToken, xbExpNode *cn, xbDbf *d)
+{
+ const char *p;
+ xbShort rc;
+ xbShort FuncTokenLen;
+ xbExpNode * SaveTree;
+
+ p = strchr( NextToken, '(' );
+ if (!p)
+ return XB_PARSE_ERROR;
+
+ p++;
+ while( IsWhiteSpace( *p )) p++;
+ if (*p == ')')
+ return XB_NO_ERROR;
+
+ /* do function paramater 1 */
+ FuncTokenLen = GetFunctionTokenLen( p );
+ SaveTree = Tree;
+ Tree = NULL;
+ if(( rc = BuildExpressionTree( p, FuncTokenLen, d )) != XB_NO_ERROR )
+ return rc;
+ cn->Sibling1 = Tree;
+ Tree->Node = cn;
+ Tree = SaveTree;
+
+ /* do function paramater 2 */
+
+ p += FuncTokenLen;
+ while( IsWhiteSpace( *p )) p++;
+ if(*p == ')')
+ return XB_NO_ERROR;
+ if( *p != ',' )
+ return XB_PARSE_ERROR;
+
+ p++;
+ while( IsWhiteSpace( *p )) p++;
+ FuncTokenLen = GetFunctionTokenLen( p );
+ SaveTree = Tree;
+ Tree = NULL;
+ if(( rc = BuildExpressionTree( p, FuncTokenLen, d )) != XB_NO_ERROR )
+ return rc;
+
+ cn->Sibling2 = Tree;
+ Tree->Node = cn;
+ Tree = SaveTree;
+
+ /* do function paramater 3 */
+ p += FuncTokenLen;
+ while( IsWhiteSpace( *p )) p++;
+ if (*p == ')')
+ return XB_NO_ERROR;
+ if( *p != ',' )
+ return XB_PARSE_ERROR;
+
+ p++;
+ while( IsWhiteSpace( *p )) p++;
+ FuncTokenLen = GetFunctionTokenLen( p );
+ SaveTree = Tree;
+ Tree = NULL;
+ if(( rc = BuildExpressionTree( p, FuncTokenLen, d )) != XB_NO_ERROR )
+ return rc;
+
+ cn->Sibling3 = Tree;
+ Tree->Node = cn;
+ Tree = SaveTree;
+
+ return XB_NO_ERROR;
+}
+/*************************************************************************/
+//! ParseExpression
+/*!
+*/
+xbShort xbExpn::ParseExpression(const char *exp, xbDbf *d) {
+ return BuildExpressionTree(exp, strlen(exp), d);
+}
+/*************************************************************************/
+//! ProcessExpression
+/*!
+*/
+xbShort xbExpn::ProcessExpression(const char *e, xbDbf *d) {
+ xbShort rc;
+ if(( rc = BuildExpressionTree( e, strlen( e ), d )) != XB_NO_ERROR )
+ return rc;
+ if(( rc = ProcessExpression( Tree )) != XB_NO_ERROR )
+ return rc;
+ return XB_NO_ERROR;
+}
+/*************************************************************************/
+#ifdef XBASE_DEBUG
+//! DumpExpressionTree
+/*!
+*/
+void xbExpn::DumpExpressionTree( xbExpNode * E, xbShort printOption )
+{
+ if( !E ) E = Tree;
+ if( !E ) return;
+ DumpExpNode( E, printOption );
+
+ if( E->Sibling1 ) DumpExpressionTree( E->Sibling1, printOption );
+ if( E->Sibling2 ) DumpExpressionTree( E->Sibling2, printOption );
+ if( E->Sibling3 ) DumpExpressionTree( E->Sibling3, printOption );
+ return;
+}
+/*************************************************************************/
+//! DumpExpNode
+/*!
+*/
+void xbExpn::DumpExpNode(xbExpNode *e, xbShort printOption)
+{
+ xbString ntext;
+
+ ntext = e->NodeText;
+ ntext.resize( e->Len + 1 );
+
+ if( printOption ){
+ FILE * dmp;
+ if(( dmp = fopen( "xbase64.log", "a" )) == NULL )
+ return;
+
+ fprintf( dmp, "******* Exp Node *******\n" );
+ fprintf( dmp, "Exp Node Address = %x\n", e );
+ fprintf( dmp, "Node Text = %s\n", ntext.getData());
+ fprintf( dmp, "Type = %c\n", e->Type );
+ fprintf( dmp, "Len = %d\n", e->Len );
+ fprintf( dmp, "InTree = %d\n", e->InTree );
+ fprintf( dmp, "Field No = %d\n", e->FieldNo );
+ fprintf( dmp, "ExpressionType = %c\n", e->ExpressionType );
+ fprintf( dmp, "StringResult = %s\n", e->StringResult.getData());
+ fprintf( dmp, "DoubResult = %d\n", e->DoubResult );
+ fprintf( dmp, "IntResult = %d\n", e->IntResult );
+ fprintf( dmp, "ResultLen = %d\n", e->ResultLen );
+ fprintf( dmp, "DataLen = %x\n", e->DataLen );
+
+ if( e->Node )
+ fprintf( dmp, "Parent = %x\n", e->Node );
+ if( e->Sibling1 )
+ fprintf( dmp, "Sibling 1 = %x\n", e->Sibling1 );
+ if( e->Sibling2 )
+ fprintf( dmp, "Sibling 2 = %x\n", e->Sibling2 );
+ if( e->Sibling3 )
+ fprintf( dmp, "Sibling 3 = %x\n", e->Sibling3 );
+ fprintf( dmp, "\n" );
+ fclose( dmp );
+ }
+ else
+ {
+ std::cout << "****** Exp Node ******";
+ std::cout << "Exp Node Address = " << e << std::endl;
+ std::cout << "Node Text = " << ntext << std::endl;
+ std::cout << "Type = " << e->Type << std::endl;
+ std::cout << "Len = " << e->Len << std::endl;
+ std::cout << "InTree = " << e->InTree << std::endl;
+ std::cout << "Field No = " << e->FieldNo << std::endl;
+ std::cout << "ExpressionType = " << e->ExpressionType << std::endl;
+ std::cout << "StringResult = " << e->StringResult << std::endl;
+ std::cout << "DoubResult = " << e->DoubResult << std::endl;
+ std::cout << "IntResult = " << e->IntResult << std::endl;
+ std::cout << "ResultLen = " << e->ResultLen << std::endl;
+ std::cout << "DataLen = " << e->DataLen << std::endl;
+ if( e->Node )
+ std::cout << "Parent = " << e->Node << std::endl;
+ if( e->Sibling1 )
+ std::cout << "Sibling 1 = " << e->Sibling1 << std::endl;
+ if( e->Sibling2 )
+ std::cout << "Sibling 2 = " << e->Sibling2 << std::endl;
+ if( e->Sibling3 )
+ std::cout << "Sibling3 = " << e->Sibling3 << std::endl;
+ }
+ return;
+}
+#endif
+
+/*************************************************************************/
+//! xbExpNode()
+/*!
+*/
+xbExpNode::xbExpNode() :
+ NodeText(0),
+ Type(0),
+ Len(0),
+ InTree(0),
+ Node(0),
+ Sibling1(0),
+ Sibling2(0),
+ Sibling3(0),
+ DataLen(0),
+ ResultLen(0),
+ DoubResult(0),
+ IntResult(0),
+ dbf(0),
+ FieldNo(-1),
+ ExpressionType(0)
+{
+}
+/*************************************************************************/
+//! ~xbExpNode()
+/*!
+*/
+xbExpNode::~xbExpNode()
+{
+ if(NodeText)
+ free(NodeText);
+
+ if(Sibling1)
+ delete Sibling1;
+
+ if(Sibling2)
+ delete Sibling2;
+
+ if(Sibling3)
+ delete Sibling3;
+}
+/*************************************************************************/
+//! Constructor.
+/*!
+*/
+xbStackElement::xbStackElement()
+{
+ Next = 0;
+ Previous = 0;
+ NodePtr = 0;
+}
+/*************************************************************************/
+//! Destructor.
+/*!
+*/
+xbStackElement::~xbStackElement()
+{
+}
+/*************************************************************************/
+
+//! Destructor.
+/*!
+*/
+
+/*************************************************************************/
+//! Short description.
+/*!
+*/
+void xbExpn::InitStack()
+{
+ xbStackElement *next;
+
+ while(First){
+ next = First->Next;
+
+ if( First->NodePtr->InTree == 0 )
+ delete First->NodePtr;
+
+ delete First;
+ First = next;
+ }
+
+ Last = 0;
+ StackDepth = 0;
+ return;
+}
+/*************************************************************************/
+//! Push a value onto the stack.
+/*!
+ \param p
+*/
+xbShort xbExpn::Push( xbExpNode *p )
+{
+ xbStackElement *Temp = new xbStackElement;
+
+ if(!Temp)
+ return XB_NO_MEMORY;
+
+ Temp->NodePtr = p;
+
+ if( !First ){
+ First = Temp;
+ Last = Temp;
+ StackDepth = 1;
+ } else {
+ Last->Next = Temp;
+ Temp->Previous = Last;
+ Last = Temp;
+ StackDepth++;
+ }
+ return XB_NO_ERROR;
+}
+/*************************************************************************/
+//! Pop the top value from the stack.
+/*!
+*/
+xbExpNode * xbExpn::Pop()
+{
+ xbExpNode *p;
+ xbStackElement *Save;
+
+ if( StackDepth == 0 )
+ return 0;
+ else {
+ p = Last->NodePtr;
+ if( StackDepth == 1 ){
+ delete First;
+ First = 0;
+ Last = 0;
+ } else { /* number of items in Stack must be > 1 */
+ Last->Previous->Next = 0;
+ Save = Last;
+ Last = Last->Previous;
+ delete Save;
+ }
+ StackDepth--;
+ return p;
+ }
+}
+/*************************************************************************/
+//! Short description.
+/*!
+*/
+#ifdef XBASE_DEBUG
+void xbExpn::DumpStack()
+{
+ xbStackElement * e;
+ if( StackDepth == 0 ){
+ std::cout << "\nStack is empty...";
+ return;
+ }
+
+ std::cout << "\nThere are " << StackDepth << " entries.";
+ std::cout << "\nFirst = " << First << " Last = " << Last;
+
+ e = First;
+ while( e ){
+ std::cout << "\n*****************************";
+ std::cout << "\nThis = " << e;
+ std::cout << "\nNext = " << e->Next;
+ std::cout << "\nPrevious = " << e->Previous;
+ std::cout << "\nNode Ptr = " << e->NodePtr;
+ e = e->Next;
+ }
+ return;
+}
+#endif // XB_EXPRESSIONS
+#endif
+/*************************************************************************/