WindowsXP-SP1/com/rpc/midl/expr/expr.cxx
2020-09-30 16:53:49 +02:00

2075 lines
55 KiB
C++

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
expr.cxx
Abstract:
expression evaluator routines implementation.
Notes:
History:
VibhasC Aug-05-1993 Created
----------------------------------------------------------------------------*/
#pragma warning ( disable : 4514 )
/****************************************************************************
* include files
***************************************************************************/
#include "nulldefs.h"
extern "C"
{
#include <stdio.h>
#include <string.h>
}
#include "expr.hxx"
#include "listhndl.hxx"
#include "nodeskl.hxx"
#include "semantic.hxx"
#include "symtable.hxx"
#include "cmdana.hxx"
#include <excpt.h>
#include <float.h>
/****************************************************************************
* extern definitions
***************************************************************************/
/****************************************************************************
* extern data
***************************************************************************/
extern SymTable * pBaseSymTbl;
extern CMD_ARG * pCommand;
/****************************************************************************
* local definitions
***************************************************************************/
/****************************************************************************
* local data
***************************************************************************/
/***************************************************************************/
short
expr_node::MakeListOfVars(
ITERATOR &
)
{
return( 0 );
}
short
expr_named_constant::MakeListOfVars(
ITERATOR &
)
{
return( 0 );
}
short
expr_variable::MakeListOfVars(
ITERATOR & pList
)
{
pList.Insert( this );
return( 1 );
}
short
expr_op_unary::MakeListOfVars(
ITERATOR & pList
)
{
short VarCount = 0;
if ( GetLeft() )
VarCount = GetLeft()->MakeListOfVars( pList );
return( VarCount );
}
short
expr_sizeof::MakeListOfVars(
ITERATOR &
)
/*++
expr_sizeof is a unary_op but it doesn't have a child!
--*/
{
return( 0 );
}
short
expr_alignof::MakeListOfVars(
ITERATOR &
)
/*++
expr_alignof is a unary_op but it doesn't have a child!
--*/
{
return( 0 );
}
short
expr_op_binary::MakeListOfVars(
ITERATOR & pList
)
{
short VarCount;
VarCount = GetLeft()->MakeListOfVars( pList );
if ( GetRight() )
{
VarCount = short( VarCount + GetRight()->MakeListOfVars( pList ) );
}
return( VarCount );
}
short
expr_ternary::MakeListOfVars(
ITERATOR & pList
)
{
short VarCount;
VarCount = GetLeft()->MakeListOfVars( pList );
if ( GetRight() )
{
VarCount = short( VarCount + GetRight()->MakeListOfVars( pList ) );
}
if ( GetRelational() )
{
VarCount = short( VarCount + GetRelational()->MakeListOfVars( pList ) );
}
return( VarCount );
}
/***************************************************************************/
void
expr_node::DecorateWithPrefix(
char * pPrefix )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
This routine decorates all the variable nodes in the expression
with a prefix.
Arguments:
pPrefix - the prefix to be prepended to each variable
Return Value:
Notes:
----------------------------------------------------------------------------*/
{
ITERATOR VarList;
expr_variable * pVarNode = 0;
short VarCount = MakeListOfVars( VarList );
if ( VarCount )
{
VarList.Init();
while ( ITERATOR_GETNEXT( VarList, pVarNode ) )
pVarNode->SetPrefix( pPrefix );
}
return;
}
expr_index::expr_index(
expr_node * pL,
expr_node * pR ) : expr_op_binary( OP_INDEX, pL, pR )
{
SetType( pL->GetType() );
}
expr_param *
expr_proc_call::SetParam(
expr_param * pParam )
{
expr_param * p = GetFirstParam();
IncrNoOfParams();
if( p )
{
return p->SetLastPeerParam( pParam );
}
else
return SetFirstParam( pParam );
}
expr_param *
expr_proc_call::SetParam(
expr_node * pExpr )
{
return SetParam( new expr_param( pExpr ));
}
expr_param *
expr_param::SetLastPeerParam(
expr_param * pParam )
{
expr_param * p = GetNextParam();
if( p )
{
return p->SetLastPeerParam( pParam );
}
else
{
return SetNextParam( pParam );
}
}
/**
** This routine attempts to recreate the string to be eaten by c compilers.
** If the user specified a string with a quote inside, substitute with an
** escape character. The new string with possible escapes will ALWAYS be
** smaller than the older one, so allocating the same amount of space is
** enough.
**/
char *
MakeNewStringWithProperQuoting(
char * pSrc )
{
char * pResult = new char [ strlen( pSrc ) + 1];
char ch;
char * pDest = pResult;
while( ( ch = *pSrc++ ) != 0 )
{
*pDest = ch;
if( ch == '\\')
{
if( ( ch = *pSrc++ ) != 0 )
{
if( (ch == '"') || ( ch == '\\') )
{
*pDest = ch;
}
else
{
*pDest++ = '\\';
*pDest = ch;
}
}
else
break;
}
pDest++;
}
*pDest = '\0';
return pResult;
}
// routines for expr_variable...
// constructor - see if the type is constant
expr_variable::expr_variable( PNAME p, node_skl * pT )
{
SetName( p );
SetType( pT );
SetConstant( FALSE );
SetPrefix( NULL );
}
// resolve forwards on GetType
node_skl *
expr_variable::GetType( void )
{
if ( pType )
{
if ( pType->NodeKind() == NODE_FORWARD )
{
node_forward* pFwd = (node_forward *) pType;
// (permanently) resolve the forward
pType = pFwd->ResolveFDecl();
// if it couldn't be resolved, put back the forward
if ( !pType )
{
pType = pFwd;
}
}
}
return pType;
}
// named constant routines...
// evaluate the variable if it is a constant
EXPR_VALUE
expr_named_constant::GetValue()
{
node_skl * pT = GetType();
NODE_T Kind = ( pT ) ? (NODE_T) pT->NodeKind()
: (NODE_T) NODE_ILLEGAL;
if ( !IsConstant() )
return 0;
// identifiers may be const... Forwards are assumed NOT const
if ( Kind == NODE_ID )
{
node_id * pId = (node_id *) pT;
node_skl * pType = pId->GetBasicType();
EXPR_VALUE Result = (pId->GetExpr()->GetValue() );
return (pType) ? pType->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result;
}
else if ( Kind == NODE_LABEL )
{
return ( (node_label *) pT)->GetValue();
}
MIDL_ASSERT(FALSE);
return 0; // for the compiler...
}
// evaluate the variable if it is a constant
expr_node *
expr_named_constant::GetExpr()
{
node_skl * pT = GetType();
NODE_T Kind = ( pT ) ? (NODE_T) pT->NodeKind()
: (NODE_T) NODE_ILLEGAL;
if ( !IsConstant() )
return 0;
// identifiers may be const... Forwards are assumed NOT const
if ( Kind == NODE_ID )
{
node_id * pId = (node_id *) pT;
return pId->GetExpr();
}
else if ( Kind == NODE_LABEL )
{
return ( (node_label *) pT)->pExpr;
}
MIDL_ASSERT(FALSE);
return 0; // for the compiler...
}
/******************************************************************************
* expression list handler
*****************************************************************************/
expr_list::expr_list()
{
SetConstant( TRUE );
}
STATUS_T
expr_list::GetPeer(
expr_node ** ppExpr )
{
return (GetNext( (void **)ppExpr ) );
}
STATUS_T
expr_list::SetPeer(
expr_node * pExpr )
{
if ( pExpr && !pExpr->IsConstant() )
SetConstant( FALSE );
return Insert( (void *) pExpr );
}
EXPR_VALUE
expr_u_arithmetic::GetValue()
{
EXPR_VALUE LeftValue = GetLeft()->GetValue();
EXPR_VALUE Result;
switch ( GetOperator() )
{
case OP_UNARY_PLUS:
{
Result = LeftValue;
break;
}
case OP_UNARY_MINUS:
{
if (IsStringConstant())
{
char * szVal = (char *)LeftValue;
char * szNewVal = new char[strlen(szVal)+2];
szNewVal[0] = '-';
strcpy(szNewVal + 1, szVal);
Result = (EXPR_VALUE) szNewVal;
}
else
{
Result = -LeftValue;
}
break;
}
default:
{
Result = 0;
break;
}
}
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result;
}
EXPR_VALUE
expr_u_not::GetValue()
{
EXPR_VALUE Result = !GetLeft()->GetValue();
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result;
}
EXPR_VALUE
expr_u_complement::GetValue()
{
EXPR_VALUE Result = ~ GetLeft()->GetValue();
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result;
}
EXPR_VALUE
expr_cast::GetValue()
{
return GetType()->
ConvertMyKindOfValueToEXPR_VALUE(GetLeft()->GetValue());
}
EXPR_VALUE
expr_constant::GetValue()
{
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Value.I64)
: Value.I64;
}
EXPR_VALUE
expr_sizeof::GetValue()
{
return (pType) ? pType->GetSize() : 0;
}
EXPR_VALUE
expr_alignof::GetValue()
{
return (pType) ? pType->GetAlign() : 0;
}
EXPR_VALUE
expr_b_arithmetic::GetValue()
{
EXPR_VALUE LeftValue = GetLeft()->GetValue();
EXPR_VALUE RightValue = GetRight()->GetValue();
EXPR_VALUE Result;
switch ( GetOperator() )
{
case OP_PLUS:
{
Result = LeftValue + RightValue;
break;
}
case OP_MINUS:
{
Result = LeftValue - RightValue;
break;
}
case OP_STAR:
{
Result = LeftValue * RightValue;
break;
}
case OP_SLASH:
{
if (RightValue == 0)
Result = 1;
else
Result = LeftValue / RightValue;
break;
}
case OP_MOD:
{
if ( 0 == RightValue )
Result = 1;
else
Result = LeftValue % RightValue;
break;
}
default:
{
Result = 0;
break;
}
}
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result ;
}
EXPR_VALUE
expr_b_logical::GetValue()
{
EXPR_VALUE LeftValue = GetLeft()->GetValue();
EXPR_VALUE RightValue = GetRight()->GetValue();
EXPR_VALUE Result;
switch ( GetOperator() )
{
case OP_LOGICAL_AND:
{
Result = LeftValue && RightValue;
break;
}
case OP_LOGICAL_OR:
{
Result = LeftValue || RightValue;
break;
}
default:
{
Result = 0;
break;
}
}
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result ;
}
EXPR_VALUE
expr_relational::GetValue()
{
EXPR_VALUE LeftValue = GetLeft()->GetValue();
EXPR_VALUE RightValue = GetRight()->GetValue();
EXPR_VALUE Result;
switch ( GetOperator() )
{
// gaj - we implicitly assume signed types
case OP_LESS:
{
Result = LeftValue < RightValue;
break;
}
case OP_LESS_EQUAL:
{
Result = LeftValue <= RightValue;
break;
}
case OP_GREATER_EQUAL:
{
Result = LeftValue >= RightValue;
break;
}
case OP_GREATER:
{
Result = LeftValue > RightValue;
break;
}
case OP_EQUAL:
{
Result = LeftValue == RightValue;
break;
}
case OP_NOT_EQUAL:
{
Result = LeftValue != RightValue;
break;
}
default:
{
Result = 0;
break;
}
}
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result;
}
EXPR_VALUE
expr_shift::GetValue()
{
EXPR_VALUE LeftValue = GetLeft()->GetValue();
EXPR_VALUE RightValue = GetRight()->GetValue();
EXPR_VALUE Result;
switch ( GetOperator() )
{
// gaj - we implicitly assume signed types
case OP_LEFT_SHIFT:
{
Result = LeftValue << RightValue;
break;
}
case OP_RIGHT_SHIFT:
{
Result = LeftValue >> RightValue;
break;
}
default:
{
Result = 0;
break;
}
}
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result;
}
EXPR_VALUE
expr_bitwise::GetValue()
{
EXPR_VALUE LeftValue = GetLeft()->GetValue();
EXPR_VALUE RightValue = GetRight()->GetValue();
EXPR_VALUE Result;
switch ( GetOperator() )
{
// gaj - we implicitly assume signed types
case OP_AND:
{
Result = LeftValue & RightValue;
break;
}
case OP_OR:
{
Result = LeftValue | RightValue;
break;
}
case OP_XOR:
{
Result = LeftValue ^ RightValue;
break;
}
default:
{
Result = 0;
break;
}
}
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result ;
}
EXPR_VALUE
expr_ternary::GetValue()
{
EXPR_VALUE RelValue = GetRelational()->GetValue();
EXPR_VALUE Result;
if ( RelValue )
Result = GetLeft()->GetValue();
else
Result = GetRight()->GetValue();
return (GetType()) ? GetType()->ConvertMyKindOfValueToEXPR_VALUE(Result) : Result;
}
////////////////////////////////////////////////////////////////////////
// analysis of expressions
//
void
expr_node::ExprAnalyze( EXPR_CTXT * pExprCtxt )
{
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
}
//
// determine the type of the expression
//
void
expr_op_unary::DetermineType()
{
node_skl * pLeftType;
if ( !GetLeft() )
{
return;
}
pLeftType = GetLeft()->AlwaysGetType();
SetConstant( GetLeft()->IsConstant() );
switch ( GetOperator() )
{
case OP_UNARY_PLUS:
case OP_UNARY_COMPLEMENT:
case OP_UNARY_MINUS:
case OP_PRE_INCR:
case OP_PRE_DECR:
case OP_POST_INCR:
case OP_POST_DECR:
{
// same type
SetType( pLeftType );
break;
}
case OP_UNARY_NOT:
{
node_skl * pTmpType;
GetBaseTypeNode( &pTmpType, SIGN_UNDEF, SIZE_UNDEF, TYPE_BOOLEAN );
SetType( pTmpType );
break;
}
case OP_UNARY_CAST:
{
SetType( GetType() );
break;
}
case OP_UNARY_SIZEOF:
case OP_UNARY_ALIGNOF:
{
node_skl * pTmpType;
GetBaseTypeNode( &pTmpType, SIGN_SIGNED, SIZE_UNDEF, TYPE_INT );
SetType( pTmpType );
SetConstant( TRUE );
break;
}
case OP_UNARY_INDIRECTION:
{
node_skl * pNode = pLeftType;
if ( pNode->NodeKind() != NODE_POINTER )
{
// probably the param or field; look down
pNode = pNode->GetBasicType();
}
// now get the pointee
pNode = pNode->GetBasicType();
SetType( pNode );
break;
}
case OP_UNARY_AND:
{
node_pointer * pPtr = new node_pointer;
pPtr->SetChild( pLeftType );
SetType( pPtr );
break;
}
default:
{
break;
}
} // end of switch
}
void
expr_op_unary::ExprAnalyze( EXPR_CTXT * pExprCtxt )
{
EXPR_CTXT LeftCtxt( pExprCtxt );
if ( GetLeft() )
{
GetLeft()->ExprAnalyze( &LeftCtxt );
pExprCtxt->MergeUpFlags( &LeftCtxt );
SetConstant( GetLeft()->IsConstant() );
}
else if ( GetOperator() != OP_UNARY_SIZEOF && GetOperator() != OP_UNARY_ALIGNOF)
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
// do type compatibility stuff
switch ( GetOperator() )
{
case OP_UNARY_PLUS:
case OP_UNARY_COMPLEMENT:
{
// same type
pExprCtxt->pType = LeftCtxt.pType;
pExprCtxt->TypeInfo = LeftCtxt.TypeInfo;
pExprCtxt->fIntegral = LeftCtxt.fIntegral;
SetType( pExprCtxt->pType );
break;
}
case OP_UNARY_MINUS:
{
node_skl * pTmp;
pExprCtxt->pType = LeftCtxt.pType;
pExprCtxt->TypeInfo = LeftCtxt.TypeInfo;
pExprCtxt->TypeInfo.TypeSign = SIGN_SIGNED;
pExprCtxt->fIntegral = LeftCtxt.fIntegral;
GetBaseTypeNode( &pTmp, pExprCtxt->TypeInfo );
if ( pTmp )
pExprCtxt->pType = pTmp;
SetType( pExprCtxt->pType );
break;
}
case OP_UNARY_NOT:
{
pExprCtxt->TypeInfo.TypeSize = SIZE_UNDEF;
pExprCtxt->TypeInfo.BaseType = TYPE_BOOLEAN;
pExprCtxt->TypeInfo.TypeSign = SIGN_UNDEF;
GetBaseTypeNode( &(pExprCtxt->pType ), pExprCtxt->TypeInfo );
pExprCtxt->fIntegral = TRUE;
SetType( pExprCtxt->pType );
break;
}
case OP_UNARY_CAST:
{
SetType( GetType() );
break;
}
case OP_UNARY_SIZEOF:
case OP_UNARY_ALIGNOF:
{
pExprCtxt->TypeInfo.TypeSize = SIZE_UNDEF;
pExprCtxt->TypeInfo.BaseType = TYPE_INT;
pExprCtxt->TypeInfo.TypeSign = SIGN_SIGNED;
GetBaseTypeNode( &(pExprCtxt->pType ), pExprCtxt->TypeInfo);
pExprCtxt->fIntegral = TRUE;
SetType( pExprCtxt->pType );
break;
}
case OP_UNARY_INDIRECTION:
{
node_skl * pNode = GetLeft()->GetType();
node_skl * pOrigNode = pNode;
node_ptr_attr * pPtrAttr;
PTRTYPE PtrKind = PTR_UNKNOWN;
if ( pNode->FInSummary( ATTR_PTR_KIND ) )
{
pPtrAttr = (node_ptr_attr *)
((named_node *)pNode)->GetAttribute( ATTR_PTR_KIND );
PtrKind = pPtrAttr->GetPtrKind();
}
if ( pNode->FInSummary( ATTR_IGNORE ) )
{
SEM_ANALYSIS_CTXT * pCtxt = pExprCtxt->GetCtxt();
// Only complain about this on the actual type, not every
// single use of the type.
if ( !pCtxt->AnyAncestorBits( IN_PARAM_LIST ) )
{
SemError(
pNode,
*pCtxt,
CORRELATION_DERIVES_FROM_IGNORE_POINTER,
NULL );
}
}
if ( pNode->NodeKind() != NODE_POINTER )
{
// probably the param or field; look down
pNode = pNode->GetBasicType();
}
if ( pNode->NodeKind() != NODE_POINTER )
{
// error
pNode = NULL;
}
else
{
// check things about type of pointer
if ( PtrKind == PTR_UNKNOWN )
{
node_interface * pIntf = pOrigNode->GetMyInterfaceNode();
if ( pOrigNode->NodeKind() == NODE_PARAM )
PtrKind = PTR_REF;
else if ( pIntf->FInSummary( ATTR_PTR_KIND ) )
{
pPtrAttr = (node_ptr_attr *)
pIntf->GetAttribute( ATTR_PTR_KIND );
PtrKind = pPtrAttr->GetPtrKind();
}
else
{
pIntf = pExprCtxt->GetCtxt()->GetInterfaceNode();
if ( pIntf->FInSummary( ATTR_PTR_KIND ) )
{
pPtrAttr = (node_ptr_attr *)
pIntf->GetAttribute( ATTR_PTR_KIND );
PtrKind = pPtrAttr->GetPtrKind();
}
else
{
if (pCommand->IsSwitchDefined( SWITCH_MS_EXT ) )
{
PtrKind = PTR_UNIQUE;
}
else
{
PtrKind = PTR_FULL;
}
}
}
}
if ( ( PtrKind == PTR_FULL ) ||
( PtrKind == PTR_UNIQUE ) )
{
SEM_ANALYSIS_CTXT * pCtxt = pExprCtxt->GetCtxt();
pExprCtxt->SetUpFlags( EX_PTR_FULL_UNIQUE );
SemError( pCtxt->GetParent(),
*pCtxt,
SIZE_LENGTH_SW_UNIQUE_OR_FULL,
NULL );
}
pNode = pNode->GetBasicType();
}
SetType( pNode );
break;
}
case OP_UNARY_AND:
{
if ( GetType() )
break;
node_pointer * pPtr = new node_pointer;
pPtr->SetChild( GetLeft()->GetType() );
SetType( pPtr );
break;
}
case OP_PRE_INCR:
case OP_PRE_DECR:
case OP_POST_INCR:
case OP_POST_DECR:
{
SetType( GetLeft()->GetType() );
break;
}
default:
{
break;
}
} // end of switch
pExprCtxt->pType = GetType();
// compute the value
if ( !pExprCtxt->AnyUpFlags( EX_VALUE_INVALID ) )
{
// tbd - update value from LeftCtxt
EXPR_VALUE & LeftValue = LeftCtxt.Value();
EXPR_VALUE & Result = pExprCtxt->Value();
switch ( GetOperator() )
{
case OP_UNARY_PLUS:
{
Result = LeftValue;
break;
}
case OP_UNARY_MINUS:
{
Result = -LeftValue;
break;
}
case OP_UNARY_NOT:
{
Result = !LeftValue;
break;
}
case OP_UNARY_COMPLEMENT:
{
Result = ~LeftValue;
break;
}
case OP_UNARY_CAST:
{
Result = LeftValue;
break;
}
case OP_UNARY_SIZEOF:
case OP_UNARY_ALIGNOF:
{
Result = GetValue();
break;
}
case OP_UNARY_INDIRECTION:
case OP_UNARY_AND:
case OP_PRE_INCR:
case OP_PRE_DECR:
case OP_POST_INCR:
case OP_POST_DECR:
{
SetConstant( FALSE );
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
break;
}
default:
{
SetConstant( FALSE );
Result = 0;
break;
}
} // end of case
} // end of if valid
}
//
// determine the type of the expression
//
void
expr_op_binary::DetermineType()
{
node_skl * pLeftType = NULL;
node_skl * pRightType = NULL;
if ( GetLeft() )
pLeftType = GetLeft()->AlwaysGetType();
if ( GetRight() )
pRightType = GetRight()->AlwaysGetType();
SetConstant( GetRight()->IsConstant() && GetLeft()->IsConstant() );
////////////////////////////////////////////////////////////////////////
// do type compatibility stuff
switch ( GetOperator() )
{
case OP_PLUS:
case OP_MINUS:
case OP_STAR:
case OP_MOD:
// gaj - we implicitly assume signed types
case OP_LEFT_SHIFT:
case OP_RIGHT_SHIFT:
case OP_AND:
case OP_OR:
case OP_XOR:
case OP_SLASH:
{
// tbd - for now, just grab one of the types
if ( !pRightType ||
(pLeftType &&
(pLeftType->GetSize() >= pRightType->GetSize() ) ) )
{
SetType( pLeftType );
}
else if ( pRightType )
{
SetType( pRightType );
}
break;
}
case OP_LOGICAL_AND:
case OP_LOGICAL_OR:
// gaj - we implicitly assume signed types
case OP_LESS:
case OP_LESS_EQUAL:
case OP_GREATER_EQUAL:
case OP_GREATER:
case OP_EQUAL:
case OP_NOT_EQUAL:
{
node_skl * pTmpType;
GetBaseTypeNode( &pTmpType, SIGN_UNDEF, SIZE_UNDEF, TYPE_BOOLEAN );
SetType( pTmpType );
break;
}
default:
{
break;
}
}
}
void
expr_op_binary::ExprAnalyze( EXPR_CTXT * pExprCtxt )
{
EXPR_CTXT LeftCtxt( pExprCtxt );
EXPR_CTXT RightCtxt( pExprCtxt );
if ( GetLeft() )
{
GetLeft()->ExprAnalyze( &LeftCtxt );
pExprCtxt->MergeUpFlags( &LeftCtxt );
SetConstant( IsConstant() && GetLeft()->IsConstant() );
}
else
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
if ( GetRight() )
{
GetRight()->ExprAnalyze( &RightCtxt );
pExprCtxt->MergeUpFlags( &RightCtxt );
SetConstant( IsConstant() && GetRight()->IsConstant() );
// check here for div by zero ( could be var / 0 )
if ( !RightCtxt.AnyUpFlags( EX_VALUE_INVALID ) &&
( GetOperator() == OP_SLASH ) &&
( RightCtxt.Value() == 0 ) )
{
SemError( pExprCtxt->GetNode(),
*(pExprCtxt->GetCtxt()),
EXPR_DIV_BY_ZERO,
NULL );
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
}
}
else
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
////////////////////////////////////////////////////////////////////////
// do type compatibility stuff
switch ( GetOperator() )
{
case OP_PLUS:
case OP_MINUS:
case OP_STAR:
case OP_MOD:
// gaj - we implicitly assume signed types
case OP_LEFT_SHIFT:
case OP_RIGHT_SHIFT:
case OP_AND:
case OP_OR:
case OP_XOR:
case OP_SLASH:
{
// tbd - for now, just grab the bigger of the types
if ( !RightCtxt.pType ||
(LeftCtxt.pType &&
(LeftCtxt.pType->GetSize() >= RightCtxt.pType->GetSize() ) ) )
{
pExprCtxt->pType = LeftCtxt.pType;
pExprCtxt->TypeInfo = LeftCtxt.TypeInfo;
pExprCtxt->fIntegral = LeftCtxt.fIntegral;
SetType( pExprCtxt->pType );
}
else if ( RightCtxt.pType )
{
pExprCtxt->pType = RightCtxt.pType;
pExprCtxt->TypeInfo = RightCtxt.TypeInfo;
pExprCtxt->fIntegral = RightCtxt.fIntegral;
SetType( pExprCtxt->pType );
}
break;
}
case OP_LOGICAL_AND:
case OP_LOGICAL_OR:
// gaj - we implicitly assume signed types
case OP_LESS:
case OP_LESS_EQUAL:
case OP_GREATER_EQUAL:
case OP_GREATER:
case OP_EQUAL:
case OP_NOT_EQUAL:
{
pExprCtxt->TypeInfo.TypeSize = SIZE_UNDEF;
pExprCtxt->TypeInfo.BaseType = TYPE_BOOLEAN;
pExprCtxt->TypeInfo.TypeSign = SIGN_UNDEF;
GetBaseTypeNode( &(pExprCtxt->pType ), pExprCtxt->TypeInfo );
pExprCtxt->fIntegral = TRUE;
SetType( pExprCtxt->pType );
break;
}
default:
{
break;
}
}
////////////////////////////////////////////////////////////////////////
// compute the value
if ( !pExprCtxt->AnyUpFlags( EX_VALUE_INVALID ) )
{
// update value directly from LeftCtxt and RightCtxt
EXPR_VALUE & LeftValue = LeftCtxt.Value();
EXPR_VALUE & RightValue = RightCtxt.Value();
EXPR_VALUE & Result = pExprCtxt->Value();
switch ( GetOperator() )
{
case OP_PLUS:
{
Result = LeftValue + RightValue;
break;
}
case OP_MINUS:
{
Result = LeftValue - RightValue;
break;
}
case OP_STAR:
{
Result = LeftValue * RightValue;
break;
}
case OP_SLASH:
{
if (RightValue == 0)
Result = 0;
else
Result = LeftValue / RightValue;
break;
}
case OP_MOD:
{
Result = LeftValue % RightValue;
break;
}
case OP_LOGICAL_AND:
{
Result = LeftValue && RightValue;
break;
}
case OP_LOGICAL_OR:
{
Result = LeftValue || RightValue;
break;
}
// gaj - we implicitly assume signed types
case OP_LESS:
{
Result = LeftValue < RightValue;
break;
}
case OP_LESS_EQUAL:
{
Result = LeftValue <= RightValue;
break;
}
case OP_GREATER_EQUAL:
{
Result = LeftValue >= RightValue;
break;
}
case OP_GREATER:
{
Result = LeftValue > RightValue;
break;
}
case OP_EQUAL:
{
Result = LeftValue == RightValue;
break;
}
case OP_NOT_EQUAL:
{
Result = LeftValue != RightValue;
break;
}
// gaj - we implicitly assume signed types
case OP_LEFT_SHIFT:
{
Result = LeftValue << RightValue;
break;
}
case OP_RIGHT_SHIFT:
{
Result = LeftValue >> RightValue;
break;
}
case OP_AND:
{
Result = LeftValue & RightValue;
break;
}
case OP_OR:
{
Result = LeftValue | RightValue;
break;
}
case OP_XOR:
{
Result = LeftValue ^ RightValue;
break;
}
default:
{
Result = 0;
break;
}
}
}
}
//
// determine the type of the expression
//
void
expr_ternary::DetermineType()
{
node_skl * pLeftType = NULL;
node_skl * pRightType = NULL;
if ( GetLeft() )
pLeftType = GetLeft()->AlwaysGetType();
if ( GetRight() )
pRightType = GetRight()->AlwaysGetType();
SetConstant( GetRight()->IsConstant() && GetLeft()->IsConstant() );
if ( pLeftType )
SetType( pLeftType );
else if ( pRightType )
SetType( pRightType );
}
void
expr_ternary::ExprAnalyze( EXPR_CTXT * pExprCtxt )
{
EXPR_CTXT LeftCtxt( pExprCtxt );
EXPR_CTXT RightCtxt( pExprCtxt );
EXPR_CTXT RelCtxt( pExprCtxt );
if ( GetLeft() )
{
GetLeft()->ExprAnalyze( &LeftCtxt );
pExprCtxt->MergeUpFlags( &LeftCtxt );
SetConstant( IsConstant() && GetLeft()->IsConstant() );
}
else
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
if ( GetRight() )
{
GetRight()->ExprAnalyze( &RightCtxt );
pExprCtxt->MergeUpFlags( &RightCtxt );
SetConstant( IsConstant() && GetRight()->IsConstant() );
}
else
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
if ( GetRelational() )
{
GetRelational()->ExprAnalyze( &RelCtxt );
pExprCtxt->MergeUpFlags( &RelCtxt );
SetConstant( IsConstant() && GetRelational()->IsConstant() );
}
else
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
// tbd - get the type from the left or right of the ':'
if ( LeftCtxt.pType )
{
pExprCtxt->pType = LeftCtxt.pType;
pExprCtxt->TypeInfo = LeftCtxt.TypeInfo;
pExprCtxt->fIntegral = LeftCtxt.fIntegral;
SetType( pExprCtxt->pType );
}
else if ( RightCtxt.pType )
{
pExprCtxt->pType = RightCtxt.pType;
pExprCtxt->TypeInfo = RightCtxt.TypeInfo;
pExprCtxt->fIntegral = RightCtxt.fIntegral;
SetType( pExprCtxt->pType );
}
else
SetType( NULL );
////////////////////////////////////////////////////////////////////////
// compute the value
if ( !pExprCtxt->AnyUpFlags( EX_VALUE_INVALID ) )
{
// update value directly from LeftCtxt and RightCtxt
EXPR_VALUE & LeftValue = LeftCtxt.Value();
EXPR_VALUE & RightValue = RightCtxt.Value();
EXPR_VALUE & RelValue = RelCtxt.Value();
EXPR_VALUE & Result = pExprCtxt->Value();
Result = (RelValue) ? LeftValue : RightValue;
}
}
//
// determine the type of the expression
//
void
expr_variable::DetermineType()
{
if ( pType->NodeKind() == NODE_FORWARD )
{
node_forward * pFwd = (node_forward *) pType;
// (permanently) resolve the forward
pType = pFwd->ResolveFDecl();
// This appears to be a better fix for the problem of unresolved
// variables in async size expressions than the NULL type pointer check
// in Fixup[Begin|Finish]ProcExpr in front\copyto.cxx. However, at this
// time we don't fully understand the implications of this change while
// the other is localized to the async_uuid interfaces only.
// e.g. ([in] long size, [in, size_is(huh)] long *p)
// 03-May-99 MikeW
/*
// if it couldn't be resolved, put back the forward
if ( !pType )
{
pType = pFwd;
}
*/
}
}
void
expr_variable::ExprAnalyze( EXPR_CTXT * pExprCtxt )
{
pExprCtxt->SetUpFlags( EX_VALUE_INVALID );
pExprCtxt->SetUpFlags( EX_NON_NUMERIC );
if ( !pType )
{
pExprCtxt->SetUpFlags( EX_UNSAT_FWD );
return;
}
if ( pType->NodeKind() == NODE_FORWARD )
{
node_forward * pFwd = (node_forward *) pType;
// (permanently) resolve the forward
pType = pFwd->ResolveFDecl();
// if it couldn't be resolved, put back the forward
if ( !pType )
{
pExprCtxt->SetUpFlags( EX_UNSAT_FWD );
pExprCtxt->TypeInfo.TypeSize = SIZE_UNDEF;
pExprCtxt->TypeInfo.BaseType = TYPE_INT;
pExprCtxt->TypeInfo.TypeSign = SIGN_SIGNED;
GetBaseTypeNode( &pType, pExprCtxt->TypeInfo);
pExprCtxt->pType = pType;
return;
}
}
// do type compatibility stuff
pExprCtxt->pType = pType;
pExprCtxt->TypeInfo.TypeSize = SIZE_UNDEF;
pExprCtxt->TypeInfo.BaseType = TYPE_UNDEF;
pExprCtxt->TypeInfo.TypeSign = SIGN_UNDEF;
pExprCtxt->fIntegral = FALSE; // for now...
if ( ( pType->NodeKind() == NODE_PARAM ) &&
pType->FInSummary( ATTR_OUT ) &&
!pType->FInSummary( ATTR_IN ) )
pExprCtxt->SetUpFlags( EX_OUT_ONLY_PARAM );
}
//
// determine the type of the expression
//
void
expr_named_constant::DetermineType()
{
// do type compatibility stuff
if ( !GetType() )
{
SetType( GetExpr()->AlwaysGetType() );
}
}
void
expr_named_constant::ExprAnalyze( EXPR_CTXT * pExprCtxt )
{
// named constants shouldn't be folded away
pExprCtxt->SetUpFlags( EX_NON_NUMERIC );
// update value
pExprCtxt->Value() = GetValue();
// do type compatibility stuff
if ( GetType() )
{
pExprCtxt->pType = GetType();
pExprCtxt->TypeInfo.TypeSize = SIZE_UNDEF;
pExprCtxt->TypeInfo.BaseType = TYPE_UNDEF;
pExprCtxt->TypeInfo.TypeSign = SIGN_UNDEF;
pExprCtxt->fIntegral = FALSE; // for now...
}
else
{
EXPR_CTXT LeftCtxt( pExprCtxt );
expr_node * pExpr = GetExpr();
pExpr->ExprAnalyze( &LeftCtxt );
pExprCtxt->pType = LeftCtxt.pType;
pExprCtxt->TypeInfo = LeftCtxt.TypeInfo;
pExprCtxt->fIntegral = LeftCtxt.fIntegral;
SetType( pExprCtxt->pType );
}
}
//
// determine the type of the expression
//
void
expr_constant::DetermineType()
{
node_skl* pNewType = 0;
// do type compatibility stuff
if ( GetType() )
return;
// do type compatibility stuff
switch (Format)
{
case VALUE_TYPE_STRING:
{
node_skl * pBottomType;
GetBaseTypeNode( &pBottomType,
SIGN_SIGNED,
SIZE_CHAR,
TYPE_INT );
pNewType = new node_pointer;
pNewType->SetChild( pBottomType );
break;
}
case VALUE_TYPE_WSTRING:
{
node_skl * pBottomType;
SymKey SKey( "wchar_t", NAME_DEF );
pBottomType = pBaseSymTbl->SymSearch( SKey );
pNewType = new node_pointer;
pNewType->SetChild( pBottomType );
break;
}
case VALUE_TYPE_CHAR:
{
GetBaseTypeNode( &pNewType,
SIGN_SIGNED,
SIZE_CHAR,
TYPE_INT );
break;
}
case VALUE_TYPE_WCHAR:
{
SymKey SKey( "wchar_t", NAME_DEF );
pNewType = pBaseSymTbl->SymSearch( SKey );
break;
}
case VALUE_TYPE_NUMERIC:
case VALUE_TYPE_HEX:
case VALUE_TYPE_OCTAL:
{
GetBaseTypeNode( &pNewType,
SIGN_SIGNED,
SIZE_UNDEF,
TYPE_INT );
break;
}
case VALUE_TYPE_NUMERIC_U:
case VALUE_TYPE_HEX_U:
case VALUE_TYPE_OCTAL_U:
{
GetBaseTypeNode( &pNewType,
SIGN_UNSIGNED,
SIZE_SHORT,
TYPE_INT );
break;
}
case VALUE_TYPE_NUMERIC_LONG:
case VALUE_TYPE_HEX_LONG:
case VALUE_TYPE_OCTAL_LONG:
{
GetBaseTypeNode( &pNewType,
SIGN_SIGNED,
SIZE_LONG,
TYPE_INT );
break;
}
case VALUE_TYPE_NUMERIC_ULONG:
case VALUE_TYPE_HEX_ULONG:
case VALUE_TYPE_OCTAL_ULONG:
{
GetBaseTypeNode( &pNewType,
SIGN_UNSIGNED,
SIZE_LONG,
TYPE_INT );
break;
}
case VALUE_TYPE_BOOL:
{
GetBaseTypeNode( &pNewType,
SIGN_UNDEF,
SIZE_UNDEF,
TYPE_BOOLEAN );
break;
}
case VALUE_TYPE_FLOAT:
{
GetBaseTypeNode( &pNewType,
SIGN_UNDEF,
SIZE_UNDEF,
TYPE_FLOAT );
break;
}
case VALUE_TYPE_DOUBLE:
{
GetBaseTypeNode( &pNewType,
SIGN_UNDEF,
SIZE_UNDEF,
TYPE_DOUBLE );
break;
}
default:
break;
}
SetType( pNewType );
}
void
expr_constant::ExprAnalyze( EXPR_CTXT * pExprCtxt )
{
// update value
pExprCtxt->Value() = GetValue();
if ( GetType() )
{
pExprCtxt->pType = GetType();
pExprCtxt->TypeInfo.TypeSize = SIZE_UNDEF;
pExprCtxt->TypeInfo.BaseType = TYPE_UNDEF;
pExprCtxt->TypeInfo.TypeSign = SIGN_UNDEF;
pExprCtxt->fIntegral = FALSE; // for now...
return;
}
// do type compatibility stuff
switch (Format)
{
case VALUE_TYPE_STRING:
{
node_skl * pBottomType;
GetBaseTypeNode( &pBottomType,
SIGN_SIGNED,
SIZE_CHAR,
TYPE_INT );
pExprCtxt->pType = new node_pointer;
pExprCtxt->pType->SetChild( pBottomType );
break;
}
case VALUE_TYPE_WSTRING:
{
node_skl * pBottomType;
SymKey SKey( "wchar_t", NAME_DEF );
pBottomType = pBaseSymTbl->SymSearch( SKey );
pExprCtxt->pType = new node_pointer;
pExprCtxt->pType->SetChild( pBottomType );
break;
}
case VALUE_TYPE_CHAR:
{
GetBaseTypeNode( &pExprCtxt->pType,
SIGN_SIGNED,
SIZE_CHAR,
TYPE_INT );
break;
}
case VALUE_TYPE_WCHAR:
{
SymKey SKey( "wchar_t", NAME_DEF );
pExprCtxt->pType = pBaseSymTbl->SymSearch( SKey );
break;
}
case VALUE_TYPE_NUMERIC:
case VALUE_TYPE_HEX:
case VALUE_TYPE_OCTAL:
{
short RealSize = SIZE_HYPER;
__int64 val = GetValue();
if ( (val <= 127) && (val >= -128 ) )
RealSize = SIZE_CHAR;
else if ( (val <= _I16_MAX) && (val >= _I16_MIN ) )
RealSize = SIZE_SHORT;
else if ( (val <= _I32_MAX) && (val >= _I32_MIN ) )
RealSize = SIZE_LONG;
GetBaseTypeNode( &pExprCtxt->pType,
SIGN_SIGNED,
RealSize,
TYPE_INT );
break;
}
case VALUE_TYPE_NUMERIC_U:
case VALUE_TYPE_HEX_U:
case VALUE_TYPE_OCTAL_U:
{
short RealSize = SIZE_LONG;
unsigned long val = (unsigned long) GetValue();
if ( val <= 255 )
RealSize = SIZE_CHAR;
else if ( val <= 65536 )
RealSize = SIZE_SHORT;
GetBaseTypeNode( &pExprCtxt->pType,
SIGN_UNSIGNED,
RealSize,
TYPE_INT );
break;
}
case VALUE_TYPE_NUMERIC_LONG:
case VALUE_TYPE_HEX_LONG:
case VALUE_TYPE_OCTAL_LONG:
{
GetBaseTypeNode( &pExprCtxt->pType,
SIGN_SIGNED,
SIZE_LONG,
TYPE_INT );
break;
}
case VALUE_TYPE_NUMERIC_ULONG:
case VALUE_TYPE_HEX_ULONG:
case VALUE_TYPE_OCTAL_ULONG:
{
GetBaseTypeNode( &pExprCtxt->pType,
SIGN_UNSIGNED,
SIZE_LONG,
TYPE_INT );
break;
}
case VALUE_TYPE_BOOL:
{
GetBaseTypeNode( &pExprCtxt->pType,
SIGN_UNDEF,
SIZE_UNDEF,
TYPE_BOOLEAN );
break;
}
case VALUE_TYPE_FLOAT:
{
GetBaseTypeNode( &pExprCtxt->pType,
SIGN_UNDEF,
SIZE_UNDEF,
TYPE_FLOAT );
break;
}
case VALUE_TYPE_DOUBLE:
{
GetBaseTypeNode( &pExprCtxt->pType,
SIGN_UNDEF,
SIZE_UNDEF,
TYPE_DOUBLE );
break;
}
default:
break;
}
SetType( pExprCtxt->pType );
}
//
// determine the type of the expression
//
void
expr_init_list::DetermineType()
{
SetType( pExpr->AlwaysGetType() );
}
void
expr_init_list::ExprAnalyze( EXPR_CTXT * pExprCtxt )
{
// tbd - for now only process first element
pExpr->ExprAnalyze( pExprCtxt );
SetConstant( pExpr->IsConstant() );
SetType( pExpr->GetType() );
}
short
expr_op_binary::MakeListOfDerefedVars( ITERATOR& List )
{
if( GetLeft() )
GetLeft()->MakeListOfDerefedVars( List );
if( GetRight() )
GetRight()->MakeListOfDerefedVars( List );
return (short) ITERATOR_GETCOUNT( List );
}
short
expr_u_deref::MakeListOfDerefedVars( ITERATOR& List )
{
expr_node * pLeft = GetLeft();
if( !pLeft ) return 0;
if( pLeft->IsAVariable() )
ITERATOR_INSERT( List, pLeft );
else if( pLeft->GetOperator() == OP_UNARY_INDIRECTION )
pLeft->MakeListOfDerefedVars( List );
return ITERATOR_GETCOUNT( List );
}
BOOL
expr_b_arithmetic::GetExprValue( SExprValue& v )
{
SExprValue LeftValue = {VALUE_TYPE_UNDEFINED, 0};
SExprValue RightValue = {VALUE_TYPE_UNDEFINED, 0};
BOOL fSuccess;
fSuccess = GetLeft()->GetExprValue( LeftValue ) &&
GetRight()->GetExprValue( RightValue ) &&
(LeftValue.format == VALUE_TYPE_DOUBLE || LeftValue.format == VALUE_TYPE_DOUBLE) &&
(RightValue.format == VALUE_TYPE_DOUBLE || RightValue.format == VALUE_TYPE_DOUBLE);
if (fSuccess)
{
v.format = LeftValue.format == VALUE_TYPE_DOUBLE || RightValue.format == VALUE_TYPE_DOUBLE ?
VALUE_TYPE_DOUBLE : VALUE_TYPE_FLOAT ;
double l = LeftValue.format == VALUE_TYPE_DOUBLE ? LeftValue.d : LeftValue.f ;
double r = RightValue.format == VALUE_TYPE_DOUBLE ? RightValue.d : RightValue.f ;
switch ( GetOperator() )
{
case OP_PLUS:
l += r;
break;
case OP_MINUS:
l -= r;
break;
case OP_STAR:
l *= r;
break;
case OP_SLASH:
__try
{
l /= r;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
fSuccess = FALSE;
}
break;
}
if (v.format == VALUE_TYPE_FLOAT)
{
v.f = (float) l;
}
else if (v.format == VALUE_TYPE_DOUBLE)
{
v.d = l;
}
}
return fSuccess;
}
BOOL
expr_u_arithmetic::GetExprValue( SExprValue& v )
{
SExprValue LeftValue = {VALUE_TYPE_UNDEFINED, 0};
BOOL fSuccess = GetLeft()->GetExprValue( LeftValue );
if (fSuccess)
{
v = LeftValue;
if (GetOperator() == OP_UNARY_MINUS)
{
switch ( v.format )
{
case VALUE_TYPE_FLOAT:
v.f = -LeftValue.f;
break;
case VALUE_TYPE_DOUBLE:
v.d = -LeftValue.d;
break;
default:
fSuccess = FALSE;
break;
}
}
}
return fSuccess;
}
void
expr_node::CopyTo( expr_node* lhs )
{
DetermineType();
lhs->pType = pType;
lhs->fFloatExpr = fFloatExpr;
lhs->fConstant = fConstant;
}
void
expr_constant::CopyTo( expr_node* pExpr )
{
expr_constant* lhs = (expr_constant*) pExpr;
expr_node::CopyTo( lhs );
lhs->Format = Format;
lhs->Value = Value;
}
void
expr_init_list::CopyTo( expr_node* pExpr )
{
expr_init_list* lhs = (expr_init_list*) pExpr;
expr_node::CopyTo( lhs );
lhs->pSibling = (expr_init_list*)pSibling->Clone();
pSibling->CopyTo(lhs->pSibling);
lhs->pExpr = pExpr->Clone();
pExpr->CopyTo(lhs->pExpr);
}
void
expr_operator::CopyTo( expr_node* pExpr )
{
expr_operator* lhs = (expr_operator*) pExpr;
expr_node::CopyTo( lhs );
lhs->Operator = Operator;
}
void
expr_op_binary::CopyTo( expr_node* pExpr )
{
expr_op_binary* lhs = (expr_op_binary*) pExpr;
expr_operator::CopyTo( lhs );
lhs->pLeft = pLeft->Clone();
pLeft->CopyTo(lhs->pLeft);
lhs->pRight = pRight->Clone();
pRight->CopyTo(lhs->pRight);
}
void
expr_param::CopyTo( expr_node* pExpr )
{
expr_param* lhs = (expr_param*) pExpr;
expr_op_binary::CopyTo( lhs );
_STRDUP( lhs->pName, pName );
}
void
expr_op_unary::CopyTo( expr_node* pExpr )
{
expr_op_unary* lhs = (expr_op_unary*) pExpr;
expr_operator::CopyTo( lhs );
lhs->pLeft = pLeft->Clone();
pLeft->CopyTo(lhs->pLeft);
}
void
expr_cast::CopyTo( expr_node* pExpr )
{
expr_cast* lhs = (expr_cast*) pExpr;
expr_op_unary::CopyTo( lhs );
lhs->fEmitModifiers = fEmitModifiers;
lhs->pCastType = pCastType;
}
void
expr_proc_call::CopyTo( expr_node* pExpr )
{
expr_proc_call* lhs = (expr_proc_call*) pExpr;
expr_op_unary::CopyTo( lhs );
_STRDUP( lhs->pName, pName );
lhs->NoOfParams = NoOfParams;
}
void
expr_sizeof::CopyTo( expr_node* pExpr )
{
expr_sizeof* lhs = (expr_sizeof*) pExpr;
expr_op_unary::CopyTo( lhs );
lhs->pType = pType;
}
void
expr_alignof::CopyTo( expr_node* pExpr )
{
expr_alignof* lhs = (expr_alignof*) pExpr;
expr_op_unary::CopyTo( lhs );
lhs->pType = pType;
}
void
expr_ternary::CopyTo( expr_node* pExpr )
{
expr_ternary* lhs = (expr_ternary*) pExpr;
expr_operator::CopyTo( lhs );
lhs->pLeft = pLeft->Clone();
pLeft->CopyTo(lhs->pLeft);
lhs->pRight = pRight->Clone();
pRight->CopyTo(lhs->pRight);
lhs->pRelational = pRelational->Clone();
pRelational->CopyTo(lhs->pRelational);
}
void
expr_variable::CopyTo( expr_node* pExpr )
{
expr_variable* lhs = (expr_variable*) pExpr;
expr_node::CopyTo( lhs );
_STRDUP( lhs->pIDName, pIDName );
_STRDUP( lhs->pPrefix, pPrefix );
}
expr_node*
expr_ternary::Clone()
{
return new expr_ternary(OP_ILLEGAL,0,0,0);
}