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.
2179 lines
65 KiB
2179 lines
65 KiB
/*****************************************************************************/
|
|
/** Microsoft LAN Manager **/
|
|
/** Copyright(c) Microsoft Corp., 1987-1990 **/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************
|
|
File : compnode.cxx
|
|
Title : struct / union / enum node handling routines
|
|
History :
|
|
08-Aug-1991 VibhasC Created
|
|
|
|
*****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
includes
|
|
****************************************************************************/
|
|
|
|
#include "nulldefs.h"
|
|
extern "C" {
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
}
|
|
#include "buffer.hxx"
|
|
#include "nodeskl.hxx"
|
|
#include "compnode.hxx"
|
|
#include "miscnode.hxx"
|
|
#include "typedef.hxx"
|
|
#include "attrnode.hxx"
|
|
#include "acfattr.hxx"
|
|
#include "newexpr.hxx"
|
|
#include "cmdana.hxx"
|
|
#include "ctxt.hxx"
|
|
#include "dict.hxx"
|
|
#include "tlnmgr.hxx"
|
|
|
|
/****************************************************************************
|
|
local defines
|
|
****************************************************************************/
|
|
|
|
#define ADJUST_OFFSET(Offset, M, AlignFactor) \
|
|
Offset += (M = Offset % AlignFactor) ? (AlignFactor-M) : 0
|
|
|
|
|
|
/****************************************************************************
|
|
extern data
|
|
****************************************************************************/
|
|
|
|
extern ATTR_SUMMARY * pPreAttrField;
|
|
extern ATTR_SUMMARY * pPreAttrUnion;
|
|
extern ATTR_SUMMARY * pPreAttrStruct;
|
|
extern CTXTMGR * pGlobalContext;
|
|
extern CMD_ARG * pCommand;
|
|
|
|
/****************************************************************************
|
|
extern procedures
|
|
****************************************************************************/
|
|
|
|
extern node_skl * StructOrUnionLargestElement( node_skl *);
|
|
extern node_skl * StructOrUnionLargestNdr( node_skl *);
|
|
extern STATUS_T DoSetAttributes( node_skl *,
|
|
ATTR_SUMMARY *,
|
|
ATTR_SUMMARY *,
|
|
type_node_list *);
|
|
extern void ParseError( STATUS_T, char * );
|
|
extern int CompareCase( void *, void * );
|
|
extern void PrintCase( void * );
|
|
extern BOOL IsIntegralType( node_skl * );
|
|
extern void SetLocalAllocState( node_state );
|
|
extern node_state SetLocalAllocField( node_skl * );
|
|
extern BOOL IsValueInRangeOfType( node_skl *, expr_node *);
|
|
extern BOOL IsCompatibleIntegralType(node_skl *,node_skl *);
|
|
extern BOOL IsTempName( char * );
|
|
extern void ReportOutOfRange( STATUS_T, expr_node * );
|
|
/****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
node_field procedures
|
|
****************************************************************************/
|
|
|
|
node_field::node_field() : node_skl( NODE_FIELD )
|
|
{
|
|
}
|
|
node_field::node_field(
|
|
char * pName ) : node_skl( NODE_FIELD )
|
|
{
|
|
SetSymName( pName );
|
|
}
|
|
|
|
node_state
|
|
node_field::PreSCheck(
|
|
BadUseInfo * pBadUseInfo )
|
|
{
|
|
UNUSED( pBadUseInfo );
|
|
return NODE_STATE_OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
PostSCheck:
|
|
semantic checks after the child of the field node has been processed.
|
|
|
|
Note:
|
|
the switch type vs switch_is checking can be done only at the use of
|
|
a union, so if the field derives from a union, then we need to do use
|
|
processing.
|
|
****************************************************************************/
|
|
node_state
|
|
node_field::PostSCheck(
|
|
BadUseInfo * pBadUseInfo )
|
|
{
|
|
|
|
node_state NState = GetNodeState();
|
|
su * pParent = (su *)
|
|
pGlobalContext->GetLastContext(C_COMP);
|
|
BOOL fParentIsUnion = ( pParent->NodeKind() == NODE_UNION );
|
|
// BOOL fLastField = pGlobalContext->IsLastField();
|
|
BOOL fLastField = GetSibling() == (node_skl *)0;
|
|
node_skl * pChildType = GetBasicType();
|
|
NODE_T BasicNodeKind = pChildType->NodeKind();
|
|
|
|
CheckBadConstructs( pBadUseInfo );
|
|
|
|
#if 0
|
|
/**
|
|
** A field may not derive from a context_handle
|
|
**/
|
|
|
|
if( HasAnyCtxtHdlSpecification() )
|
|
ParseError( BAD_CON_CTXT_HDL_FIELD, (char *)NULL );
|
|
|
|
#endif // 0
|
|
|
|
//
|
|
// a field cannot derive from a primitive handle or a context_handle.
|
|
//
|
|
|
|
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_FIELD, (char *)0 );
|
|
|
|
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 the basic type is a handle_t, then reset that because an error
|
|
// would already have been reported.
|
|
//
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_BASIC_TYPE_HANDLE_T ) )
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_BASIC_TYPE_HANDLE_T );
|
|
|
|
/**
|
|
** If the field derives from a conformant array, then it must be the
|
|
** last in the structure. The presence of a conformant array underneath
|
|
** is by the node-state-conf-array, and the context manager can tell if the
|
|
** field was the last field.
|
|
**/
|
|
|
|
if( NState & NODE_STATE_CONF_ARRAY )
|
|
{
|
|
if ( !fLastField && !fParentIsUnion )
|
|
ParseError( CONFORMANT_ARRAY_NOT_LAST, (char *)NULL );
|
|
}
|
|
|
|
/**
|
|
** If the field derives from an unsized string, then it is rpcable. Why ??
|
|
** If the field derives from a ptr to conf-struct then it IS rpcable.
|
|
**/
|
|
|
|
if( pBadUseInfo->AnyReasonForNonRPCAble() )
|
|
{
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_UNSIZED_STRING ) )
|
|
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_UNSIZED_STRING );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_P_TO_C_STRUCT ) )
|
|
pBadUseInfo->ResetNonRPCAbleBecause(
|
|
NR_DERIVES_FROM_P_TO_C_STRUCT );
|
|
|
|
|
|
//In ms_ext mode, we don't report errors for non-rpcable fields.
|
|
if( !pCommand->IsSwitchDefined( SWITCH_MS_EXT ) )
|
|
{
|
|
//
|
|
// if the import mode is osf (used_single) then any non-rpcable stuff
|
|
// must be reported to the user, since we will generate aux routines
|
|
// for such a struct / union
|
|
|
|
if( pCommand->GetImportMode() == IMPORT_OSF )
|
|
{
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_INT ) ||
|
|
pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT ) )
|
|
ParseError( NON_RPC_FIELD_INT, (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_VOID ) )
|
|
ParseError( NON_RPC_FIELD_PTR_TO_VOID, (char *)0 );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_BIT_FIELDS ) )
|
|
ParseError( NON_RPC_FIELD_BIT_FIELDS, (char *)0 );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_NON_RPC_UNION ))
|
|
ParseError( NON_RPC_FIELD_NON_RPC_UNION, (char *)0 );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_FUNC ))
|
|
ParseError( NON_RPC_FIELD_FUNC_PTR, (char *)0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
** The backend wants that if the field derives from a pointer then
|
|
** then it should not inherit the node-state-varying array. ??
|
|
** Also, a field inherits the node_state_union ONLY if the basic type
|
|
** is not a structure.
|
|
**/
|
|
|
|
|
|
if( BasicNodeKind == NODE_POINTER )
|
|
|
|
NState = ResetNodeState( NODE_STATE_VARYING_ARRAY );
|
|
|
|
#if 0
|
|
else if( ( pChildType->GetNodeState() & NODE_STATE_UNION ) &&
|
|
#endif // 0
|
|
if( ( pChildType->GetNodeState() & NODE_STATE_UNION ) &&
|
|
( BasicNodeKind != NODE_STRUCT ) )
|
|
|
|
NState = SetNodeState( NODE_STATE_UNION );
|
|
|
|
//
|
|
// if this is the last field, and it is an encapsulated union, then
|
|
// this is a struct / union containing an encap union as the last member
|
|
// so the backend can throw off alignment information.
|
|
//
|
|
|
|
if( fLastField )
|
|
{
|
|
BOOL f;
|
|
|
|
if( f = (pChildType->IsLastMemberEncapUnion() || pChildType->IsEncapsulatedStruct() ))
|
|
pParent->SetLastMemberIsEncapUnion();
|
|
}
|
|
|
|
/**
|
|
** If the field is a field of a union, then
|
|
** check if the field has a case label or default. If not, the union
|
|
** is not rpcable. This error is not reported here, but is reported
|
|
** at use time, since only if the structure is used, is this of any
|
|
** significance.
|
|
**/
|
|
|
|
if( fParentIsUnion )
|
|
{
|
|
BOOL fCaseExpr = FInSummary( ATTR_CASE );
|
|
|
|
if( !IsEmptyArm() )
|
|
pParent->ResetHasOnlyEmptyArm();
|
|
|
|
if( !(fCaseExpr || FInSummary( ATTR_DEFAULT ) ) )
|
|
{
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_NON_RPC_UNION );
|
|
pParent->SetNonRPCAble();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// register the fact that a case label or a default label has
|
|
// been seen.
|
|
//
|
|
|
|
pBadUseInfo->IncrementNoOfArmsWithCaseLabels();
|
|
|
|
/**
|
|
** Check for duplicate case labels
|
|
**/
|
|
|
|
if( fCaseExpr )
|
|
{
|
|
/**
|
|
** insert the case values into the dictionary. The dictionary
|
|
** will complain if the case value is duplicate.
|
|
**/
|
|
|
|
node_case * pCase= (node_case *)GetAttribute( ATTR_CASE );
|
|
|
|
((node_union *)pParent)->SetCaseExpr( pCase->GetExprList() );
|
|
|
|
}
|
|
|
|
/**
|
|
** the parent needs use processing, to set up the switch type
|
|
** or switch is
|
|
**/
|
|
|
|
pParent->SetUseProcessingNeeded();
|
|
|
|
}
|
|
|
|
//
|
|
// if the field is a field of a union, it must not derive from a
|
|
// conformant or varying array or struct.
|
|
//
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CONF ) ||
|
|
pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_VARY ) ||
|
|
pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CONF_PTR ) ||
|
|
pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_VARY_PTR )
|
|
)
|
|
{
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_CONF );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_VARY );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_CONF_PTR );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_VARY_PTR );
|
|
ParseError( BAD_CON_UNION_FIELD_CONF, (char *)0 );
|
|
}
|
|
|
|
//
|
|
// The field of an encapsulated union cannot derive from another
|
|
// encapsulated union.
|
|
//
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_BAD_RT_NE_UNION ) )
|
|
{
|
|
ParseError( NE_UNION_FIELD_NE_UNION, (char *)0 );
|
|
}
|
|
|
|
if( GetNodeState() & NODE_STATE_CONF_ARRAY )
|
|
{
|
|
if( DerivesFromTransmitAs() )
|
|
{
|
|
node_skl * pBT = GetBasicTransmissionType();
|
|
if( pBT && pBT->FInSummary( ATTR_TRANSMIT ) )
|
|
{
|
|
node_skl * pTT = ((node_def *)pBT)->GetTransmitAsType();
|
|
if( pTT &&
|
|
((pTT->GetNodeState() & NODE_STATE_CONF_ARRAY) == NODE_STATE_CONF_ARRAY )
|
|
)
|
|
NState = ResetNodeState( NODE_STATE_CONF_ARRAY );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
** The field may need use processing if say it has a string attribute
|
|
** underneath , or a union underneath etc
|
|
**/
|
|
|
|
if( NeedsUseProcessing() )
|
|
{
|
|
UseProcessing();
|
|
NState = ResetNodeState( NODE_STATE_NEEDS_USE_PROCESSING );
|
|
}
|
|
return SetNodeState( NState );
|
|
}
|
|
|
|
void
|
|
node_field::CheckBadConstructs(
|
|
BadUseInfo * pBadUseInfo )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
check bad field constructs
|
|
|
|
Arguments:
|
|
|
|
pBadUseInfo - pointer to a bad use information block.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
/**
|
|
** Check if the field is contructed properly. ie it has valid
|
|
** members underneath.
|
|
** There are 2 kinds of errors which can occur here. Errors which
|
|
** are bad c constructs. They are bad osf constructs also. Some errors
|
|
** are valid c (therefore valid in c_port) but not in ms_ext or c_port
|
|
**/
|
|
|
|
if( pBadUseInfo->AnyReasonForBadConstruct() )
|
|
{
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_VOID ) )
|
|
{
|
|
ParseError( BAD_CON_FIELD_VOID, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_VOID );
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_PTR_TO_VOID ) )
|
|
{
|
|
// should we really disallow the use of void ptr in a struct ? I dont think so
|
|
// as long as he does not use a void ptr in an rpc, it should be fine.
|
|
#if 0
|
|
ParseError( BAD_CON_FIELD_VOID_PTR, (char *)NULL );
|
|
#endif
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_PTR_TO_VOID);
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_INT ) ||
|
|
pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_PTR_TO_INT ) )
|
|
{
|
|
ParseError( BAD_CON_INT, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_INT );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_PTR_TO_INT );
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_FUNC ) )
|
|
{
|
|
ParseError( BAD_CON_FIELD_FUNC, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_FUNC );
|
|
}
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_UNSIZED_ARRAY) &&
|
|
!pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_UNSIZED_STRING))
|
|
{
|
|
ParseError( UNSIZED_ARRAY, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause(
|
|
BC_DERIVES_FROM_UNSIZED_ARRAY );
|
|
}
|
|
|
|
#if 0
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_UNSIZED_STRING))
|
|
{
|
|
ParseError( UNSIZED_ARRAY, (char *)NULL );
|
|
pBadUseInfo->ResetBadConstructBecause(
|
|
BC_DERIVES_FROM_UNSIZED_STRING );
|
|
}
|
|
#endif // 0
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_E_STAT_T))
|
|
{
|
|
ParseError( BAD_CON_E_STAT_T_FIELD, (char *)0 );
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_E_STAT_T );
|
|
|
|
}
|
|
|
|
//
|
|
// the use of a type with ignore is fine in a field. If the bad use
|
|
// info says this, reset it.
|
|
//
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_IGNORE))
|
|
{
|
|
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_IGNORE );
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// we dont allow a field to derive from transmit_as in this version.
|
|
// So report the error and reset the condition so that the user of
|
|
// this struct does not report it again!.
|
|
//
|
|
|
|
if( pBadUseInfo->BadConstructBecause( BC_MAY_DERIVE_EMBEDDED_TRANSMIT ))
|
|
{
|
|
ParseError( EMBEDDED_TRANSMIT_AS , (char *)0 );
|
|
pBadUseInfo->ResetBadConstructBecause(
|
|
BC_MAY_DERIVE_EMBEDDED_TRANSMIT );
|
|
}
|
|
#endif // 0
|
|
}
|
|
|
|
//
|
|
// if it is an unnamed field, then this is invalid except under
|
|
// ms_ext or imp local. In any event, set the bad construct information,
|
|
// so that the struct node can check for duplicate names.
|
|
// If it is an unnamed field, the basic type must be a struct/union.
|
|
// However if the basic type is yet unresolved, then dont report error.
|
|
//
|
|
|
|
if( !IsNamedNode() )
|
|
{
|
|
|
|
NODE_T NT = GetBasicType()->NodeKind();
|
|
|
|
if( NT != NODE_ERROR )
|
|
{
|
|
if( !pGlobalContext->IsSecondSemanticPass() )
|
|
ParseError( BAD_CON_UNNAMED_FIELD, (char *)0 );
|
|
|
|
if( (NT != NODE_STRUCT) &&
|
|
(NT != NODE_UNION) &&
|
|
(NT != NODE_FORWARD) )
|
|
ParseError( BAD_CON_UNNAMED_FIELD_NO_STRUCT, (char *)0 );
|
|
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_UNNAMED_FIELD);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
node_field::SetAttribute(
|
|
type_node_list * pAttrList )
|
|
{
|
|
DoSetAttributes( this, pPreAttrField, (ATTR_SUMMARY *)NULL, pAttrList );
|
|
}
|
|
|
|
expr_list *
|
|
node_field::GetCaseExprList()
|
|
{
|
|
|
|
if( FInSummary( ATTR_CASE ) )
|
|
{
|
|
node_case * pCase;
|
|
|
|
pCase = (node_case *)GetAttribute(ATTR_CASE);
|
|
|
|
return pCase->GetExprList();
|
|
}
|
|
|
|
return (expr_list *)NULL;
|
|
}
|
|
|
|
BOOL
|
|
node_field::IsEmptyArm()
|
|
{
|
|
return ( GetBasicType()->NodeKind() == NODE_ERROR );
|
|
|
|
}
|
|
|
|
short
|
|
node_field::GetTopLevelNames(
|
|
TLNDICT * pTLNDict,
|
|
BOOL fReportError )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
fill the top level names dictionary supplied with all top level names.
|
|
|
|
Arguments:
|
|
|
|
pTLNDict - a pointer to a pre-allocated top-level names dictionary.
|
|
fReportError- report error if true and there is an error.
|
|
|
|
Return Value:
|
|
|
|
a count of the number of top level names that got added.
|
|
|
|
Notes:
|
|
|
|
If this is a named field then it is a top level name, else if it has
|
|
a structure underneath, then the fields of that structure are top-level
|
|
names.
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
short Count = 0;
|
|
node_skl * pNode;
|
|
NODE_T NT;
|
|
STATUS_T Status;
|
|
char * pN;
|
|
|
|
pGlobalContext->PushContext( this );
|
|
|
|
//
|
|
// if this node is a named node, then the user cannot access it w/o the
|
|
// name, hence this is not considered a top level name.
|
|
|
|
if( !IsNamedNode() )
|
|
{
|
|
|
|
//
|
|
// if this is an unnamed node, then it must derive from a structure,
|
|
// else this is a syntax error reported elsewhere.
|
|
//
|
|
|
|
NT = (pNode = GetBasicType())->NodeKind();
|
|
|
|
if( (NT == NODE_STRUCT ) || (NT == NODE_UNION ) )
|
|
{
|
|
Count += pNode->GetTopLevelNames( pTLNDict, fReportError );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TLNBLOCK * pTLNBlk = new TLNBLOCK(
|
|
pGlobalContext->GetCurrentSymbolTable(),
|
|
pN = GetSymName() );
|
|
if( (Status = pTLNDict->InsertTLNBlock( pTLNBlk ) ) != STATUS_OK )
|
|
{
|
|
ParseError( Status, pN);
|
|
delete pTLNBlk;
|
|
}
|
|
else
|
|
Count++;
|
|
}
|
|
|
|
pGlobalContext->PopContext();
|
|
|
|
return Count;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
node_bitfield procedures
|
|
****************************************************************************/
|
|
node_state
|
|
node_bitfield::PostSCheck(
|
|
BadUseInfo * pBadUseInfo )
|
|
{
|
|
node_skl * pBasicType = GetBasicType();
|
|
NODE_T BasicNT = pBasicType->NodeKind();
|
|
|
|
/**
|
|
** if the compiler mode is osf, then bit fields are an error anyway.
|
|
**/
|
|
|
|
ParseError(BAD_CON_BIT_FIELDS, (char *)NULL );
|
|
|
|
/**
|
|
** the bit field can be applied to declarators which are only base types
|
|
** and that too the integral types.
|
|
**/
|
|
|
|
if( !IsIntegralType( pBasicType ) &&
|
|
!(BasicNT == NODE_CHAR ) &&
|
|
!(BasicNT == NODE_WCHAR_T ) )
|
|
|
|
{
|
|
ParseError( BAD_CON_BIT_FIELD_NOT_INTEGRAL, (char *)NULL );
|
|
}
|
|
|
|
/**
|
|
** ansi allows bit fields only on int or unsigned int, msft allows
|
|
** bit fields on any integral type. Report this as a warning at
|
|
** level 3
|
|
**/
|
|
|
|
if( pBasicType->NodeKind() != NODE_INT )
|
|
{
|
|
ParseError( BAD_CON_BIT_FIELD_NON_ANSI, (char *)NULL );
|
|
}
|
|
|
|
/**
|
|
** if the field derives from a bit field specification, then
|
|
** the structure is non-rpcable
|
|
**/
|
|
|
|
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_BIT_FIELDS );
|
|
|
|
return NODE_STATE_IS_NON_RPCABLE_TYPE;
|
|
|
|
}
|
|
/****************************************************************************
|
|
su procedures
|
|
****************************************************************************/
|
|
|
|
su::su(
|
|
NODE_T Nt ) : node_skl( Nt )
|
|
{
|
|
|
|
ResetOriginalTypedefName();
|
|
SUInfo.pOriginalTypedefName = 0;
|
|
SUInfo.pBadUseInfo = new BadUseInfo;
|
|
ForcedAlignment = 0;
|
|
fLastMemberIsEncapUnion = 0;
|
|
fDerivesFromTransmitAs = 0;
|
|
fDontGenerateAuxRoutines= 0;
|
|
|
|
SetHasOnlyEmptyArm();
|
|
|
|
}
|
|
/****************************************************************************
|
|
RegFDAndSetE:
|
|
This routine exists because of the possiblility that fdecls can exists in
|
|
a structure decl, and will not be registered if no semantic check is done
|
|
eg if the struct/union is a return type of a proc which is typedefed and
|
|
or is in local . For that same reason, edges will not be set up if this
|
|
happens.
|
|
|
|
NOTE: the current context is the parents context, so dont push context
|
|
here.
|
|
****************************************************************************/
|
|
void
|
|
su::RegFDAndSetE()
|
|
{
|
|
node_skl * pParent = pGlobalContext->GetCurrentNode();
|
|
|
|
node_skl::RegFDAndSetE();
|
|
|
|
if( !IsEdgeSetUp() )
|
|
{
|
|
|
|
if( pParent )
|
|
pParent->SetEdgeType( EDGE_DEF );
|
|
|
|
pParent = pGlobalContext->GetClosestEnclosingScopeForEdge();
|
|
|
|
/**
|
|
** It might be that the parent is really the same node we got
|
|
** last time, but do this anyway
|
|
**/
|
|
|
|
while( pParent && (pParent != this ) )
|
|
{
|
|
pParent->SetEdgeType( EDGE_DEF );
|
|
|
|
assert( pParent != pParent->GetBasicType() );
|
|
|
|
pParent = pParent->GetBasicType();
|
|
}
|
|
|
|
EdgeSetUp();
|
|
}
|
|
|
|
}
|
|
BOOL
|
|
su::HasOnlyFirstLevelRefPtr()
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
node_skl * pNode;
|
|
BOOL fHasOnlyFLevelRef = TRUE;
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
if( !pNode->HasOnlyFirstLevelRefPtr() )
|
|
{
|
|
fHasOnlyFLevelRef = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
delete pTNList;
|
|
return fHasOnlyFLevelRef;
|
|
}
|
|
|
|
BOOL
|
|
su::HasSizedComponent()
|
|
{
|
|
BOOL fHasAConfArray = ((GetNodeState() & NODE_STATE_CONF_ARRAY) ==
|
|
NODE_STATE_CONF_ARRAY);
|
|
BOOL fHasSizedComponent = CheckNodeStateInMembers( NODE_STATE_SIZE );
|
|
BOOL fHasComponentWithStructSize = CheckNodeStateInMembers(
|
|
NODE_STATE_STRUCT_SIZE );
|
|
BOOL f1 = TRUE, f2 = TRUE;
|
|
|
|
if((fHasSizedComponent && !fHasAConfArray) ||
|
|
fHasComponentWithStructSize )
|
|
f1 = TRUE;
|
|
|
|
// BIG HACK. The backend wants that normally if there is a conformant array
|
|
// the has sized component call must return a NO, except if the array is an
|
|
// array of pointers which have the string attribute
|
|
|
|
node_skl *pConfArray = (node_skl *)GetConfArrayNode();
|
|
node_skl *pPtr;
|
|
|
|
if( pConfArray &&
|
|
(pPtr = pConfArray->GetBasicType())->NodeKind() == NODE_POINTER)
|
|
{
|
|
// if it is a conformant array of pointers then if the basic type of
|
|
// the pointer is a conformant structure or the pointer has string,
|
|
// say yes to sized component question. Else say no.
|
|
|
|
if( pPtr )
|
|
{
|
|
do
|
|
{
|
|
if( pPtr->FInSummary( ATTR_STRING ))
|
|
{
|
|
f2 = TRUE;
|
|
goto label1; // sorry
|
|
}
|
|
} while( pPtr && pPtr->GetBasicType()->NodeKind() == NODE_POINTER );
|
|
if(((pPtr->GetNodeState()& NODE_STATE_CONF_ARRAY )==
|
|
NODE_STATE_CONF_ARRAY ) ||
|
|
pPtr->FInSummary( ATTR_STRING ));
|
|
f2 = TRUE;
|
|
}
|
|
}
|
|
|
|
label1:
|
|
return (f1 || f2);
|
|
}
|
|
BOOL
|
|
su::HasLengthedComponent()
|
|
{
|
|
BOOL fHasLengthedComponent = CheckNodeStateInMembers( NODE_STATE_LENGTH );
|
|
return fHasLengthedComponent;
|
|
}
|
|
|
|
short
|
|
su::GetTopLevelNames(
|
|
TLNDICT * pTLNDict,
|
|
BOOL fReportError)
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
fill the top level names dictionary supplied with all top level names.
|
|
|
|
Arguments:
|
|
|
|
pTLNDict - a pointer to a pre-allocated top-level names dictionary.
|
|
fReportError- report error if true.
|
|
|
|
Return Value:
|
|
|
|
a count of the number of top level names that got added.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
short Count = 0;
|
|
node_skl * pNode;
|
|
|
|
pGlobalContext->PushContext( this );
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
Count += pNode->GetTopLevelNames( pTLNDict, fReportError );
|
|
}
|
|
|
|
delete pTNList;
|
|
|
|
pGlobalContext->PopContext();
|
|
return Count;
|
|
}
|
|
|
|
SymTable *
|
|
su::GetSymScopeOfTopLevelName(
|
|
char * pName )
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Get the symbol table scope of the top level name.
|
|
|
|
Arguments:
|
|
|
|
pName - the top level name for which this search is being made.
|
|
|
|
Return Value:
|
|
|
|
the symbol scope of the top level name.
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
TLNDICT * pTLNDict = new TLNDICT;
|
|
|
|
if( GetTopLevelNames( pTLNDict, FALSE ) )
|
|
{
|
|
|
|
// at least 1 top level name.
|
|
|
|
return pTLNDict->GetSymTableForTopLevelName( pName );
|
|
|
|
}
|
|
|
|
return (SymTable *)0;
|
|
}
|
|
|
|
void
|
|
su::MarkUsage()
|
|
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
Routine Description:
|
|
|
|
Mark the usage of this structure.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Notes:
|
|
|
|
This routine marks the usage of the struct or union as context handle or
|
|
as a structure itself. Structs and unions result in auxillary routines
|
|
and the backend decides when to generate these. If the usage of the struct
|
|
or union is only as a context handle and not otherwise, then the aux
|
|
routines need not be produced, since the underlying type is not marshalled
|
|
for a context handle.
|
|
|
|
Assume that the global context is setup already.
|
|
Dont do this if we are making a second semantic pass, the info in the
|
|
first pass is good enough.
|
|
|
|
----------------------------------------------------------------------------*/
|
|
{
|
|
node_skl * pLastContext;
|
|
EnCtxt LastContextCode;
|
|
BOOL fUsageAsContextHandle = FALSE;
|
|
|
|
if( pGlobalContext->IsSecondSemanticPass() )
|
|
return;
|
|
|
|
//
|
|
// get to the last usage context. If the last usage context is not
|
|
// another structure or typedef or a parameter, then this is a standalone
|
|
// structure or union definition, and we need to produce the aux routines
|
|
// for this structure or union.
|
|
//
|
|
|
|
if( !(pLastContext =
|
|
pGlobalContext->GetLastEnclosingContext( LastContextCode = C_COMP )))
|
|
{
|
|
if( !( pLastContext =
|
|
pGlobalContext->GetLastEnclosingContext( LastContextCode = C_DEF )))
|
|
{
|
|
if( !( pLastContext =
|
|
pGlobalContext->GetLastEnclosingContext(LastContextCode = C_PARAM)))
|
|
fUsageAsContextHandle = FALSE;
|
|
}
|
|
}
|
|
|
|
if( pLastContext && pLastContext->FInSummary( ATTR_CONTEXT ) )
|
|
fUsageAsContextHandle = TRUE;
|
|
|
|
//
|
|
// set the appropriate status.
|
|
//
|
|
|
|
SetUsageAsCtxtHdl( fUsageAsContextHandle );
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
node_struct procedures
|
|
****************************************************************************/
|
|
|
|
unsigned long
|
|
node_struct::GetSize(
|
|
unsigned long CurOffset )
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
unsigned long CurOffsetSave = CurOffset;
|
|
unsigned long Mod;
|
|
unsigned long CurAlign;
|
|
node_skl * pNode;
|
|
|
|
/**
|
|
** the alignment of the struct is the alignment of the largest
|
|
** element of the structure. Calculate the alignment of the largest
|
|
** element , adjust the offset of the start of the structure, and
|
|
** get the size
|
|
**/
|
|
|
|
CurAlign = GetMscAlign();
|
|
ADJUST_OFFSET( CurOffset, Mod, CurAlign );
|
|
|
|
/**
|
|
** now just calculate the size of each element and return the
|
|
** size of the struct
|
|
**/
|
|
|
|
GetMembers( pTNList );
|
|
pTNList->Init();
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
CurOffset += pNode->GetSize( CurOffset );
|
|
}
|
|
|
|
delete pTNList;
|
|
|
|
//.. The struct has to be aligned at the end, too, as it would
|
|
//.. within an array.
|
|
|
|
ADJUST_OFFSET( CurOffset, Mod, CurAlign );
|
|
|
|
return CurOffset - CurOffsetSave;
|
|
}
|
|
|
|
node_skl *
|
|
node_struct::GetLargestElement()
|
|
{
|
|
return StructOrUnionLargestElement( this );
|
|
}
|
|
|
|
node_skl *
|
|
node_struct::GetLargestNdr()
|
|
{
|
|
return StructOrUnionLargestNdr( this );
|
|
}
|
|
|
|
node_state
|
|
node_struct::PostSCheck(
|
|
BadUseInfo * pB)
|
|
{
|
|
|
|
node_skl * pParent = pGlobalContext->GetParentContext();
|
|
EDGE_T EdgeType= EDGE_USE ;
|
|
|
|
//
|
|
// if the structure/union derives from non-rpcable types, then indicate
|
|
// not to generate aux routines. The backend may try to generate aux
|
|
// routines even if the structure is non-rpcable because it passes when
|
|
// the c_ext switch is specified.
|
|
// Dont worry about such a structure being used or not used. Becuase if
|
|
// it is used, the parameter node will report the error. It is only when
|
|
// c_ext is specified along with import osf mode that the backend will
|
|
// try to generate the aux routine. That will certainly fail since the
|
|
// backend is setup to assume nothing wrong with the type graph.
|
|
//
|
|
|
|
if( pB->AnyReasonForNonRPCAble() )
|
|
{
|
|
if(
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_INT ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_VOID ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_VOID ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_FUNC ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_FUNC ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_NON_RPC_UNION ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_BIT_FIELDS )
|
|
)
|
|
{
|
|
DontGenerateAuxRoutines();
|
|
}
|
|
}
|
|
|
|
//
|
|
// if the edge to this has not been set up, set it. The edge needs to
|
|
// be set from not just the parent, but also from the last typedef
|
|
// node / field node etc. The backend needs it so.
|
|
//
|
|
|
|
if( !IsEdgeSetUp() )
|
|
{
|
|
|
|
EdgeType = EDGE_DEF;
|
|
|
|
if( pParent )
|
|
pParent->SetEdgeType( EdgeType );
|
|
|
|
pParent = pGlobalContext->GetClosestEnclosingScopeForEdge();
|
|
|
|
/**
|
|
** It might be that the parent is really the same node we got
|
|
** last time, but do this anyway. Also, all the nodes below the
|
|
** parent get the def edge.
|
|
**/
|
|
|
|
while( pParent && (pParent != this ) )
|
|
{
|
|
pParent->SetEdgeType( EdgeType );
|
|
|
|
assert( pParent != pParent->GetBasicType() );
|
|
|
|
pParent = pParent->GetBasicType();
|
|
}
|
|
|
|
EdgeSetUp();
|
|
}
|
|
|
|
//
|
|
// dont allow definition of the struct in a param list.
|
|
//
|
|
|
|
if( (EdgeType == EDGE_DEF ) && pGlobalContext->GetLastContext( C_PROC ) )
|
|
{
|
|
ParseError( COMP_DEF_IN_PARAM_LIST, (char *)0 );
|
|
}
|
|
|
|
/**
|
|
** store all bad use reasons collected from the field nodes. If the struct
|
|
** has a conformant array, transform bad construct reason from conf
|
|
** array to conformant struct
|
|
**/
|
|
|
|
if( pB->BadConstructBecause( BC_DERIVES_FROM_CONF ) )
|
|
{
|
|
pB->ResetBadConstructBecause( BC_DERIVES_FROM_CONF );
|
|
pB->SetBadConstructBecause( BC_DERIVES_FROM_CONF_STRUCT );
|
|
}
|
|
|
|
if( pB->BadConstructBecause( BC_DERIVES_FROM_VARY ) )
|
|
{
|
|
pB->ResetBadConstructBecause( BC_DERIVES_FROM_VARY );
|
|
pB->SetBadConstructBecause( BC_DERIVES_FROM_VARY_STRUCT );
|
|
}
|
|
|
|
//
|
|
// if it derives from a pointer equivalent of a conformant array
|
|
// or varying array, it is fine, because it is properly encapsulated.
|
|
// But this structure must not be used in the definition of a presented
|
|
// type in a transmit_as construct. Therefore, note that and complain
|
|
// in the typedef analysis.
|
|
//
|
|
|
|
if( pB->BadConstructBecause( BC_DERIVES_FROM_CONF_PTR ) )
|
|
{
|
|
pB->ResetBadConstructBecause( BC_DERIVES_FROM_CONF_PTR );
|
|
pB->SetBadConstructBecause( BC_CV_PTR_STRUCT_BAD_IN_XMIT_AS );
|
|
}
|
|
|
|
if( pB->BadConstructBecause( BC_DERIVES_FROM_VARY_PTR ) )
|
|
{
|
|
pB->ResetBadConstructBecause( BC_DERIVES_FROM_VARY_PTR );
|
|
pB->SetBadConstructBecause( BC_CV_PTR_STRUCT_BAD_IN_XMIT_AS );
|
|
}
|
|
|
|
//
|
|
// if the reason for bad construct is that an array of unions may be
|
|
// derived, set that at rest because the struct node includes this
|
|
// and the union is therefore encapsulated properly.
|
|
//
|
|
|
|
if( pB->BadConstructBecause( BC_MAY_DERIVE_ARRAY_OF_UNIONS ) )
|
|
{
|
|
pB->ResetBadConstructBecause( BC_MAY_DERIVE_ARRAY_OF_UNIONS );
|
|
}
|
|
if( pB->BadConstructBecause( BC_BAD_RT_NE_UNION ) )
|
|
{
|
|
pB->ResetBadConstructBecause( BC_BAD_RT_NE_UNION );
|
|
}
|
|
|
|
if( pB->NonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR ) )
|
|
{
|
|
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR );
|
|
}
|
|
|
|
if( pB->NonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR ) )
|
|
{
|
|
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR );
|
|
}
|
|
|
|
//
|
|
// if this struct derives from an unnamed field, check for duplicate
|
|
// top level names.
|
|
//
|
|
|
|
if( pB->BadConstructBecause( BC_DERIVES_FROM_UNNAMED_FIELD ) )
|
|
{
|
|
TLNDICT * pTLNDict = new TLNDICT;
|
|
|
|
//
|
|
// this routine reports an error if we send it a true as the
|
|
// fReportError field. After this call returns we can throw the dict
|
|
// away.
|
|
//
|
|
|
|
GetTopLevelNames( pTLNDict, TRUE );
|
|
|
|
delete pTLNDict;
|
|
|
|
//
|
|
// reset this bad construct because we have already reported the
|
|
// error.
|
|
//
|
|
|
|
pB->ResetBadConstructBecause( BC_DERIVES_FROM_UNNAMED_FIELD );
|
|
}
|
|
|
|
SetAllBadConstructReasons( pB );
|
|
SetAllNonRPCAbleReasons( pB );
|
|
|
|
//
|
|
// Any handle specifications in encapsulations are not valid anymore
|
|
// so reset all such specifications.
|
|
//
|
|
|
|
pB->ResetAllHdlSpecifications();
|
|
// pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_TRANSMIT_AS );
|
|
|
|
/**
|
|
** if the struct node derives from conf array, then under certain
|
|
** cases it is non-rpcable.
|
|
**/
|
|
|
|
if( GetNodeState() & NODE_STATE_CONF_ARRAY )
|
|
{
|
|
SetNonRPCAbleReason( NR_DERIVES_FROM_CONF_STRUCT );
|
|
}
|
|
|
|
/****************************************************
|
|
** hack for node-state-size and length
|
|
****************************************************
|
|
|
|
SetLocalAllocField( this );
|
|
|
|
************** end of hack *************************/
|
|
|
|
/**
|
|
** If the struct has a pointer field , set node-state-embedded-ptr for
|
|
** the backend.
|
|
**/
|
|
|
|
if( GetNodeState() & NODE_STATE_POINTER )
|
|
{
|
|
SetNodeState( NODE_STATE_EMBEDDED_PTR );
|
|
}
|
|
|
|
if( CheckNodeStateInMembers( NODE_STATE_SIZE ) )
|
|
{
|
|
if( (GetNodeState() & NODE_STATE_CONF_ARRAY ) == NODE_STATE_CONF_ARRAY)
|
|
SetNodeState( NODE_STATE_STRUCT_SIZE );
|
|
}
|
|
|
|
if( pB->NonRPCAbleBecause( NR_DERIVES_FROM_TRANSMIT_AS ) )
|
|
SetDerivesFromTransmitAs();
|
|
|
|
#if 0
|
|
if( CheckNodeStateInMembers( NODE_STATE_LENGTH ) )
|
|
{
|
|
if( (GetNodeState() & NODE_STATE_CONF_ARRAY ) == NODE_STATE_CONF_ARRAY)
|
|
SetNodeState( NODE_STATE_STRUCT_LENGTH );
|
|
}
|
|
#endif // 0
|
|
|
|
return GetNodeState();
|
|
|
|
}
|
|
|
|
void
|
|
node_struct::SetAttribute(
|
|
type_node_list * pAttrList )
|
|
{
|
|
|
|
UNUSED( pAttrList );
|
|
return;
|
|
|
|
// DoSetAttributes( this, pPreAttrStruct, (ATTR_SUMMARY *)NULL, pAttrList );
|
|
|
|
}
|
|
|
|
BOOL
|
|
node_struct::IsStringableStruct()
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
BOOL fIsStringable = TRUE;
|
|
NODE_T NT;
|
|
node_skl * pNode;
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
NT = (pNode->GetBasicType())->NodeKind();
|
|
|
|
if( !(( NT == NODE_WCHAR_T ) || ( NT == NODE_CHAR ) ||
|
|
( NT == NODE_BYTE ) || ( NT == NODE_ERROR ) ||
|
|
( NT == NODE_FORWARD )
|
|
)
|
|
)
|
|
{
|
|
fIsStringable = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
delete pTNList;
|
|
return fIsStringable;
|
|
}
|
|
|
|
/****************************************************************************
|
|
node_union procedures
|
|
****************************************************************************/
|
|
node_union::node_union(
|
|
char * pName ) : su(NODE_UNION)
|
|
{
|
|
SetSymName( pName );
|
|
SetNodeState( NODE_STATE_UNION );
|
|
SetNodeState( NODE_STATE_EMBEDDED_UNION );
|
|
}
|
|
|
|
void
|
|
node_union::SetAttribute(
|
|
type_node_list * pAttrList )
|
|
{
|
|
DoSetAttributes( this, pPreAttrUnion, (ATTR_SUMMARY *)NULL, pAttrList );
|
|
}
|
|
|
|
node_skl *
|
|
node_union::GetLargestElement()
|
|
{
|
|
return StructOrUnionLargestElement( this );
|
|
}
|
|
|
|
node_skl *
|
|
node_union::GetLargestNdr()
|
|
{
|
|
return StructOrUnionLargestNdr( this );
|
|
}
|
|
|
|
unsigned long
|
|
node_union::GetSize(
|
|
unsigned long CurOffset )
|
|
{
|
|
unsigned long LargestSize = 0;
|
|
type_node_list * pTNList = new type_node_list;
|
|
node_skl * pNode;
|
|
unsigned long Temp;
|
|
|
|
/**
|
|
** this looks strange! Should we not be doing an alignment adjustment
|
|
** over the largest element of the union ? It seems to work for th
|
|
** backend for now (??), so I wont touch it, but this needs to be looked
|
|
** into
|
|
**/
|
|
|
|
UNUSED( CurOffset );
|
|
|
|
GetMembers(pTNList);
|
|
pTNList->Init();
|
|
while( pTNList->GetPeer(&pNode) == STATUS_OK)
|
|
{
|
|
if( (Temp = pNode->GetSize(0)) >= LargestSize )
|
|
{
|
|
LargestSize = Temp;
|
|
}
|
|
}
|
|
delete pTNList;
|
|
return LargestSize;
|
|
}
|
|
node_state
|
|
node_union::PreSCheck(
|
|
BadUseInfo * pB)
|
|
{
|
|
|
|
UNUSED( pB );
|
|
|
|
/**
|
|
** Allocate a dictionary which holds the case values
|
|
**/
|
|
|
|
Info.pCaseValueDict = new Dictionary( CompareCase, PrintCase );
|
|
fCaseChecked = 0;
|
|
fCaseValueDictReleased = 0;
|
|
|
|
//
|
|
// clear the info for no of arms with case labels. This is checked for
|
|
// in post scheck.
|
|
//
|
|
|
|
pB->InitNoOfArmsWithCaseLabels();
|
|
|
|
return SetNodeState( NODE_STATE_UNION );
|
|
|
|
}
|
|
node_state
|
|
node_union::PostSCheck(
|
|
BadUseInfo * pB)
|
|
{
|
|
|
|
UNUSED( pB );
|
|
|
|
node_skl * pParentAndTemp = pGlobalContext->GetParentContext();
|
|
EDGE_T EdgeType= EDGE_USE;
|
|
short Temp;
|
|
|
|
|
|
//
|
|
// if the structure/union derives from non-rpcable types, then indicate
|
|
// not to generate aux routines. The backend may try to generate aux
|
|
// routines even if the structure is non-rpcable because it passes when
|
|
// the c_ext switch is specified.
|
|
// Dont worry about such a structure being used or not used. Becuase if
|
|
// it is used, the parameter node will report the error. It is only when
|
|
// c_ext is specified along with import osf mode that the backend will
|
|
// try to generate the aux routine. That will certainly fail since the
|
|
// backend is setup to assume nothing wrong with the type graph.
|
|
//
|
|
|
|
if( pB->AnyReasonForNonRPCAble() )
|
|
{
|
|
if(
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_INT ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_VOID ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_VOID ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_FUNC ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_FUNC ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_NON_RPC_UNION ) ||
|
|
pB->NonRPCAbleBecause( NR_DERIVES_FROM_BIT_FIELDS )
|
|
)
|
|
{
|
|
DontGenerateAuxRoutines();
|
|
}
|
|
}
|
|
|
|
//
|
|
// a union with a ';' as a field member only is syntactically permissible
|
|
// but should not be allowed.
|
|
//
|
|
|
|
if( HasOnlyEmptyArm() )
|
|
ParseError( UNION_NO_FIELDS, (char *)0 );
|
|
|
|
//
|
|
// set up the union for back end
|
|
//
|
|
|
|
//
|
|
// if the edge to it has not been set up , set it. Look at the
|
|
// struct::PostSCheck for more comments.
|
|
//
|
|
|
|
|
|
if( !IsEdgeSetUp() )
|
|
{
|
|
|
|
EdgeType = EDGE_DEF;
|
|
|
|
if( pParentAndTemp )
|
|
pParentAndTemp->SetEdgeType( EdgeType );
|
|
|
|
pParentAndTemp = pGlobalContext->GetClosestEnclosingScopeForEdge();
|
|
|
|
/**
|
|
** It might be that the parent is really the same node we got
|
|
** last time, but do this anyway
|
|
**/
|
|
|
|
while( pParentAndTemp && (pParentAndTemp != this ) )
|
|
{
|
|
pParentAndTemp->SetEdgeType( EdgeType );
|
|
|
|
assert( pParentAndTemp != pParentAndTemp->GetBasicType() );
|
|
|
|
pParentAndTemp = pParentAndTemp->GetBasicType();
|
|
}
|
|
|
|
EdgeSetUp();
|
|
}
|
|
|
|
// RegisterFDeclUse();
|
|
|
|
if( pB->NonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR ) )
|
|
{
|
|
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR );
|
|
}
|
|
|
|
if( pB->NonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR ) )
|
|
{
|
|
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR );
|
|
}
|
|
|
|
/**
|
|
** If the union has a pointer field , set node-state-embedded-ptr for
|
|
** the backend.
|
|
**/
|
|
|
|
if( GetNodeState() & NODE_STATE_POINTER )
|
|
{
|
|
SetNodeState( NODE_STATE_EMBEDDED_PTR );
|
|
}
|
|
|
|
|
|
if( CheckNodeStateInMembers( NODE_STATE_SIZE ) )
|
|
{
|
|
if( (GetNodeState() & NODE_STATE_CONF_ARRAY ) == NODE_STATE_CONF_ARRAY)
|
|
SetNodeState( NODE_STATE_STRUCT_SIZE );
|
|
}
|
|
#if 0
|
|
|
|
if( CheckNodeStateInMembers( NODE_STATE_LENGTH ) )
|
|
{
|
|
if( (GetNodeState() & NODE_STATE_CONF_ARRAY ) == NODE_STATE_CONF_ARRAY)
|
|
SetNodeState( NODE_STATE_STRUCT_LENGTH );
|
|
}
|
|
|
|
#endif // 0
|
|
|
|
//
|
|
// check for bad syntactic constructs.
|
|
//
|
|
|
|
// dont allow definition of the struct in a param list.
|
|
//
|
|
|
|
if( (EdgeType == EDGE_DEF ) && pGlobalContext->GetLastContext( C_PROC ) )
|
|
{
|
|
ParseError( COMP_DEF_IN_PARAM_LIST, (char *)0 );
|
|
}
|
|
|
|
//
|
|
// if the number of arms with case labels dont match the number of fields
|
|
// then the user has specified a hybrid union which is not rpcable.
|
|
// Dont check this if it is the second semantic pass, since the second
|
|
// pass will be passed onto only those fields which have forward decls
|
|
// in them, and thus the count of number of arms will be wrong. In the first
|
|
// pass, even though a field is forward declared, the count will be
|
|
// fine since the case label is applied to the field node and a forward
|
|
// declaration will not change this.
|
|
//
|
|
|
|
if( !pGlobalContext->IsSecondSemanticPass() )
|
|
{
|
|
if( (Temp = pB->GetNoOfArmsWithCaseLabels() ) > 0 )
|
|
{
|
|
if( Temp != GetMemberCount() )
|
|
{
|
|
ParseError( CASE_LABELS_MISSING_IN_UNION, (char *)0 );
|
|
}
|
|
}
|
|
|
|
//
|
|
// check for absence of a default case ONLY if it is an rpcable
|
|
// union. Also check for the switch value in range only if it is
|
|
// an rpcable union.
|
|
//
|
|
|
|
if( ! pB->NonRPCAbleBecause( NR_DERIVES_FROM_NON_RPC_UNION ) )
|
|
{
|
|
|
|
type_node_list * pTNList = new type_node_list;
|
|
BOOL fHasDefault = FALSE;
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pParentAndTemp ) == STATUS_OK )
|
|
{
|
|
if( fHasDefault = pParentAndTemp->FInSummary( ATTR_DEFAULT ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
delete pTNList;
|
|
|
|
if( !fHasDefault )
|
|
ParseError( NO_UNION_DEFAULT, (char *)0 );
|
|
|
|
//
|
|
// check for case values being in range. Dont do this if the switch
|
|
// type is not specified, it will be done at use time.
|
|
// If the import mode is osf, then the backend will generate aux
|
|
// routines for the union irrespective of use. Since the union
|
|
// may actually not be used, we may never set the type. Prevent this
|
|
// by mandating the use of switch type when the import mode is osf.
|
|
//
|
|
|
|
if( FInSummary( ATTR_SWITCH_TYPE ) )
|
|
CheckCaseValuesInRange();
|
|
else if( !IsEncapsulatedUnion() &&
|
|
(pCommand->GetImportMode() == IMPORT_OSF ) )
|
|
ParseError( SWITCH_TYPE_REQD_THIS_IMP_MODE, (char *)0 );
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// if the union IS an rpcable union then we need to ensure that the user
|
|
// never tries to marshall an array of such unions. We do this by setting
|
|
// this info in the bad use info block. If it is not an rpcable union
|
|
// then the use of such a union will report an error anyways.
|
|
// When the array node sees that there is a potential bad construct
|
|
// because the array derives from an array of non-encapsulated unions
|
|
// it reports an error.
|
|
//
|
|
|
|
if( ! pB->NonRPCAbleBecause( NR_DERIVES_FROM_NON_RPC_UNION ) )
|
|
{
|
|
pB->SetBadConstructBecause( BC_MAY_DERIVE_ARRAY_OF_UNIONS );
|
|
|
|
if( !IsEncapsulatedUnion() )
|
|
{
|
|
pB->SetBadConstructBecause( BC_BAD_RT_NE_UNION );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( !pCommand->IsSwitchDefined( SWITCH_C_EXT ) )
|
|
ParseError( BAD_CON_NON_RPC_UNION, (char *)0 );
|
|
}
|
|
|
|
//
|
|
// if this union derives from an unnamed field, check for duplicate
|
|
// top level names.
|
|
//
|
|
|
|
if( pB->BadConstructBecause( BC_DERIVES_FROM_UNNAMED_FIELD ) )
|
|
{
|
|
TLNDICT * pTLNDict = new TLNDICT;
|
|
|
|
//
|
|
// this routine reports an error if we send it a true as the
|
|
// fReportError field. After this call returns we can throw the dict
|
|
// away.
|
|
//
|
|
|
|
GetTopLevelNames( pTLNDict, TRUE );
|
|
|
|
delete pTLNDict;
|
|
|
|
//
|
|
// reset this bad construct because we have already reported the
|
|
// error.
|
|
//
|
|
|
|
pB->ResetBadConstructBecause( BC_DERIVES_FROM_UNNAMED_FIELD );
|
|
}
|
|
|
|
//
|
|
// if a union has a conformant/varying structure underneath, it is fine.
|
|
//
|
|
|
|
if( pB->BadConstructBecause( BC_DERIVES_FROM_CONF_STRUCT ) )
|
|
pB->ResetBadConstructBecause( BC_DERIVES_FROM_CONF_STRUCT );
|
|
|
|
if( pB->BadConstructBecause( BC_DERIVES_FROM_VARY_STRUCT ) )
|
|
pB->ResetBadConstructBecause( BC_DERIVES_FROM_VARY_STRUCT );
|
|
|
|
/****************************************************
|
|
** hack for node-state-size and length
|
|
****************************************************
|
|
|
|
SetLocalAllocField( this );
|
|
|
|
************** end of hack *************************/
|
|
|
|
SetAllBadConstructReasons( pB );
|
|
SetAllNonRPCAbleReasons( pB );
|
|
|
|
|
|
if( pB->NonRPCAbleBecause( NR_DERIVES_FROM_TRANSMIT_AS ) )
|
|
SetDerivesFromTransmitAs();
|
|
|
|
//
|
|
// Any handle specifications in encapsulations are not valid anymore
|
|
// so reset all such specifications.
|
|
//
|
|
|
|
pB->ResetAllHdlSpecifications();
|
|
// pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_TRANSMIT_AS );
|
|
|
|
return GetNodeState();
|
|
}
|
|
|
|
/****************************************************************************
|
|
SetCaseExpr:
|
|
Given a list of case expressions, evaluate each and find if case labels
|
|
values are duplicate. If so , report error.
|
|
****************************************************************************/
|
|
void
|
|
node_union::SetCaseExpr(
|
|
expr_list * pList )
|
|
{
|
|
//long Value;
|
|
expr_node * pExpr;
|
|
node_skl * pSwType = GetSwitchType();
|
|
|
|
pList->Init();
|
|
|
|
while( pList->GetPeer( &pExpr ) == STATUS_OK )
|
|
{
|
|
|
|
if(Info.pCaseValueDict->Dict_Insert((void*)pExpr)
|
|
== ITEM_ALREADY_PRESENT )
|
|
{
|
|
BufferManager * pBuffer = new BufferManager( 10 );
|
|
char TempBuf[ 20 ];
|
|
|
|
// sprintf( TempBuf, "%ld", Value );
|
|
|
|
pExpr->PrintExpr( 0, 0, pBuffer );
|
|
pBuffer->Print( TempBuf );
|
|
|
|
ParseError( DUPLICATE_CASE, TempBuf );
|
|
delete pBuffer;
|
|
}
|
|
|
|
}
|
|
}
|
|
/****************************************************************************
|
|
UseProcessingAction:
|
|
This union indicated that it needs use processing. If we get here,
|
|
the user node wants the union to see if the use is all right.
|
|
The node union indicates that it needs use processing, because it has the
|
|
switch type attribute and needs to verify that the switch_is (applied
|
|
at use time) is the same type as the switch_type.
|
|
****************************************************************************/
|
|
void
|
|
node_union::UseProcessingAction()
|
|
{
|
|
node_skl * pUseNode;
|
|
|
|
|
|
if( !(pUseNode = pGlobalContext->GetLastContext( C_FIELD ) ) )
|
|
pUseNode = pGlobalContext->GetLastContext( C_PARAM );
|
|
|
|
/**
|
|
** The union needs use processing if it has the switch_type attribute.
|
|
** If the user field does not have a switch_is, then this is an error.
|
|
** If the type of the switch_is in the field node is not the same as
|
|
** the type in the union, then this is an error again.
|
|
**/
|
|
|
|
if( pUseNode )
|
|
{
|
|
if( !pUseNode->FInSummary( ATTR_SWITCH_IS ) )
|
|
{
|
|
ParseError( NO_SWITCH_IS, (char *)NULL );
|
|
}
|
|
else
|
|
{
|
|
node_skl * pSwitchIsType = pUseNode->GetSwitchIsType();
|
|
node_skl * pSwitchType = GetSwitchType();
|
|
|
|
if( pSwitchType )
|
|
{
|
|
node_skl * pST = pSwitchType->GetBasicType();
|
|
node_skl * pSIsT = pSwitchIsType->GetBasicType();
|
|
BOOL fSTUnsigned =
|
|
pST->FInSummary( ATTR_UNSIGNED );
|
|
BOOL fSIsTUnsigned =
|
|
pSIsT->FInSummary( ATTR_UNSIGNED );
|
|
|
|
if( (pST->NodeKind() != pSIsT->NodeKind()) ||
|
|
(fSTUnsigned != fSIsTUnsigned )
|
|
)
|
|
{
|
|
BOOL fSTIsCharOrBoolOrWChar =
|
|
( pST->NodeKind() == NODE_CHAR ) ||
|
|
( pST->NodeKind() == NODE_BOOLEAN )||
|
|
( pST->NodeKind() == NODE_WCHAR_T );
|
|
|
|
BOOL fSIsTIsCharOrBoolOrWChar =
|
|
( pSIsT->NodeKind() == NODE_CHAR ) ||
|
|
( pSIsT->NodeKind() == NODE_BOOLEAN )||
|
|
( pSIsT->NodeKind() == NODE_WCHAR_T );
|
|
//
|
|
// do this if both switch type and switch is of integral
|
|
// type, the error otherwise is reported elsewhere.
|
|
//
|
|
|
|
if( ( IsIntegralType( pST ) || (fSTIsCharOrBoolOrWChar)) &&
|
|
( IsIntegralType( pSIsT) || (fSIsTIsCharOrBoolOrWChar))
|
|
)
|
|
{
|
|
node_base_attr * pAttr = pUseNode->GetAttribute( ATTR_SWITCH_IS );
|
|
expr_node * pExpr = pAttr->GetExpr();
|
|
BOOL fReportError = FALSE;
|
|
|
|
|
|
if( pExpr->IsConstant() )
|
|
{
|
|
if( !IsCompatibleIntegralType( pST, pSIsT ) )
|
|
fReportError = TRUE;
|
|
if( !((expr_constant *)pExpr)->
|
|
IsAValidConstantOfType( pST ) )
|
|
fReportError = TRUE;
|
|
}
|
|
else
|
|
fReportError = TRUE;
|
|
|
|
if( fReportError )
|
|
ParseError( SWITCH_TYPE_MISMATCH, (char *)NULL);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/**
|
|
** the union does not have a switch type. Set it as the
|
|
** switch_is.Note that this means that from now on, all the
|
|
** switch_is must match with this switch_is.
|
|
** Report a warning about switch type, but not if it is
|
|
** an encapsulated union. Also, this warning needs to be
|
|
** reported only if the import mode is import osf, since
|
|
** aux routines would be generated for it.
|
|
**/
|
|
|
|
if( !IsEncapsulatedUnion() &&
|
|
!(pCommand->GetImportMode() == IMPORT_OSF) )
|
|
{
|
|
ParseError( NO_SWITCH_TYPE_AT_DEF, (char *)0 );
|
|
}
|
|
|
|
node_skl::SetAttribute( (node_base_attr *)
|
|
new node_switch_type( (node_skl *)pSwitchIsType ) );
|
|
}
|
|
|
|
//
|
|
// at this point, the switch type has been set. Check for each
|
|
// case label to be in the range of the switch type. There is a
|
|
// similar check made at the Post check time, but we do this
|
|
// anyway, since the user may not have the switch is specified
|
|
// at the time of definition of the union. This routine will
|
|
// not check the values in case it is done already.
|
|
//
|
|
|
|
CheckCaseValuesInRange();
|
|
|
|
}
|
|
}
|
|
/**
|
|
** A union with the switch is always needs use processing.We need
|
|
** to check every time a union is used, to make sure that the switch_is
|
|
** and switch_type match. So we do not reset the needs use processing
|
|
** status
|
|
**/
|
|
|
|
}
|
|
|
|
node_skl *
|
|
node_union::GetSwitchType()
|
|
{
|
|
node_switch_type * pSWT = (node_switch_type *)NULL;
|
|
|
|
if( FInSummary( ATTR_SWITCH_TYPE ) )
|
|
{
|
|
GetAttribute( (node_skl **)&pSWT, ATTR_SWITCH_TYPE );
|
|
pSWT = (node_switch_type *)(pSWT->GetSwitchType());
|
|
}
|
|
return (node_skl *)pSWT;
|
|
}
|
|
|
|
void
|
|
node_union::CheckCaseValuesInRange()
|
|
{
|
|
|
|
//
|
|
// go thru each case value in the case dictionary and report if the
|
|
// value is likely out of range. Do that if it has not been done already.
|
|
//
|
|
|
|
if( !fCaseChecked && Info.pCaseValueDict )
|
|
{
|
|
|
|
node_skl * pSwType = GetSwitchType()->GetBasicType();
|
|
expr_node * pExpr;
|
|
BOOL fError = FALSE;
|
|
|
|
fCaseChecked = 1;
|
|
|
|
//
|
|
// go thru each case value one by one. Set the dictionary to the top
|
|
// first.
|
|
//
|
|
|
|
Info.pCaseValueDict->Dict_Prev( pExpr = 0 );
|
|
|
|
while( Info.pCaseValueDict->Dict_Next( (pUserType) pExpr ) == SUCCESS )
|
|
{
|
|
|
|
pExpr = (expr_node *) Info.pCaseValueDict->Dict_Curr_Item();
|
|
|
|
assert( pExpr != (expr_node *)0 );
|
|
|
|
//
|
|
// check value being in range of type.
|
|
//
|
|
|
|
if( pSwType->NodeKind() == NODE_BOOLEAN )
|
|
{
|
|
long Value = pExpr->GetValue();
|
|
if( (Value != 0) && ( Value != 1 ) )
|
|
fError = TRUE;
|
|
}
|
|
else if( ! IsValueInRangeOfType( pSwType, pExpr ) )
|
|
{
|
|
fError = TRUE;
|
|
}
|
|
|
|
if( fError )
|
|
{
|
|
ReportOutOfRange( CASE_VALUE_OUT_OF_RANGE, pExpr );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/****************************************************************************
|
|
node_enum procedures
|
|
****************************************************************************/
|
|
node_state
|
|
node_enum::SCheck(
|
|
BadUseInfo * pB)
|
|
{
|
|
|
|
UNUSED( pB );
|
|
|
|
node_state NState = NODE_STATE_ENUM;
|
|
EDGE_T EdgeType= EDGE_USE;
|
|
|
|
if( !AreSemanticsDone() )
|
|
{
|
|
|
|
/**
|
|
** if the edge to it has not been set up , set it . Look at
|
|
** struct::PostSCheck for additional comments
|
|
**/
|
|
|
|
if( !IsEdgeSetUp() )
|
|
{
|
|
node_skl * pParent;
|
|
|
|
pGlobalContext->PushContext( this );
|
|
|
|
pParent = pGlobalContext->GetParentContext();
|
|
EdgeType= EDGE_DEF;
|
|
|
|
if( pParent )
|
|
pParent->SetEdgeType( EdgeType );
|
|
|
|
pParent = pGlobalContext->GetClosestEnclosingScopeForEdge();
|
|
|
|
/**
|
|
** It might be that the parent is really the same node we got
|
|
** last time, but do this anyway
|
|
**/
|
|
|
|
while( pParent && (pParent != this ) )
|
|
{
|
|
pParent->SetEdgeType( EdgeType );
|
|
|
|
assert( pParent != pParent->GetBasicType() );
|
|
|
|
pParent = pParent->GetBasicType();
|
|
}
|
|
|
|
EdgeSetUp();
|
|
|
|
pGlobalContext->PopContext();
|
|
}
|
|
//
|
|
// dont allow definition of the struct in a param list.
|
|
//
|
|
|
|
if( (EdgeType == EDGE_DEF ) && pGlobalContext->GetLastContext( C_PROC ) )
|
|
{
|
|
ParseError( COMP_DEF_IN_PARAM_LIST, (char *)0 );
|
|
}
|
|
|
|
NState |= SemReturn( GetNodeState() );
|
|
}
|
|
|
|
return NState;
|
|
|
|
}
|
|
/****************************************************************************
|
|
node_label procedures
|
|
****************************************************************************/
|
|
|
|
node_label::node_label(
|
|
char * pLabelName ,
|
|
class expr_node * pE ) : node_skl( NODE_LABEL )
|
|
{
|
|
SetSymName( pLabelName );
|
|
SetExpr( pE );
|
|
}
|
|
long
|
|
node_label::GetValue()
|
|
{
|
|
return pExpr->GetValue();
|
|
}
|
|
void
|
|
node_label::SetExpr(
|
|
class expr_node * pE )
|
|
{
|
|
pExpr = pE;
|
|
}
|
|
/****************************************************************************
|
|
general procedures
|
|
****************************************************************************/
|
|
|
|
node_skl *
|
|
StructOrUnionLargestElement(
|
|
node_skl * pThisNode )
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
node_skl * pNode;
|
|
node_skl * pNodeReturn;
|
|
long LargestSize = 0;
|
|
long Temp;
|
|
NODE_T NodeType = pThisNode->NodeKind();
|
|
|
|
pThisNode->GetMembers(pTNList);
|
|
pTNList->Init();
|
|
while( pTNList->GetPeer(&pNode) == STATUS_OK)
|
|
{
|
|
pNode = pNode->GetLargestElement();
|
|
|
|
if( (Temp = pNode->GetSize(0)) >= LargestSize )
|
|
{
|
|
pNodeReturn = pNode;
|
|
LargestSize = Temp;
|
|
}
|
|
}
|
|
delete pTNList;
|
|
return pNodeReturn;
|
|
}
|
|
|
|
node_skl *
|
|
StructOrUnionLargestNdr(
|
|
node_skl * pThisNode )
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
node_skl * pNode;
|
|
node_skl * pNodeReturn;
|
|
long LargestSize = 0;
|
|
long Temp;
|
|
NODE_T NodeType = pThisNode->NodeKind();
|
|
|
|
pThisNode->GetMembers(pTNList);
|
|
pTNList->Init();
|
|
while( pTNList->GetPeer(&pNode) == STATUS_OK)
|
|
{
|
|
if( ((node_field *)pNode)->IsEmptyArm() )
|
|
Temp = 0;
|
|
else
|
|
Temp = pNode->GetNdrAlign();
|
|
|
|
if( Temp >= LargestSize )
|
|
{
|
|
pNodeReturn = pNode;
|
|
LargestSize = Temp;
|
|
}
|
|
}
|
|
delete pTNList;
|
|
return pNodeReturn;
|
|
}
|
|
int
|
|
CompareCase(
|
|
void * pE1 ,
|
|
void * pE2 )
|
|
{
|
|
long p1 = ((expr_node *)pE1)->GetValue();
|
|
long p2 = ((expr_node *)pE2)->GetValue();
|
|
|
|
if( (long) p1 < (long) p2 ) return -1;
|
|
else if( (long) p1 > (long) p2 ) return 1;
|
|
return 0;
|
|
}
|
|
void
|
|
PrintCase(
|
|
void * p )
|
|
{
|
|
(void) p;
|
|
}
|
|
/*****************************************************************************
|
|
These virtual functions exist here because the MIPS compiler screws up on
|
|
virtual in-lined functions
|
|
*****************************************************************************/
|
|
BOOL
|
|
node_field::IsBitField()
|
|
{
|
|
return FALSE;
|
|
}
|
|
unsigned short
|
|
node_field::GetFieldSize()
|
|
{
|
|
return 0;
|
|
}
|
|
void
|
|
su::UpdateBadUseInfo( class BadUseInfo *p )
|
|
{
|
|
CopyAllBadUseReasons( p, SUInfo.pBadUseInfo );
|
|
}
|
|
|
|
unsigned short
|
|
su::AllocWRTOtherAttrs()
|
|
{
|
|
#if 0
|
|
return
|
|
(SUInfo.pBadUseInfo->NonRPCAbleBecause(
|
|
NR_DERIVES_FROM_TRANSMIT_AS ))
|
|
? TRANSMIT_AS_WITH_ALLOCATE : 0;
|
|
#endif
|
|
//Allow allocate(all_nodes) with transmit_as.
|
|
return 0;
|
|
}
|
|
BOOL
|
|
su::HasEmbeddedFixedArrayOfStrings()
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
node_skl * pNode;
|
|
BOOL fResult = FALSE;
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
node_skl * pBT = pNode->GetBasicType();
|
|
|
|
if( pBT->NodeKind() == NODE_ARRAY )
|
|
{
|
|
while( (pBT->NodeKind() == NODE_ARRAY ) &&
|
|
(pBT->FInSummary( ATTR_INT_SIZE ) ) &&
|
|
(pBT->GetBasicType()->NodeKind() == NODE_ARRAY )
|
|
)
|
|
{
|
|
pBT = pBT->GetBasicType();
|
|
}
|
|
|
|
//
|
|
// pBT is pointing to the last (innermost) array node. Check if
|
|
// this has a string attribute.
|
|
|
|
if( pBT->FInSummary( ATTR_STRING ) )
|
|
{
|
|
fResult = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( (fResult = pBT->HasEmbeddedFixedArrayOfStrings()) == TRUE )
|
|
break;
|
|
}
|
|
}
|
|
delete pTNList;
|
|
return fResult;
|
|
}
|
|
|
|
void
|
|
su::GetPtrTypeCastOfOriginalName(
|
|
char * pBuffer )
|
|
{
|
|
if( HasOriginalTypedefName() )
|
|
{
|
|
sprintf( pBuffer, "( %s * )", GetOriginalTypedefName() );
|
|
}
|
|
else
|
|
{
|
|
sprintf( pBuffer,
|
|
"( %s %s * )",
|
|
(NodeKind() == NODE_STRUCT) ? "struct" : "union",
|
|
GetSymName() );
|
|
}
|
|
}
|
|
|
|
node_skl *
|
|
su::GetFirstNamedFieldInNesting()
|
|
{
|
|
|
|
//
|
|
// assume the type graph is setup properly for unnamed fields. That is
|
|
// the front end has checked the struct to be correctly specified.
|
|
//
|
|
|
|
node_skl * pNode = GetFirstMember();
|
|
|
|
if( IsTempName( pNode->GetSymName() ) )
|
|
{
|
|
NODE_T NT = (pNode = pNode->GetBasicType())->NodeKind();
|
|
|
|
assert( ( NT == NODE_STRUCT ) || (NT == NODE_UNION) );
|
|
return ((su *)pNode)->GetFirstNamedFieldInNesting();
|
|
}
|
|
else
|
|
return pNode;
|
|
}
|
|
|
|
void
|
|
node_union::SetUpUnionSwitch(
|
|
class BufferManager *pB )
|
|
{
|
|
if( !fCaseValueDictReleased )
|
|
{
|
|
delete Info.pCaseValueDict;
|
|
fCaseValueDictReleased = 1;
|
|
}
|
|
Info.pSwStringBuffer = pB;
|
|
}
|