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

806 lines
17 KiB
C++

/**********************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1987-1999 **/
/**********************************************************************/
/*
symtable.cxx
MIDL Compiler Symbol Table Implementation
This class centralizes access to the symbol table throughout the
compiler.
*/
/*
FILE HISTORY :
DonnaLi 08-25-1990 Created.
*/
#pragma warning ( disable : 4514 )
#include "nulldefs.h"
extern "C" {
#include <stdio.h>
#include <string.h>
}
#include "common.hxx"
#include "errors.hxx"
#include "symtable.hxx"
#include "tlgen.hxx"
#include "mbcs.hxx"
BOOL gfCaseSensitive = TRUE; // initialize things under case sensitive mode
CaseStack gCaseStack;
class named_node;
/**********************************************************************\
NAME: SymEntry
SYNOPSIS: Defines an entry in the symbol table.
INTERFACE:
CAVEATS: This is an internal class used by the symbol table only.
NOTES:
HISTORY:
Donnali 08-25-1990 Initial creation
\**********************************************************************/
class SymEntry : public SymKey
{
named_node * pTypeGraph; // pointer to type graph associated with entry
SymTable * pNextScope; // pointer to next scope associated with entry
public:
SymEntry(void)
{
pTypeGraph = (named_node *)0;
pNextScope = (SymTable *)0;
}
SymEntry( SymKey NewKey )
: SymKey( &NewKey )
{
pTypeGraph = (named_node *)0;
pNextScope = (SymTable *)0;
}
SymEntry(
SymKey NewKey,
SymTable * pNext,
named_node * pNode) : SymKey( &NewKey )
{
pTypeGraph = pNode;
pNextScope = pNext;
}
void SetTypeGraph (named_node * pNode)
{
pTypeGraph = pNode;
}
named_node * GetTypeGraph (void)
{
return pTypeGraph;
}
void SetNextScope (SymTable * pNext)
{
pNextScope = pNext;
}
SymTable * GetNextScope (void)
{
return pNextScope;
}
// here is the use of the private memory allocator
private:
static
FreeListMgr MyFreeList;
public:
void * operator new (size_t size)
{
return (MyFreeList.Get (size));
}
void operator delete (void * pX)
{
MyFreeList.Put (pX);
}
} ;
// initialize the memory allocator for SymEntry
FreeListMgr
SymEntry::MyFreeList( sizeof ( SymEntry ) );
/**********************************************************************\
NAME: PrintSymbol
SYNOPSIS: Prints out the name of a symbol table entry.
ENTRY: sym - the key to symbol table entry to be printed.
EXIT:
NOTES:
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
void
SymTable::Print(
void * sym
)
{
printf ("%s", ((SymKey *)sym)->name);
}
/**********************************************************************\
NAME: CompareSymbol
SYNOPSIS: Compares keys to two symbol table entries.
ENTRY: sym1 - the key to 1st symbol table entry to be compared.
sym2 - the key to 2nd symbol table entry to be compared.
EXIT: Returns a positive number if sym1 > sym2.
Returns a negative number if sym1 < sym2.
Returns 0 if sym1 = sym2.
NOTES:
Since all the strings are in the lex table, we can just compare
pointers to do the string compares.
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
SSIZE_T
SymTable::Compare(
void * sym1,
void * sym2
)
{
int result;
#ifdef unique_lextable
// compare pointers into lex table
result = ( (int)((SymKey *)sym1)->name )
- ( (int)((SymKey *)sym2)->name );
#else
// compare names from keys
// 1 refers to the value for the flag NORM_IGNORECASE
result = CurrentCharSet.CompareDBCSString( ((SymKey *)sym1)->name,
((SymKey *)sym2)->name,
gfCaseSensitive ? 0 : 1);
#endif // unique_lextable
if (!result)
{
return ( ( ((SymKey *)sym1)->kind & NAME_MASK )-
( ((SymKey *)sym2)->kind & NAME_MASK ) );
}
else
{
return result;
}
}
/**********************************************************************\
NAME: SymTable::SymInsert
SYNOPSIS: Inserts a symbol into the symbol table.
ENTRY: NewKey - identifies the symbol table entry.
pNext - points to the next scope.
pNode - points to the type graph.
EXIT:
NOTES:
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
named_node *
SymTable::SymInsert(
SymKey NewKey,
SymTable * pNext,
named_node * pNode
)
{
SymEntry * NewSymbol;
Dict_Status Status;
NewSymbol = new SymEntry(NewKey, pNext, pNode);
CaselessEntry * NewEntry = new CaselessEntry(NewSymbol);
if (!gfCaseSensitive)
{
if (NULL != caseless_list.Find(NewEntry))
{
// it's allready entered into the caseless table
// and we're in case insensitive mode so we
// should fail here (duplicate identifier)
delete NewSymbol;
delete NewEntry;
return NULL;
}
}
Status = Dict_Insert(NewSymbol);
if (Status == SUCCESS)
{
caseless_list.Add(NewEntry);
return pNode;
}
delete NewSymbol;
delete NewEntry;
return (named_node *)0;
}
/**********************************************************************\
NAME: SymTable::SymDelete
SYNOPSIS: Deletes a symbol from the symbol table.
ENTRY: OldKey - identifies the symbol table entry.
EXIT: Returns the type graph associated with the entry.
NOTES:
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
named_node *
SymTable::SymDelete(
SymKey OldKey
)
{
SymEntry TempEntry( OldKey );
CaselessEntry * OldEntry = new CaselessEntry(&TempEntry);
SymEntry * OldSymbol;
// make sure we delete the right symbol from both tables
if (!gfCaseSensitive)
{
OldSymbol = (caseless_list.Delete(OldEntry))->pSymEntry;
}
else
{
OldSymbol = &TempEntry;
caseless_list.DeleteExact(OldEntry);
}
named_node * pNode;
Dict_Status Status;
Status = Dict_Delete((void ** )&OldSymbol);
if (Status == SUCCESS)
{
pNode = OldSymbol->GetTypeGraph();
delete OldSymbol;
#ifdef gajdebug3
printf("\t\t--- deleting name from symbol table: %d - %s\n",
OldKey.GetKind(), OldKey.GetString());
#endif
return pNode;
}
else
{
return (named_node *)0;
}
}
/**********************************************************************\
NAME: SymTable::SymSearch
SYNOPSIS: Searches the symbol table for a symbol.
ENTRY: OldKey - identifies the symbol table entry.
EXIT: Returns the type graph associated with the entry.
NOTES:
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
named_node *
SymTable::SymSearch(
SymKey OldKey
)
{
Dict_Status Status;
if (gfCaseSensitive)
{
Status = Dict_Find(&OldKey);
if (Status == SUCCESS)
{
return ((SymEntry * )Dict_Curr_Item())->GetTypeGraph();
}
else
{
return NULL;
}
}
else
{
SymEntry TempEntry(OldKey);
CaselessEntry OldEntry(&TempEntry);
CaselessEntry * pFound = caseless_list.Find(&OldEntry);
if (pFound)
{
return pFound->pSymEntry->GetTypeGraph();
}
else
{
return NULL;
}
}
}
/**********************************************************************\
NAME: SymTable::EnterScope
SYNOPSIS: Transition from current scope to inner scope.
ENTRY: key - identifies the symbol table entry.
EXIT: ContainedDict - returns the inner scope.
NOTES:
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
STATUS_T
SymTable::EnterScope(
SymKey key,
SymTable ** ContainedDict
)
{
SymEntry ContainerNode( key );
Dict_Status Status;
if (ContainedDict == (SymTable **)0)
{
return I_ERR_NULL_OUT_PARAM;
}
Status = Dict_Find(&ContainerNode);
if (Status != SUCCESS)
{
return I_ERR_SYMBOL_NOT_FOUND;
}
else if (((SymEntry * )Dict_Curr_Item())->GetNextScope() == (SymTable *)0)
{
return I_ERR_NO_NEXT_SCOPE;
}
else
{
* ContainedDict = ((SymEntry * )Dict_Curr_Item())->GetNextScope();
(*ContainedDict)->pPrevScope = this;
return STATUS_OK;
}
}
/**********************************************************************\
NAME: SymTable::ExitScope
SYNOPSIS: Transition from current scope to outer scope.
ENTRY:
EXIT: ContainerDict - returns the outer scope.
NOTES:
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
STATUS_T
SymTable::ExitScope(
SymTable ** ContainerDict
)
{
if (ContainerDict == (SymTable **)0)
{
return I_ERR_NULL_OUT_PARAM;
}
else if (pPrevScope == (SymTable *)0)
{
return I_ERR_NO_PREV_SCOPE;
}
else
{
* ContainerDict = pPrevScope;
pPrevScope = (SymTable *)0;
return STATUS_OK;
}
}
/**********************************************************************\
NAME: SymTable::DiscardScope
SYNOPSIS: Discard all entries in the current scope (if no fwds).
ENTRY:
EXIT: .
NOTES:
HISTORY:
\**********************************************************************/
void
SymTable::DiscardScope()
{
// do nothing if there are forwards
if ( fHasFwds )
return;
SymEntry * pCurrent;
// delete all the SymEntry's in this scope
while ( ( pCurrent = (SymEntry *) Dict_Delete_One() ) != 0 )
{
delete pCurrent;
}
}
CaselessEntry::CaselessEntry(SymEntry * pItem)
{
pSymEntry = pItem;
// compute the hash value
hash = 0;
char ch;
unsigned u = 0;
while (0 != (ch = pSymEntry->name[u++]))
{
hash += ch | 32; // makes sure the hash value is case insensitive
};
}
int CaselessEntry::Compare(CaselessEntry * pEntry2)
{
int rval = hash - pEntry2->hash;
if (0 == rval)
{
rval = CurrentCharSet.CompareDBCSString(pSymEntry->name, pEntry2->pSymEntry->name, 1); // ignore case
if (0 == rval)
{
rval = pSymEntry->kind - pEntry2->pSymEntry->kind;
}
}
return rval;
}
CaselessEntry * CaselessList::Add(CaselessEntry * pEl)
{
CaselessListElement * pNew = new CaselessListElement(pEl);
pNew->pNext = pHead;
pHead = pNew;
return pEl;
}
CaselessEntry * CaselessList::Find(CaselessEntry * pEntry)
{
CaselessListElement * pThis = pHead;
while (pThis && 0 != pThis->pEntry->Compare(pEntry))
{
pThis = pThis->pNext;
}
if (pThis != NULL)
return pThis->pEntry;
else
return NULL;
}
CaselessEntry * CaselessList::Delete(CaselessEntry * pEntry)
{
CaselessListElement ** ppThis = &pHead;
while (*ppThis)
{
if (0 == (*ppThis)->pEntry->Compare(pEntry))
{
CaselessListElement * pFound = *ppThis;
*ppThis = pFound->pNext;
CaselessEntry * pReturn = pFound->pEntry;
delete pFound;
return pReturn;
}
ppThis = &((*ppThis)->pNext);
}
return NULL;
}
CaselessList::~CaselessList()
{
CaselessListElement * pNext;
while(pHead);
{
pNext = pHead->pNext;
delete pHead;
pHead = pNext;
}
}
CaselessEntry * CaselessList::DeleteExact(CaselessEntry * pEntry)
{
CaselessListElement ** ppThis = &pHead;
while (*ppThis)
{
if ((*ppThis)->pEntry->hash == pEntry->hash)
{
if (0 == strcmp((*ppThis)->pEntry->pSymEntry->name, pEntry->pSymEntry->name))
{
if ((*ppThis)->pEntry->pSymEntry->kind == pEntry->pSymEntry->kind)
{
CaselessListElement * pFound = *ppThis;
*ppThis = pFound->pNext;
CaselessEntry * pReturn = pFound->pEntry;
delete pFound;
return pReturn;
}
}
}
ppThis = &((*ppThis)->pNext);
}
return NULL;
}
SSIZE_T
CaselessDictionary::Compare(void * p1, void *p2)
{
return ((CaselessEntry *)p1)->Compare((CaselessEntry *) p2);
}
/**********************************************************************\
NAME: GlobalSymTable::SymInsert
SYNOPSIS: Inserts a symbol into the symbol table.
ENTRY: NewKey - identifies the symbol table entry.
pNext - points to the next scope.
pNode - points to the type graph.
EXIT:
NOTES:
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
named_node *
GlobalSymTable::SymInsert(
SymKey NewKey,
SymTable * pNext,
named_node * pNode
)
{
SymEntry * NewSymbol;
Dict_Status Status;
NewSymbol = new SymEntry(NewKey, pNext, pNode);
CaselessEntry * NewEntry = new CaselessEntry(NewSymbol);
if (!gfCaseSensitive)
{
Status = pCaselessDictionary->Dict_Find(NewEntry);
if (SUCCESS == Status)
{
// it's allready entered into the caseless table
// and we're in case insensitive mode so we
// should fail here (duplicate identifier)
delete NewSymbol;
delete NewEntry;
return NULL;
}
}
Status = Dict_Insert(NewSymbol);
if (Status == SUCCESS)
{
Status = pCaselessDictionary->Dict_Insert(NewEntry);
if (SUCCESS != Status)
{
// We must be in case sensitive mode otherwise the
// Dict_Find above would have succeeded and we would
// have already returned failure to the caller.
// Therefore, it doesn't really matter that this name
// won't have an entry in the caseless table. Just
// clean up the new entry and move on.
delete NewEntry;
}
return pNode;
}
delete NewSymbol;
delete NewEntry;
return (named_node *)0;
}
/**********************************************************************\
NAME: GlobalSymTable::SymDelete
SYNOPSIS: Deletes a symbol from the symbol table.
ENTRY: OldKey - identifies the symbol table entry.
EXIT: Returns the type graph associated with the entry.
NOTES: This operation could potentially mess up the case insensitive
table because there is no guarantee that the symbol removed
from the case insensitive table will match the symbol removed
from the case sensitive table. However, since MIDL always
re-adds the symbol to the symbol table immediately after
deleting it (deletions only serve to replace forward references)
it will effectively correct any inconsistencies between the
two tables when it re-adds the symbol.
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
named_node *
GlobalSymTable::SymDelete(
SymKey OldKey
)
{
SymEntry TempEntry( OldKey );
CaselessEntry * OldEntry = new CaselessEntry(&TempEntry);
SymEntry * OldSymbol;
Dict_Status Status;
Status = pCaselessDictionary->Dict_Delete((void **)&OldEntry);
if (!gfCaseSensitive && SUCCESS == Status)
{
// make sure we delete the same symbol from the case
// sensitive table
OldSymbol = OldEntry->pSymEntry;
}
else
{
OldSymbol = &TempEntry;
}
named_node * pNode;
Status = Dict_Delete((void ** )&OldSymbol);
if (Status == SUCCESS)
{
pNode = OldSymbol->GetTypeGraph();
delete OldSymbol;
#ifdef gajdebug3
printf("\t\t--- deleting name from symbol table: %d - %s\n",
OldKey.GetKind(), OldKey.GetString());
#endif
return pNode;
}
else
{
return (named_node *)0;
}
}
/**********************************************************************\
NAME: GlobalSymTable::SymSearch
SYNOPSIS: Searches the symbol table for a symbol.
ENTRY: OldKey - identifies the symbol table entry.
EXIT: Returns the type graph associated with the entry.
NOTES:
HISTORY:
Donnali 08-06-1991 Move to LM/90 UI Coding Style
\**********************************************************************/
named_node *
GlobalSymTable::SymSearch(
SymKey OldKey
)
{
Dict_Status Status;
// DBCSDefaultToCaseSensitive() is introduced to handle the
// equivalence of full width and half width characters in
// far east languages; specifically Japanese
if (gfCaseSensitive || CurrentCharSet.DBCSDefaultToCaseSensitive())
{
Status = Dict_Find(&OldKey);
if (Status == SUCCESS)
{
return ((SymEntry * )Dict_Curr_Item())->GetTypeGraph();
}
else
{
return NULL;
}
}
else
{
SymEntry TempEntry(OldKey);
CaselessEntry OldEntry(&TempEntry);
Status = pCaselessDictionary->Dict_Find(&OldEntry);
if (Status == SUCCESS)
{
return ((CaselessEntry *)(pCaselessDictionary->Dict_Curr_Item()))->pSymEntry->GetTypeGraph();
}
else
{
return NULL;
}
}
}