Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1455 lines
38 KiB

/*****************************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1987-1990 **/
/*****************************************************************************/
/*****************************************************************************
File : procnode.cxx
Title : proc / param semantic analyser routines
History :
10-Aug-1991 VibhasC Created
*****************************************************************************/
/****************************************************************************
includes
****************************************************************************/
#include "nulldefs.h"
extern "C" {
#include <stdio.h>
#include <assert.h>
#include <string.h>
}
#include "nodeskl.hxx"
#include "miscnode.hxx"
#include "procnode.hxx"
#include "ptrarray.hxx"
#include "acfattr.hxx"
#include "cmdana.hxx"
#include "ctxt.hxx"
#include "idict.hxx"
/****************************************************************************
local defines
****************************************************************************/
/****************************************************************************
externs
****************************************************************************/
extern node_error * pErrorTypeNode;
extern short CompileMode;
extern ATTR_SUMMARY * pPreAttrParam;
extern ATTR_SUMMARY * pPreAttrProc;
extern CTXTMGR * pGlobalContext;
extern SymTable * pBaseSymTbl,
* pCurSymTbl;
extern CMD_ARG * pCommand;
extern idict * pDictProcsWOHandle;
extern node_interface * pBaseInterfaceNode;
/****************************************************************************
extern procedures
****************************************************************************/
extern STATUS_T DoSetAttributes( node_skl *,
ATTR_SUMMARY *,
ATTR_SUMMARY *,
type_node_list *);
extern void ParseError( STATUS_T, char * );
extern BOOL IsIntegralType( node_skl * );
extern BOOL fAtLeastOneProcWOHandle;
extern BOOL fAtLeastOneRemoteProc;
extern BOOL IsTempName( char * );
extern BOOL fOnlyCallBacks;
extern BOOL fInterfaceHasCallback;
extern short NoOfNormalProcs;
extern short NoOfCallbackProcs;
extern short NoOfMopProcs;
/****************************************************************************/
/****************************************************************************
param node procedures
****************************************************************************/
/****************************************************************************
PreSCheck:
The method is called to do any checks prior to the semantics of its
children.
****************************************************************************/
node_state
node_param::PreSCheck(
BadUseInfo * pB)
{
UNUSED( pB );
/**
** If the parameter was not specified with either in out out, then
** it is by default, an IN parameter. But beware! A void param list
** is at least one param node with the basic type as void. We must NOT
** set the in attribute on it.
**/
if( GetBasicType()->NodeKind() != NODE_VOID )
{
if( !( FInSummary( ATTR_IN ) || FInSummary( ATTR_OUT ) ) )
{
ParseError( NO_EXPLICIT_IN_OUT_ON_PARAM, (char *)0 );
node_skl::SetAttribute( (ATTR_T) ATTR_IN );
}
if( FInSummary( ATTR_CONTEXT ) )
{
SetNodeState( NODE_STATE_CONTEXT_HANDLE );
}
}
return GetNodeState();
}
/****************************************************************************
PostSCheck:
The method is called to do any checks after the semantics of its
children have been completed. This is really the place where the param
node knows more about the type graph underneath.
****************************************************************************/
node_state
node_param::PostSCheck(
BadUseInfo * pBadUseInfo )
{
char * pName = GetSymName();
node_state NState = GetNodeState();
BOOL fIn = FInSummary( ATTR_IN );
BOOL fOut = FInSummary( ATTR_OUT );
node_skl * pChildType = GetChild();
BOOL fHasContextHandle = HasAnyCtxtHdlSpecification();
BOOL fHasHandleSpecification = HasAnyHandleSpecification();
node_proc * pParent = (node_proc *)
pGlobalContext->GetLastContext(C_PROC);
CheckBadConstructs( pBadUseInfo );
CheckHandleSpecs( pBadUseInfo,
pParent,
fIn,
fOut,
pGlobalContext->IsFirstParam() );
/**
** If this parameter is non-rpcable for any reason,
** indicate the reason why.
**/
if( pBadUseInfo->AnyReasonForNonRPCAble() )
{
/**
** we let him specify a param which derives from int *, only if
** it has a handle attribute AND the compiler mode is not osf.
** OSF Mode permits a context handle only on a void ptr, not
** int. A param of this kind can derive only form int *, not
** int. Similarly for use of c declarative type modifiers/
** qualifiers.
**/
if(fHasHandleSpecification && pCommand->IsSwitchDefined(SWITCH_MS_EXT))
{
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT) )
pBadUseInfo->ResetNonRPCAbleBecause(NR_DERIVES_FROM_PTR_TO_INT);
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_CDECL ))
pBadUseInfo->ResetNonRPCAbleBecause( NR_DERIVES_FROM_CDECL);
}
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_VOID ) )
{
/**
** If a param derives from void, it is ok, if and only if
** 1.the basic type of the param itself is a void.
** 2. if void is the only param in the proc
** Check no 2 has already been done by CheckBadConstructs.
**/
if( GetBasicType()->NodeKind() != NODE_VOID )
ParseError( NON_RPC_PARAM_VOID, (char *)NULL );
else
{
pBadUseInfo->ResetNonRPCAbleBecause(NR_DERIVES_FROM_VOID);
}
}
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_UNSIZED_STRING ) )
{
/**
** if an unsized string array / pointer is used, then
** it cannot be an out only parameter
**/
if( fIn )
pBadUseInfo->ResetNonRPCAbleBecause(
NR_DERIVES_FROM_UNSIZED_STRING );
}
if( pBadUseInfo->NonRPCAbleBecause(
NR_DERIVES_FROM_P_TO_C_STRUCT ) )
{
/**
** if the parameter derives from a pointer to a conformant
** struct / array, then the param should be an in or inout
** it is an error, else it is ok
**/
if( !fOut || fIn )
{
pBadUseInfo->ResetNonRPCAbleBecause(
NR_DERIVES_FROM_P_TO_C_STRUCT );
}
}
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_NE_UNIQUE_PTR ) ||
pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_NE_FULL_PTR ) )
{
if( fOut && !fIn )
{
ParseError( UNIQUE_FULL_PTR_OUT_ONLY, (char *)0 );
}
}
/**
** we now print all reasons why the specification is
** not rpcable.
**/
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_INT ) ||
pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT ))
ParseError( NON_RPC_PARAM_INT, (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause(NR_DERIVES_FROM_VOID ) ||
pBadUseInfo->NonRPCAbleBecause(NR_DERIVES_FROM_PTR_TO_VOID ))
ParseError( NON_RPC_PARAM_VOID , (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_BIT_FIELDS ))
ParseError( NON_RPC_PARAM_BIT_FIELDS , (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause(NR_DERIVES_FROM_NON_RPC_UNION ))
ParseError( NON_RPC_UNION , (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause (NR_DERIVES_FROM_PTR_TO_FUNC ))
ParseError( NON_RPC_PARAM_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_C_STRUCT ) )
ParseError( DERIVES_FROM_PTR_TO_CONF, (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_CDECL ) )
ParseError( NON_RPC_PARAM_CDECL, (char *)0 );
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_WCHAR_T ) )
ParseError( WCHAR_T_NEEDS_MS_EXT_TO_RPC, (char *)0 );
}
pChildType = GetBasicType();
if( (pChildType->GetNodeState() & NODE_STATE_UNION) == NODE_STATE_UNION )
{
if( pChildType->NodeKind() != NODE_STRUCT )
SetNodeState( NODE_STATE_UNION );
}
if( fOut )
{
/**
** if it is an out param, then it should be a pointer. Warn the user
** if it is not.
**/
if( (pChildType->NodeKind() != NODE_POINTER) &&
(pChildType->NodeKind() != NODE_ARRAY ) )
ParseError( NON_PTR_OUT, (char *)NULL );
}
/******************************************************************
** hack for node-state-size and length
******************************************************************
if( (pChildType->NodeKind() != NODE_STRUCT ) &&
(pChildType->NodeKind() != NODE_UNION ) )
{
if( pChildType->FInSummary( ATTR_STRING ) )
NState |= ( NODE_STATE_PROC_SIZE | NODE_STATE_PROC_LENGTH );
}
****************** end of hack ***********************************/
if( ((GetNodeState() & NODE_STATE_SIZE) == NODE_STATE_SIZE ) ||
((GetNodeState() & NODE_STATE_STRUCT_SIZE) == NODE_STATE_STRUCT_SIZE )
)
{
ResetNodeState( NODE_STATE_STRUCT_SIZE );
SetNodeState( NODE_STATE_SIZE );
}
if( ((GetNodeState() & NODE_STATE_LENGTH) == NODE_STATE_LENGTH ) ||
((GetNodeState() & NODE_STATE_STRUCT_LENGTH) == NODE_STATE_STRUCT_LENGTH )
)
{
ResetNodeState( NODE_STATE_STRUCT_LENGTH );
SetNodeState( NODE_STATE_LENGTH );
}
/**
** If the parameter needs use processing, do it
**/
if( NeedsUseProcessing() )
UseProcessing();
return NState;
}
void
node_param::CheckBadConstructs(
BadUseInfo * pBadUseInfo )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
check bad parameter constructs.
Arguments:
pBadUseInfo - pointer to bad use information.
Return Value:
Notes:
----------------------------------------------------------------------------*/
{
char * pMyName = GetSymName();
node_skl * pParent = pGlobalContext->GetParentContext();
assert( pParent != 0 );
/**
** If this parameter is named with an elipsis, then it is not
** rpcable
**/
if( strcmp( pMyName, "..." ) == 0 )
ParseError( PARAM_IS_ELIPSIS, (char *)NULL );
if( IsTempName( pMyName ) )
ParseError( ABSTRACT_DECL, (char *)0 );
/**
** check if the param construct is bad for any other reason, and report
** errors.
**/
if( pBadUseInfo->AnyReasonForBadConstruct() )
{
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_FUNC ) )
ParseError( BAD_CON_PARAM_FUNC, (char *)NULL );
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_UNSIZED_ARRAY ) )
ParseError( UNSIZED_ARRAY, (char *)NULL );
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_VOID ) )
{
char * pName;
if( !pGlobalContext->IsFirstParam() )
{
if( pParent->HasManyChildren())
ParseError( VOID_NON_FIRST_PARAM, (char *)0 );
}
else if( !IsTempName( pName = GetSymName() ) &&
( strcmp( pName, "void") != 0 ) )
ParseError( VOID_PARAM_WITH_NAME, pName );
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_VOID);
}
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_IGNORE ) )
ParseError( BAD_CON_PARAM_RT_IGNORE, (char *)NULL );
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_RECURSIVE_REF ) )
ParseError( RECURSION_THRU_REF, (char *)0 );
if( pBadUseInfo->BadConstructBecause( BC_REF_PTR_BAD_RT ) )
{
pBadUseInfo->ResetBadConstructBecause( BC_REF_PTR_BAD_RT );
}
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_RECURSIVE_UNION ))
{
ParseError( RECURSIVE_UNION, (char *)0 );
}
UpdateUseOfCDecls( pBadUseInfo );
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CDECL ))
{
ParseError( BAD_CON_MSC_CDECL , (char *)0 );
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_CDECL );
}
}
}
void
node_param::CheckHandleSpecs(
BadUseInfo * pB,
node_proc * pParent,
BOOL fIn,
BOOL fOut,
BOOL fFirstParameter )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Routine Description:
Check handle semantics.
Arguments:
pB - BadUseInfo pointer.
pParent - a pointer to the parent procedure.
fIn - flag indicating if parameter is [in].
fOut - flag indicating if parameter is [out].
fFirstParameter - flag indicating if it is the first parameter.
Return Value:
None.
Notes:
If this is not a handle of any sort, dont do anything.
----------------------------------------------------------------------------*/
{
BOOL fIsABindingHandle = FALSE;
BOOL fOutOnly = fOut && !fIn;
BOOL fParamContext = FInSummary( ATTR_CONTEXT );
//
// check whether this is a handle specification. If not, we dont have to
// do anything. If yes, then a set of checks need to be performed.
//
if( pB->HasAnyHandleSpecification() || fParamContext )
{
BOOL fBasicPrimitiveHandle;
BOOL fBasicGenericHandle;
BOOL fBasicContextHandle;
BOOL fPtrToBasicPrimitiveHandle;
BOOL fPtrToBasicGenericHandle;
BOOL fPtrToBasicContextHandle;
BOOL fPrimitiveHandle;
BOOL fGenericHandle;
BOOL fContextHandle;
BOOL fDerivedContextHandle;
fBasicPrimitiveHandle = pB->NonRPCAbleBecause( NR_PRIMITIVE_HANDLE );
fPtrToBasicPrimitiveHandle= pB->NonRPCAbleBecause(
NR_PTR_TO_PRIMITIVE_HANDLE );
fBasicGenericHandle = pB->NonRPCAbleBecause( NR_GENERIC_HANDLE );
fPtrToBasicGenericHandle= pB->NonRPCAbleBecause(
NR_PTR_TO_GENERIC_HANDLE );
fBasicContextHandle = pB->NonRPCAbleBecause( NR_CTXT_HDL );
fPtrToBasicContextHandle= pB->NonRPCAbleBecause(
NR_PTR_TO_CTXT_HDL );
fPrimitiveHandle= fBasicPrimitiveHandle || fPtrToBasicPrimitiveHandle;
fGenericHandle = fBasicGenericHandle || fPtrToBasicGenericHandle;
fDerivedContextHandle=(fBasicContextHandle || fPtrToBasicContextHandle);
if( fDerivedContextHandle )
{
if( fParamContext )
ParseError( PARAM_ALREADY_CTXT_HDL, (char *)0 );
}
//
// special case of context_handles. An out context handle must be
// a pointer to a pointer.
//
if( fContextHandle = (fDerivedContextHandle || fParamContext) )
{
if( fOut )
#if 0
if( !fPtrToBasicContextHandle )
#endif // 1
if( (GetBasicType())->GetBasicType()->NodeKind()
!= NODE_POINTER )
ParseError( OUT_CONTEXT_GENERIC_HANDLE, "(missing * ?)" );
//
// if it is a context_handle, it must not have a transmit_as.
//
if( fContextHandle )
{
if( pB->NonRPCAbleBecause( NR_DERIVES_FROM_TRANSMIT_AS ) )
ParseError( CTXT_HDL_TRANSMIT_AS, (char *)0 );
}
#if 0
//
// if it is not an in context handle, then it is not a binding
// handle anyways.
//
if( !fIn )
fContextHandle = FALSE;
#endif // 0
if( fParamContext && fGenericHandle )
ParseError( CTXT_HDL_GENERIC_HDL, (char *)0 );
//
// In any case, whether this is a binding handle or not, we must
// reset errors deriving from int or void
//
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_VOID );
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_VOID );
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_INT );
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT );
}
//
// in ms_ext mode, the binding handle need not be the first parameter.
// Instead the leftmost handle parameter is taken as the binding handle.
// In osf mode, if the first parameter is not a binding handle, then
// the proc is considered an auto_bind proc, to be finally decided by
// the acf. In case of context_handles, this restriction does not
// apply.
//
if( !pGlobalContext->IsSecondSemanticPass() )
{
if( !pParent->HasAtLeastOneHandle() )
{
if( (fContextHandle && fIn ) )
fIsABindingHandle = TRUE;
else
{
//
// in osf mode, the binding handle needs to be the
// first parameter. If the first parameter is not a handle
// then this procedure is an auto_handle procedure.
// Also, if the generic handle is an out only parameter
// then it is not considered the binding handle.
//
BOOL fMsExtOrFirstParam =
(pCommand->IsSwitchDefined( SWITCH_MS_EXT ) ||
fFirstParameter);
if( fPrimitiveHandle || fGenericHandle )
{
if( fMsExtOrFirstParam )
fIsABindingHandle = TRUE;
}
}
}
}
else
{
if( IsThisTheBindingHandle() )
fIsABindingHandle = TRUE;
}
//
// different semantic checks need to be applied depending upon
// whether this is a binding handle at all or not.
//
if( fIsABindingHandle )
{
#if 0
fprintf(stderr, "Param %s is the Binding handle for proc %s\n", GetSymName(), pParent->GetSymName() );
#endif // 0
pParent->SetHasAtLeastOneHandle();
ThisIsTheBindingHandle();
//
// a handle is not supported in presence of callbacks.
//
if( pParent->FInSummary( ATTR_CALLBACK ) )
{
ParseError( HANDLES_WITH_CALLBACK, (char *)0 );
}
//
// any binding handle cannot be out only. If it is an in handle,
// then it cannot be a unique/ptr pointer.
//
if( fOut && !fIn )
{
ParseError( BINDING_HANDLE_IS_OUT_ONLY, (char *)0 );
}
else if(fPtrToBasicPrimitiveHandle ||
fPtrToBasicGenericHandle ||
fPtrToBasicContextHandle )
{
node_pointer * pBasicType = (node_pointer *)GetBasicType();
assert( pBasicType->NodeKind() == NODE_POINTER );
if( pBasicType->FInSummary( ATTR_PTR ) ||
pBasicType->FInSummary( ATTR_UNIQUE ) )
#if 0
ATTR_T PtrAttr;
if( ( ( PtrAttr = pBasicType->WhatPtrIsThis()) == ATTR_PTR ) ||
( PtrAttr == ATTR_UNIQUE ) )
#endif // 0
{
ParseError( PTR_TO_HDL_UNIQUE_OR_FULL, (char *)0 );
}
}
//
// It is a binding handle. If it is a generic handle, then it needs
// to be marshalled and must be transmissible.
// If a generic handle is an out, then it must be a pointer to
// a generic handle.
//
if( !fGenericHandle )
{
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_VOID );
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_INT );
pB->ResetNonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT );
}
else
{
if( fOut && !fPtrToBasicGenericHandle )
ParseError( OUT_CONTEXT_GENERIC_HANDLE, (char *)0 );
}
//
// A primitive binding handle must not have [out] applied
// to it.
//
if( pB->NonRPCAbleBecause( NR_BASIC_TYPE_HANDLE_T ) )
{
if( fOut )
ParseError( HANDLE_T_CANNOT_BE_OUT, (char *)0 );
}
}
else
{
#if 0
fprintf(stderr, "Param %s is not a binding handle for proc %s\n", GetSymName(), pParent->GetSymName() );
#endif // 0
//
// The backend wants a reset of node-state-handle. We must however
// not reset node-state-context-handle because the backend still
// needs that to generate a call the context-marshall and
// unmarshall routines.
//
ResetNodeState( NODE_STATE_HANDLE );
//
// if it is a primitive handle, and not the binding handle, then
// it is an error.
//
if( fPrimitiveHandle )
ParseError( HANDLE_T_NO_TRANSMIT, (char *)0 );
}
}
else if( pB->NonRPCAbleBecause( NR_BASIC_TYPE_HANDLE_T ) )
{
//
// if the basic type is a handle_t and it is not a binding handle,
// it is an error.
//
ParseError( HANDLE_T_NO_TRANSMIT, (char *)0 );
}
}
void
node_param::SetAttribute(
type_node_list * pAttrList )
{
DoSetAttributes(this,
pPreAttrParam,
(ATTR_SUMMARY *)NULL,
pAttrList );
}
node_state
node_param::AcfSCheck()
{
node_state NState = node_skl::AcfSCheck();
node_skl * pBasic = GetBasicType();
node_skl * pBasicBasic = (node_skl *)NULL;
BOOL fBasicIsPointer;
// PATCH PATCH PATCH !!!
// this is a patch put in for the back end. For allocate attributes
// the backend wants that if the param is a pointer to pionter then
// if the pointer has an allocate attribute, then the pointer undeneath
// must also have the same allocate attribute.
if( (fBasicIsPointer = (pBasic->NodeKind() == NODE_POINTER ) ) )
{
pBasicBasic = pBasic->GetBasicType();
if( pBasicBasic->NodeKind() == NODE_POINTER &&
pBasic->FInSummary( ATTR_ALLOCATE ) )
{
node_base_attr * pAlloc = pBasic->GetAttribute(ATTR_ALLOCATE);
pBasicBasic->SetAttribute( pAlloc );
}
}
/**
** if the param has the byte count attribute:
** . the param must be an out pointer to a fixed size entity.
** . the param which IS the byte count must be of integral type
** and must not be in ( if it is out only, it is an error, if
** it is in-out, it is a warning
**
**/
if( FInSummary( ATTR_BYTE_COUNT ) )
{
node_byte_count * pByteCount = (node_byte_count *)
GetAttribute( ATTR_BYTE_COUNT );
STATUS_T Status = STATUS_OK;
char * pAdditionalInfo = (char *)NULL;
BOOL fOutOnly = FInSummary( ATTR_OUT ) &&
!FInSummary( ATTR_IN );
assert( pByteCount != (node_byte_count *) NULL );
if( !(fBasicIsPointer && fOutOnly) )
Status = BYTE_COUNT_NOT_OUT_PTR;
else
{
if( pBasic->HasAnySizeAttributes() )
Status = BYTE_COUNT_WITH_SIZE_ATTR;
else if( pBasicBasic->GetNodeState() & NODE_STATE_CONF_ARRAY )
Status = BYTE_COUNT_ON_CONF;
else
{
/**
** Search For the param specified as the byte_count
**/
char * pName = pByteCount->GetByteCountParamName();
SymKey SKey( pName, NAME_MEMBER);
pBasicBasic = pCurSymTbl->SymSearch( SKey );
if( !pBasicBasic )
{
Status = UNDEFINED_SYMBOL;
pAdditionalInfo = pName;
}
else
{
if( !IsIntegralType( pBasicBasic->GetBasicType() ) )
Status = BYTE_COUNT_PARAM_NOT_INTEGRAL;
else if( !pBasicBasic->FInSummary( ATTR_IN ) )
Status = BYTE_COUNT_PARAM_NOT_IN;
}
}
}
if( Status == STATUS_OK )
{
pBasic->SetAttribute( pByteCount );
#ifdef RPCDEBUG
pAdditionalInfo = pBasic->GetByteCountParamName();
printf( "ByteCountParamName = %s\n", pAdditionalInfo );
#endif // RPCDEBUG
}
else
ParseError( Status, pAdditionalInfo );
}
#if 0
//
// if the align attribute is specified, then the allocate all nodes must
// be supplied too.
//
if( FInSummary( ATTR_ALIGN ) )
{
node_allocate * pAttr = (node_allocate *)
pBasic->GetAttribute(ATTR_ALLOCATE);
if( pAttr->GetAllocateDetails() != ALLOCATE_ALL_NODES )
ParseError( ALIGN_NOT_WITH_ALLOCATE_ALL, (char *)0);
}
#endif // 0
return SetNodeState(NState);
}
void
node_param::RegisterFDeclUse()
{
if( AreForwardDeclarationsPresent() && !FInSummary( ATTR_CONTEXT ) )
{
GetChild()->RegisterFDeclUse();
}
}
/****************************************************************************
proc node procedures
****************************************************************************/
node_proc::node_proc(
short Level,
BOOL fLocalInterface) : node_skl( NODE_PROC )
{
ImportLevel = Level;
fIsErrorStatusTReturn = 0;
fErrorStatusTParamDetected = 0;
fDefinedInLocalInterface = fLocalInterface;
fHasAHandle = 0;
fHasAPotentialHandle = 0;
pReturnType = (node_skl *)NULL;
SetNodeState( NODE_STATE_IMPROPER_IN_CONSTRUCT |
NODE_STATE_IS_NON_RPCABLE_TYPE );
}
/****************************************************************************
SCheck:
analyse the return type first and the param types. For error_status_t
processing, we need to recognise if the return type is error_status_t,
so we need to scheck that first.
Note that a proc need not be semantically analysed, if it belongs to a
local interface, or import level > 0, or it has the local attribute.
BUT, if the proc node is reached because of it being a typedef, then
it MUST be analysed. If it is a POINTER to a proc, then it need not be
analysed.
****************************************************************************/
node_state
node_proc::SCheck(
BadUseInfo * pBadUseInfo)
{
if( !AreSemanticsDone() )
{
node_skl * pNode;
BOOL fIsAPtrToProc = FALSE;
BOOL fHasLocalAttr = FInSummary( ATTR_LOCAL );
BOOL fNOTImportedOrLocal;
fNOTImportedOrLocal = !( (ImportLevel > 0 ) ||
fHasLocalAttr ||
(fDefinedInLocalInterface) );
fIsAPtrToProc = ( (pNode = pGlobalContext->GetCurrentNode()) &&
(pNode->NodeKind() == NODE_POINTER ) );
if( FInSummary( ATTR_LOCAL ) )
ParseError( LOCAL_ATTR_ON_PROC, (char *)NULL );
if( !( fIsAPtrToProc ) && fNOTImportedOrLocal )
{
if( pReturnType )
{
pGlobalContext->PushContext( this );
SetNodeState( pReturnType->SCheck( pBadUseInfo ));
/**
** if the return type is not marshallable, report why not.
** Do that only if the proc is not defined in a typedef.
** If it is defined in a typedef, then the use of this
** typedef will report an error anyhow.
**/
if( pBadUseInfo->AnyReasonForNonRPCAble() /* && !TypedefNode */ )
{
/**
** Correct all reasons why it IS RPCAble. A return
** type of void does not make the proc a non-rpcable proc.
**/
if( pBadUseInfo->NonRPCAbleBecause(
NR_DERIVES_FROM_VOID ))
pBadUseInfo->ResetNonRPCAbleBecause(
NR_DERIVES_FROM_VOID );
//
// if return type derives from a pointer to void, then the
// return type should have a handle specification set.
// This error will be returned ONLY if the return type of
// the procedure was not a typedef and the context_handle
// attribute was applied to the proc node itself. Thus
// The check for context_handle attribute therefore must be
// made on the proc node itself.
//
if( pBadUseInfo->NonRPCAbleBecause(
NR_DERIVES_FROM_PTR_TO_VOID ))
{
if( FInSummary( ATTR_CONTEXT ) )
pBadUseInfo->ResetNonRPCAbleBecause(
NR_DERIVES_FROM_PTR_TO_VOID );
}
/**
** A return type of char * with the string attribute is
** fine.
**/
if( pBadUseInfo->NonRPCAbleBecause(
NR_DERIVES_FROM_UNSIZED_STRING ) )
{
pBadUseInfo->ResetNonRPCAbleBecause(
NR_DERIVES_FROM_UNSIZED_STRING );
}
/**
** Report all other errors to the user
**/
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_INT ) ||
pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_PTR_TO_INT ))
ParseError( NON_RPC_RTYPE_INT, (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause(NR_DERIVES_FROM_PTR_TO_VOID ))
ParseError( NON_RPC_RTYPE_VOID , (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause( NR_DERIVES_FROM_BIT_FIELDS ))
ParseError( NON_RPC_RTYPE_BIT_FIELDS , (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause(NR_DERIVES_FROM_NON_RPC_UNION ))
ParseError( NON_RPC_RTYPE_UNION , (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause (NR_DERIVES_FROM_PTR_TO_FUNC ))
ParseError( NON_RPC_RTYPE_FUNC_PTR , (char *)NULL );
if( pBadUseInfo->NonRPCAbleBecause( NR_PRIMITIVE_HANDLE ) ||
pBadUseInfo->NonRPCAbleBecause(
NR_PTR_TO_PRIMITIVE_HANDLE ) )
{
ParseError( NON_RPC_RTYPE_HANDLE_T, (char *)0 );
}
}
if( pBadUseInfo->AnyReasonForBadConstruct() )
{
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_IGNORE) )
ParseError( BAD_CON_PARAM_RT_IGNORE, (char *)0 );
//
// if the return type is a context handle, then ignore
// the ref pointer restriction on return types. If this
// attribute was on a return type, then it appears in the
// summary attribute of the proc. Thats why the check
// below.
//
if( pBadUseInfo->BadConstructBecause( BC_REF_PTR_BAD_RT ) )
{
if( FInSummary( ATTR_CONTEXT ) )
pBadUseInfo->ResetBadConstructBecause( BC_REF_PTR_BAD_RT );
else
ParseError( BAD_CON_REF_RT , (char *)0 );
}
if( pBadUseInfo->BadConstructBecause( BC_BAD_RT_NE_UNION) )
{
ParseError( RETURN_OF_UNIONS_ILLEGAL, (char *)0 );
}
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CONF_STRUCT ) )
{
ParseError( RETURN_OF_CONF_STRUCT, (char *)0 );
}
}
if( NeedsUseProcessing() )
UseProcessing();
pGlobalContext->PopContext();
}
/**
** A call to return type semantic check may result in setting the
** semantics done flags, reset them
**/
ResetNodeState(
NODE_STATE_SEMANTICS_DONE | NODE_STATE_POST_SEMANTICS_DONE );
/**
** send this bad info block to params after clearing it. As yet
** we dont know of a reason why the proc node should check for
** bad use after param analysis. The param node currently is
** fully capable of detecting errors of use in a proc.
**/
pBadUseInfo->InitBadUseInfo();
SetNodeState (node_skl::SCheck( pBadUseInfo ));
/**
** If we are doing semantics of the procedure, then this proc
** has been remoted. Register forward declarations in this proc.
** This proc node may be reached from a typedef also. Even in that
** case, register the use of forward declarations.
**/
RegisterFDeclUse();
/*****************************************************
** these are the hacks for node-state-proc-length etc
*****************************************************
if( GetNodeState() & NODE_STATE_PROC_SIZE )
{
ResetNodeState( NODE_STATE_PROC_SIZE );
SetNodeState( NODE_STATE_SIZE );
}
if( GetNodeState() & NODE_STATE_PROC_LENGTH )
{
ResetNodeState( NODE_STATE_PROC_LENGTH );
SetNodeState( NODE_STATE_LENGTH );
}
******************************************************/
}
else
{
/**
** This is the case when the semantics did not occur on the
** procedure node. But we HAVE to ensure that the type graph
** does not contain the forward decl node, since we do not
** expose it to the backend. Normally, during semantic check, this
** forward decl will get registered. But not when the proc is
** a local. So what
**/
RegFDAndSetE();
}
/**** end of hack ****/
}
pBadUseInfo->SetBadConstructBecause( BC_DERIVES_FROM_FUNC );
pBadUseInfo->SetNonRPCAbleBecause( NR_DERIVES_FROM_FUNC );
return SemReturn( GetNodeState() );
}
/****************************************************************************
RegFDAndSetE:
Register the definition of a forward declarator. This happens only if the
proc did not get semantically analysed. In that case the forward decl
does not get registered. So we have to explicitly register it. This does
mean a walk over a part of the type graph, but cannot be helped, because
we cannot have the forward node exposed to the back end.
****************************************************************************/
void
node_proc::RegFDAndSetE()
{
/**
** pass the message to children as usual, then pass it to the return
** type too!
**/
node_skl::RegFDAndSetE();
pGlobalContext->PushContext( this );
if( pReturnType )
pReturnType->RegFDAndSetE();
pGlobalContext->PopContext();
}
/****************************************************************************
RegisterFDecl:
Why do we have this as a separate method for node_proc ? Because node_proc
needs to register the return type too !
****************************************************************************/
void
node_proc::RegisterFDeclUse()
{
/**
** pass the message to children as usual, then pass it to the return
** type too!
**/
node_skl::RegisterFDeclUse();
pGlobalContext->PushContext( this );
if( pReturnType && !FInSummary( ATTR_CONTEXT ) )
pReturnType->RegisterFDeclUse();
pGlobalContext->PopContext();
}
/****************************************************************************
UseProcessing:
Send the use processing message to the return type.
****************************************************************************/
void
node_proc::UseProcessing()
{
node_skl * pNode = GetBasicType();
/**
** if the return type is a string, we will need
** to generate a string expression of the form
** strlen( _ret_value ). To facilitate this, enter
** a _ret_value in the base symbol table, then delete it
**/
SymKey SKey( RET_VAL, NAME_ID );
pBaseSymTbl->SymInsert( SKey, (SymTable *)NULL, pReturnType );
/**
** do the processing on return type
**/
pGlobalContext->PushContext( this );
pNode->UseProcessing();
pGlobalContext->PopContext();
/**
** free the symbol table entry for the ret_value
**/
pBaseSymTbl->SymDelete( SKey );
/**
** use processing for params need not be done, as they do their own
**/
}
/****************************************************************************
HasHandle:
If the proc has at least 1 param with a handle specification, get all
the params with the handle spec. Return the count of number of params
with the handle spec. The input is a non-null type node list;
****************************************************************************/
short
node_proc::HasHandle(
type_node_list * pReturnList )
{
if( HasAnyHandleSpecification() )
{
type_node_list * pTNList = new type_node_list;
node_skl * pNode;
GetMembers( pTNList );
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
if( pNode->HasAnyHandleSpecification() )
pReturnList->SetPeer( pNode );
delete pTNList;
}
return (short)pReturnList->GetCount();
}
node_state
node_proc::PostSCheck(
BadUseInfo * pBadUseInfo)
{
node_skl * pType = GetBasicType();
/**
** The backend wants that if the return type is a pointer, the pointer
** must be unique.
**/
if( pType->NodeKind() == NODE_POINTER )
{
pType->ResetAttribute( ATTR_REF );
pType->ResetAttribute( ATTR_PTR );
pType->SetAttribute( ATTR_UNIQUE );
}
if( !pGlobalContext->IsSecondSemanticPass() &&
!HasAtLeastOneHandle() &&
!FInSummary( ATTR_CALLBACK ) )
{
pDictProcsWOHandle->AddElement( (IDICTELEMENT) GetSymName() );
fAtLeastOneProcWOHandle = TRUE;
}
// check the use of c decl attributes
UpdateUseOfCDecls( pBadUseInfo );
if( pBadUseInfo->BadConstructBecause( BC_DERIVES_FROM_CDECL ))
{
ParseError( BAD_CON_MSC_CDECL , (char *)0 );
pBadUseInfo->ResetBadConstructBecause( BC_DERIVES_FROM_CDECL );
}
//
// Since we arrived here, the interface is not local and so on
//
fAtLeastOneRemoteProc = TRUE;
//
// If this is not a callback procedure, reset the flag which says
// only callbacks are present in this interface.
//
if( !pGlobalContext->IsSecondSemanticPass() )
{
if( !FInSummary( ATTR_CALLBACK ) )
{
fOnlyCallBacks = FALSE;
NoOfNormalProcs++;
}
else
{
fInterfaceHasCallback = TRUE;
NoOfCallbackProcs++;
}
}
return NODE_STATE_OK;
}
void
node_proc::SetAttribute(
type_node_list * pAttrList )
{
DoSetAttributes(this,
pPreAttrProc,
(ATTR_SUMMARY *)NULL,
pAttrList );
}
STATUS_T
node_proc::SetBasicType(
node_skl * pBasicType )
{
if( pBasicType )
{
if( pReturnType )
return pReturnType->SetBasicType( pBasicType );
else
{
pReturnType = pBasicType;
}
}
return STATUS_OK;
}
BOOL
node_proc::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;
}
node_skl *
node_proc::GetBasicType()
{
if( !pReturnType || (pReturnType->NodeKind() != NODE_DEF ) )
return pReturnType;
return pReturnType->GetBasicType();
}
short
node_proc::GetNumberOfArguments()
{
short Count;
type_node_list * pTNList = new type_node_list;
GetMembers( pTNList );
if( (Count = pTNList->GetCount()) == 1 )
{
node_skl * pNode;
pTNList->GetPeer( &pNode );
if( pNode->GetBasicType()->NodeKind() == NODE_VOID )
Count = 0;
}
delete pTNList;
return Count;
}
node_state
node_proc::AcfSCheck()
{
node_skl * pNode;
type_node_list * pTNList = new type_node_list;
node_state NState = NODE_STATE_OK;
#if 0
fprintf( stderr, "\n FE::No Of Normal Procs = %d\n NoOfCallBackProcs = %d\n",
NoOfNormalProcs, NoOfCallbackProcs );
#endif // 0
node_skl::AcfSCheck();
if( FInSummary( ATTR_INTERPRET ) )
NoOfMopProcs++;
GetMembers( pTNList );
pGlobalContext->PushContext( this );
while( pTNList->GetPeer( &pNode ) == STATUS_OK )
{
NState |= pNode->AcfSCheck();
}
pGlobalContext->PopContext();
delete pTNList;
return SetNodeState( NState );
}
node_skl *
node_proc::GetBindingHandle()
{
type_node_list * pTNList = new type_node_list;
node_skl * pHandleNode;
GetMembers( pTNList );
while( pTNList->GetPeer( &pHandleNode ) == STATUS_OK )
{
if( pHandleNode->IsThisTheBindingHandle() )
return pHandleNode;
}
return (node_skl *)0;
}
BOOL
node_proc::HasSizedComponent()
{
node_skl * pRT = GetReturnType();
#if 0
BOOL fResult;
fResult = CheckNodeStateInMembers( NODE_STATE_SIZE ) ||
((pRT->GetNodeState() & NODE_STATE_SIZE) == NODE_STATE_SIZE) ||
pRT->HasSizedComponent();
return fResult;
#endif // 0
if( pRT->HasSizedComponent() )
return TRUE;
if( pRT->NodeKind() == NODE_POINTER )
{
while( pRT->NodeKind() == NODE_POINTER )
{
pRT = pRT->GetBasicType();
}
//
// finally we have reached the non-pointer node.
//
if( pRT->HasSizedComponent() )
return TRUE;
}
return FALSE;
}
BOOL
node_proc::HasLengthedComponent()
{
#if 0
BOOL fResult;
node_skl * pRT = GetReturnType();
fResult = CheckNodeStateInMembers( NODE_STATE_LENGTH ) ||
((pRT->GetNodeState() & NODE_STATE_LENGTH)==NODE_STATE_LENGTH) ||
pRT->HasSizedComponent();
return fResult;
#endif // 0
return CheckNodeStateInMembers( NODE_STATE_SIZE );
}
BOOL
node_proc::IsSuitableForMops()
{
//
// for now no analysis is performed. Suitability is determined by the
// application of the interpret attribute on the procedure or the
// whole interface.
//
return ( FInSummary( ATTR_INTERPRET ) ||
(pBaseInterfaceNode->FInSummary( ATTR_INTERPRET ) &&
!FInSummary(ATTR_NOINTERPRET )) ||
(( pCommand->GetOptimOption() & OPTIM_OI ) == OPTIM_OI )
);
}