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.
2667 lines
62 KiB
2667 lines
62 KiB
/*****************************************************************************/
|
|
/** Microsoft LAN Manager **/
|
|
/** Copyright(c) Microsoft Corp., 1987-1990 **/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************
|
|
File : nodeskl.cxx
|
|
Title : skeletal node build routines
|
|
History :
|
|
04-Aug-1991 VibhasC Created
|
|
|
|
*****************************************************************************/
|
|
/****************************************************************************
|
|
local defines and includes
|
|
****************************************************************************/
|
|
|
|
#include "nulldefs.h"
|
|
extern "C"
|
|
{
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
}
|
|
#include "nodeskl.hxx"
|
|
#include "attrnode.hxx"
|
|
#include "acfattr.hxx"
|
|
#include "miscnode.hxx"
|
|
#include "procnode.hxx"
|
|
#include "compnode.hxx"
|
|
#include "typedef.hxx"
|
|
#include "newexpr.hxx"
|
|
#include "ctxt.hxx"
|
|
#include "baduse.hxx"
|
|
#include "cmdana.hxx"
|
|
|
|
#define BASETYPEALIGN( Size ) ((Size >= ZeePee) || (Size == 0)) ? ZeePee : Size
|
|
|
|
#define ADJUST_OFFSET(Offset, M, AlignFactor) \
|
|
Offset += (M = Offset % AlignFactor) ? (AlignFactor-M) : 0
|
|
|
|
/****************************************************************************
|
|
external data
|
|
****************************************************************************/
|
|
|
|
extern unsigned short EnumSize;
|
|
extern class attrdict * pGlobalAttrDict;
|
|
extern CTXTMGR * pGlobalContext;
|
|
extern ATTR_SUMMARY * pCDeclAttributes;
|
|
extern CMD_ARG * pCommand;
|
|
extern node_e_attr * pErrorAttrNode;
|
|
extern node_error * pErrorTypeNode;
|
|
extern SymTable * pBaseSymTbl;
|
|
|
|
/****************************************************************************
|
|
external procs
|
|
****************************************************************************/
|
|
|
|
extern BOOL IsTempName( char * );
|
|
extern void ParseError( STATUS_T, char * );
|
|
extern node_state SynthesiseStates(node_skl *, node_state );
|
|
extern STATUS_T DoSetAttributes( node_skl *,
|
|
ATTR_SUMMARY *,
|
|
ATTR_SUMMARY *,
|
|
type_node_list *);
|
|
|
|
extern void CollectAttributes( node_skl *,
|
|
ATTR_SUMMARY *,
|
|
type_node_list * );
|
|
extern void CollectSummaryAttributes( node_skl *,
|
|
ATTR_SUMMARY *,
|
|
ATTR_SUMMARY * );
|
|
|
|
extern void SetAttributeVector( PATTR_SUMMARY, ATTR_T );
|
|
extern BOOL IsMultipleAttributeApplicable( NODE_T, ATTR_T );
|
|
extern BOOL IsOkToApplyAttributeAgain(node_skl *,
|
|
node_base_attr *);
|
|
/****************************************************************************/
|
|
|
|
|
|
/****************************************************************************
|
|
typenode:
|
|
the constructor
|
|
****************************************************************************/
|
|
node_skl::node_skl(
|
|
NODE_T Nt )
|
|
{
|
|
fUseTreeBuffer = 0;
|
|
fHasTreeBuffer = 0;
|
|
fAllocateAlign = 0;
|
|
fRecursiveType = 0;
|
|
Edge = EDGE_USE;
|
|
NodeState = NODE_STATE_OK;
|
|
pAttrKey = pGlobalAttrDict->GetNullAttrSummary();
|
|
pAttrList = (type_node_list *)NULL;
|
|
pSymName = (char *)NULL;
|
|
ClientRefCount =
|
|
ServerRefCount = 0;
|
|
NodeType = Nt;
|
|
|
|
#ifdef MIDL_INTERNAL
|
|
pTempName = GetNodeNameString();
|
|
#endif // MIDL_INTERNAL
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
AreSemanticsDone:
|
|
Have the semantics been done for this node ?
|
|
****************************************************************************/
|
|
BOOL
|
|
node_skl::AreSemanticsDone()
|
|
{
|
|
if( pGlobalContext->IsSecondSemanticPass() )
|
|
{
|
|
if( AreForwardDeclarationsPresent() )
|
|
return ((NodeState & NODE_STATE_POST_SEMANTICS_DONE) != 0);
|
|
else
|
|
return TRUE;
|
|
}
|
|
else
|
|
return ((NodeState & NODE_STATE_SEMANTICS_DONE) != 0 );
|
|
}
|
|
|
|
/****************************************************************************
|
|
IsNonRPCAble:
|
|
Is the given type non-rpcable. It is if it derives fro one, or is itself
|
|
non-rpcable
|
|
****************************************************************************/
|
|
BOOL
|
|
node_skl::IsNonRPCAble()
|
|
{
|
|
node_state NState = GetNodeState();
|
|
|
|
return (( NState & NODE_STATE_HAS_NON_RPCABLE_TYPE) ||
|
|
( NState & NODE_STATE_IS_NON_RPCABLE_TYPE) );
|
|
}
|
|
|
|
/****************************************************************************
|
|
FInSummary:
|
|
Is the given attribute in the vector
|
|
****************************************************************************/
|
|
BOOL
|
|
node_skl::FInSummary(
|
|
ATTR_T A )
|
|
{
|
|
ATTR_SUMMARY AttrVector[ MAX_ATTR_SUMMARY_ELEMENTS ];
|
|
|
|
GetAttribute( &AttrVector[0] );
|
|
|
|
return (IS_ATTR( AttrVector, A ) != (ATTR_SUMMARY) 0 );
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetAttribute:
|
|
Get the attribute summary vector
|
|
****************************************************************************/
|
|
STATUS_T
|
|
node_skl::GetAttribute(
|
|
ATTR_SUMMARY * pAttrVector )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < MAX_ATTR_SUMMARY_ELEMENTS; ++i )
|
|
{
|
|
pAttrVector[ i ] = pAttrKey[ i ];
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetAttribute:
|
|
Given an attribute enumeration, return the pointer to the attribute node.
|
|
Attributes which are characterised by their presence in the summary
|
|
attribute vector, do not have an attribute node associated with them and
|
|
this call will fail on such attributes. It is the callers responsiblity
|
|
to ensure that the call is made only on attributes which have attribute
|
|
nodes associated with them.
|
|
****************************************************************************/
|
|
node_base_attr *
|
|
node_skl::GetAttribute(
|
|
ATTR_T Attr )
|
|
{
|
|
|
|
node_base_attr * pAttrNode;
|
|
|
|
pAttrList->Init();
|
|
while( pAttrList->GetPeer( (node_skl **)&pAttrNode ) == STATUS_OK )
|
|
{
|
|
if(pAttrNode->IsAttrID( Attr ) )
|
|
return pAttrNode;
|
|
}
|
|
return (node_base_attr *)0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
NewAttributeSummary:
|
|
set the summary attribute to indicate the presence of the given attribute
|
|
****************************************************************************/
|
|
void
|
|
node_skl::NewAttributeSummary(
|
|
ATTR_SUMMARY * pNewAttr )
|
|
{
|
|
ATTR_SUMMARY Attributes[ MAX_ATTR_SUMMARY_ELEMENTS ];
|
|
|
|
CLEAR_ATTR( Attributes );
|
|
|
|
OR_ATTR( Attributes, pNewAttr );
|
|
|
|
pAttrKey = pGlobalAttrDict->AttrInsert( Attributes );
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
SetAttribute:
|
|
set the summary attribute to indicate the presence of the given attribute
|
|
****************************************************************************/
|
|
void
|
|
node_skl::SetAttribute(
|
|
ATTR_T A )
|
|
{
|
|
|
|
ATTR_SUMMARY Attr[ MAX_ATTR_SUMMARY_ELEMENTS ];
|
|
|
|
assert( A < ATTR_END );
|
|
|
|
GetAttribute( &Attr[0] );
|
|
SET_ATTR( Attr, A );
|
|
|
|
NewAttributeSummary( &Attr[0] );
|
|
|
|
|
|
}
|
|
|
|
void
|
|
node_skl::ResetAttribute(
|
|
ATTR_T A )
|
|
{
|
|
ATTR_SUMMARY Attr[ MAX_ATTR_SUMMARY_ELEMENTS ];
|
|
|
|
assert( A < ATTR_END );
|
|
|
|
GetAttribute( &Attr[0] );
|
|
RESET_ATTR( Attr, A );
|
|
|
|
NewAttributeSummary( &Attr[0] );
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
SetAttribute:
|
|
insert the given attribute node into the attribute list and updat the
|
|
summary attribute
|
|
****************************************************************************/
|
|
void
|
|
node_skl::SetAttribute(
|
|
node_base_attr * pAttr )
|
|
{
|
|
|
|
/**
|
|
** if there was no attribute list so far, add one.
|
|
**/
|
|
|
|
if( !pAttrList )
|
|
pAttrList = new type_node_list;
|
|
|
|
/**
|
|
** update the attribute summary to indicate the presence of this
|
|
** attribute
|
|
**/
|
|
|
|
SetAttribute( pAttr->GetAttrID() );
|
|
|
|
/**
|
|
** if this attribute was just a bit attribute, then we could just
|
|
** set a bit in the summary attribute for it and would not need to enter
|
|
** into the attribute list.
|
|
**/
|
|
|
|
if( !pAttr->IsBitAttr() )
|
|
pAttrList->SetPeer( (node_skl *)pAttr );
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetAttributeList:
|
|
return the list of attribute nodes associated with this typenode
|
|
****************************************************************************/
|
|
|
|
type_node_list *
|
|
node_skl::GetAttributeList( void )
|
|
{
|
|
return pAttrList;
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetSize:
|
|
return the size of the type represented by this type node. This function
|
|
should return the size of basic types for basic types nodes, the size
|
|
of return type if the node is a proc node. Structures/Unions/Arrays have
|
|
their own routines to return size, since alignment plays a part.
|
|
****************************************************************************/
|
|
|
|
unsigned long
|
|
node_skl::GetSize(
|
|
unsigned long CurOffset)
|
|
{
|
|
NODE_T NodeType;
|
|
unsigned long Mod;
|
|
unsigned long CurOffsetSave = CurOffset;
|
|
unsigned long CurAlign;
|
|
node_skl * pChildPtr;
|
|
unsigned long MySize;
|
|
unsigned short ZeePee = pCommand->GetZeePee();
|
|
|
|
NodeType = NodeKind();
|
|
|
|
|
|
switch( NodeType )
|
|
{
|
|
case NODE_FLOAT: MySize = sizeof(float); goto calc;
|
|
case NODE_DOUBLE: MySize = sizeof(double); goto calc;
|
|
case NODE_HYPER: MySize = sizeof(LONGLONG); goto calc;
|
|
case NODE_LONG: MySize = sizeof(long); goto calc;
|
|
case NODE_LONGLONG: MySize = sizeof(LONGLONG); goto calc;
|
|
|
|
case NODE_ENUM: MySize = EnumSize; goto calc;
|
|
case NODE_LABEL:
|
|
case NODE_SHORT: MySize = sizeof(short); goto calc;
|
|
case NODE_INT: MySize = sizeof(int); goto calc;
|
|
|
|
case NODE_SMALL: MySize = sizeof(char); goto calc;
|
|
case NODE_CHAR: MySize = sizeof(char); goto calc;
|
|
case NODE_BOOLEAN: MySize = sizeof(char); goto calc;
|
|
case NODE_BYTE: MySize = sizeof(char); goto calc;
|
|
case NODE_POINTER: MySize = sizeof(char *) ; goto calc;
|
|
case NODE_HANDLE_T: MySize = sizeof( long ); goto calc;
|
|
calc:
|
|
CurAlign = BASETYPEALIGN( MySize );
|
|
|
|
CurAlign = GetMscAlign();
|
|
ADJUST_OFFSET(CurOffset, Mod, CurAlign);
|
|
CurOffset += MySize;
|
|
return CurOffset - CurOffsetSave;
|
|
|
|
case NODE_FORWARD:
|
|
case NODE_VOID:
|
|
case NODE_ERROR:
|
|
|
|
return 0;
|
|
default:
|
|
|
|
pChildPtr = GetBasicType();
|
|
|
|
if(pChildPtr)
|
|
{
|
|
return pChildPtr->GetSize(CurOffset);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetBasicSize:
|
|
return the size of the basic type of the node. This has meaning in case
|
|
of arrays and pointers, and should be called only on these.
|
|
****************************************************************************/
|
|
unsigned long
|
|
node_skl::GetBasicSize()
|
|
{
|
|
node_skl * pChildNode;
|
|
|
|
switch( NodeKind() )
|
|
{
|
|
case NODE_POINTER:
|
|
case NODE_ARRAY:
|
|
if( (pChildNode = GetChild() ) )
|
|
{
|
|
return pChildNode->GetSize(0);
|
|
}
|
|
break;
|
|
}
|
|
return GetSize( 0 );
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetLargestElement:
|
|
return the largest element of the type subgraph underneath this node.
|
|
This call is really meaningful in case of structures where the aligment
|
|
of the structure is the aligment of the largest element in the structure.
|
|
For the rest this is the largest element of the child. If this is a
|
|
pointer node, the largest element is this node itself (why did we do
|
|
this special case ??? , Dont remember. )
|
|
****************************************************************************/
|
|
|
|
node_skl *
|
|
node_skl::GetLargestElement()
|
|
{
|
|
node_skl *pNode;
|
|
if( (pNode = GetChild()) && (NodeKind() != NODE_POINTER) )
|
|
return pNode->GetLargestElement();
|
|
return this;
|
|
}
|
|
|
|
node_skl *
|
|
node_skl::GetLargestNdr()
|
|
{
|
|
node_skl *pNode;
|
|
if( (pNode = GetChild()) && (NodeKind() != NODE_POINTER) )
|
|
return pNode->GetLargestNdr();
|
|
return this;
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetMscAlign:
|
|
return the alignment of the type in memory. MscAlign is Microsoft C
|
|
alignment (the name is because of historic reasons )
|
|
|
|
****************************************************************************/
|
|
unsigned short
|
|
node_skl::GetMscAlign()
|
|
{
|
|
NODE_T NodeType = NodeKind();
|
|
node_skl * pChildPtr;
|
|
unsigned long MySize;
|
|
unsigned short ZeePee = pCommand->GetZeePee();
|
|
|
|
switch( NodeType )
|
|
{
|
|
case NODE_FLOAT: MySize = sizeof( float ); goto calc;
|
|
case NODE_DOUBLE: MySize = sizeof( double ); goto calc;
|
|
case NODE_HYPER: MySize = sizeof( LONGLONG ); goto calc;
|
|
case NODE_LONG: MySize = sizeof( long ); goto calc;
|
|
case NODE_LONGLONG: MySize = sizeof( LONGLONG ); goto calc;
|
|
case NODE_SHORT: MySize = sizeof( short ); goto calc;
|
|
case NODE_INT: MySize = sizeof( int ); goto calc;
|
|
case NODE_SMALL: MySize = sizeof( char ); goto calc;
|
|
case NODE_CHAR: MySize = sizeof( char ); goto calc;
|
|
case NODE_BOOLEAN: MySize = sizeof( char ); goto calc;
|
|
case NODE_BYTE: MySize = sizeof( char ); goto calc;
|
|
case NODE_POINTER: MySize = sizeof( char * ); goto calc;
|
|
case NODE_LABEL: MySize = sizeof( int ); goto calc;
|
|
case NODE_HANDLE_T: MySize = sizeof( long ); goto calc;
|
|
calc:
|
|
return BASETYPEALIGN( (unsigned short)MySize );
|
|
|
|
case NODE_ENUM:
|
|
|
|
return BASETYPEALIGN( EnumSize );
|
|
|
|
case NODE_ERROR:
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
pChildPtr =
|
|
((NodeType == NODE_STRUCT) || (NodeType == NODE_UNION) ) ?
|
|
GetLargestElement() : GetChild();
|
|
if( pChildPtr )
|
|
return pChildPtr->GetMscAlign();
|
|
return 1;
|
|
|
|
}
|
|
}
|
|
/****************************************************************************
|
|
GetNdrAlign:
|
|
return the alignment of the type according to the ndr.
|
|
****************************************************************************/
|
|
unsigned short
|
|
node_skl::GetNdrAlign()
|
|
{
|
|
NODE_T NodeType = NodeKind();
|
|
node_skl * pChildPtr;
|
|
|
|
switch( NodeType )
|
|
{
|
|
case NODE_HYPER:
|
|
case NODE_LONGLONG:
|
|
return 8;
|
|
case NODE_LONG:
|
|
return 4;
|
|
case NODE_ENUM:
|
|
return EnumSize;
|
|
case NODE_LABEL:
|
|
case NODE_SHORT:
|
|
return 2;
|
|
case NODE_INT:
|
|
return sizeof(int); /* GetAligns should really never be called
|
|
on ints, isnt it ? */
|
|
case NODE_CHAR:
|
|
case NODE_SMALL:
|
|
case NODE_BOOLEAN:
|
|
case NODE_BYTE:
|
|
return 1;
|
|
case NODE_POINTER:
|
|
return 4;
|
|
case NODE_DOUBLE:
|
|
return 8;
|
|
case NODE_FLOAT:
|
|
return 4;
|
|
case NODE_HANDLE_T:
|
|
return 4;
|
|
|
|
case NODE_ERROR:
|
|
assert( FALSE );
|
|
return 0;
|
|
case NODE_DEF:
|
|
if( FInSummary( ATTR_TRANSMIT ) )
|
|
{
|
|
return ((node_def *)this)->GetTransmitAsType()->GetNdrAlign();
|
|
}
|
|
else
|
|
return GetChild()->GetNdrAlign();
|
|
default:
|
|
if( (NodeType == NODE_STRUCT ) || (NodeType == NODE_UNION) )
|
|
{
|
|
if( IsEncapsulatedStruct() )
|
|
{
|
|
node_en_struct *p = (node_en_struct *) this;
|
|
pChildPtr = p->GetSwitchField();
|
|
}
|
|
else
|
|
pChildPtr = GetLargestNdr();
|
|
#if 0
|
|
pChildPtr = GetLargestElement();
|
|
#endif // 0
|
|
}
|
|
else
|
|
pChildPtr = GetChild();
|
|
|
|
#if 0
|
|
pChildPtr =
|
|
( (NodeType == NODE_STRUCT) || (NodeType == NODE_UNION) )
|
|
? GetLargestElement() : GetChild();
|
|
#endif // 0
|
|
|
|
if( pChildPtr )
|
|
return pChildPtr->GetNdrAlign();
|
|
return 1;
|
|
|
|
}
|
|
}
|
|
/***************************************************************************
|
|
GetBasicType:
|
|
Get the basic type of the typenode
|
|
***************************************************************************/
|
|
node_skl *
|
|
node_skl::GetBasicType()
|
|
{
|
|
node_skl *pChildPtr;
|
|
|
|
switch( NodeKind() )
|
|
{
|
|
case NODE_STRUCT:
|
|
case NODE_ENUM:
|
|
case NODE_UNION:
|
|
|
|
return this;
|
|
|
|
case NODE_ID:
|
|
|
|
return GetChild();
|
|
|
|
default:
|
|
if( pChildPtr = GetChild() )
|
|
{
|
|
if(pChildPtr->NodeKind() == NODE_DEF)
|
|
return pChildPtr->GetBasicType();
|
|
return pChildPtr;
|
|
}
|
|
return this;
|
|
}
|
|
}
|
|
|
|
//
|
|
// sorry, this is a hack to get embedded transmit_as to work.
|
|
//
|
|
|
|
node_skl *
|
|
node_skl::GetBasicTransmissionType()
|
|
{
|
|
node_skl * pC;
|
|
|
|
switch( NodeKind() )
|
|
{
|
|
case NODE_STRUCT:
|
|
case NODE_UNION:
|
|
case NODE_ENUM:
|
|
case NODE_POINTER:
|
|
return this;
|
|
case NODE_PROC:
|
|
return
|
|
((node_proc *)this)->GetReturnType()->GetBasicTransmissionType();
|
|
default:
|
|
if( pC = GetChild() )
|
|
{
|
|
if( (pC->NodeKind() == NODE_DEF ) &&
|
|
(pC->FInSummary( ATTR_TRANSMIT ))
|
|
)
|
|
return pC;
|
|
else
|
|
return pC->GetBasicTransmissionType();
|
|
}
|
|
return this;
|
|
}
|
|
}
|
|
/****************************************************************************
|
|
SetBasicType:
|
|
Set the basic type of this type to the input type. Node that the node_proc
|
|
handles its own set basic type
|
|
****************************************************************************/
|
|
STATUS_T
|
|
node_skl::SetBasicType(
|
|
node_skl * pNode )
|
|
{
|
|
node_skl * pChildPtr;
|
|
|
|
if( pNode )
|
|
{
|
|
if( pChildPtr = GetChild() )
|
|
return pChildPtr->SetBasicType( pNode );
|
|
else
|
|
SetChild( pNode );
|
|
}
|
|
return STATUS_OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
SetMembers:
|
|
set the members of the type graph to those specified int the list. That
|
|
means the firt member of the list is the direct child of this node,
|
|
the others are siblings of the direct child.
|
|
****************************************************************************/
|
|
STATUS_T
|
|
node_skl::SetMembers(
|
|
type_node_list *pTNList )
|
|
{
|
|
node_skl * pSub,
|
|
* pPeer;
|
|
NODE_T NodeType = NodeKind();
|
|
STATUS_T Status = I_ERR_NO_MEMBER;
|
|
char fSingleChild = 0;
|
|
|
|
switch( NodeType )
|
|
{
|
|
case NODE_ARRAY:
|
|
case NODE_DEF:
|
|
case NODE_FIELD:
|
|
case NODE_FILE:
|
|
case NODE_PARAM:
|
|
case NODE_POINTER:
|
|
case NODE_ID:
|
|
|
|
fSingleChild = 1;
|
|
// fall thru
|
|
case NODE_SOURCE:
|
|
case NODE_INTERFACE:
|
|
case NODE_STRUCT:
|
|
case NODE_UNION:
|
|
case NODE_PROC:
|
|
case NODE_ENUM:
|
|
case NODE_ECHO_STRING:
|
|
|
|
pTNList->Init();
|
|
if(pTNList->GetPeer(&pSub) == STATUS_OK)
|
|
{
|
|
SetChild( pSub );
|
|
|
|
if( !fSingleChild )
|
|
{
|
|
while(pTNList->GetPeer(&pPeer) == STATUS_OK)
|
|
{
|
|
pSub->SetSibling( pPeer );
|
|
pPeer->SetSibling( (node_skl *)NULL );
|
|
pSub = pPeer;
|
|
}
|
|
}
|
|
Status = STATUS_OK;
|
|
}
|
|
break;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
node_skl *
|
|
node_skl::GetLastMember( void )
|
|
{
|
|
node_skl * pLastMember = NULL;
|
|
node_skl * pChild = GetChild();
|
|
|
|
if ( pChild )
|
|
{
|
|
do
|
|
{
|
|
pLastMember = pChild;
|
|
pChild = pChild->GetSibling();
|
|
}
|
|
while ( pChild );
|
|
}
|
|
return( pLastMember );
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetMembers:
|
|
get the children and all its siblings .
|
|
****************************************************************************/
|
|
STATUS_T
|
|
node_skl::GetMembers(
|
|
type_node_list *pTNList )
|
|
{
|
|
node_skl * pNode;
|
|
NODE_T NodeType = NodeKind();
|
|
STATUS_T Status = I_ERR_NO_MEMBER;
|
|
char fSingleChild = 0;
|
|
|
|
// we know for certain which nodes can take only one child. Make
|
|
// use of that fact.
|
|
|
|
switch(NodeType)
|
|
{
|
|
case NODE_ARRAY:
|
|
case NODE_DEF:
|
|
case NODE_FIELD:
|
|
case NODE_FILE:
|
|
case NODE_PARAM:
|
|
case NODE_POINTER:
|
|
case NODE_ID:
|
|
|
|
fSingleChild = 1;
|
|
// fall thru
|
|
case NODE_SOURCE:
|
|
case NODE_INTERFACE:
|
|
case NODE_STRUCT:
|
|
case NODE_UNION:
|
|
case NODE_PROC:
|
|
case NODE_ENUM:
|
|
case NODE_ECHO_STRING:
|
|
|
|
if( pNode = GetChild() )
|
|
{
|
|
do {
|
|
pTNList->SetPeer( pNode );
|
|
} while( ! fSingleChild && (pNode = pNode->GetSibling()));
|
|
Status = STATUS_OK;
|
|
}
|
|
break;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
short
|
|
node_skl::GetMemberCount()
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
short Count;
|
|
|
|
GetMembers( pTNList );
|
|
|
|
Count = pTNList->GetCount();
|
|
|
|
delete pTNList;
|
|
|
|
return Count;
|
|
}
|
|
/****************************************************************************
|
|
GetSymName:
|
|
get the symbol name
|
|
****************************************************************************/
|
|
char *
|
|
node_skl::GetSymName()
|
|
{
|
|
return pSymName;
|
|
}
|
|
|
|
STATUS_T
|
|
node_skl::GetSymName(
|
|
char ** p )
|
|
{
|
|
*p = pSymName;
|
|
return STATUS_OK;
|
|
}
|
|
/****************************************************************************
|
|
GetBasicHandle:
|
|
(This message is never sent to a proc node). Get the basic handle associa
|
|
ted with the typenode. If the node is handle_t return a primitive handle,
|
|
if it has a context handle attribute return context handle. If it has a
|
|
handle attribute, return a generic handle. If it is none of the above,
|
|
send the message to the child node. This call should never fail becuase
|
|
it would be invoked on a type which has a handle anyway
|
|
****************************************************************************/
|
|
#pragma optimize( "g", off )
|
|
HDL_TYPE
|
|
node_skl::GetBasicHandle(
|
|
node_skl ** ppNode )
|
|
{
|
|
HDL_TYPE HandleType = HDL_NONE;
|
|
node_skl * pChildPtr;
|
|
|
|
if( NodeKind() == NODE_PARAM )
|
|
{
|
|
|
|
// if this is not a context handle and not a binding handle either
|
|
// return no handle
|
|
|
|
if( !FInSummary( ATTR_CONTEXT ) &&
|
|
!((GetNodeState() & NODE_STATE_CONTEXT_HANDLE) == NODE_STATE_CONTEXT_HANDLE) &&
|
|
!IsThisTheBindingHandle() )
|
|
return HDL_NONE;
|
|
}
|
|
|
|
|
|
if( FInSummary( ATTR_CONTEXT ) )
|
|
HandleType = HDL_CONTEXT;
|
|
else if( FInSummary( ATTR_HANDLE ) )
|
|
HandleType = HDL_GENERIC;
|
|
else if( NodeKind() == NODE_HANDLE_T )
|
|
HandleType = HDL_PRIMITIVE;
|
|
else if( pChildPtr = GetChild() )
|
|
return pChildPtr->GetBasicHandle( ppNode );
|
|
|
|
*ppNode = this;
|
|
return HandleType;
|
|
|
|
}
|
|
#pragma optimize( "", on )
|
|
/****************************************************************************
|
|
general semantic check procedures
|
|
****************************************************************************/
|
|
node_state
|
|
node_skl::PreSCheck(
|
|
class BadUseInfo * pBadUseInfo )
|
|
{
|
|
|
|
UNUSED( pBadUseInfo );
|
|
|
|
return NODE_STATE_OK;
|
|
}
|
|
/****************************************************************************
|
|
SCheck::
|
|
Semantic check on any node. Node that PushContext and PopContext need
|
|
to be done, irrespective of whether the node get semantically analysed or
|
|
not. This is because, the context manager gathers some specific info
|
|
about the type like last field , first param etc.
|
|
****************************************************************************/
|
|
node_state
|
|
node_skl::SCheck(
|
|
BadUseInfo * pB)
|
|
{
|
|
|
|
char * pName;
|
|
BadUseInfo * pBTemp = new BadUseInfo;
|
|
NODE_T NT = NodeKind();
|
|
|
|
pName = GetSymName();
|
|
|
|
pGlobalContext->PushContext( this );
|
|
|
|
/**
|
|
** check if semantics have already not been done for this. If done,
|
|
** then dont do it again.
|
|
**/
|
|
|
|
if( ! AreSemanticsDone() )
|
|
{
|
|
|
|
/**
|
|
** Semantics of this node not completed thus far. if we reached this
|
|
** node again, while its semantics were in progress, then this is
|
|
** a recursive definition of type which must be thru a pointer to be
|
|
** valid.
|
|
**/
|
|
|
|
if( SemanticsInProgress() )
|
|
{
|
|
STATUS_T Status;
|
|
|
|
if( (Status = pGlobalContext->IsValidRecursion( this )) !=
|
|
STATUS_OK )
|
|
{
|
|
|
|
//
|
|
// if the recursion is thru a ref pointer, then this is an
|
|
// error. BUT, he may not use this structure at all. Therefore
|
|
// report the error only at the use of such a structure.
|
|
//
|
|
|
|
if( Status == RECURSION_THRU_REF )
|
|
{
|
|
|
|
//
|
|
// if the import mode is osf then we will try to generate
|
|
// support routines for this. Therefore, this must be
|
|
// reported as an error. In other modes, dont report an
|
|
// error here, it should be reported at use time, by
|
|
// the param node.
|
|
//
|
|
|
|
if( pCommand->GetImportMode() == IMPORT_OSF )
|
|
ParseError( Status, pName );
|
|
pB->SetBadConstructBecause( BC_DERIVES_FROM_RECURSIVE_REF );
|
|
}
|
|
else if((Status == RECURSIVE_UNION )&&( !IsEncapsulatedUnion()))
|
|
{
|
|
pB->SetBadConstructBecause(BC_DERIVES_FROM_RECURSIVE_UNION);
|
|
}
|
|
else
|
|
ParseError( Status, pName );
|
|
}
|
|
|
|
// If we call semreturn here we will see (as Mario did),
|
|
// a very interesting problem. SemReturn will reset the semantics
|
|
// in progress flag. If there is another field we have not reached
|
|
// yet and that field is an invalid nesting of struct (not thru ptr)
|
|
// then we will never report that since we already reset the
|
|
// semantics in progress flag and we will never reach the error
|
|
// checking code. For that we actually do all we were doing in
|
|
// finish: and then set the semantics in progress flag again. It
|
|
// will be finally reset when the outermost call to SCheck returns.
|
|
|
|
// originally this code was a goto finish and we saw this problem
|
|
// of not reporting a wrong nested structure when the wrong nesting
|
|
// followed a correct nesting.
|
|
|
|
pGlobalContext->PopContext();
|
|
|
|
#if 0
|
|
SemReturn( GetNodeState() );
|
|
SetSemanticsInProgress();
|
|
SetNodeState( NODE_STATE_RESOLVE );
|
|
return ResetPostSemanticsDone();
|
|
#endif // 0
|
|
return GetNodeState();
|
|
|
|
}
|
|
|
|
/**
|
|
** This is a valid semantic check in progress. Lock this node
|
|
** to indicate that this has been visited. Prepare the context
|
|
** stack to reflect this.
|
|
**/
|
|
|
|
SetSemanticsInProgress();
|
|
|
|
|
|
/**
|
|
** Do we need to do any semantics check before we pass the
|
|
** message to every child ?
|
|
**/
|
|
|
|
SetNodeState( PreSCheck( pB ) );
|
|
|
|
/**
|
|
** Send the semantics message to every child node.
|
|
**/
|
|
|
|
node_skl * pNode;
|
|
type_node_list * pTNList;
|
|
|
|
GetMembers( pTNList = new type_node_list );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
|
|
pBTemp->InitBadUseInfo();
|
|
|
|
SetNodeState( SynthesiseStates(this, pNode->SCheck( pBTemp )) );
|
|
|
|
CopyAllBadUseReasons( pB, pBTemp );
|
|
CopyNoOfArmsWithCaseLabels( pB, pBTemp );
|
|
|
|
}
|
|
|
|
delete pTNList;
|
|
|
|
/**
|
|
** Send SemanticCheck message to every attribute node
|
|
**/
|
|
|
|
if( pTNList = GetAttributeList() )
|
|
{
|
|
node_base_attr * pAttr;
|
|
|
|
while( pTNList->GetPeer( (node_skl **)&pAttr ) == STATUS_OK )
|
|
{
|
|
SetNodeState(SynthesiseStates(this,pAttr->SCheck()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
** Do we need to analyse it after the typegraph underneath has
|
|
** been analysed ?
|
|
**/
|
|
|
|
SetNodeState( PostSCheck( pB ));
|
|
|
|
}
|
|
|
|
//
|
|
// for struct / union nodes, mark usage, so that the backend can decide
|
|
// whether to produce aux routines or not.
|
|
//
|
|
|
|
if( ( NT == NODE_STRUCT ) || ( NT == NODE_UNION ) )
|
|
{
|
|
MarkUsage();
|
|
}
|
|
|
|
UpdateBadUseInfo( pB );
|
|
|
|
delete pBTemp;
|
|
|
|
/**
|
|
** set the node state and return
|
|
**/
|
|
|
|
// finish:
|
|
|
|
/**
|
|
** restore the global context to that before entry.
|
|
**/
|
|
|
|
pGlobalContext->PopContext();
|
|
|
|
return SemReturn( GetNodeState() );
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
SemReturn:
|
|
this routine sets the node_state to that passed in, resets the
|
|
semantics in progress flag. In case of the second pass, it resets also
|
|
the forward declaration status.
|
|
****************************************************************************/
|
|
node_state
|
|
node_skl::SemReturn(
|
|
node_state NS )
|
|
{
|
|
UNUSED( NS );
|
|
if( pGlobalContext->IsSecondSemanticPass() )
|
|
{
|
|
SetPostSemanticsDone();
|
|
ResetNodeState( NODE_STATE_RESOLVE );
|
|
}
|
|
else
|
|
SetSemanticsDone();
|
|
|
|
return ResetSemanticsInProgress();
|
|
|
|
}
|
|
|
|
node_state
|
|
node_skl::PostSCheck(
|
|
class BadUseInfo * pBadUseInfo )
|
|
{
|
|
UNUSED( pBadUseInfo );
|
|
|
|
return NODE_STATE_OK;
|
|
}
|
|
|
|
/***************************************************************************
|
|
UseProcessing:
|
|
This method is used to fixup any details left over during actual
|
|
semantic analysis, because semantics may be done at a time the use of
|
|
a type node is not known. This is also used to check validity of the
|
|
type at use time. Use time could be use of the type in a field of a
|
|
structure or union or param
|
|
***************************************************************************/
|
|
void
|
|
node_skl::UseProcessing()
|
|
{
|
|
type_node_list * pTNList;
|
|
node_skl * pNode;
|
|
|
|
/**
|
|
** if this node needs use processing, then send the message to each child
|
|
** and then perform use processing on this node.
|
|
**/
|
|
|
|
pGlobalContext->PushContext( this );
|
|
|
|
if( NeedsUseProcessing() )
|
|
{
|
|
|
|
|
|
if( !IsUseProcessingInProgress() )
|
|
{
|
|
|
|
SetUseProcessingInProgress();
|
|
|
|
pTNList = new type_node_list;
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
pNode->UseProcessing();
|
|
}
|
|
|
|
delete pTNList;
|
|
ResetUseProcessingInProgress();
|
|
}
|
|
|
|
|
|
UseProcessingAction();
|
|
|
|
}
|
|
|
|
pGlobalContext->PopContext();
|
|
|
|
}
|
|
/***************************************************************************
|
|
CloneAction:
|
|
The actual cloning action. We are given an instance of a clone, we need
|
|
to make the basic structure of the clone look like ours. The caller,
|
|
normally the class that is being cloned, will instantiate another node
|
|
of its own class. In all cases everything will be already set up when the
|
|
clone is passed to this routine, the only thing that needs to be done is
|
|
to clone the attribute list, and set the attributes of the clone with that
|
|
attribute list
|
|
***************************************************************************/
|
|
node_skl *
|
|
node_skl::CloneAction(
|
|
node_skl * pClone )
|
|
{
|
|
node_skl * pCloneOfMyChild = (node_skl *)NULL;
|
|
type_node_list * pTNList = GetAttributeList();
|
|
node_base_attr * pAttrNode;
|
|
|
|
/**
|
|
** Set the child type of the clone, only if this node has a child type
|
|
**/
|
|
|
|
if( pCloneOfMyChild = GetChild() )
|
|
pCloneOfMyChild = pCloneOfMyChild->Clone();
|
|
|
|
pClone->SetBasicType( pCloneOfMyChild );
|
|
|
|
/**
|
|
** Pick up attribute summary, then individual attribute nodes.
|
|
**/
|
|
|
|
pClone->SetAttrKey( GetAttrKey() );
|
|
|
|
if( pTNList )
|
|
{
|
|
|
|
pTNList->Init();
|
|
while( pTNList->GetPeer( (node_skl **)&pAttrNode ) == STATUS_OK )
|
|
{
|
|
pClone->SetAttribute( pAttrNode->Clone() );
|
|
}
|
|
|
|
}
|
|
|
|
return pClone;
|
|
}
|
|
|
|
/***************************************************************************
|
|
RegFDAndSetE:
|
|
register the fact the the forward declaration was defined. Parts of the
|
|
type graph may never be semantically analysed and therefore the forward
|
|
declaration never registered. This method will do just that. Register the
|
|
forward declaration as defined, so that the backend never gets the forward
|
|
node, which it cannot handle. The forward node is a purely front end
|
|
beast, and should never be exposed to the bakend.
|
|
***************************************************************************/
|
|
void
|
|
node_skl::RegFDAndSetE()
|
|
{
|
|
|
|
/**
|
|
** send message to each child. push context on the way, so that
|
|
** the forward declarator node can know the parent context
|
|
**/
|
|
|
|
type_node_list * pTNList = new type_node_list;
|
|
node_skl * pNode;
|
|
|
|
pGlobalContext->PushContext( this );
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
pNode->RegFDAndSetE();
|
|
|
|
pGlobalContext->PopContext();
|
|
|
|
delete pTNList;
|
|
|
|
}
|
|
|
|
/***************************************************************************
|
|
RegisterFDeclUse:
|
|
If this node has a node-state-resolve, it means it has a child somewhere
|
|
that is a forward node. This method is usually called from the proc node,
|
|
so that only those forward declarations are registered which are actually
|
|
involved in an rpc procedure. Note that this method can potentially walk
|
|
the entire graph but in practice, it does not happen that way. Only
|
|
subgraphs are walked.
|
|
***************************************************************************/
|
|
void
|
|
node_skl::RegisterFDeclUse()
|
|
{
|
|
|
|
if( AreForwardDeclarationsPresent() )
|
|
{
|
|
|
|
/**
|
|
** send message to each child. push context on the way, so that
|
|
** the forward declarator node can know the parent context
|
|
**/
|
|
|
|
type_node_list * pTNList = new type_node_list;
|
|
node_skl * pNode;
|
|
|
|
pGlobalContext->PushContext( this );
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
pNode->RegisterFDeclUse();
|
|
|
|
pGlobalContext->PopContext();
|
|
|
|
delete pTNList;
|
|
|
|
}
|
|
}
|
|
/***************************************************************************
|
|
HasAnySizeAttributes:
|
|
***************************************************************************/
|
|
BOOL
|
|
node_skl::HasAnySizeAttributes()
|
|
{
|
|
return ( FInSummary( ATTR_SIZE ) ||
|
|
FInSummary( ATTR_MAX ) ||
|
|
((NodeKind() != NODE_POINTER) && FInSummary( ATTR_INT_SIZE )));
|
|
}
|
|
/***************************************************************************
|
|
HasAnyLengthAttributes:
|
|
***************************************************************************/
|
|
BOOL
|
|
node_skl::HasAnyLengthAttributes()
|
|
{
|
|
return ( FInSummary( ATTR_LENGTH ) ||
|
|
FInSummary( ATTR_LAST )||
|
|
FInSummary( ATTR_FIRST ) );
|
|
}
|
|
/***************************************************************************
|
|
IsFundamentalTypeByteOrChar:
|
|
Helps find if the fundamental type of the node is byte or char. An array
|
|
is of fundamentaltype byte or char if the basic type is so. A structure
|
|
is byte or char if it has only one child and its basic type is byte or char
|
|
***************************************************************************/
|
|
BOOL
|
|
node_skl::IsFundamentalTypeByteOrChar()
|
|
{
|
|
NODE_T Nt = GetFundamentalType()->NodeKind();
|
|
|
|
return ( ( Nt == NODE_WCHAR_T ) ||
|
|
( Nt == NODE_BYTE ) ||
|
|
( Nt == NODE_CHAR ) );
|
|
}
|
|
|
|
node_skl *
|
|
node_skl::GetFundamentalType()
|
|
{
|
|
|
|
node_skl * pC;
|
|
|
|
if( IsBaseTypeNode() ||
|
|
(NodeKind() == NODE_WCHAR_T) ||
|
|
(NodeKind() == NODE_ERROR_STATUS_T) ||
|
|
(NodeKind() == NODE_STRUCT) ||
|
|
(NodeKind() == NODE_UNION)
|
|
)
|
|
return this;
|
|
|
|
if( pC = GetChild() )
|
|
return pC->GetFundamentalType();
|
|
return pErrorTypeNode;
|
|
|
|
}
|
|
|
|
/***************************************************************************
|
|
PrintReasonWhyImproperConstruct:
|
|
It was determined that the construct is really wrong, and hence the user
|
|
must be told. This method prints out all the error messages corresponding
|
|
to the construct errors
|
|
***************************************************************************/
|
|
void
|
|
node_skl::PrintReasonWhyImproperConstruct(
|
|
BadUseInfo * pBadUseInfo)
|
|
{
|
|
#if 0
|
|
if( pBadUseInfo->AnyReasonForBadConstruct() )
|
|
{
|
|
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_VOID ) )
|
|
ParseError( DERIVES_FROM_VOID , (char *)NULL );
|
|
else if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_FUNC) )
|
|
ParseError( DERIVES_FROM_FUNC , (char *)NULL );
|
|
else
|
|
assert( FALSE );
|
|
}
|
|
#endif // 0
|
|
}
|
|
|
|
/***************************************************************************
|
|
PrintReasonWhyNotRPCAble:
|
|
It was determined that the use is really wrong, and hence the user
|
|
must be told. This method prints out all the error messages corresponding
|
|
to the internal errors. This is called ONLY from param nodes.
|
|
***************************************************************************/
|
|
void
|
|
node_skl::PrintReasonWhyNotRPCAble(
|
|
BadUseInfo * pBadUseInfo )
|
|
{
|
|
|
|
#if 0
|
|
if( pBadUseInfo->AnyReasonForNonRPCAble() )
|
|
{
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_INT ) )
|
|
ParseError( DERIVES_FROM_INT , (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT ))
|
|
ParseError( DERIVES_FROM_PTR_TO_INT, (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause(NR_DERIVES_FROM_VOID ) )
|
|
ParseError( DERIVES_FROM_VOID , (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause(NR_DERIVES_FROM_PTR_TO_VOID ))
|
|
ParseError( DERIVES_FROM_VOID_PTR , (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_BIT_FIELDS ))
|
|
ParseError( DERIVES_FROM_BIT_FIELDS , (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause(NR_DERIVES_FROM_NON_RPC_UNION ))
|
|
ParseError( DERIVES_FROM_NRPC_UNION , (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause (NR_DERIVES_FROM_PTR_TO_FUNC ))
|
|
ParseError( DERIVES_FROM_FUNC_PTR , (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause(
|
|
NR_DERIVES_FROM_UNSIZED_STRING ) )
|
|
ParseError( DERIVES_FROM_UNSIZED_STRING, (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause(
|
|
NR_DERIVES_FROM_CONF_STRUCT ) )
|
|
ParseError( OPEN_STRUCT_AS_PARAM, (char *)NULL );
|
|
|
|
if( pBadUseInfo->NonRPCAbleBecause(
|
|
NR_DERIVES_FROM_P_TO_CONF_STRUCT ) )
|
|
ParseError( DERIVES_FROM_PTR_TO_CONF, (char *)NULL );
|
|
}
|
|
#endif // 0
|
|
}
|
|
|
|
/***************************************************************************
|
|
Dump:
|
|
Dump the type graph for debug purposes
|
|
***************************************************************************/
|
|
|
|
node_skl *
|
|
node_skl::GetSwitchIsType()
|
|
{
|
|
|
|
/**
|
|
** if switch_is is present return the type of the switch_is or
|
|
** els return a null;
|
|
**/
|
|
|
|
if( FInSummary( ATTR_SWITCH_IS ) )
|
|
{
|
|
node_switch_is * pSwitchIs = (node_switch_is *)GetAttribute( ATTR_SWITCH_IS );
|
|
|
|
if( pSwitchIs )
|
|
return pSwitchIs->GetSwitchIsType();
|
|
}
|
|
return (node_skl *)NULL;
|
|
|
|
}
|
|
node_skl *
|
|
node_skl::GetSwitchType()
|
|
{
|
|
|
|
/**
|
|
** if switch_is is present return the type of the switch_is or
|
|
** els return a null;
|
|
**/
|
|
|
|
if( FInSummary( ATTR_SWITCH_TYPE ) )
|
|
{
|
|
ta * pSwitchType = (ta *)GetAttribute( ATTR_SWITCH_TYPE );
|
|
|
|
if( pSwitchType )
|
|
return pSwitchType->GetType();
|
|
}
|
|
return (node_skl *)NULL;
|
|
|
|
}
|
|
void
|
|
node_skl::PrintSizeofString(
|
|
BufferManager * pOutput)
|
|
{
|
|
node_skl * pC;
|
|
char * pN;
|
|
NODE_T NT = NodeKind();
|
|
|
|
GetSymName( &pN );
|
|
|
|
if( NT == NODE_FORWARD )
|
|
{
|
|
NAME_T Tag;
|
|
char * pPrefix;
|
|
|
|
((node_forward *)this)->GetSymDetails( &Tag, &pN );
|
|
|
|
switch( Tag )
|
|
{
|
|
case NAME_TAG: pPrefix = "struct "; break;
|
|
case NAME_UNION:pPrefix = "union "; break;
|
|
case NAME_ENUM: pPrefix = "enum "; break;
|
|
default: pPrefix = ""; break;
|
|
}
|
|
pOutput->ConcatTail( pPrefix );
|
|
pOutput->ConcatTail( pN );
|
|
}
|
|
else if( IS_BASE_TYPE_NODE( NT ) || (NT == NODE_WCHAR_T) )
|
|
{
|
|
if( FInSummary( ATTR_CONST ) )
|
|
pOutput->ConcatTail( "const " );
|
|
|
|
if( FInSummary( ATTR_UNSIGNED ) )
|
|
pOutput->ConcatTail( "unsigned ");
|
|
|
|
pOutput->ConcatTail( pN );
|
|
}
|
|
else
|
|
{
|
|
switch( NodeKind() )
|
|
{
|
|
case NODE_POINTER:
|
|
|
|
if( pC = GetChild() )
|
|
pC->PrintSizeofString( pOutput );
|
|
|
|
if( FInSummary( ATTR_RPC_FAR ) || FInSummary( ATTR_FAR ) )
|
|
{
|
|
pOutput->ConcatTail( " __RPC_FAR " );
|
|
}
|
|
|
|
pOutput->ConcatTail(" * ");
|
|
break;
|
|
|
|
case NODE_STRUCT:
|
|
case NODE_UNION:
|
|
case NODE_ENUM:
|
|
|
|
pOutput->ConcatTail( GetNodeNameString() );
|
|
// fall thru
|
|
case NODE_ID:
|
|
case NODE_DEF:
|
|
default:
|
|
|
|
pOutput->ConcatTail( " " );
|
|
pOutput->ConcatTail( pN );
|
|
pOutput->ConcatTail( " " );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
expr_node *
|
|
node_skl::GetSwitchIsExpr()
|
|
{
|
|
expr_node * pExpr = (expr_node *)NULL;
|
|
|
|
if( FInSummary( ATTR_SWITCH_IS ) )
|
|
{
|
|
node_switch_is * pNode;
|
|
|
|
pNode = (node_switch_is *)GetAttribute(ATTR_SWITCH_IS );
|
|
pExpr = pNode->GetExpr();
|
|
}
|
|
return pExpr;
|
|
}
|
|
|
|
|
|
short
|
|
node_skl::GetAllocateDetails()
|
|
{
|
|
if( FInSummary( ATTR_ALLOCATE ) )
|
|
{
|
|
node_allocate * pAlloc;
|
|
pAlloc = (node_allocate *)GetAttribute( ATTR_ALLOCATE );
|
|
if( pAlloc )
|
|
return pAlloc->GetAllocateDetails();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
node_state
|
|
node_skl::AcfSCheck()
|
|
{
|
|
type_node_list * pTNList = GetAttributeList();
|
|
node_state NState = NODE_STATE_OK;
|
|
node_base_attr * pAttrNode;
|
|
|
|
if( !pTNList )
|
|
return NState;
|
|
|
|
pGlobalContext->PushContext( this );
|
|
|
|
pTNList->Init();
|
|
while( pTNList->GetPeer( (node_skl **) &pAttrNode ) == STATUS_OK )
|
|
{
|
|
if( pAttrNode->IsAcfAttr() )
|
|
NState |= pAttrNode->SCheck();
|
|
}
|
|
pGlobalContext->PopContext();
|
|
|
|
return SetNodeState( NState );
|
|
}
|
|
void
|
|
node_skl::SetUpUnionSwitch(
|
|
class BufferManager * p )
|
|
{
|
|
node_skl * pChildPtr = GetChild();
|
|
if( pChildPtr )
|
|
pChildPtr->SetUpUnionSwitch( p );
|
|
}
|
|
char *
|
|
node_skl::GetByteCountParamName()
|
|
{
|
|
node_byte_count * pByteCount = (node_byte_count *) GetAttribute(
|
|
ATTR_BYTE_COUNT );
|
|
if( pByteCount )
|
|
{
|
|
return pByteCount->GetByteCountParamName();
|
|
}
|
|
return (char *)NULL;
|
|
}
|
|
|
|
node_skl *
|
|
node_skl::GetAttributeExprType(
|
|
ATTR_T Attr )
|
|
{
|
|
node_base_attr * pAttr;
|
|
expr_node * pExpr;
|
|
|
|
if( FInSummary( Attr ) )
|
|
{
|
|
pAttr = GetAttribute( Attr );
|
|
pExpr = pAttr->GetExpr();
|
|
|
|
if( pExpr )
|
|
return pExpr->GetType();
|
|
}
|
|
|
|
return (node_skl *)NULL;
|
|
}
|
|
|
|
BOOL
|
|
node_skl::IsAttributeExprConstant(
|
|
ATTR_T Attr )
|
|
{
|
|
node_base_attr * pAttr;
|
|
expr_node * pExpr;
|
|
|
|
if( FInSummary( Attr ) )
|
|
{
|
|
pAttr = GetAttribute( Attr );
|
|
pExpr = pAttr->GetExpr();
|
|
|
|
if( pExpr )
|
|
return pExpr->IsConstant();
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
node_skl *
|
|
node_skl::GetOneNEUnionSwitchType()
|
|
{
|
|
node_skl * pC = GetChild();
|
|
|
|
if( pC )
|
|
return pC->GetOneNEUnionSwitchType();
|
|
return (node_skl *)0;
|
|
}
|
|
|
|
short
|
|
node_skl::GetNEUnionSwitchType(
|
|
type_node_list * pResultList )
|
|
{
|
|
NODE_T Nt = NodeKind();
|
|
short count = 0;
|
|
|
|
if( (Nt == NODE_STRUCT ) || (Nt == NODE_PROC) )
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
node_skl * pST;
|
|
node_skl * pNode;
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
if( pST = pNode->GetOneNEUnionSwitchType() )
|
|
{
|
|
pResultList->SetPeer( pST );
|
|
count++;
|
|
}
|
|
}
|
|
delete pTNList;
|
|
}
|
|
return count;
|
|
}
|
|
/***
|
|
*** Does any member have the given node state set
|
|
***/
|
|
|
|
BOOL
|
|
node_skl::CheckNodeStateInMembers(
|
|
node_state N )
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
node_skl * pNode;
|
|
BOOL flag = FALSE;
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
if( (pNode->GetNodeState() & N ) == N )
|
|
{
|
|
flag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
delete pTNList;
|
|
return flag;
|
|
}
|
|
|
|
char *
|
|
node_skl::GetNodeNameString()
|
|
{
|
|
NODE_T NT;
|
|
static char *Names[] =
|
|
{
|
|
"illegal"
|
|
,"float"
|
|
,"double"
|
|
,"hyper"
|
|
,"long"
|
|
,"longlong"
|
|
,"short"
|
|
,"int"
|
|
,"small"
|
|
,"char"
|
|
,"boolean"
|
|
,"byte"
|
|
,"void"
|
|
,"handle_t"
|
|
,"forward"
|
|
,"struct"
|
|
,"union"
|
|
,"enum"
|
|
,"short_enum"
|
|
,"long_enum"
|
|
,"label"
|
|
,"bitset"
|
|
,"pipe"
|
|
,"error_status_t"
|
|
,"iso_latin_1"
|
|
,"private_char_8"
|
|
,"iso_multi_lingual"
|
|
,"private_char_16"
|
|
,"iso_mocs"
|
|
,"wchar_t"
|
|
,"procedure"
|
|
,"return"
|
|
,"parameter"
|
|
,"field"
|
|
,"typedef"
|
|
,"pointer"
|
|
,"array "
|
|
,"notify"
|
|
,"file"
|
|
,"interface"
|
|
,"const"
|
|
,"unimpl"
|
|
,"error"
|
|
,"identifier"
|
|
,"echo_string"
|
|
,"guid"
|
|
,"version"
|
|
,"endpoint"
|
|
,"endpoint_sub"
|
|
,"implicit"
|
|
,"explicit"
|
|
,"transmit"
|
|
,"switch_type"
|
|
,"first"
|
|
,"iid"
|
|
,"last"
|
|
,"length"
|
|
,"int_length"
|
|
,"min"
|
|
,"max"
|
|
,"size"
|
|
,"int_size"
|
|
,"byte_count"
|
|
,"switch_is"
|
|
,"base_attr"
|
|
,"auto"
|
|
,"represent_as"
|
|
,"nocode"
|
|
,"code"
|
|
,"outofline"
|
|
,"inline"
|
|
,"string"
|
|
,"ptrsize"
|
|
,"callquota"
|
|
,"callbackquota"
|
|
,"clientquota"
|
|
,"serverquota"
|
|
,"commstat"
|
|
,"heap"
|
|
,"manual"
|
|
,"allocate"
|
|
,"offline"
|
|
,"handle"
|
|
,"context"
|
|
,"case"
|
|
,"source"
|
|
};
|
|
NT = NodeKind();
|
|
return Names[NT];
|
|
}
|
|
|
|
void
|
|
node_skl::UpdateUseOfCDecls(
|
|
BadUseInfo * pB )
|
|
{
|
|
ATTR_SUMMARY AttrVector[ MAX_ATTR_SUMMARY_ELEMENTS ];
|
|
PATTR_SUMMARY pAttr = GetAttrKey();
|
|
|
|
CLEAR_ATTR( AttrVector );
|
|
OR_ATTR( AttrVector, pCDeclAttributes );
|
|
AND_ATTR( AttrVector, pAttr );
|
|
|
|
if( !IS_CLEAR_ATTR( AttrVector ) )
|
|
{
|
|
pB->SetBadConstructBecause( BC_DERIVES_FROM_CDECL );
|
|
pB->SetNonRPCAbleBecause( NR_DERIVES_FROM_CDECL );
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef MIDL_INTERNAL
|
|
|
|
struct DStruct
|
|
{
|
|
NODE_T NT;
|
|
node_skl * pSib;
|
|
node_skl * pCh;
|
|
short MyNumber, ChildNumber, SiblingNumber, RtNumber;
|
|
char * Buffer;
|
|
node_proc * pProc;
|
|
EDGE_T Edge;
|
|
};
|
|
|
|
short
|
|
node_skl::Dump( short Number )
|
|
{
|
|
struct DStruct * pDump = new struct DStruct;
|
|
char * pName;
|
|
|
|
static char *NodeName[]=
|
|
{
|
|
"NODE_FLOAT"
|
|
,"NODE_DOUBLE"
|
|
,"NODE_HYPER"
|
|
,"NODE_LONG"
|
|
,"NODE_LONGLONG"
|
|
,"NODE_SHORT"
|
|
,"NODE_INT"
|
|
,"NODE_SMALL"
|
|
,"NODE_CHAR"
|
|
,"NODE_BOOLEAN"
|
|
,"NODE_BYTE"
|
|
,"NODE_VOID"
|
|
,"NODE_HANDLE_T"
|
|
,"NODE_FORWARD"
|
|
,"NODE_STRUCT"
|
|
,"NODE_UNION"
|
|
,"NODE_ENUM"
|
|
,"NODE_SHORT_ENUM"
|
|
,"NODE_LONG_ENUM"
|
|
,"NODE_LABEL"
|
|
,"NODE_BITSET"
|
|
,"NODE_PIPE"
|
|
,"NODE_ERROR_STATUS_T"
|
|
,"NODE_ISO_LATIN_1"
|
|
,"NODE_PRIVATE_CHAR_8"
|
|
,"NODE_ISO_MULTI_LINGUAL"
|
|
,"NODE_PRIVATE_CHAR_16"
|
|
,"NODE_ISO_MOCS"
|
|
,"NODE_WCHAR_T"
|
|
,"NODE_PROC"
|
|
,"NODE_RETURN"
|
|
,"NODE_PARAM"
|
|
,"NODE_FIELD"
|
|
,"NODE_DEF"
|
|
,"NODE_POINTER"
|
|
,"NODE_ARRAY "
|
|
,"NODE_NOTIFY"
|
|
,"NODE_FILE"
|
|
,"NODE_INTERFACE"
|
|
,"NODE_CONST"
|
|
,"NODE_UNIMPL"
|
|
,"NODE_ERROR"
|
|
,"NODE_ID"
|
|
,"NODE_ECHO_STRING"
|
|
,"NODE_GUID"
|
|
,"NODE_VERSION"
|
|
,"NODE_ENDPOINT"
|
|
,"NODE_ENDPOINT_SUB"
|
|
,"NODE_IMPLICIT"
|
|
,"NODE_EXPLICIT"
|
|
,"NODE_TRANSMIT"
|
|
,"NODE_SWITCH_TYPE"
|
|
,"NODE_FIRST"
|
|
,"NODE_IID"
|
|
,"NODE_LAST"
|
|
,"NODE_LENGTH"
|
|
,"NODE_INT_LENGTH"
|
|
,"NODE_MIN"
|
|
,"NODE_MAX"
|
|
,"NODE_SIZE"
|
|
,"NODE_INT_SIZE"
|
|
,"NODE_BYTE_COUNT"
|
|
,"NODE_SWITCH_IS"
|
|
,"NODE_BASE_ATTR"
|
|
,"NODE_AUTO"
|
|
,"NODE_REPRESENT_AS"
|
|
,"NODE_NOCODE"
|
|
,"NODE_CODE"
|
|
,"NODE_OUTOFLINE"
|
|
,"NODE_INLINE"
|
|
,"NODE_STRING"
|
|
,"NODE_PTRSIZE"
|
|
,"NODE_CALLQUOTA"
|
|
,"NODE_CALLBACKQUOTA"
|
|
,"NODE_CLIENTQUOTA"
|
|
,"NODE_SERVERQUOTA"
|
|
,"NODE_COMMSTAT"
|
|
,"NODE_HEAP"
|
|
,"NODE_MANUAL"
|
|
,"NODE_ALLOCATE"
|
|
,"NODE_OFFLINE"
|
|
,"NODE_HANDLE"
|
|
,"NODE_CONTEXT"
|
|
,"NODE_CASE"
|
|
,"NODE_SOURCE"
|
|
};
|
|
|
|
pDump->MyNumber = Number++;
|
|
if(GetNDMask())
|
|
return Number;
|
|
SetNDMask( GetNDMask() | (unsigned short)0x8000) ;
|
|
|
|
pDump->ChildNumber = pDump->SiblingNumber = pDump->RtNumber = 0;
|
|
pDump->pSib = pDump->pCh = (node_skl *)NULL;
|
|
|
|
pDump->NT = NodeKind();
|
|
if(pDump->pCh = (node_skl *) GetChild() )
|
|
{
|
|
pDump->ChildNumber = Number;
|
|
Number = pDump->pCh->Dump(Number);
|
|
}
|
|
|
|
if(pDump->pSib = (node_skl *)GetSibling() )
|
|
pDump->SiblingNumber = Number;
|
|
|
|
if(pDump->NT == NODE_PROC)
|
|
{
|
|
node_skl * pReturnType;
|
|
|
|
pDump->pProc = (node_proc *)this;
|
|
pDump->RtNumber = Number;
|
|
pReturnType = pDump->pProc->GetBasicType();
|
|
|
|
if( pReturnType == (node_skl *)NULL)
|
|
pDump->RtNumber = 0;
|
|
else
|
|
Number = pReturnType->Dump(Number);
|
|
}
|
|
|
|
|
|
printf("--ND %d--", pDump->MyNumber);
|
|
printf("%15s:", NodeName[ pDump->NT - BASE_NODE_START ]);
|
|
printf("(%.2x)", pDump->NT);
|
|
printf("%.8lx:", GetNodeState());
|
|
printf("Ch %d, Si %d Rt %d:", pDump->ChildNumber,pDump->SiblingNumber,pDump->RtNumber);
|
|
pDump->Edge = GetEdgeType();
|
|
printf("Edge: %c:",(pDump->Edge == EDGE_DEF) ? 'D':(pDump->Edge == EDGE_USE) ? 'U':'I');
|
|
printf("Name : %s", (pName = GetSymName()) ? pName : "UnNamed" );
|
|
|
|
/***************************************************************************/
|
|
// print attributes if any
|
|
printf("\n\t\tSummary Attribute: %.8lx", pAttrKey[0]);
|
|
printf("\n\t\t : %.8lx", pAttrKey[1]);
|
|
printf("\n\t\t : %.8lx", pAttrKey[2]);
|
|
printf("\n\t\t : %.8lx", pAttrKey[3]);
|
|
/***************************************************************************/
|
|
printf("\n");
|
|
|
|
SetNDMask(pDump->MyNumber);
|
|
if(pDump->pSib)
|
|
Number = pDump->pSib->Dump(Number);
|
|
// delete pDump->Buffer;
|
|
delete pDump;
|
|
return Number;
|
|
}
|
|
|
|
#endif // MIDL_INTERNAL
|
|
|
|
/*** StaticSize **************************************************************
|
|
* Purpose : calculate size of the total underlying types
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
node_skl *
|
|
node_skl::StaticSize(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
unsigned long * CurrTotal)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (CurrTotal);
|
|
//return I_ERR_INCOMPLETE_GRAPH;
|
|
return (node_skl *)0;
|
|
}
|
|
/*** UpperBoundNode **********************************************************
|
|
* Purpose : calculate size of the total underlying types
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
node_skl *
|
|
node_skl::UpperBoundNode(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
unsigned long * CurrTotal)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (CurrTotal);
|
|
//return I_ERR_INCOMPLETE_GRAPH;
|
|
return (node_skl *)0;
|
|
}
|
|
/*** UpperBoundTree **********************************************************
|
|
* Purpose : calculate size of the total underlying types
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
node_skl *
|
|
node_skl::UpperBoundTree(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
unsigned long * CurrTotal)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (CurrTotal);
|
|
//return I_ERR_INCOMPLETE_GRAPH;
|
|
return (node_skl *)0;
|
|
}
|
|
/*** EmitProc **************************************************************
|
|
* Purpose : calculate size of the total underlying types
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::EmitProc(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
BufferManager * pBuffer)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
/*** WalkTree **************************************************************
|
|
* Purpose : walk the underlying tree
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::WalkTree(
|
|
ACTION_T Action,
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
BufferManager * pBuffer)
|
|
{
|
|
UNUSED (Action);
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
/*** CalcSize **************************************************************
|
|
* Purpose : calculate size of the total underlying types
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::CalcSize(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
BufferManager * pBuffer)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
/*** SendNode ***************************************************************
|
|
* Purpose :
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::SendNode(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
BufferManager * pBuffer)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
/*** RecvNode ***************************************************************
|
|
* Purpose :
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::RecvNode(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
BufferManager * pBuffer)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
|
|
/*** PeekNode ***************************************************************
|
|
* Purpose :
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::PeekNode(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
BufferManager * pBuffer)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
|
|
/*** InitNode ***************************************************************
|
|
* Purpose :
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::InitNode(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
BufferManager * pBuffer)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
|
|
/*** FreeNode ***************************************************************
|
|
* Purpose :
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::FreeNode(
|
|
SIDE_T Side,
|
|
NODE_T Parent,
|
|
BufferManager * pBuffer)
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
|
|
/*** PrintType ***************************************************************
|
|
* Purpose :
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::PrintType( SIDE_T Side, NODE_T Parent, BufferManager * pBuffer )
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
/*** PrintDecl **************************************************************
|
|
* Purpose :
|
|
* Input :
|
|
* Output :
|
|
* Notes :
|
|
***************************************************************************/
|
|
STATUS_T
|
|
node_skl::PrintDecl( SIDE_T Side, NODE_T Parent, BufferManager * pBuffer )
|
|
{
|
|
UNUSED (Side);
|
|
UNUSED (Parent);
|
|
UNUSED (pBuffer);
|
|
return I_ERR_INCOMPLETE_GRAPH;
|
|
}
|
|
/****************************************************************************
|
|
utility procedures
|
|
****************************************************************************/
|
|
/****************************************************************************
|
|
SynthesiseStates:
|
|
Certain attribute of a type subgraph or node must be propogated up to
|
|
the parent nodes, in order to indicate some characteristic of the
|
|
type graph underneath. For example, if a type derives from a non-rpcable
|
|
type, the param node needs to indicate to the user that it derives from
|
|
a non-rpcable type and thus is an error. I call this process - synthesis
|
|
of attributes. The process of synthesis depend on the type of the node
|
|
being synthesised for.
|
|
****************************************************************************/
|
|
node_state
|
|
SynthesiseStates(
|
|
node_skl * pNode,
|
|
node_state NewState )
|
|
{
|
|
|
|
node_state Template = NODE_STATE_INIT;
|
|
|
|
/**
|
|
** The template determines which node states get synthesised for a
|
|
** particular node. These one below get synthesised anyways.
|
|
**/
|
|
|
|
Template |= ( NODE_STATE_RESOLVE
|
|
| NODE_STATE_POINTER
|
|
| NODE_STATE_NEEDS_USE_PROCESSING
|
|
| NODE_STATE_IS_NON_RPCABLE_TYPE
|
|
| NODE_STATE_HAS_NON_RPCABLE_TYPE
|
|
| NODE_STATE_ENUM
|
|
| NODE_STATE_CONF_ARRAY
|
|
| NODE_STATE_IMPROPER_IN_CONSTRUCT
|
|
| NODE_STATE_VARYING_ARRAY
|
|
| NODE_STATE_EMBEDDED_UNION
|
|
| NODE_STATE_FIRST_LEVEL_REF
|
|
| NODE_STATE_ANY_ARRAY
|
|
| NODE_STATE_PTR_TO_ANY_ARRAY
|
|
| NODE_STATE_EMBEDDED_PTR
|
|
| NODE_STATE_PTR_TO_EMBEDDED_PTR
|
|
| NODE_STATE_TRANSMIT_AS
|
|
| NODE_STATE_SIZE
|
|
| NODE_STATE_LENGTH
|
|
| NODE_STATE_STRUCT_SIZE
|
|
| NODE_STATE_STRUCT_LENGTH
|
|
);
|
|
|
|
/**
|
|
** if the type derives from another type which is non-rpcable, then
|
|
** we set a node_state to indicate that this "has" a non-rpcable type.
|
|
**/
|
|
|
|
if( NewState & NODE_STATE_IS_NON_RPCABLE_TYPE )
|
|
{
|
|
NewState &= ~NODE_STATE_IS_NON_RPCABLE_TYPE;
|
|
NewState |= NODE_STATE_HAS_NON_RPCABLE_TYPE;
|
|
}
|
|
|
|
switch( pNode->NodeKind() )
|
|
{
|
|
case NODE_ARRAY:
|
|
/**
|
|
** An array node inherits node-state-context-handle for error
|
|
** checking only. An array does not inherit node state pointer.
|
|
**/
|
|
|
|
Template |= (NODE_STATE_CONTEXT_HANDLE);
|
|
Template &= ~(NODE_STATE_FIRST_LEVEL_REF |
|
|
//////////////////// NODE_STATE_POINTER |
|
|
NODE_STATE_VARYING_ARRAY);
|
|
break;
|
|
|
|
case NODE_FIELD:
|
|
|
|
/**
|
|
** a field node inherits context_handle for the purpose
|
|
** of error checking
|
|
**/
|
|
Template |= ( /**** NODE_STATE_UNION | ****/
|
|
NODE_STATE_CONTEXT_HANDLE );
|
|
break;
|
|
|
|
case NODE_STRUCT:
|
|
|
|
Template |= NODE_STATE_UNION;
|
|
Template &= ~(NODE_STATE_FIRST_LEVEL_REF |
|
|
NODE_STATE_ANY_ARRAY |
|
|
NODE_STATE_PTR_TO_ANY_ARRAY |
|
|
NODE_STATE_SIZE |
|
|
NODE_STATE_LENGTH |
|
|
NODE_STATE_STRUCT_SIZE |
|
|
NODE_STATE_STRUCT_LENGTH |
|
|
// NODE_STATE_EMBEDDED_PTR |
|
|
// NODE_STATE_PTR_TO_EMBEDDED_PTR |
|
|
NODE_STATE_TRANSMIT_AS);
|
|
break;
|
|
|
|
case NODE_UNION:
|
|
|
|
Template &= ~(NODE_STATE_FIRST_LEVEL_REF |
|
|
NODE_STATE_ANY_ARRAY |
|
|
NODE_STATE_PTR_TO_ANY_ARRAY |
|
|
NODE_STATE_SIZE |
|
|
NODE_STATE_LENGTH |
|
|
NODE_STATE_STRUCT_SIZE |
|
|
NODE_STATE_STRUCT_LENGTH |
|
|
// NODE_STATE_EMBEDDED_PTR |
|
|
// NODE_STATE_PTR_TO_EMBEDDED_PTR |
|
|
NODE_STATE_TRANSMIT_AS );
|
|
break;
|
|
|
|
case NODE_PROC:
|
|
Template |= (NODE_STATE_HANDLE |
|
|
NODE_STATE_CONTEXT_HANDLE );
|
|
Template &= ~(NODE_STATE_FIRST_LEVEL_REF |
|
|
NODE_STATE_SIZE |
|
|
NODE_STATE_LENGTH |
|
|
NODE_STATE_STRUCT_SIZE |
|
|
NODE_STATE_STRUCT_LENGTH |
|
|
NODE_STATE_TRANSMIT_AS);
|
|
break;
|
|
|
|
case NODE_PARAM:
|
|
Template |= (NODE_STATE_HANDLE |
|
|
/** NODE_STATE_UNION | **/
|
|
NODE_STATE_CONTEXT_HANDLE );
|
|
break;
|
|
case NODE_DEF:
|
|
Template |= (NODE_STATE_HANDLE |
|
|
NODE_STATE_UNION |
|
|
NODE_STATE_CONTEXT_HANDLE );
|
|
break;
|
|
|
|
case NODE_POINTER:
|
|
Template |= (NODE_STATE_HANDLE |
|
|
NODE_STATE_PTR_TO_ANY_ARRAY |
|
|
NODE_STATE_CONTEXT_HANDLE );
|
|
|
|
/**
|
|
** a pointer DOES NOT SYNTHESISE these states. Instead, the
|
|
** varying attributes (length_is etc ) force this state on the
|
|
** pointer. Therefore a pointer to anything which has varying
|
|
** array does not get this state. It gets this state only if
|
|
** IT has the varying attributes applied to it. Similarly a
|
|
** pointer does not inherit conf array. If a struct contains a
|
|
** pointer to a conf. struct, then THIS struct need not get the
|
|
** conf array attribute.
|
|
**/
|
|
|
|
Template &= ~(NODE_STATE_CONF_ARRAY |
|
|
NODE_STATE_EMBEDDED_UNION |
|
|
NODE_STATE_VARYING_ARRAY );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return NewState & Template;
|
|
|
|
}
|
|
/***************************************************************************
|
|
DoSetAttributes:
|
|
this routine exists becuase the code is similar in all
|
|
node types. Any special cases are handled by individual
|
|
member functions for the node types
|
|
**************************************************************************/
|
|
STATUS_T
|
|
DoSetAttributes(
|
|
node_skl * pNode,
|
|
ATTR_SUMMARY * pPreAttr,
|
|
ATTR_SUMMARY * pPostAttr,
|
|
type_node_list * pAttrList )
|
|
{
|
|
node_skl * pChildPtr;
|
|
|
|
/**
|
|
** attributes are applied in a simple fashion. The list of attributes
|
|
** is plucked from, if needed, passed down to the child nodes, till
|
|
** it cant be passed further, and then is passed back, when the
|
|
** parent nodes can pluck the attributes again.
|
|
**
|
|
** What attributes to pluck on the way down and on the way up are
|
|
** dictated by the lists passed in.
|
|
**/
|
|
|
|
CollectAttributes( pNode, pPreAttr, pAttrList );
|
|
|
|
/**
|
|
**pass on the attributes to the child
|
|
**/
|
|
|
|
if( pNode->NodeKind() == NODE_PROC )
|
|
{
|
|
((node_proc *)pNode)->GetReturnType( &pChildPtr );
|
|
}
|
|
else
|
|
pChildPtr = pNode->GetChild();
|
|
|
|
if(pChildPtr)
|
|
{
|
|
pChildPtr->SetAttribute( pAttrList );
|
|
}
|
|
|
|
/**
|
|
** if we need to pluck attributes on the way up, do that
|
|
**/
|
|
|
|
CollectAttributes( pNode, pPostAttr, pAttrList );
|
|
|
|
return STATUS_OK;
|
|
}
|
|
|
|
void
|
|
CollectAttributes(
|
|
node_skl * pNode,
|
|
ATTR_SUMMARY * pAttrVector,
|
|
type_node_list * pAttrList )
|
|
{
|
|
node_base_attr * pAttrNode;
|
|
ATTR_SUMMARY Attr[ MAX_ATTR_SUMMARY_ELEMENTS ],
|
|
AttrCollected[ MAX_ATTR_SUMMARY_ELEMENTS ];
|
|
int Count;
|
|
ATTR_T AttrID;
|
|
|
|
if( pAttrVector && pAttrList && ( pAttrList->GetCount() != 0 ) )
|
|
{
|
|
CLEAR_ATTR( AttrCollected );
|
|
|
|
pAttrList->Init();
|
|
if( Count = pAttrList->GetCount() )
|
|
{
|
|
while( Count-- )
|
|
{
|
|
pAttrList->GetCurrent( (void **)&pAttrNode );
|
|
|
|
CLEAR_ATTR( Attr );
|
|
|
|
SetAttributeVector( Attr, ( AttrID = pAttrNode->GetAttrID() ) );
|
|
|
|
// if the attribute is one of those which must be plucked
|
|
// AND has already not been plucked, pluck it. However if
|
|
// it is an error attribute, remove it from the list w/o
|
|
// applying it anywhere. This situation corresponds to a
|
|
// an unimplemented attribute being applied and hence appearing
|
|
// in the list.
|
|
|
|
if( pAttrNode == pErrorAttrNode )
|
|
pAttrList->Remove();
|
|
else
|
|
{
|
|
BOOL fMustBePlucked;
|
|
BOOL fNotCollectedYet;
|
|
BOOL fRedundantApplicationOk;
|
|
|
|
fMustBePlucked = COMPARE_ATTR( pAttrVector, Attr );
|
|
fNotCollectedYet= !COMPARE_ATTR( AttrCollected, Attr );
|
|
fRedundantApplicationOk = IsOkToApplyAttributeAgain(
|
|
pNode, pAttrNode );
|
|
|
|
|
|
if( fMustBePlucked &&
|
|
(fNotCollectedYet || fRedundantApplicationOk ) )
|
|
{
|
|
pNode->SetAttribute( pAttrNode );
|
|
pAttrList->Remove();
|
|
|
|
// record that we just collected the attribute, so that
|
|
// we do not collect it again
|
|
|
|
OR_ATTR( AttrCollected, Attr );
|
|
}
|
|
else if( !fRedundantApplicationOk )
|
|
{
|
|
pAttrList->Remove();
|
|
}
|
|
}
|
|
|
|
pAttrList->Advance();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*****************************************************************************
|
|
utility functions
|
|
*****************************************************************************/
|
|
|
|
BOOL
|
|
COMPARE_ATTR(
|
|
ATTR_VECTOR * A1,
|
|
ATTR_VECTOR * A2 )
|
|
{
|
|
int i;
|
|
for( i = 0; i < MAX_ATTR_SUMMARY_ELEMENTS; ++i )
|
|
{
|
|
if( (A1[ i ] & A2[ i ] ) != A2[i] )
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
OR_ATTR(
|
|
ATTR_VECTOR * A1,
|
|
ATTR_VECTOR * A2 )
|
|
{
|
|
int i;
|
|
for( i= 0; i < MAX_ATTR_SUMMARY_ELEMENTS; ++i )
|
|
{
|
|
A1[ i ] |= A2[ i ];
|
|
}
|
|
}
|
|
void
|
|
XOR_ATTR(
|
|
ATTR_VECTOR * A1,
|
|
ATTR_VECTOR * A2 )
|
|
{
|
|
int i;
|
|
for( i= 0; i < MAX_ATTR_SUMMARY_ELEMENTS; ++i )
|
|
{
|
|
A1[ i ] ^= A2[ i ];
|
|
}
|
|
}
|
|
void
|
|
CLEAR_ATTR(
|
|
ATTR_VECTOR * A1 )
|
|
{
|
|
int i;
|
|
for( i= 0; i < MAX_ATTR_SUMMARY_ELEMENTS; ++i )
|
|
{
|
|
A1[ i ] = (ATTR_VECTOR)0;
|
|
}
|
|
}
|
|
void
|
|
AND_ATTR(
|
|
ATTR_VECTOR * A1,
|
|
ATTR_VECTOR * A2 )
|
|
{
|
|
int i;
|
|
for( i= 0; i < MAX_ATTR_SUMMARY_ELEMENTS; ++i )
|
|
{
|
|
A1[ i ] &= A2[ i ];
|
|
}
|
|
}
|
|
void
|
|
COPY_ATTR(
|
|
ATTR_VECTOR * A1,
|
|
ATTR_VECTOR * A2 )
|
|
{
|
|
int i;
|
|
for( i= 0; i < MAX_ATTR_SUMMARY_ELEMENTS; ++i )
|
|
{
|
|
A1[ i ] = A2[ i ];
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
IS_CLEAR_ATTR(
|
|
ATTR_VECTOR * A1 )
|
|
{
|
|
int i;
|
|
for( i = 0; i < MAX_ATTR_SUMMARY_ELEMENTS ; ++i)
|
|
{
|
|
if( A1[ i ] != (ATTR_VECTOR)0 )
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
/*****************************************************************************
|
|
These are functions which can be inlined but are not because the MIPS
|
|
compiler does not like virtual in-line functions
|
|
*****************************************************************************/
|
|
BOOL
|
|
node_skl::IsFixedSizedArray()
|
|
{
|
|
return FALSE;
|
|
}
|
|
void
|
|
node_skl::UseProcessingAction()
|
|
{
|
|
ResetNodeState( NODE_STATE_NEEDS_USE_PROCESSING );
|
|
}
|
|
void
|
|
node_skl::SetAttribute(
|
|
type_node_list * pTNList )
|
|
{
|
|
}
|
|
void
|
|
node_skl::UpdateBadUseInfo(
|
|
class BadUseInfo * p )
|
|
{
|
|
}
|
|
node_skl *
|
|
node_skl::Clone()
|
|
{
|
|
return this;
|
|
}
|
|
BOOL
|
|
node_skl::IsNamedNode()
|
|
{
|
|
return !IsTempName(GetSymName());
|
|
}
|
|
short
|
|
node_skl::GetOrdinalNumberOfMember(
|
|
node_skl * pN )
|
|
{
|
|
type_node_list * pTNList = new type_node_list;
|
|
short Number = 0;
|
|
node_skl * pNode;
|
|
BOOL fFound = FALSE;
|
|
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
Number++;
|
|
if( pNode == pN )
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
delete pTNList;
|
|
return (fFound == TRUE ) ? Number : 0;
|
|
}
|
|
|
|
BOOL
|
|
node_skl::IsClonedNode()
|
|
{
|
|
if( NodeKind() == NODE_DEF )
|
|
{
|
|
SymKey SKey( GetSymName(), NAME_DEF );
|
|
if( pBaseSymTbl->SymSearch( SKey ) != this )
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Returns true if this attribute has not been applied or if it is ok to
|
|
// apply the attribute again.
|
|
// The caller must ensure that this routine is called only after it has been
|
|
// checked that the attribute IS applicable to this node.
|
|
//
|
|
|
|
BOOL
|
|
IsOkToApplyAttributeAgain(
|
|
node_skl * pNode,
|
|
node_base_attr * pAttrNode )
|
|
{
|
|
|
|
ATTR_T NewAttribute = pAttrNode->GetAttrID();
|
|
|
|
static ATTR_T Info[] =
|
|
{
|
|
ATTR_REF,
|
|
ATTR_PTR,
|
|
ATTR_UNIQUE
|
|
};
|
|
|
|
short iIndex;
|
|
|
|
//
|
|
// Assuming that this attribute is applicable, check if it has been
|
|
// applied. If it has not been applied already, then it is ok to
|
|
// apply this attribute. If it HAS been applied already, check to see if
|
|
// it is ok to apply this again. If it is , then return TRUE.
|
|
|
|
if( pNode->FInSummary( NewAttribute ) )
|
|
{
|
|
ParseError(REDUNDANT_ATTRIBUTE, pAttrNode->GetNodeNameString());
|
|
for( iIndex = 0;
|
|
iIndex < sizeof( Info ) / sizeof( ATTR_T );
|
|
iIndex++
|
|
)
|
|
{
|
|
if( NewAttribute == Info[ iIndex ] )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
node_skl::Has8ByteElementWithZp8()
|
|
{
|
|
type_node_list * pTNList;
|
|
node_skl * pNode;
|
|
BOOL fIsDouble = FALSE;
|
|
|
|
if( pCommand->GetZeePee() != 8 )
|
|
return FALSE;
|
|
|
|
pTNList = new type_node_list;
|
|
GetMembers( pTNList );
|
|
|
|
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
|
|
{
|
|
if( pNode->GetBasicType()->NodeKind() == NODE_DOUBLE )
|
|
fIsDouble = TRUE;
|
|
}
|
|
|
|
|
|
delete pTNList;
|
|
return fIsDouble;
|
|
}
|