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.
564 lines
14 KiB
564 lines
14 KiB
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
semutil.cxx
|
|
|
|
Abstract:
|
|
|
|
semantic analysis utility routines
|
|
|
|
Notes:
|
|
|
|
|
|
Author:
|
|
|
|
GregJen 28-Oct-1993 Created.
|
|
|
|
Notes:
|
|
|
|
|
|
----------------------------------------------------------------------------*/
|
|
|
|
/****************************************************************************
|
|
* 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()) &&
|
|
( 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 ) )
|
|
{
|
|
SetChild( pRef );
|
|
}
|
|
}
|
|
return (named_node *) GetChild();
|
|
}
|
|
|
|
void
|
|
node_proc::AddExplicitHandle( SEM_ANALYSIS_CTXT * pParentCtxt )
|
|
{
|
|
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 );
|
|
|
|
// 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 ) );
|
|
|
|
AddFirstMember( pParm );
|
|
|
|
// update the information for the parameter
|
|
pParm->SemanticAnalysis( pParentCtxt );
|
|
|
|
fHasExplicitHandle = TRUE;
|
|
fHasAtLeastOneIn = TRUE;
|
|
}
|
|
|
|
BOOL
|
|
node_base_type::RangeCheck( long 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 <= 65535 );
|
|
else
|
|
return ( Val >= -32768 ) && ( Val <= 32767 );
|
|
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_INT:
|
|
return TRUE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
node_base_type::IsAssignmentCompatible( node_base_type * pOther )
|
|
{
|
|
unsigned long MySize = GetSize(0);
|
|
unsigned long HisSize = pOther->GetSize(0);
|
|
|
|
// 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_OBJECT:
|
|
return " Object ";
|
|
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;
|
|
}
|
|
|
|
// to prevent warnings
|
|
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_OBJECT:
|
|
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_OBJECT:
|
|
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 += 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 * pNode,
|
|
WALK_CTXT & 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 += strlen(pName);
|
|
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(long 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;
|
|
}
|