mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1863 lines
51 KiB
1863 lines
51 KiB
/*****************************************************************************/
|
|
/** Microsoft LAN Manager **/
|
|
/** Copyright(c) Microsoft Corp., 1987-1990 **/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************
|
|
File : ptrarray.cxx
|
|
Title : semantic analyser for pointer and array nodes
|
|
History :
|
|
08-Aug-1991 VibhasC Created
|
|
|
|
*****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
includes
|
|
****************************************************************************/
|
|
|
|
#include "nulldefs.h"
|
|
extern "C" {
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
}
|
|
#include "nodeskl.hxx"
|
|
#include "ptrarray.hxx"
|
|
#include "miscnode.hxx"
|
|
#include "attrnode.hxx"
|
|
#include "newexpr.hxx"
|
|
#include "cmdana.hxx"
|
|
#include "gramutil.hxx"
|
|
#include "ctxt.hxx"
|
|
#include "baduse.hxx"
|
|
|
|
/****************************************************************************
|
|
local defines
|
|
****************************************************************************/
|
|
|
|
#define ADJUST_OFFSET(Offset, M, AlignFactor) \
|
|
Offset += (M = Offset % AlignFactor) ? (AlignFactor-M) : 0
|
|
|
|
/****************************************************************************
|
|
externs
|
|
****************************************************************************/
|
|
extern ATTR_SUMMARY * pPreAttrArray;
|
|
extern ATTR_SUMMARY * pPostAttrArray;
|
|
extern ATTR_SUMMARY * pPreAttrPointer;
|
|
extern ATTR_SUMMARY * pPostAttrPointer;
|
|
extern CTXTMGR * pGlobalContext;
|
|
extern ATTR_T PtrDefaultAttr;
|
|
extern BOOL fAtLeastOnePtrWODefault;
|
|
extern CMD_ARG * pCommand;
|
|
extern IINFODICT * pInterfaceInfoDict;
|
|
extern BOOL fHasUserBeenWarnedAboutPtr;
|
|
|
|
/****************************************************************************
|
|
extern procedures
|
|
****************************************************************************/
|
|
|
|
extern void SetAttributeVector( ATTR_SUMMARY *,
|
|
ATTR_T );
|
|
extern STATUS_T DoSetAttributes( node_skl *,
|
|
ATTR_SUMMARY *,
|
|
ATTR_SUMMARY *,
|
|
type_node_list *);
|
|
extern void ParseError( STATUS_T, char *);
|
|
|
|
extern void CheckSizeAndLengthTypeMismatch( node_skl *);
|
|
extern ATTR_T XlateToTempPtrAttr( ATTR_T A );
|
|
|
|
/****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
npa procedures
|
|
****************************************************************************/
|
|
void
|
|
npa::UseProcessingAction()
|
|
{
|
|
|
|
/**
|
|
** if the pointer or array has a string attribute invoke the action
|
|
** on the string attribute node
|
|
**/
|
|
|
|
if( FInSummary( ATTR_STRING ) )
|
|
{
|
|
node_string * pStringAttrNode = (node_string *)
|
|
GetAttribute( ATTR_STRING );
|
|
pStringAttrNode->UseProcessingAction();
|
|
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
node_array procedures
|
|
****************************************************************************/
|
|
/****************************************************************************
|
|
The constructor:
|
|
Need to check whether the array is conformant array, if so, set the
|
|
node_state. Also make some sanity checks for array bounds
|
|
****************************************************************************/
|
|
node_array::node_array(
|
|
expr_node * pLBoundExpr,
|
|
expr_node * pUBoundExpr ) : npa( NODE_ARRAY )
|
|
{
|
|
|
|
BOOL fIsNotConformantArray = TRUE;
|
|
BOOL fUnsigned = FALSE;
|
|
BOOL fReportError = FALSE;
|
|
|
|
|
|
/**
|
|
** We identify a conformant array as one which has a lower bound set
|
|
** as (expr_node *)0, and upper bound set as (expr_node *)-1, by the
|
|
** parser
|
|
**/
|
|
|
|
if( (pLowerBound = pLBoundExpr) == (expr_node * ) 0 )
|
|
{
|
|
pLowerBound = (expr_node *) new expr_constant( 0L );
|
|
}
|
|
|
|
if( ( pUpperBound = pUBoundExpr ) == (expr_node *) -1 )
|
|
{
|
|
SetNodeState( NODE_STATE_CONF_ARRAY |
|
|
NODE_STATE_NEEDS_USE_PROCESSING );
|
|
fIsNotConformantArray = FALSE;
|
|
}
|
|
else
|
|
{
|
|
|
|
/**
|
|
** The upper bound being present, we can set internal size
|
|
** attributes so that we can compute bound expressions for
|
|
** arrays, pointers when the back end asks for them
|
|
**/
|
|
|
|
expr_node * pExpr;
|
|
|
|
pExpr = new expr_op_binary( OP_MINUS, pUpperBound, pLowerBound );
|
|
// pExpr = new expr_constant( (long)( pUpperBound->Evaluate() - pLowerBound->Evaluate()) );
|
|
|
|
pExpr->SCheck( (SymTable *)0 );
|
|
|
|
node_skl * pT = pExpr->GetType();
|
|
|
|
if( pT->FInSummary( ATTR_UNSIGNED ) )
|
|
fUnsigned = TRUE;
|
|
|
|
/**
|
|
** both the internal size is and internal length is attributes
|
|
** share this expr.
|
|
**/
|
|
|
|
node_skl::SetAttribute((node_base_attr *)new node_int_size_is(pExpr));
|
|
node_skl::SetAttribute((node_base_attr *)new node_int_length_is(pExpr));
|
|
|
|
}
|
|
|
|
/**
|
|
** we must do some sanity check like the upper bound being greater than
|
|
** the lower bound and so forth. But only if the array is not a
|
|
** conformant array
|
|
**/
|
|
|
|
if( fIsNotConformantArray )
|
|
{
|
|
unsigned long Size= pUpperBound->Evaluate() - pLowerBound->Evaluate();
|
|
unsigned long SizeLimit;
|
|
|
|
if( (pCommand->GetEnv() == ENV_GENERIC ) ||
|
|
(pCommand->GetEnv() == ENV_DOS ) ||
|
|
(pCommand->GetEnv() == ENV_WIN16 )
|
|
)
|
|
SizeLimit = 0xffff;
|
|
else
|
|
{
|
|
SizeLimit = 0xffffffff;
|
|
}
|
|
|
|
if( fUnsigned == TRUE )
|
|
{
|
|
if( Size == 0 )
|
|
fReportError = TRUE;
|
|
}
|
|
|
|
else
|
|
{
|
|
if( (Size == 0) || (Size > SizeLimit/2 ) )
|
|
fReportError = TRUE;
|
|
}
|
|
|
|
if( fReportError )
|
|
{
|
|
ParseError( ILLEGAL_ARRAY_BOUNDS, (char *)NULL );
|
|
}
|
|
|
|
ArraySize = Size;
|
|
}
|
|
|
|
/**
|
|
** this node state is needed by the backend.
|
|
**/
|
|
|
|
SetNodeState( NODE_STATE_ANY_ARRAY );
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
PostSCheck:
|
|
Check semantics of array after the child has been processed.
|
|
Note:
|
|
to get the nonrpcable reason, we have to probe the child and not the
|
|
basic type, becuase we want the def node (may have important info
|
|
about non-rpcability) and getbasictype will overlook the def nodes
|
|
****************************************************************************/
|
|
node_state
|
|
node_array::PostSCheck(
|
|
BadUseInfo * pBadUseInfo)
|
|
{
|
|
node_skl * pChildType = GetChild();
|
|
BOOL fHasStringAttribute;
|
|
BOOL fHasAnySizeAttributes;
|
|
BOOL fHasAnyLengthAttributes;
|
|
|
|
|
|
// check for bad constructs and report any errors.
|
|
|
|
CheckBadConstructs( pBadUseInfo );
|
|
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR );
|
|
}
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR );
|
|
}
|
|
|
|
//
|
|
// We do not allow an out only parameter to be a pointer to open structure,
|
|
// because we do not know the size of the open structure on the in-side.
|
|
// But an array of pointers to open structure is fine. Why ? The array of
|
|
// pointers to an open structure is presented to the manager routine as
|
|
// an array of null pointers and hence we just need to know the size of the
|
|
// array. Therefore, even if the array of pointers to open structure is
|
|
// used as a parameter, the manager routines on the server side can be
|
|
// presented with an array of null pointers.
|
|
|
|
// This will not work in the case of a single pointer as a parameter, since
|
|
// a single pointer is a ref pointer, is never transmitted and the server
|
|
// side stub does not know if the pointer was null or not. The array is
|
|
// ALWAYS transmitted even if the pointers are null.
|
|
|
|
// therefore, we should not barf on a paramter of type arrray of pointers
|
|
// to conf structs.
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_P_TO_C_STRUCT ) )
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_P_TO_C_STRUCT );
|
|
|
|
#if 0
|
|
/**
|
|
** An Array Cannot derive from a context handle
|
|
**/
|
|
|
|
if( GetNodeState() & NODE_STATE_CONTEXT_HANDLE )
|
|
ParseError( BAD_CON_CTXT_HDL_ARRAY, (char *)NULL );
|
|
#endif // 0
|
|
|
|
//
|
|
// An array element cannot derive from a primitive handle or context_handle
|
|
// or their pointer derivatives.
|
|
//
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_PRIMITIVE_HANDLE ) ||
|
|
pBadUseInfo->NonRPCAbleBecause( NR_PTR_TO_PRIMITIVE_HANDLE ) ||
|
|
pBadUseInfo->NonRPCAbleBecause( NR_CTXT_HDL ) ||
|
|
pBadUseInfo->NonRPCAbleBecause( NR_PTR_TO_CTXT_HDL ) )
|
|
{
|
|
ParseError( BAD_CON_CTXT_HDL_ARRAY, (char *)NULL );
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_PRIMITIVE_HANDLE );
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_PTR_TO_PRIMITIVE_HANDLE );
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_CTXT_HDL );
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_PTR_TO_CTXT_HDL );
|
|
}
|
|
|
|
//
|
|
// If an array element is a generic handle, then it loses the handle
|
|
// property and is a pure rpc type.
|
|
//
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_GENERIC_HANDLE ) ||
|
|
pBadUseInfo->NonRPCAbleBecause( NR_PTR_TO_GENERIC_HANDLE ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_GENERIC_HANDLE );
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_PTR_TO_GENERIC_HANDLE );
|
|
}
|
|
|
|
/**
|
|
** The array elements seem to be valid. Check for attributes being valid
|
|
** Note that we check for presence of size attributes and their mutual
|
|
** validity here, rather that at the attribute semantics, so that there is
|
|
** a single place where this can be checked, rather than repeating the
|
|
** checks at all the attribute nodes.
|
|
** size_is and length_is both cannot be specified, so also length_is and
|
|
** last_is.
|
|
**/
|
|
|
|
if( FInSummary( ATTR_SIZE ) && FInSummary( ATTR_MAX ) )
|
|
{
|
|
ParseError( MAX_AND_SIZE, (char *)NULL );
|
|
}
|
|
|
|
if( FInSummary( ATTR_LENGTH ) && FInSummary( ATTR_LAST ) )
|
|
{
|
|
ParseError( LAST_AND_LENGTH, (char *)NULL );
|
|
}
|
|
|
|
/** Examine if this array is rpcable, or is a bad construct.
|
|
** If the conf array has no size attributes, then it is an error, except if
|
|
** there is a string attribute present. If NO size info is present then
|
|
** this array is indeed a bad rpc construct. Report this error only if
|
|
** it is used. An array with no size attribute but having a string
|
|
** attribute is RPCAble only if it is an out param. So since we may not
|
|
** know for sure if it is used in an out param, we need to mark this as
|
|
** not-rpcable and let the param decide.
|
|
**
|
|
** The string attribute verifies
|
|
** if the application is to a char or byte etc, so we dont need to check it
|
|
** here. What we do want to do, is to indicate the need for use processing
|
|
** which means that at use time, we need to set up the string expression.
|
|
** There is no point doing it at definition time(now),since we dont know if
|
|
** the array will be used at all in an remote procedure.
|
|
**/
|
|
|
|
fHasAnySizeAttributes = ( FInSummary( ATTR_SIZE ) ||
|
|
FInSummary( ATTR_INT_SIZE) ||
|
|
FInSummary( ATTR_MAX) );
|
|
fHasStringAttribute = FInSummary( ATTR_STRING );
|
|
|
|
fHasAnyLengthAttributes = HasAnyLengthAttributes();
|
|
|
|
//
|
|
// if it has string attributes and no size attributes then it is an
|
|
// unsized string array which cannot be used as out only. This is verified
|
|
// by the param node. If it has size attributes then set the node_state
|
|
// varying array. If it does not have a string attribute and no size
|
|
// attribute, then this is an unsized array, a bad construct for the
|
|
// param node to catch.
|
|
//
|
|
// Initially we used to set the node-state-varying array even for the case
|
|
// when string was applied to a conformant array. But the backend
|
|
// requested this change: Do not set the node_state_varying array when
|
|
// string is applied to a conformant array. But set varying array when
|
|
// string is applied to an array which has a size specification.
|
|
//
|
|
|
|
if( fHasStringAttribute )
|
|
{
|
|
if( !fHasAnySizeAttributes )
|
|
{
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_UNSIZED_STRING );
|
|
pBadUseInfo->SetBadConstructBecause(
|
|
BC_DERIVES_FROM_UNSIZED_STRING );
|
|
}
|
|
else
|
|
SetNodeState( NODE_STATE_VARYING_ARRAY );
|
|
}
|
|
else
|
|
{
|
|
if( !fHasAnySizeAttributes )
|
|
pBadUseInfo->SetBadConstructBecause(BC_DERIVES_FROM_UNSIZED_ARRAY );
|
|
}
|
|
|
|
#if 0 ///////////////////////////////////////////////////////////////////////
|
|
if( !fHasAnySizeAttributes )
|
|
{
|
|
|
|
// if it has a string, then it is unsized string. It cannot be used
|
|
// as out-only, and that decision is made by the pointer node. We need
|
|
// to set the non-rpcable status for the param node to check and report
|
|
// properly.
|
|
// But if it is not a string, then treat as an unsized array. Which
|
|
// cannot be used as in or out. Again, the actual error is reported
|
|
// by the user of the node (param / field etc).
|
|
|
|
// Also,if it has a string attribute, then if it is a conformant array
|
|
// (which is why you are in this if block) then reset the conformant
|
|
// array status. This is a change requested by the backend. This is
|
|
// because a conformant array which has the string attribute has the
|
|
// size and the length determined by the string attribute.
|
|
|
|
if( fHasStringAttribute )
|
|
{
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_UNSIZED_STRING );
|
|
|
|
#if 0
|
|
// temporarily reset. Need to check if everything is fine. Bug #2820.
|
|
if((GetNodeState() & NODE_STATE_CONF_ARRAY )
|
|
== NODE_STATE_CONF_ARRAY)
|
|
|
|
ResetNodeState( NODE_STATE_CONF_ARRAY );
|
|
#endif // 0
|
|
}
|
|
else
|
|
{
|
|
pBadUseInfo->SetBadConstructBecause(BC_DERIVES_FROM_UNSIZED_ARRAY );
|
|
SetNodeState( NODE_STATE_VARYING_ARRAY );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( fHasStringAttribute )
|
|
SetNodeState( NODE_STATE_VARYING_ARRAY );
|
|
}
|
|
|
|
#endif // 0 /////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// if it has length attributes (other than string), then set the
|
|
// node_state_varying array.
|
|
|
|
if( fHasAnyLengthAttributes )
|
|
{
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_VARY );
|
|
SetNodeState( NODE_STATE_VARYING_ARRAY );
|
|
}
|
|
|
|
/**
|
|
** if this array is a conformant array, then set the bad use info to
|
|
** indicate that. Let the user decide whether it is really a bad use or
|
|
** not. The user here referes to the type that uses it.
|
|
**/
|
|
|
|
if( pUpperBound == (expr_node *)-1 )
|
|
{
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_CONF );
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_VARY );
|
|
}
|
|
|
|
/**
|
|
** if it has a string attribute, then we need to set up the bound expressio
|
|
** for the backend. Indicate the need for use processing.
|
|
**/
|
|
|
|
if( fHasStringAttribute )
|
|
SetUseProcessingNeeded();
|
|
|
|
/**
|
|
** Check for type mismatch between size and length attributes
|
|
**/
|
|
|
|
CheckSizeAndLengthTypeMismatch( this );
|
|
|
|
/**
|
|
** if the array derives from a compnode with an embedded pointer,
|
|
** translate that into a ptr-to-comp-with-embedded ptr at the backend
|
|
** request.
|
|
**/
|
|
if( GetNodeState() & NODE_STATE_EMBEDDED_PTR )
|
|
{
|
|
ResetNodeState( NODE_STATE_EMBEDDED_PTR );
|
|
SetNodeState( NODE_STATE_PTR_TO_EMBEDDED_PTR );
|
|
}
|
|
|
|
return GetNodeState();
|
|
|
|
}
|
|
|
|
void
|
|
node_array::CheckBadConstructs(
|
|
BadUseInfo * pBadUseInfo )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
check for bad array constructs
|
|
|
|
Arguments:
|
|
|
|
pBadUseInfo - pointer to bad use information block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
/**
|
|
** Check whether the elements of the array are valid ones. This check is
|
|
** independent of whether the array is used in an rpc operation or not.
|
|
** For example, the c language syntax does not restrict the user from
|
|
** declaring an array of functions or array of void. This should be
|
|
** semantically eliminated. Also, currently midl does not suport
|
|
** and array of conformant array.
|
|
** In almost all cases where we report errors, we want to reset the bad
|
|
** construct condition, so that the we dont have a cascade of the same
|
|
** error wherever this type is used. If it is an error, the compilation
|
|
** fails anyway.
|
|
**/
|
|
|
|
short Env;
|
|
|
|
if( pBadUseInfo->AnyReasonForBadConstruct() )
|
|
{
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_VOID ) )
|
|
{
|
|
ParseError( BAD_CON_ARRAY_VOID, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_VOID );
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_FUNC ) )
|
|
{
|
|
ParseError( BAD_CON_ARRAY_FUNC, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_FUNC );
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CONF ) )
|
|
{
|
|
ParseError( ILLEGAL_CONFORMANT_ARRAY, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_CONF );
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CONF_STRUCT ))
|
|
{
|
|
ParseError( ILLEGAL_CONFORMANT_ARRAY, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause(
|
|
BC_DERIVES_FROM_CONF_STRUCT );
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_MAY_DERIVE_ARRAY_OF_UNIONS ) )
|
|
{
|
|
ParseError( ARRAY_OF_UNIONS_ILLEGAL, (char *)0 );
|
|
pBadUseInfo->ResetBadConstructBecause(
|
|
BC_MAY_DERIVE_ARRAY_OF_UNIONS );
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_REF_PTR_BAD_RT ) )
|
|
{
|
|
pBadUseInfo->ResetBadConstructBecause( BC_REF_PTR_BAD_RT );
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// an array must not derive from a type which has a transmit_as since
|
|
// we dont support this yet. Dont report this on all array dimensions
|
|
// do it only on the outermost dimension.
|
|
//
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_MAY_DERIVE_EMBEDDED_TRANSMIT) )
|
|
{
|
|
if( IsThisOutermostDimension() )
|
|
{
|
|
ParseError( EMBEDDED_TRANSMIT_AS, (char *)0 );
|
|
}
|
|
|
|
//
|
|
// we dont want the usage of the array to report the error again,
|
|
// so since we have reported it already, reset it.
|
|
//
|
|
|
|
pBadUseInfo->ResetBadConstructBecause(
|
|
BC_MAY_DERIVE_EMBEDDED_TRANSMIT );
|
|
}
|
|
#endif // 0
|
|
|
|
//
|
|
// an array element cannot be error_status_t.
|
|
//
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_E_STAT_T ) )
|
|
{
|
|
ParseError( E_STAT_T_ARRAY_ELEMENT, (char *)0 );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_E_STAT_T );
|
|
|
|
}
|
|
}
|
|
|
|
UpdateUseOfCDecls( pBadUseInfo );
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CDECL ))
|
|
{
|
|
ParseError( BAD_CON_MSC_CDECL , (char *)0 );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_CDECL );
|
|
}
|
|
|
|
//
|
|
// if this is an embedded array, then application of pointer attributes
|
|
// is useless.
|
|
//
|
|
|
|
if( FInSummary( ATTR_REF ) ||
|
|
FInSummary( ATTR_PTR ) ||
|
|
FInSummary( ATTR_UNIQUE ) )
|
|
{
|
|
if( pGlobalContext->IsThisAnEmbeddedArray() )
|
|
{
|
|
ParseError( PTR_ATTRS_ON_EMBEDDED_ARRAY, (char *)0 );
|
|
}
|
|
}
|
|
|
|
//
|
|
// check the total size of this array not to exceed 64k. Do this check only
|
|
// when:
|
|
// 1. This is the top level array dimension (outermost)
|
|
// 2. This is not a conformant array (ie. has a fixed size)
|
|
// 3. The env option is dos.
|
|
//
|
|
|
|
|
|
|
|
if( ((Env = pCommand->GetEnv()) == ENV_DOS ) ||
|
|
(Env == ENV_WIN16) ||
|
|
(Env == ENV_GENERIC)
|
|
)
|
|
{
|
|
unsigned long Size = 0xffffffff;
|
|
BOOL fIsConformantArray =
|
|
((GetNodeState() & NODE_STATE_CONF_ARRAY) == NODE_STATE_CONF_ARRAY);
|
|
BOOL fCheckIt = FALSE;
|
|
node_array * pActualArray;
|
|
|
|
if( IsThisOutermostDimension() )
|
|
{
|
|
|
|
fCheckIt = TRUE;
|
|
|
|
if( fIsConformantArray )
|
|
{
|
|
if( (pActualArray = (node_array *)GetBasicType())->NodeKind()
|
|
!= NODE_ARRAY )
|
|
{
|
|
|
|
// this is a 1 dimensional conformant array . We cannot
|
|
// make any checks at compile time. Let go.
|
|
|
|
fCheckIt = FALSE;
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pActualArray = this;
|
|
}
|
|
}
|
|
|
|
|
|
if( fCheckIt && (Size = pActualArray->GetFixedDimension()) )
|
|
{
|
|
node_skl * pNode = pActualArray->GetChild();
|
|
unsigned long TotalSize = pNode->GetSize( 0 );
|
|
|
|
if( (TotalSize * Size) > 0x00010000 )
|
|
ParseError( ARRAY_SIZE_EXCEEDS_64K, (char *)0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned long
|
|
node_array::GetSize(
|
|
unsigned long CurOffset )
|
|
{
|
|
node_skl * pNode;
|
|
long CurAlign;
|
|
long Mod,CurOffsetSave;
|
|
|
|
/**
|
|
** a conformant array is not sized
|
|
**/
|
|
|
|
if( GetNodeState() & NODE_STATE_CONF_ARRAY )
|
|
return 0;
|
|
|
|
/**
|
|
** the array may be nested in a struct, adjust the start adddress
|
|
** of the array
|
|
**/
|
|
|
|
CurAlign = GetMscAlign();
|
|
ADJUST_OFFSET(CurOffset, Mod, CurAlign);
|
|
|
|
/**
|
|
** the size of the array element may be odd (like if the array element
|
|
** is a structure of odd size). Calculate the size of the element,
|
|
** adjust the offset for the alignment, and calculate the array size
|
|
**/
|
|
|
|
CurOffsetSave = CurOffset;
|
|
pNode = GetChild();
|
|
CurOffset += pNode->GetSize(CurOffset);
|
|
|
|
ADJUST_OFFSET(CurOffset, Mod, CurAlign);
|
|
return (CurOffset- CurOffsetSave) * ( ArraySize );
|
|
|
|
}
|
|
void
|
|
node_array::SetAttribute(
|
|
type_node_list * pAttrList )
|
|
{
|
|
ATTR_SUMMARY Attr[ MAX_ATTR_SUMMARY_ELEMENTS ];
|
|
short Count;
|
|
|
|
/**
|
|
** Pick up the attribute bits from the pre-allocated attribute masks
|
|
**/
|
|
|
|
COPY_ATTR( Attr, pPreAttrArray );
|
|
|
|
/**
|
|
** If the array did not have a bound specified, then it collects the
|
|
** size-is attribute on the way down
|
|
**/
|
|
|
|
SetAttributeVector( Attr, ATTR_MIN );
|
|
SetAttributeVector( Attr, ATTR_MAX );
|
|
SetAttributeVector( Attr, ATTR_SIZE );
|
|
SetAttributeVector( Attr, ATTR_FIRST );
|
|
SetAttributeVector( Attr, ATTR_LAST );
|
|
SetAttributeVector( Attr, ATTR_LENGTH );
|
|
|
|
//
|
|
// If the array is a fixed array, then these attributes will be reported
|
|
// as an error. But this can result in a very shoddy error message
|
|
// reported when semantic analysis proceeds, especially in case of a struct
|
|
// where the error is reported after the structure ends.Although we give the
|
|
// context, it is still a shoddy error.
|
|
|
|
if( FInSummary( ATTR_INT_SIZE ) )
|
|
{
|
|
node_base_attr * pAttrNode;
|
|
if( pAttrList && ( Count = pAttrList->GetCount() ) )
|
|
{
|
|
pAttrList->Init();
|
|
|
|
while( Count-- )
|
|
{
|
|
ATTR_T AID;
|
|
|
|
pAttrList->GetCurrent( (void **)&pAttrNode );
|
|
|
|
AID = pAttrNode->GetAttrID();
|
|
|
|
if(
|
|
(AID == ATTR_MAX ) ||
|
|
(AID == ATTR_SIZE )
|
|
)
|
|
{
|
|
|
|
//
|
|
// report an inapplicable attribute error.
|
|
//
|
|
|
|
ParseError( INAPPLICABLE_ATTRIBUTE,
|
|
pAttrNode->GetNodeNameString() );
|
|
pAttrList->Remove();
|
|
}
|
|
pAttrList->Advance();
|
|
}
|
|
}
|
|
}
|
|
|
|
DoSetAttributes(this,
|
|
Attr,
|
|
pPostAttrArray,
|
|
pAttrList );
|
|
}
|
|
node_skl *
|
|
node_array::Clone()
|
|
{
|
|
node_array * pClone = new node_array( pLowerBound, pUpperBound );
|
|
return CloneAction( pClone );
|
|
}
|
|
/****************************************************************************
|
|
node_pointer procedures
|
|
****************************************************************************/
|
|
/****************************************************************************
|
|
The constructor:
|
|
set up a default internal length of 1 as an internal size_is attribute
|
|
****************************************************************************/
|
|
|
|
|
|
node_pointer::node_pointer(
|
|
ATTR_T Attribute ) :
|
|
npa( NODE_POINTER )
|
|
/*++
|
|
This constructor is needed only to create a dummy pointer node for
|
|
pickling walking.
|
|
--*/
|
|
{
|
|
expr_node * pExpr;
|
|
ATTR_T A = ATTR_NONE;
|
|
|
|
if ( Attribute == ATTR_UNIQUE || Attribute == ATTR_REF ||
|
|
Attribute == ATTR_PTR )
|
|
A = Attribute;
|
|
|
|
/**
|
|
** treat the pointer as having an internal size attribute as 1
|
|
** Also set up the node_state_pointer for nodes to inherit.
|
|
**/
|
|
|
|
pExpr = (expr_node *)new expr_constant( 1L );
|
|
|
|
node_skl::SetAttribute( (node_base_attr *) new node_int_size_is( pExpr ) );
|
|
SetNodeState( NODE_STATE_POINTER );
|
|
|
|
node_skl::SetAttribute( A );
|
|
}
|
|
|
|
#ifndef OLD_POINTER_BEHAVIOUR
|
|
|
|
node_pointer::node_pointer() : npa( NODE_POINTER )
|
|
{
|
|
|
|
expr_node * pExpr;
|
|
ATTR_T A = ATTR_NONE;
|
|
|
|
/**
|
|
** treat the pointer as having an internal size attribute as 1
|
|
** Also set up the node_state_pointer for nodes to inherit.
|
|
**/
|
|
|
|
pExpr = (expr_node *)new expr_constant( 1L );
|
|
|
|
node_skl::SetAttribute( (node_base_attr *) new node_int_size_is( pExpr ) );
|
|
SetNodeState( NODE_STATE_POINTER );
|
|
|
|
/*********************************************************************
|
|
In osf mode, the pointer default is the attribute a pointer gets at
|
|
instantiation time.
|
|
|
|
But then we discovered that the DEC idl compiler actually issues just
|
|
a warning and not an error. So, we do the same, but in osf mode, we
|
|
assume a default pointer default to be unique, to be consistent with
|
|
the ms_ext mode default pointer default.
|
|
|
|
This might change if we learn what decs default ptr default is.
|
|
|
|
In ms_ext mode, at instantiation, if the interface
|
|
has a pointer default, then take that else get the base interface
|
|
pointer default. If that does not exist too, take unique.
|
|
*********************************************************************/
|
|
|
|
if( !FInSummary( ATTR_TEMP_REF ) &&
|
|
!FInSummary( ATTR_TEMP_UNIQUE) &&
|
|
!FInSummary( ATTR_TEMP_PTR ) )
|
|
{
|
|
if( !pCommand->IsSwitchDefined( SWITCH_MS_EXT ) )
|
|
{
|
|
A = pInterfaceInfoDict->GetInterfacePtrAttribute();
|
|
}
|
|
else
|
|
{
|
|
if((A = pInterfaceInfoDict->GetInterfacePtrAttribute()) == ATTR_NONE)
|
|
{
|
|
if((A = pInterfaceInfoDict->GetBaseInterfacePtrAttribute())
|
|
== ATTR_NONE)
|
|
{
|
|
A = ATTR_UNIQUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
node_skl::SetAttribute( XlateToTempPtrAttr( A ) );
|
|
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
PreSCheck:
|
|
check the semantics of the pointer before the child has been processed.
|
|
****************************************************************************/
|
|
node_state
|
|
node_pointer::PreSCheck(
|
|
BadUseInfo * pB )
|
|
{
|
|
ATTR_T A;
|
|
BOOL fFirstLevelPointer = FALSE;
|
|
BOOL fParamContextPresent =
|
|
(pGlobalContext->GetLastContext( C_PARAM ) != 0 );
|
|
BOOL fTypedefContextPresent =
|
|
(pGlobalContext->GetLastContext( C_DEF ) != 0 );
|
|
BOOL fProcContextPresent =
|
|
(pGlobalContext->GetLastContext( C_PROC ) != 0 );
|
|
BOOL fCompContextPresent =
|
|
(pGlobalContext->GetLastContext( C_COMP ) != 0 );
|
|
BOOL fIDContextPresent = FALSE;
|
|
|
|
BOOL fIsAPointerEmbeddedInArray =
|
|
(pGlobalContext->IsItAPointerEmbeddedInArray() == TRUE);
|
|
|
|
unsigned short CurrentIndLevel =
|
|
pGlobalContext->GetCurrentIndirectionLevel();
|
|
|
|
UNUSED( pB );
|
|
|
|
if( ! fCompContextPresent )
|
|
{
|
|
|
|
if( pCommand->IsSwitchDefined( SWITCH_MS_EXT ) )
|
|
{
|
|
if( fParamContextPresent && (CurrentIndLevel == 1 ) &&
|
|
!fIsAPointerEmbeddedInArray )
|
|
fFirstLevelPointer = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if( fParamContextPresent && !fTypedefContextPresent &&
|
|
(CurrentIndLevel == 1 ) && !fIsAPointerEmbeddedInArray )
|
|
fFirstLevelPointer = TRUE;
|
|
}
|
|
|
|
if( !fParamContextPresent && !fTypedefContextPresent &&
|
|
!fProcContextPresent )
|
|
fIDContextPresent = TRUE;
|
|
}
|
|
|
|
//
|
|
// first level pointers are ref, no matter what, unless there is an
|
|
// explicit application of a pointer attribute.
|
|
//
|
|
|
|
if(!FInSummary( ATTR_REF ) &&
|
|
!FInSummary( ATTR_UNIQUE ) &&
|
|
!FInSummary( ATTR_PTR ) )
|
|
{
|
|
if( fFirstLevelPointer )
|
|
node_skl::SetAttribute( ATTR_REF );
|
|
else
|
|
{
|
|
if( !pCommand->IsSwitchDefined( SWITCH_MS_EXT ) )
|
|
{
|
|
if( FInSummary( ATTR_TEMP_REF ) )
|
|
A = ATTR_REF;
|
|
else if( FInSummary( ATTR_TEMP_UNIQUE ) )
|
|
A = ATTR_UNIQUE;
|
|
else if( FInSummary( ATTR_TEMP_PTR ) )
|
|
A = ATTR_PTR;
|
|
else
|
|
{
|
|
BOOL fReportError = TRUE;
|
|
A = ATTR_PTR;
|
|
|
|
//
|
|
// we reach here only if we are not a top level pointer
|
|
// Now we could have a typedef context present, in which
|
|
// case the definition of the typedef would have reported
|
|
// this error. Thus report this error if paramcontext is
|
|
// not present and typedef context is not present, ie
|
|
// only if the pointer is a bare pointer.
|
|
//
|
|
|
|
#if 0
|
|
if( fTypedefContextPresent )
|
|
{
|
|
if( fParamContextPresent || fProcContextPresent ||
|
|
fCompContextPresent )
|
|
fReportError = FALSE;
|
|
}
|
|
else if( fIDContextPresent )
|
|
fReportError = FALSE;
|
|
#else // 0
|
|
if( fIDContextPresent )
|
|
fReportError = FALSE;
|
|
|
|
#endif // 0
|
|
if( fReportError &&
|
|
!pInterfaceInfoDict->IsPtrDefErrorReported() )
|
|
{
|
|
ParseError(
|
|
PTR_WITH_NO_DEFAULT,
|
|
pInterfaceInfoDict->GetInterfaceName() );
|
|
pInterfaceInfoDict->SetPtrDefErrorReported();
|
|
}
|
|
}
|
|
node_skl::SetAttribute( A );
|
|
}
|
|
else
|
|
{
|
|
|
|
// in ms_ext mode , a non-top level pointer gets a pointer
|
|
// default depedent upon the defining or the base interface.
|
|
// The constructor of the pointer already took care of this.
|
|
// So we need to just translate the temp attributes into the
|
|
// main ones.
|
|
|
|
if( ( CurrentIndLevel > 1 ) ||
|
|
fCompContextPresent ||
|
|
fIsAPointerEmbeddedInArray )
|
|
{
|
|
A = ATTR_NONE;
|
|
|
|
if ( !fIDContextPresent &&
|
|
(pInterfaceInfoDict->GetBaseInterfacePtrAttribute() == ATTR_NONE) )
|
|
{
|
|
fAtLeastOnePtrWODefault = TRUE;
|
|
}
|
|
|
|
if( FInSummary( ATTR_TEMP_REF ) )
|
|
A = ATTR_REF;
|
|
else if( FInSummary( ATTR_TEMP_UNIQUE ) )
|
|
A = ATTR_UNIQUE;
|
|
else if( FInSummary( ATTR_TEMP_PTR ) )
|
|
A = ATTR_PTR;
|
|
|
|
assert( A != ATTR_NONE );
|
|
|
|
node_skl::SetAttribute( A );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
A = FInSummary( ATTR_PTR ) ? ATTR_PTR :
|
|
FInSummary( ATTR_REF ) ? ATTR_REF : ATTR_UNIQUE;
|
|
}
|
|
|
|
//
|
|
// if the pointer is a [ptr] and this warning has not been emitted yet
|
|
// go ahead and warn the user
|
|
//
|
|
|
|
if( !fIDContextPresent && (A == ATTR_PTR ) )
|
|
{
|
|
if( !pInterfaceInfoDict->IsPtrWarningIssued() )
|
|
{
|
|
ParseError( PTR_NOT_FULLY_IMPLEMENTED, (char *)0 );
|
|
pInterfaceInfoDict->SetPtrWarningIssued();
|
|
}
|
|
}
|
|
|
|
return NODE_STATE_OK;
|
|
}
|
|
|
|
#else // OLD_POINTER_BEHAVIOUR
|
|
|
|
node_pointer::node_pointer() : ( NODE_POINTER )
|
|
{
|
|
|
|
expr_node * pExpr;
|
|
ATTR_T A = ATTR_NONE;
|
|
|
|
/**
|
|
** treat the pointer as having an internal size attribute as 1
|
|
** Also set up the node_state_pointer for nodes to inherit.
|
|
**/
|
|
|
|
pExpr = (expr_node *)new expr_constant( 1L );
|
|
|
|
node_skl::SetAttribute( (node_base_attr *) new node_int_size_is( pExpr ) );
|
|
SetNodeState( NODE_STATE_POINTER );
|
|
|
|
/*********************************************************************
|
|
In -import osf mode, the pointer gets the interface default and no
|
|
attribute can be applied to it again. In -import ms_nt and -import ms_ext
|
|
the interface default is supplied by the base interface, but we can
|
|
apply a pointer attribute at the use site. The way we do this,
|
|
is to apply the pointer attribute at instantiation time in osf mode, but
|
|
not otherwise.
|
|
*********************************************************************/
|
|
|
|
if( pCommand->GetImportMode() == IMPORT_OSF )
|
|
{
|
|
A = pInterfaceInfoDict->GetInterfacePtrAttribute();
|
|
}
|
|
else
|
|
{
|
|
if( (A = pInterfaceInfoDict->GetBaseInterfacePtrAttribute())
|
|
== ATTR_NONE)
|
|
{
|
|
A = ATTR_UNIQUE;
|
|
}
|
|
}
|
|
|
|
|
|
node_skl::SetAttribute( XlateToTempPtrAttr( A ) );
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
PreSCheck:
|
|
check the semantics of the pointer before the child has been processed.
|
|
****************************************************************************/
|
|
node_state
|
|
node_pointer::PreSCheck(
|
|
BadUseInfo * pB )
|
|
{
|
|
BOOL fFirstLevelPointer = FALSE;
|
|
ATTR_T A;
|
|
BOOL fParamContextPresent =
|
|
(pGlobalContext->GetLastContext( C_PARAM ) != 0 );
|
|
BOOL fTypedefContextPresent =
|
|
(pGlobalContext->GetLastContext( C_DEF ) != 0 );
|
|
BOOL fProcContextPresent =
|
|
(pGlobalContext->GetLastContext( C_PROC ) != 0 );
|
|
BOOL fCompContextPresent =
|
|
(pGlobalContext->GetLastContext( C_COMP ) != 0 );
|
|
BOOL fIDContextPresent = FALSE;
|
|
|
|
if( ! fCompContextPresent )
|
|
{
|
|
if( fParamContextPresent && !fTypedefContextPresent &&
|
|
(pGlobalContext->GetCurrentIndirectionLevel() == 1 ) )
|
|
fFirstLevelPointer = TRUE;
|
|
|
|
if( !fParamContextPresent && !fTypedefContextPresent &&
|
|
!fProcContextPresent )
|
|
fIDContextPresent = TRUE;
|
|
}
|
|
|
|
//
|
|
// first level pointers are ref, no matter what, unless there is an
|
|
// explicit application of a pointer attribute.
|
|
//
|
|
|
|
if(!FInSummary( ATTR_REF ) &&
|
|
!FInSummary( ATTR_UNIQUE ) &&
|
|
!FInSummary( ATTR_PTR ) )
|
|
{
|
|
if( fFirstLevelPointer )
|
|
node_skl::SetAttribute( ATTR_REF );
|
|
else
|
|
{
|
|
if( pCommand->GetImportMode() == IMPORT_OSF )
|
|
{
|
|
if( FInSummary( ATTR_TEMP_REF ) )
|
|
A = ATTR_REF;
|
|
else if( FInSummary( ATTR_TEMP_UNIQUE ) )
|
|
A = ATTR_UNIQUE;
|
|
else if( FInSummary( ATTR_TEMP_PTR ) )
|
|
A = ATTR_PTR;
|
|
else
|
|
{
|
|
BOOL fReportError = TRUE;
|
|
A = ATTR_NONE;
|
|
|
|
//
|
|
// we reach here only if we are not a top level pointer
|
|
// Now we could have a typedef context present, in which
|
|
// case the definition of the typedef would have reported
|
|
// this error. Thus report this error if paramcontext is
|
|
// not present and typedef context is not present, ie
|
|
// only if the pointer is a bare pointer.
|
|
//
|
|
|
|
if( fTypedefContextPresent )
|
|
{
|
|
if( fParamContextPresent || fProcContextPresent ||
|
|
fCompContextPresent )
|
|
fReportError = FALSE;
|
|
}
|
|
else if( fIDContextPresent )
|
|
fReportError = FALSE;
|
|
|
|
if( fReportError )
|
|
ParseError( PTR_WITH_NO_DEFAULT, (char *)0 );
|
|
}
|
|
node_skl::SetAttribute( A );
|
|
}
|
|
else
|
|
{
|
|
if( FInSummary( ATTR_TEMP_REF ) )
|
|
A = ATTR_REF;
|
|
else if( FInSummary( ATTR_TEMP_UNIQUE ) )
|
|
A = ATTR_UNIQUE;
|
|
else if( FInSummary( ATTR_TEMP_PTR ) )
|
|
A = ATTR_PTR;
|
|
|
|
else if( !fIDContextPresent &&
|
|
(pInterfaceInfoDict->GetBaseInterfacePtrAttribute() == ATTR_NONE) )
|
|
{
|
|
fAtLeastOnePtrWODefault = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#if 0
|
|
if( fFirstLevelPointer )
|
|
{
|
|
if(!FInSummary( ATTR_REF ) &&
|
|
!FInSummary( ATTR_UNIQUE ) &&
|
|
!FInSummary( ATTR_PTR ) )
|
|
{
|
|
node_skl::SetAttribute( ATTR_REF );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pCommand->GetImportMode() == IMPORT_OSF )
|
|
{
|
|
if( FInSummary( ATTR_TEMP_REF ) )
|
|
A = ATTR_REF;
|
|
else if( FInSummary( ATTR_TEMP_UNIQUE ) )
|
|
A = ATTR_UNIQUE;
|
|
else if( FInSummary( ATTR_TEMP_PTR ) )
|
|
A = ATTR_PTR;
|
|
node_skl::SetAttribute( A );
|
|
}
|
|
|
|
}
|
|
|
|
#endif // 0
|
|
|
|
return NODE_STATE_OK;
|
|
}
|
|
|
|
#endif // OLD_POINTER_BEHAVIOUR
|
|
/****************************************************************************
|
|
PostSCheck:
|
|
check the semantics of the pointer after the child has been processed.
|
|
****************************************************************************/
|
|
|
|
node_state
|
|
node_pointer::PostSCheck(
|
|
BadUseInfo * pBadUseInfo)
|
|
{
|
|
|
|
node_skl * pChildType = GetChild();
|
|
ATTR_T PtrAttr;
|
|
|
|
//Check if this is an interface pointer
|
|
if(FInSummary(ATTR_IID) ||
|
|
(pChildType->FInSummary(ATTR_IID) && (pChildType->NodeKind() == NODE_DEF)))
|
|
{
|
|
//Interface pointers must be [unique]
|
|
node_skl::ResetAttribute(ATTR_REF);
|
|
node_skl::ResetAttribute(ATTR_PTR);
|
|
node_skl::SetAttribute(ATTR_UNIQUE);
|
|
}
|
|
|
|
|
|
PtrAttr = WhatPtrIsThis();
|
|
|
|
// check for bad constructs for a pointer
|
|
|
|
CheckBadConstructs( pBadUseInfo );
|
|
|
|
/**
|
|
** check for non-rpcablility of the constructs underneath. Note that the
|
|
** pointer to non-rpcable constructs may actually be ok in certain cases.
|
|
** For this reason, we transform the bad use info in such cases to indicate
|
|
** a pointer to such types, so that proper errors may be reported.
|
|
**/
|
|
|
|
if( pBadUseInfo->AnyReasonForNonRPCAble() )
|
|
{
|
|
|
|
/**
|
|
** if it derives from an unsized string, then this becomes a
|
|
** pointer to unsized string, which can be an out. So reset the
|
|
** non-rpcable condition
|
|
**/
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_UNSIZED_STRING ) )
|
|
pBadUseInfo->ResetNonRPCAbleBecause(
|
|
NR_DERIVES_FROM_UNSIZED_STRING );
|
|
|
|
/**
|
|
** check for string attribute w/o size
|
|
**/
|
|
|
|
BOOL fHasAnySizeAttribute = ( FInSummary( ATTR_SIZE ) ||
|
|
FInSummary( ATTR_MAX ) );
|
|
|
|
if( !fHasAnySizeAttribute && FInSummary( ATTR_STRING ))
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_UNSIZED_STRING );
|
|
|
|
/**
|
|
** if it is a pointer deriving from void, then set use state to
|
|
** indicate a derivation from void ptr.
|
|
**/
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_VOID ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_VOID );
|
|
if(!FInSummary(ATTR_SIZE) && !FInSummary(ATTR_MAX) && !FInSummary(ATTR_IID))
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_VOID );
|
|
}
|
|
|
|
/**
|
|
** if it is a pointer deriving from int, then set use state to
|
|
** indicate a derivation from int ptr.
|
|
**/
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_INT ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_INT );
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT );
|
|
}
|
|
|
|
/**
|
|
** if it is a pointer to a conformant struct, then it is a warning
|
|
** to the user that if used, it may be truncated on the stack.
|
|
**
|
|
** If it is a pointer to pointer to a conformant struct, then we are
|
|
** fine
|
|
**/
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_CONF_STRUCT ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_CONF_STRUCT );
|
|
pBadUseInfo->SetNonRPCAbleBecause(
|
|
NR_DERIVES_FROM_P_TO_C_STRUCT );
|
|
}
|
|
|
|
else if( pBadUseInfo->NonRPCAbleBecause(
|
|
NR_DERIVES_FROM_P_TO_C_STRUCT ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause(
|
|
NR_DERIVES_FROM_P_TO_C_STRUCT );
|
|
}
|
|
|
|
/**
|
|
** if it is a pointer to func,say so
|
|
**/
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_FUNC ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_FUNC );
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_FUNC );
|
|
}
|
|
|
|
/**
|
|
** if it is a pointer to a unique pointer, then the restriction on
|
|
** first pointer (not necessarily top level) cannot be unique does not
|
|
** apply , since that pointer is not a first level pointer anymore.
|
|
**/
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR);
|
|
}
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR);
|
|
}
|
|
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_PRIMITIVE_HANDLE ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_PRIMITIVE_HANDLE );
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_PTR_TO_PRIMITIVE_HANDLE );
|
|
}
|
|
else if( pBadUseInfo->NonRPCAbleBecause( NR_PTR_TO_PRIMITIVE_HANDLE ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_PTR_TO_PRIMITIVE_HANDLE );
|
|
}
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_GENERIC_HANDLE ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_GENERIC_HANDLE );
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_PTR_TO_GENERIC_HANDLE );
|
|
}
|
|
else if( pBadUseInfo->NonRPCAbleBecause( NR_PTR_TO_GENERIC_HANDLE ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_PTR_TO_GENERIC_HANDLE );
|
|
}
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_CTXT_HDL ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_CTXT_HDL );
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_PTR_TO_CTXT_HDL );
|
|
}
|
|
else if( pBadUseInfo->NonRPCAbleBecause( NR_PTR_TO_CTXT_HDL ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_PTR_TO_CTXT_HDL );
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_PTR_TO_PTR_TO_CTXT_HDL );
|
|
}
|
|
else if( pBadUseInfo->NonRPCAbleBecause( NR_PTR_TO_PTR_TO_CTXT_HDL ) )
|
|
{
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_PTR_TO_PTR_TO_CTXT_HDL );
|
|
}
|
|
}
|
|
|
|
pChildType = GetBasicType();
|
|
|
|
/**
|
|
** a pointer inherits node_state_union ONLY if the basic type is not
|
|
** a struct
|
|
**/
|
|
|
|
if( ( pChildType->GetNodeState() & NODE_STATE_UNION ) )
|
|
if( pChildType->NodeKind() != NODE_STRUCT )
|
|
SetNodeState( NODE_STATE_UNION );
|
|
|
|
/**
|
|
** check for presence of conflicting attributes.
|
|
**/
|
|
|
|
if( FInSummary( ATTR_SIZE ) && FInSummary( ATTR_MAX ) )
|
|
ParseError( MAX_AND_SIZE, (char *)NULL );
|
|
|
|
if( FInSummary( ATTR_LENGTH ) && FInSummary( ATTR_LAST ) )
|
|
ParseError( LAST_AND_LENGTH, (char *)NULL );
|
|
|
|
/**
|
|
** Make checks of the size and string attributes for a pointer. For a
|
|
** pointer, the checks are different from an array. The pointer need not
|
|
** have size attributes, but if it has a string attribute and does not
|
|
** have size, then it is non-rpcable, if it is an out. Again, we mark
|
|
** such a pointer as non-rpcable, and let the param decide. Also note
|
|
** that the pointer ALWAYS has an int size, so check for size attributes
|
|
** should be on size_is and max_is.
|
|
** if the pointer has any string attribute and a size attribute,
|
|
** the backend wants a node-state-varying-array on it.
|
|
**/
|
|
|
|
BOOL fHasAnySizeAttributes = ( FInSummary( ATTR_SIZE ) ||
|
|
FInSummary( ATTR_MAX) );
|
|
|
|
BOOL fHasStringAttribute = FInSummary( ATTR_STRING ) ||
|
|
FInSummary( ATTR_BSTRING );
|
|
#if 0
|
|
BOOL fHasAnyLengthAttributes= FInSummary( ATTR_LENGTH ) ||
|
|
FInSummary( ATTR_LAST );
|
|
#endif // 0
|
|
|
|
BOOL fHasAnyLengthAttributes= HasAnyLengthAttributes();
|
|
|
|
if( fHasStringAttribute )
|
|
{
|
|
if( !fHasAnySizeAttributes )
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_UNSIZED_STRING );
|
|
else
|
|
SetNodeState( NODE_STATE_VARYING_ARRAY );
|
|
}
|
|
else if( fHasAnyLengthAttributes && !fHasAnySizeAttributes )
|
|
{
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_UNSIZED_ARRAY );
|
|
}
|
|
|
|
/**
|
|
** Check for type mismatch between size and length attributes
|
|
**/
|
|
|
|
CheckSizeAndLengthTypeMismatch( this );
|
|
|
|
//
|
|
// if the pointer has any size or length attributes, then this is not
|
|
// allowed as part of a union arm. This must be checked by the union node
|
|
//
|
|
|
|
if( fHasAnySizeAttributes )
|
|
{
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_CONF_PTR );
|
|
}
|
|
|
|
if( fHasAnyLengthAttributes )
|
|
{
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_CONF_PTR );
|
|
}
|
|
|
|
/**
|
|
** adjust the embedded ref ptr info for the back end. If the ptr is ref,
|
|
** set the node-state-first-level-ref. Else reset it.
|
|
**/
|
|
|
|
if( PtrAttr == ATTR_REF )
|
|
{
|
|
SetNodeState( NODE_STATE_FIRST_LEVEL_REF );
|
|
}
|
|
else
|
|
ResetNodeState( NODE_STATE_FIRST_LEVEL_REF );
|
|
|
|
/**
|
|
** if this pointer is unique make sure that the baduse info says, it is
|
|
** an error because the first ptr in a type cannot be unique. If there is
|
|
** a pointer on top of this, it will take care of this too. Note that
|
|
** we must not check for interface pointer default here. Only if unique
|
|
** attribute is applied here should we report a case of non-embedded
|
|
** unique pointer.
|
|
**/
|
|
|
|
if( FInSummary( ATTR_UNIQUE ))
|
|
{
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR );
|
|
}
|
|
|
|
if( FInSummary( ATTR_PTR ))
|
|
{
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR );
|
|
}
|
|
|
|
/**
|
|
** for the backend, if a pointer has node-state-embedded ptr, then
|
|
** reset that and set node-state-ptr-to-embedded-ptr. The node-state-
|
|
** embedded ptr is set by the struct / union nodes if they have
|
|
** pointers in them.
|
|
**/
|
|
|
|
if( GetNodeState() & NODE_STATE_EMBEDDED_PTR )
|
|
{
|
|
ResetNodeState( NODE_STATE_EMBEDDED_PTR );
|
|
SetNodeState( NODE_STATE_PTR_TO_EMBEDDED_PTR );
|
|
}
|
|
|
|
if( GetNodeState() & NODE_STATE_ANY_ARRAY )
|
|
{
|
|
ResetNodeState( NODE_STATE_ANY_ARRAY );
|
|
SetNodeState( NODE_STATE_PTR_TO_ANY_ARRAY );
|
|
}
|
|
|
|
// if it has the size or string, then it is like a pointer to
|
|
// an array
|
|
|
|
if( fHasAnySizeAttributes || fHasStringAttribute )
|
|
{
|
|
SetNodeState( NODE_STATE_PTR_TO_ANY_ARRAY );
|
|
}
|
|
|
|
/******************
|
|
// if the pointer does not have any pointer attributes defined, then
|
|
// set a flag
|
|
|
|
if( !FInSummary( ATTR_REF ) && !FInSummary(ATTR_UNIQUE) &&
|
|
!FInSummary( ATTR_UNIQUE ) )
|
|
{
|
|
// if the last context was not a parameter, ie. this is not a
|
|
// first level pointer, then prepare to report an error if the
|
|
// interface is specified without the pointer_default.
|
|
// Also report the error if this pointer has an indirection level > 1.
|
|
// Because that is not a top-level pointer anymore.
|
|
|
|
if( pGlobalContext->GetLastContext( C_COMP ) ||
|
|
(pGlobalContext->GetCurrentIndirectionLevel() > 1) )
|
|
fAtLeastOnePtrWODefault = TRUE;
|
|
}
|
|
*******************/
|
|
|
|
//
|
|
// if a pointer has the ignore attribute then this should not be used
|
|
// in a parameter and in a field. The proper use of this in a field/
|
|
// param type will be determined by those nodes.
|
|
//
|
|
|
|
if( FInSummary( ATTR_IGNORE ) )
|
|
{
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_IGNORE );
|
|
}
|
|
|
|
if( PtrAttr == ATTR_REF )
|
|
{
|
|
pBadUseInfo->SetBadConstructBecause( BC_REF_PTR_BAD_RT );
|
|
}
|
|
|
|
return GetNodeState();
|
|
}
|
|
|
|
void
|
|
node_pointer::CheckBadConstructs(
|
|
BadUseInfo * pBadUseInfo )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
check for bad pointer constructs
|
|
|
|
Arguments:
|
|
|
|
pBadUseInfo - pointer to bad use information block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
short Count = 0;
|
|
BOOL fHasAnySizeAttribute = FInSummary( ATTR_SIZE ) ||
|
|
FInSummary( ATTR_MAX );
|
|
|
|
/**
|
|
** Check for any improper constructs.
|
|
** Currently we do not support pointer to conformant array.
|
|
**/
|
|
|
|
//
|
|
// if more than one pointer attribute got applied to this pointer,
|
|
// then it is an error.
|
|
//
|
|
|
|
if( FInSummary( ATTR_PTR ) ) Count++;
|
|
if( FInSummary( ATTR_UNIQUE ) ) Count++;
|
|
if( FInSummary( ATTR_REF ) ) Count++;
|
|
|
|
if( Count > 1 )
|
|
ParseError( MORE_THAN_ONE_PTR_ATTR, (char *)0 );
|
|
|
|
if( pBadUseInfo->AnyReasonForBadConstruct() )
|
|
{
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CONF))
|
|
{
|
|
ParseError( ILLEGAL_CONFORMANT_ARRAY, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_CONF );
|
|
}
|
|
|
|
/**
|
|
** if it is a pointer to a conf struct, then this is not a bad
|
|
** construct anymore
|
|
**/
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CONF_STRUCT ) )
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_CONF_STRUCT );
|
|
|
|
/**
|
|
** if it derives from function , it is actually ok as a construct
|
|
** but not rpcable.
|
|
**/
|
|
|
|
if( pBadUseInfo->BadConstructBecause(
|
|
BC_DERIVES_FROM_FUNC ) )
|
|
pBadUseInfo->ResetBadConstructBecause(
|
|
BC_DERIVES_FROM_FUNC);
|
|
|
|
/**
|
|
** if it derives from handle_t , it is actually ok.
|
|
**/
|
|
|
|
if( pBadUseInfo->BadConstructBecause(
|
|
BC_DERIVES_FROM_HANDLE_T ) )
|
|
pBadUseInfo->ResetBadConstructBecause(
|
|
BC_DERIVES_FROM_HANDLE_T);
|
|
|
|
/**
|
|
** if it derives from a void, it is a void pointer, so modify the
|
|
** bad use info. Similarly, if it derives from an int, modify the
|
|
** bad use info.
|
|
**/
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_VOID ) )
|
|
{
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_VOID );
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_PTR_TO_VOID );
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_INT ) )
|
|
{
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_INT );
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_PTR_TO_INT );
|
|
}
|
|
|
|
//
|
|
// a pointer notation equivalent to an array is also bad.
|
|
//
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_MAY_DERIVE_ARRAY_OF_UNIONS ) )
|
|
{
|
|
if( FInSummary( ATTR_SIZE ) ||
|
|
FInSummary( ATTR_MAX ) ||
|
|
FInSummary( ATTR_MIN ) ||
|
|
FInSummary( ATTR_LENGTH ) ||
|
|
FInSummary( ATTR_FIRST ) ||
|
|
FInSummary( ATTR_LAST )
|
|
)
|
|
{
|
|
ParseError( ARRAY_OF_UNIONS_ILLEGAL, (char *)0 );
|
|
}
|
|
|
|
//
|
|
// prevent a cascade of errors.
|
|
//
|
|
|
|
pBadUseInfo->ResetBadConstructBecause(
|
|
BC_MAY_DERIVE_ARRAY_OF_UNIONS );
|
|
}
|
|
|
|
//
|
|
// if it is a pointer to a ref pointer, then this is not a bad
|
|
// return type anymore.
|
|
//
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_REF_PTR_BAD_RT ) )
|
|
{
|
|
pBadUseInfo->ResetBadConstructBecause( BC_REF_PTR_BAD_RT );
|
|
}
|
|
|
|
}
|
|
UpdateUseOfCDecls( pBadUseInfo );
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CDECL ))
|
|
{
|
|
ParseError( BAD_CON_MSC_CDECL , (char *)0 );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_CDECL );
|
|
}
|
|
|
|
}
|
|
|
|
ATTR_T
|
|
node_pointer::WhatPtrIsThis()
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
WhatKind of pointer is this ?
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
the pointer attribute:
|
|
|
|
ATTR_REF if reference pointer
|
|
ATTR_PTR if full pointer
|
|
ATTR_UNIQUE if unique pointer
|
|
|
|
Notes:
|
|
|
|
returns the interface default pointer if none of the attributes are
|
|
actually present on the pointer node.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
if( FInSummary( ATTR_REF ) )
|
|
return ATTR_REF;
|
|
else if( FInSummary( ATTR_UNIQUE ) )
|
|
return ATTR_UNIQUE;
|
|
else if( FInSummary( ATTR_PTR ) )
|
|
return ATTR_PTR;
|
|
else if( FInSummary( ATTR_TEMP_REF ) )
|
|
return ATTR_REF;
|
|
else if( FInSummary( ATTR_TEMP_UNIQUE ) )
|
|
return ATTR_UNIQUE;
|
|
else if( FInSummary( ATTR_TEMP_PTR ) )
|
|
return ATTR_PTR;
|
|
// return pInterfaceInfoDict->GetBaseInterfacePtrAttribute();
|
|
return ATTR_NONE;
|
|
}
|
|
|
|
void
|
|
node_pointer::SetAttribute(
|
|
type_node_list * pAttrList )
|
|
{
|
|
ATTR_SUMMARY Attr[ MAX_ATTR_SUMMARY_ELEMENTS ];
|
|
|
|
CLEAR_ATTR( Attr );
|
|
COPY_ATTR( Attr, pPreAttrPointer );
|
|
|
|
/**
|
|
** If the basic type of the pointer is an arraym then these attributes
|
|
** are passed on to the array first. If the array does not collect them
|
|
** then they are picked up on the way back.
|
|
**/
|
|
|
|
#if 1
|
|
SetAttributeVector( Attr, ATTR_FIRST );
|
|
SetAttributeVector( Attr, ATTR_LAST );
|
|
SetAttributeVector( Attr, ATTR_LENGTH );
|
|
SetAttributeVector( Attr, ATTR_SIZE );
|
|
SetAttributeVector( Attr, ATTR_MIN );
|
|
SetAttributeVector( Attr, ATTR_MAX );
|
|
#else // 0
|
|
if( GetBasicType()->NodeKind() != NODE_ARRAY )
|
|
{
|
|
SetAttributeVector( Attr, ATTR_FIRST );
|
|
SetAttributeVector( Attr, ATTR_LAST );
|
|
SetAttributeVector( Attr, ATTR_LENGTH );
|
|
SetAttributeVector( Attr, ATTR_SIZE );
|
|
SetAttributeVector( Attr, ATTR_MIN );
|
|
SetAttributeVector( Attr, ATTR_MAX );
|
|
}
|
|
#endif // 0
|
|
|
|
DoSetAttributes(this,
|
|
Attr,
|
|
pPostAttrPointer,
|
|
pAttrList );
|
|
}
|
|
node_skl *
|
|
node_pointer::Clone()
|
|
{
|
|
node_pointer * pClone = new node_pointer();
|
|
return CloneAction( pClone );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
utility routines.
|
|
*****************************************************************************/
|
|
ATTR_T
|
|
XlateToTempPtrAttr(
|
|
ATTR_T A )
|
|
{
|
|
switch( A )
|
|
{
|
|
case ATTR_REF: return ATTR_TEMP_REF;
|
|
case ATTR_UNIQUE: return ATTR_TEMP_UNIQUE;
|
|
case ATTR_PTR: return ATTR_TEMP_PTR;
|
|
default: return ATTR_NONE;
|
|
}
|
|
}
|
|
/*****************************************************************************
|
|
The MIPS compiler is of poor intelligence. It does not like virtual in-line
|
|
functions. So I have to take care of the fellow and out of line these
|
|
*****************************************************************************/
|
|
void
|
|
npa::GetAllocBoundInfo(
|
|
BufferManager *p1,
|
|
BufferManager *p2,
|
|
BOUND_PAIR *pP,
|
|
node_skl *p )
|
|
{
|
|
}
|
|
void
|
|
npa::GetValidBoundInfo(
|
|
BufferManager *p1,
|
|
BufferManager *p2,
|
|
BOUND_PAIR *pP,
|
|
node_skl *p )
|
|
{
|
|
}
|
|
BOOL
|
|
node_array::IsFixedSizedArray()
|
|
{
|
|
return !(GetNodeState() & NODE_STATE_CONF_ARRAY);
|
|
}
|
|
|
|
//
|
|
// Must be called from within the semantic analysis, 'cause this needs the
|
|
// context stack.
|
|
//
|
|
|
|
BOOL
|
|
node_array::IsThisOutermostDimension()
|
|
{
|
|
return pGlobalContext->IsOutermostArrayDimension();
|
|
}
|
|
|
|
unsigned long
|
|
node_array::GetFixedDimension()
|
|
{
|
|
expr_node * pExpr;
|
|
unsigned long Result;
|
|
ATTR_T Attr;
|
|
|
|
Attr = FInSummary( ATTR_SIZE ) ? ATTR_SIZE :
|
|
FInSummary( ATTR_MAX ) ? ATTR_MAX : ATTR_INT_SIZE;
|
|
|
|
if( FInSummary( Attr ) )
|
|
{
|
|
pExpr = ((sa *)(GetAttribute( Attr )))->GetExpr();
|
|
|
|
if( !pExpr->IsConstant() )
|
|
return 0;
|
|
|
|
Result = (unsigned long)pExpr->Evaluate();
|
|
|
|
if( Attr == ATTR_MAX )
|
|
Result += 1UL;
|
|
|
|
return Result;
|
|
}
|
|
return 0;
|
|
}
|
|
|