windows-nt/Source/XPSP1/NT/com/rpc/midl/front/semutil.cxx
2020-09-26 16:20:57 +08:00

691 lines
18 KiB
C++

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1989-1999 Microsoft Corporation
Module Name:
semutil.cxx
Abstract:
semantic analysis utility routines
Notes:
Author:
GregJen 28-Oct-1993 Created.
Notes:
----------------------------------------------------------------------------*/
#pragma warning ( disable : 4514 4710 )
/****************************************************************************
* include files
***************************************************************************/
#include "nulldefs.h"
extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
}
#include "allnodes.hxx"
#include "semantic.hxx"
#include "symtable.hxx"
#include "cmdana.hxx"
/****************************************************************************
* local data
***************************************************************************/
/****************************************************************************
* externs
***************************************************************************/
extern SymTable * pBaseSymTbl;
extern ATTR_SUMMARY DisallowedAttrs[INTERNAL_NODE_END];
extern BOOL IsTempName( char * );
extern CMD_ARG * pCommand;
/****************************************************************************
* definitions
***************************************************************************/
void
WALK_CTXT::FindImportantPosition(tracked_node & Posn)
{
WALK_CTXT * pCurCtxt = this;
WALK_CTXT * pParCtxt;
node_skl * pNode;
// walk up until we find one whose PARENT was not important
while ( (pParCtxt=(WALK_CTXT *)pCurCtxt->GetParentContext()) != 0 &&
( pParCtxt->IsImportantPosition() ) )
{
pCurCtxt = pParCtxt;
}
// continue walking up until we find one with a position
do
{
pNode = pCurCtxt->GetParent();
pNode->GetPositionInfo( Posn );
pCurCtxt = (WALK_CTXT *) pCurCtxt->GetParentContext();
}
while( !Posn.HasTracking() && pCurCtxt );
}
void
SEM_ANALYSIS_CTXT::CheckAttributes()
{
ATTR_VECTOR & BadAttrs = DisallowedAttrs[ GetParent()->NodeKind() ];
ATTR_VECTOR ExcessAttrs;
ATTR_T Attr;
node_base_attr * pAttr;
char * pAttrName;
MASKED_COPY_ATTR( ExcessAttrs, *(pDownAttrList->GetSummary()), BadAttrs );
while (!IS_CLEAR_ATTR( ExcessAttrs ) )
{
Attr = CLEAR_FIRST_SET_ATTR( ExcessAttrs );
pAttr = ExtractAttribute( Attr );
pAttrName = pAttr->GetNodeNameString();
if (pAttr->IsAcfAttr() )
AcfError( (acf_attr *)pAttr,
GetParent(),
*this,
INAPPLICABLE_ATTRIBUTE,
pAttrName);
else
SemError( GetParent(), *this, INAPPLICABLE_ATTRIBUTE ,pAttrName);
}
}
void
SEM_ANALYSIS_CTXT::RejectAttributes()
{
ATTR_VECTOR ExcessAttrs;
ATTR_T Attr;
node_base_attr * pAttr;
char * pAttrName;
COPY_ATTR( ExcessAttrs, *(pDownAttrList->GetSummary()));
while (!IS_CLEAR_ATTR( ExcessAttrs ) )
{
Attr = CLEAR_FIRST_SET_ATTR( ExcessAttrs );
pAttr = ExtractAttribute( Attr );
pAttrName = pAttr->GetNodeNameString();
if (pAttr->IsAcfAttr() )
AcfError( (acf_attr *)pAttr,
GetParent(),
*this,
INAPPLICABLE_ATTRIBUTE,
pAttrName);
else
SemError( GetParent(), *this, INAPPLICABLE_ATTRIBUTE ,pAttrName);
}
}
//
// resolve forward declarations
//
named_node *
node_forward::ResolveFDecl()
{
if ( !GetChild() )
{
named_node * pRef = pSymTbl->SymSearch( SKey );
if (pRef && ( pRef != this ) && ( pRef->NodeKind() != NODE_FORWARD ) )
{
SetChild( pRef );
}
}
return (named_node *) GetChild();
}
void
node_proc::AddExplicitHandle (
SEM_ANALYSIS_CTXT* pParentCtxt,
unsigned int uParamNumber
)
{
node_skl * pHand;
node_param * pParm;
// only add the handle once
if ( !strcmp( GetChild()->GetSymName(), "IDL_handle" ) )
return;
GetBaseTypeNode( &pHand, SIGN_UNDEF, SIZE_UNDEF, TYPE_HANDLE_T, 0 );
// set up [in] param "IDL_handle", pointing to handle_t, add as first parameter
pParm = new node_param;
pParm->SetSymName( "IDL_handle" );
pParm->SetChild( pHand );
pParm->SetAttribute( new battr( ATTR_IN ) );
if ( uParamNumber == 1 )
{
AddFirstMember( pParm );
}
else
{
AddSecondMember( pParm );
}
// update the information for the parameter
pParm->SemanticAnalysis( pParentCtxt );
fHasExplicitHandle = TRUE;
fHasAtLeastOneIn = TRUE;
}
void
node_proc::AddFullAsyncHandle (
SEM_ANALYSIS_CTXT* pParentCtxt,
node_skl* pType,
char* szTypeName
)
{
const char* szNameSuffix = "_AsyncHandle";
char* szFullName = new char[strlen(GetSymName()) + strlen(szNameSuffix) + 1];
strcpy(szFullName, GetSymName());
strcat(szFullName, szNameSuffix);
node_skl* pAsyncHandle = new node_async_handle( szTypeName );
if ( pType )
{
pAsyncHandle->SetChild( pType );
}
node_param* pParm = new node_param;
pParm->SetSymName( szFullName );
pParm->SetChild( pAsyncHandle );
pParm->SetAttribute( new battr( ATTR_IN ) );
AddFirstMember( pParm );
pParm->SemanticAnalysis( pParentCtxt );
SetHasAsyncHandle();
pParm->SetIsAsyncHandleParam();
fHasAtLeastOneIn = TRUE;
}
BOOL
node_base_type::RangeCheck( __int64 Val )
{
NODE_T Kind = NodeKind();
switch ( Kind )
{
case NODE_BOOLEAN:
return ( Val >= 0 ) && ( Val <= 1 );
case NODE_SHORT:
if ( FInSummary( ATTR_UNSIGNED ) )
return ( Val >= 0 ) && ( Val <= _UI16_MAX );
else
return ( Val >= _I16_MIN ) && ( Val <= _I16_MAX );
case NODE_BYTE:
return ( Val >= 0 ) && ( Val <= 255 );
case NODE_CHAR:
if ( FInSummary( ATTR_UNSIGNED ) )
return ( Val >= 0 ) && ( Val <= 255 );
else if ( FInSummary( ATTR_SIGNED ) )
return ( Val >= -128 ) && ( Val <= 127 );
else if ( pCommand->GetCharOption() == CHAR_SIGNED )
return ( Val >= 0 ) && ( Val <= 255 );
else
return ( Val >= -128 ) && ( Val <= 127 );
case NODE_SMALL:
if ( FInSummary( ATTR_UNSIGNED ) )
return ( Val >= 0 ) && ( Val <= 255 );
else if ( FInSummary( ATTR_SIGNED ) )
return ( Val >= -128 ) && ( Val <= 127 );
else if ( pCommand->GetCharOption() == CHAR_UNSIGNED )
return ( Val >= -128 ) && ( Val <= 127 );
else
return ( Val >= 0 ) && ( Val <= 255 );
case NODE_LONG:
case NODE_INT32:
case NODE_INT:
if ( FInSummary( ATTR_UNSIGNED ) )
return ( Val >= 0 ) && ( Val <= _UI32_MAX );
else
return ( Val >= _I32_MIN ) && ( Val <= _I32_MAX );
case NODE_INT3264:
if ( ! pCommand->Is64BitEnv() )
{
if ( FInSummary( ATTR_UNSIGNED ) )
return ( Val >= 0 ) && ( Val <= _UI32_MAX );
else
return ( Val >= _I32_MIN ) && ( Val <= _I32_MAX );
}
// else fall through to 64b integral
case NODE_HYPER:
case NODE_INT64:
case NODE_INT128:
return TRUE;
}
return TRUE;
}
BOOL
node_base_type::IsAssignmentCompatible( node_base_type * pOther )
{
unsigned long MySize = GetSize();
unsigned long HisSize = pOther->GetSize();
// tbd - fill in more cases
if ( MySize < HisSize )
return FALSE;
// unsigned <= signed
if ( FInSummary( ATTR_UNSIGNED ) &&
!pOther->FInSummary( ATTR_UNSIGNED ) )
return FALSE;
// signed <= unsigned ( only OK if dest is larger )
if ( pOther->FInSummary( ATTR_UNSIGNED ) &&
FInSummary( ATTR_SIGNED ) &&
(MySize <= HisSize) )
return FALSE;
if ( ( NodeKind() == NODE_BOOLEAN ) &&
( pOther->NodeKind() != NODE_BOOLEAN ) )
return FALSE;
return TRUE;
}
char *
GetErrorNamePrefix( node_skl * pNode )
{
if ( !pNode )
return NULL;
switch ( pNode->NodeKind() )
{
case NODE_FIELD:
return " Field ";
case NODE_STRUCT:
return " Struct ";
case NODE_UNION:
return " Union ";
case NODE_ENUM:
return " Enum ";
case NODE_PARAM:
return " Parameter ";
case NODE_PROC:
return " Procedure ";
case NODE_INTERFACE:
case NODE_INTERFACE_REFERENCE:
return " Interface ";
case NODE_PIPE_INTERFACE:
return " Object Pipe ";
case NODE_DEF:
return " Type ";
case NODE_LIBRARY:
return " Library ";
case NODE_MODULE:
return " Module ";
case NODE_COCLASS:
return " Coclass ";
case NODE_DISPINTERFACE:
return " Dispinterface ";
default:
return NULL;
}
}
#define SUFFIX_SIZE 1000
#define CONTEXT_STR_SIZE 1000
void
GetSemContextString(
char * pResult,
node_skl * pNode,
WALK_CTXT * pCtxt )
{
node_skl * pBase = NULL;
node_skl * pParent = NULL;
node_skl * pUsage = NULL;
char * pPrefix;
pResult[0] = '\0';
if ( !pNode )
{
pNode = ( pCtxt ) ? pCtxt->GetParent() : NULL;
}
// compute base part and parent part
while ( pCtxt && !pParent && pNode )
{
switch ( pNode->NodeKind() )
{
case NODE_FIELD:
case NODE_PARAM:
pBase = pNode;
break;
case NODE_STRUCT:
case NODE_UNION:
case NODE_ENUM:
case NODE_PROC:
case NODE_INTERFACE:
case NODE_PIPE_INTERFACE:
case NODE_INTERFACE_REFERENCE:
case NODE_DEF:
case NODE_LIBRARY:
case NODE_MODULE:
case NODE_COCLASS:
case NODE_DISPINTERFACE:
pParent = pNode;
break;
}
pCtxt = pCtxt->GetParentContext();
pNode = ( pCtxt ) ? pCtxt->GetParent() : NULL;
}
// compute usage part (param or proc or interface)
// note that pCtxt is one level up above the current pNode
pCtxt = pCtxt->GetParentContext();
while ( pCtxt && ! pUsage )
{
switch ( pCtxt->GetParent()->NodeKind() )
{
// stop at the top-most level ( child of interface, or proc )
// therefore highest type/proc/param
case NODE_INTERFACE:
case NODE_PIPE_INTERFACE:
case NODE_PROC:
case NODE_LIBRARY:
case NODE_MODULE:
case NODE_COCLASS:
case NODE_DISPINTERFACE:
pUsage = pNode;
break;
}
pNode = ( pCtxt ) ? pCtxt->GetParent() : NULL;
pCtxt = pCtxt->GetParentContext();
}
if ( pBase || pParent || pUsage )
{
strcat( pResult, "[");
if ( pBase )
{
pPrefix = GetErrorNamePrefix( pBase );
if ( pPrefix )
strcat( pResult, pPrefix );
if ( !IsTempName( pBase->GetSymName() ) )
{
strcat( pResult, "'");
strcat( pResult, pBase->GetSymName() );
strcat( pResult, "' ");
}
}
if ( pParent )
{
if ( !IsTempName( pParent->GetSymName() ) )
{
if ( pBase )
strcat(pResult, "of");
pPrefix = GetErrorNamePrefix( pParent );
if ( pPrefix )
strcat( pResult, pPrefix );
strcat( pResult, "'");
strcat( pResult, pParent->GetSymName() );
strcat( pResult, "' ");
}
else
{
pPrefix = GetErrorNamePrefix( pBase );
if ( pPrefix && !pBase )
strcat( pResult, pPrefix );
}
}
if ( pUsage )
{
strcat( pResult, "(");
pPrefix = GetErrorNamePrefix( pUsage );
if ( pPrefix )
strcat( pResult, pPrefix );
strcat( pResult, "'");
strcat( pResult, pUsage->GetSymName() );
strcat( pResult, "' )");
}
strcat( pResult, " ]");
}
}
void
SemError(
node_skl * pNode,
WALK_CTXT & Ctxt,
STATUS_T ErrNum,
char * pExtra )
{
ErrorInfo ErrStats( ErrNum );
// if the error is not relevant to this compile, return right away
if ( !ErrStats.IsRelevant() )
return;
short CurLen = 1; // for the null byte
char Suffix[SUFFIX_SIZE];
char ContextStr[ CONTEXT_STR_SIZE ];
char * pSuffix = Suffix;
char * pFile;
short Line;
tracked_node Posn((void*)NULL);
WALK_CTXT * pCurCtxt;
// extract file and line info, and context info
pCurCtxt = &Ctxt;
GetSemContextString( ContextStr, pNode, &Ctxt );
CurLen = short( CurLen + strlen( ContextStr ) );
// unless the string is REALLY long, just use stack space
if ( CurLen + 1 > SUFFIX_SIZE )
pSuffix = new char [CurLen + 1];
if ( pExtra || strlen( ContextStr ) )
{
strcpy( pSuffix, ": " );
if ( pExtra )
strcat( pSuffix, pExtra );
// make sure pSuffix has a trailing space at this point
if ( pSuffix[ strlen(pSuffix) - 1 ] != ' ' )
{
strcat( pSuffix, " " );
}
if ( strlen(ContextStr) )
{
strcat( pSuffix, ContextStr );
}
}
else
strcpy( pSuffix, "" );
// fetch the file position from the context stack
Ctxt.FindImportantPosition(Posn);
Posn.GetLineInfo( pFile, Line);
ErrStats.ReportError( pFile,
Line,
pSuffix );
// clean up if we had to allocate space
if ( pSuffix != Suffix )
delete pSuffix;
}
void
AcfError(
acf_attr * pAttr,
node_skl * ,
WALK_CTXT & ,
STATUS_T ErrNum,
char * pExtra )
{
short CurLen = 1; // for the null byte
char Suffix[SUFFIX_SIZE];
char * pSuffix = Suffix;
char * pName;
char * pFile;
short Line;
tracked_node Posn((void*)NULL);
// extract file and line info, and context info
pName = pAttr->GetNodeNameString();
// <name>[: <extra>]
CurLen = short( CurLen + strlen(pName) );
CurLen = short( CurLen + ( (pExtra) ? strlen(pExtra) + 2 : 0 ) );
// unless the string is REALLY long, just use stack space
if ( CurLen + 1 > SUFFIX_SIZE )
pSuffix = new char [CurLen + 1];
strcpy( pSuffix, pName );
if (pExtra)
{
strcat( pSuffix, ": " );
strcat( pSuffix, pExtra );
}
// fetch the file position from the context stack
pAttr->Position.GetLineInfo( pFile, Line);
RpcError( pFile,
Line,
ErrNum,
pSuffix );
// clean up if we had to allocate space
if ( pSuffix != Suffix )
delete pSuffix;
}
BOOL CIDLIST::AddId(__int64 lId, char * szName)
{
IDLISTMEM ** pThis = &pHead;
while (*pThis && (*pThis)->lId < lId)
{
pThis = &((*pThis)->pNext);
}
if (*pThis && (*pThis)->lId == lId)
{
if (_stricmp(szName, (*pThis)->szName))
return FALSE;
else
return TRUE;
}
IDLISTMEM * pNew = new IDLISTMEM;
pNew->lId = lId;
pNew->pNext = *pThis;
pNew->szName = szName;
*pThis = pNew;
return TRUE;
}
/*
Nishad
bool
node_base_type::IsCompatibleType(
TypeSet set
)
{
bool fReturnCode = false;
NODE_T nodeKind = NodeKind();
switch ( set )
{
case ts_UnsignedFixedPoint:
fReturnCode = (
nodeKind == NODE_INT128 ||
nodeKind == NODE_HYPER ||
nodeKind == NODE_INT64 ||
nodeKind == NODE_INT32 ||
nodeKind == NODE_LONG ||
nodeKind == NODE_LONGLONG ||
nodeKind == NODE_SHORT ||
nodeKind == NODE_INT ||
nodeKind == NODE_SMALL ||
nodeKind == NODE_CHAR ||
nodeKind == NODE_BOOLEAN ||
nodeKind == NODE_BYTE
)
&&
IsUnsigned();
break;
case ts_FixedPoint:
fReturnCode = (
nodeKind == NODE_INT128 ||
nodeKind == NODE_HYPER ||
nodeKind == NODE_INT64 ||
nodeKind == NODE_INT32 ||
nodeKind == NODE_LONG ||
nodeKind == NODE_LONGLONG ||
nodeKind == NODE_SHORT ||
nodeKind == NODE_INT ||
nodeKind == NODE_SMALL ||
nodeKind == NODE_CHAR ||
nodeKind == NODE_BOOLEAN ||
nodeKind == NODE_BYTE
);
break;
case ts_FloatingPoint:
fReturnCode = ( nodeKind == NODE_FLOAT ||
nodeKind == NODE_DOUBLE ||
nodeKind == NODE_FLOAT80 ||
nodeKind == NODE_FLOAT128 );
break;
case ts_Character:
fReturnCode = ( nodeKind == NODE_CHAR || nodeKind == NODE_BYTE || nodeKind == NODE_WCHAR_T );
break;
case ts_String:
// TBD
break;
case ts_Interface:
// TBD
break;
}
return fReturnCode;
}
*/