// // Copyright (c) Microsoft Corporation 1995 // // symtab.c // // This file contains the symbol table functions. // // History: // 04-30-95 ScottH Created // #include "proj.h" #define SYMTAB_SIZE_GROW 10 // in elements // // Symbol table entry routines // /*---------------------------------------------------------- Purpose: Create a symbol table entry Returns: RES_OK RES_E_OUTOFMEMORY RES_E_INVALIDPARAM Cond: -- */ RES PUBLIC STE_Create( PSTE * ppste, LPCSTR pszIdent, DATATYPE dt) { RES res; PSTE pste; ASSERT(ppste); ASSERT(pszIdent); pste = GAllocType(STE); if (pste) { res = RES_OK; // assume success if ( !GSetString(&pste->pszIdent, pszIdent) ) res = RES_E_OUTOFMEMORY; else { pste->dt = dt; } } else res = RES_E_OUTOFMEMORY; // Did anything above fail? if (RFAILED(res)) { // Yes; clean up STE_Destroy(pste); pste = NULL; } *ppste = pste; return res; } /*---------------------------------------------------------- Purpose: Destroy the STE element Returns: -- Cond: -- */ void CALLBACK STE_DeletePAPtr( LPVOID pv, LPARAM lparam) { STE_Destroy(pv); } /*---------------------------------------------------------- Purpose: Destroys symbol table entry Returns: RES_OK RES_E_INVALIDPARAM Cond: -- */ RES PUBLIC STE_Destroy( PSTE this) { RES res; if (this) { if (this->pszIdent) GSetString(&this->pszIdent, NULL); // free // (The evalres field should not be freed. It is // a copy from somewhere else.) GFree(this); res = RES_OK; } else res = RES_E_INVALIDPARAM; return res; } /*---------------------------------------------------------- Purpose: Retrieves the symbol table entry value. The type depends on the datatype. Returns: RES_OK RES_E_FAIL (for a type that does not have a value) RES_E_INVALIDPARAM Cond: -- */ RES PUBLIC STE_GetValue( PSTE this, PEVALRES per) { RES res; ASSERT(this); ASSERT(per); if (this && per) { res = RES_OK; // assume success switch (this->dt) { case DATA_INT: case DATA_BOOL: case DATA_STRING: case DATA_LABEL: case DATA_PROC: per->dw = this->er.dw; break; default: ASSERT(0); res = RES_E_FAIL; break; } } else res = RES_E_INVALIDPARAM; return res; } // // Symbol Table functions // /*---------------------------------------------------------- Purpose: Creates a symbol table Returns: RES_OK RES_E_OUTOFMEMORY RES_E_INVALIDPARAM Cond: -- */ RES PUBLIC Symtab_Create( PSYMTAB * ppst, PSYMTAB pstNext) // May be NULL { RES res; PSYMTAB pst; ASSERT(ppst); pst = GAllocType(SYMTAB); if (pst) { if (PACreate(&pst->hpaSTE, SYMTAB_SIZE_GROW)) { pst->pstNext = pstNext; res = RES_OK; } else res = RES_E_OUTOFMEMORY; } else res = RES_E_INVALIDPARAM; // Did anything above fail? if (RFAILED(res) && pst) { // Yes; clean up Symtab_Destroy(pst); pst = NULL; } *ppst = pst; return res; } /*---------------------------------------------------------- Purpose: Destroys a symbol table Returns: RES_OK RES_E_INVALIDPARAM Cond: -- */ RES PUBLIC Symtab_Destroy( PSYMTAB this) { RES res; if (this) { if (this->hpaSTE) { PADestroyEx(this->hpaSTE, STE_DeletePAPtr, 0); } GFree(this); res = RES_OK; } else res = RES_E_INVALIDPARAM; return res; } /*---------------------------------------------------------- Purpose: Compare symbol table entries by name. Returns: Cond: -- */ int CALLBACK Symtab_Compare( LPVOID pv1, LPVOID pv2, LPARAM lParam) { PSTE pste1 = pv1; PSTE pste2 = pv2; return lstrcmpi(pste1->pszIdent, pste2->pszIdent); } /*---------------------------------------------------------- Purpose: Looks for pszIdent in the symbol table entry. If STFF_IMMEDIATEONLY is not set, this function will look in successive scopes if the symbol is not found within this immediate scope. Symbol table entry is returned in *psteOut. Returns: RES_OK (if found) RES_FALSE (if not found) RES_E_INVALIDPARAM Cond: -- */ RES PUBLIC Symtab_FindEntry( PSYMTAB this, LPCSTR pszIdent, DWORD dwFlags, PSTE * ppsteOut, // May be NULL PSYMTAB * ppstScope) // May be NULL { RES res; // Default return values to NULL if (ppsteOut) *ppsteOut = NULL; if (ppstScope) *ppstScope = NULL; if (this && pszIdent) { DWORD iste; STE ste; // Peform a binary search. Find a match? ste.pszIdent = (LPSTR)pszIdent; iste = PASearch(this->hpaSTE, &ste, 0, Symtab_Compare, (LPARAM)this, PAS_SORTED); if (PA_ERR != iste) { // Yes PSTE pste = PAFastGetPtr(this->hpaSTE, iste); if (ppsteOut) *ppsteOut = pste; if (ppstScope) *ppstScope = this; res = RES_OK; } // Check other scopes? else if (IsFlagClear(dwFlags, STFF_IMMEDIATEONLY) && this->pstNext) { // Yes res = Symtab_FindEntry(this->pstNext, pszIdent, dwFlags, ppsteOut, ppstScope); } else res = RES_FALSE; } else res = RES_E_INVALIDPARAM; return res; } /*---------------------------------------------------------- Purpose: Insert the given symbol table entry into the symbol table. This function does not prevent duplicate symbols. Returns: RES_OK RES_E_OUTOFMEMORY Cond: -- */ RES PUBLIC Symtab_InsertEntry( PSYMTAB this, PSTE pste) { RES res; ASSERT(this); ASSERT(pste); if (PAInsertPtr(this->hpaSTE, PA_APPEND, pste)) { PASort(this->hpaSTE, Symtab_Compare, (LPARAM)this); res = RES_OK; } else res = RES_E_OUTOFMEMORY; return res; } /*---------------------------------------------------------- Purpose: This function generates a unique label name. Returns: RES_OK RES_INVALIDPARAM Cond: Caller must free *ppszIdent. */ RES PUBLIC Symtab_NewLabel( PSYMTAB this, LPSTR pszIdentBuf) // must be size MAX_BUF_KEYWORD { static int s_nSeed = 0; #pragma data_seg(DATASEG_READONLY) const static char c_szLabelPrefix[] = "__ssh%u"; #pragma data_seg() RES res; char sz[MAX_BUF_KEYWORD]; PSTE pste; ASSERT(pszIdentBuf); do { // Generate name wsprintf(sz, c_szLabelPrefix, s_nSeed++); // Is this unique? res = Symtab_FindEntry(this, sz, STFF_DEFAULT, NULL, NULL); if (RES_FALSE == res) { // Yes res = STE_Create(&pste, sz, DATA_LABEL); if (RSUCCEEDED(res)) { res = Symtab_InsertEntry(this, pste); if (RSUCCEEDED(res)) { lstrcpyn(pszIdentBuf, sz, MAX_BUF_KEYWORD); res = RES_FALSE; // break out of this loop } } } } while(RES_OK == res); if (RES_FALSE == res) res = RES_OK; return res; }