/****************************************************************************
**
**  Name:  symadd.cpp
**
**  Description:
**     This module contains routines for adding to the symbol pool.
**
**  Status:  PRELIMINARY
**
**  $Log:   S:/tbird/arcppc/symbol/symadd.cpv  $
** 
**    Rev 1.4   31 Mar 1998 12:00:36   Winky
** C++
** 
**    Rev 1.3   14 Mar 1997 17:28:34   hera
** 
**    Rev 1.2   12 Mar 1997 14:47:52   hera
** No change.
** 
**    Rev 1.1   03 Mar 1997 15:48:18   hera
** 
**    Rev 1.2   09 Sep 1996 09:28:20   kevin
** Hera's modification
** 
**    Rev 1.1   02 Aug 1996 13:29:46   kevin
** To support MRI ASM files
** 
**    Rev 1.1   23 Jul 1996 16:09:06   Judy
** To support MRI ASM file
** 
**    Rev 1.0   10 Jul 1996 15:34:24   Judy
** Initial revision.
** 
**    Rev 1.0   07 Sep 1995 11:16:44   gene
** Initial revision.
** 
**    Rev 1.76   28 Feb 1994 17:43:46   nghia
** Fixed bug for PV 2.1:  GPF in Symbol server when load Tandberg's BSG000_.ABS
** on-demand.  GlobalReAlloc() expands table caused pointer to be invalid.
** Added SymStat[] to tally symbol types.
** 
**    Rev 1.75   22 Nov 1993 13:26:48   nghia
** Fixed bug: Cannot Create Base Index for loading symbol.
** Added check for bit EntryCount in SymAddLoadStart() to detect symbol loaded.
** 
**    Rev 1.74   22 Oct 1993 09:20:18   nghia
** Fixed UAE bug. - When symbol table extends its size, any pointer dereference
** to the symbol table prior to the size extending will be wiped out.  Updated
** pointer after operations that might cause the symbol table to extend its size
** st.AllocBytes(), st.PutString(), st.PutBytes()....
** Fixed Bug - Cannot set section base.  Checked if the lastOpened offset is
** > the rootOffset, which indicates that there are symbol in table.
** 
**    Rev 1.73   30 Sep 1993 14:59:42   nghia
** Removed check for typeIndex in adding function symbol.
** 
**    Rev 1.72   24 Sep 1993 10:24:34   nghia
** Support forward reference types
** Fixed record size of typedef type.
** SymAddFunctionOpen will use UNKNOWN type if the input type is undefined.
** 
**    Rev 1.71   14 Jul 1993 12:03:18   nghia
** Added SymAddModuleOpenByDesc() to allow the Loader open module by desc.
** 
**    Rev 1.70   08 Dec 1992 07:00:28   brucea
** Cosmetic cleanups
** 
**    Rev 1.69   03 Dec 1992 07:41:06   brucea
** Changed comparison of symbol descriptors to compare to NULL_SYMBOL rather
**    than if (!...)
** 
**    Rev 1.68   06 Nov 1992 07:05:56   brucea
** Modified: SymAddModuleCreate by removing call to ht.LookupName in order to
**    speed up module adds.  The call to ht.PutName is still made.
**    If it returns
**    duplicate name, then the name is modified (second control byte) and the
**    exercise repeated.
** 
**    Rev 1.67   04 Nov 1992 07:23:16   brucea
** Cleanup
** 
**    Rev 1.66   15 Oct 1992 18:43:28   brucea
** Added: localsLoaded parameter to SymAddModuleClose which sets fileOffset to
**    SYMBOLS_LOADED
** 
**    
** 
**    Rev 1.65   08 Sep 1992 13:04:56   brucea
** Added: events.h include
** 
**    Rev 1.64   13 Aug 1992 19:22:50   brucea
** Fixed: on-demand bug where local vars were not going into function;
**    now setting currentOpenContext in SymAddFuncOpen
** 
**    Rev 1.63   13 Aug 1992 11:04:10   brucea
** Changed: wsprintf to sprintf
** 
**    Rev 1.62   06 Aug 1992 15:23:34   brucea
** Bug fix: comparison to tmpSymType not correct in SymAddSymbolSetAddr
**          same type of comparison in SymAddVarPublic and SymAddVarLifetimeInfo
** 
** 
**    Rev 1.61   06 Aug 1992 10:13:20   brucea
** Changed access to .typeIndex.symType to use &0xF
** 
**    Rev 1.60   25 Jul 1992 16:41:36   brucea
** Added: SymInitialize
** Removed: SymInitSymServer
** 
**    Rev 1.59   19 Jul 1992 21:58:50   brucea
** Added: check for public label already in hash table
** Added: adding public var address to by-address table
** 
**    Rev 1.58   10 Jul 1992 19:08:20   brucea
** Added: HUGE to all casts of st.GetHugeDataPtr()  (didn't make a difference in
**    the memory access bug
** 
** 
**    Rev 1.57   24 Jun 1992 18:01:30   brucea
** Fixed: bug which put static vars located outside a function inside the
**    previously closed function.  SW was not keeping the state of the current
**    open symbol (module, func, or unnamed block).  Required the recalculation
**    of lastLabel and lastVariable that point to the end of the label/variable
**    linked list of the current symbol when a new one becomes the current
**    context.
** 
** 
**    Rev 1.56   15 Jun 1992 09:23:46   brucea
** Fixed up: LPU8 cast of second param to GetString
** Changed: enumValue to U32 in SymAddTypeEnum
** Bug fix: added breaks in case clauses in registerClass test in function
**    SymAddVarLifetimeInfo
** Fixed up: switch statements in UpdateBlockInfo
** 
**    Rev 1.55   11 May 1992 09:55:36   brucea
** Added: PRIVATE lastPublicLabel and lastPublicVariable.  Public labels and vars
**    are now added separately from module-level labels and vars.  This fixes a
**    bug in which public labels were being added to the last module rather than
**    root.  To do this, SymAddLabelPublic and SymAddVarPublic were modified; the
**    latter heavily.
** 
**    Rev 1.54   30 Apr 1992 18:31:10   brucea
** Fixed: SymAddVar to set up the correct size for static vars
** 
**    Rev 1.53   20 Apr 1992 09:06:14   brucea
** Removed: initialization of PRIVATE vars at point of declaration
** Added: init of PRIVATE vars in InitSymTable including calls to 
**    BasetblResetCacheVars and AdlookupResetCacheVars
** Bug fix: PPR5356, PPR5357 -> in SymAddVarPublic, now fill in type index from
**    previously entered var type in order to calculate size of var correctly
** 
**    Rev 1.52   01 Apr 1992 23:43:20   brucea
** Fixed: compiler warnings
** 
**    Rev 1.51   14 Feb 1992 15:11:18   brucea
** Removed code which initialized symbol table from SymAddLoadStart
** Changed casting of loadFilename to (LPSTR)
** 
**    Rev 1.50   04 Feb 1992 16:23:08   brucea
** In SymAddLoadStart, added call to SymInitialize if a new load and symbols
**    have not been loaded yet.
** 
**    Rev 1.49   29 Jan 1992 15:07:20   brucea
** Changed the initial value of the typeHdr.memberCount to 0.
** 
**    Rev 1.48   22 Jan 1992 14:58:34   brucea
** Changed tmpArray[255] to tmpArray[MAX_SYMNAME_LENGTH]
** 
**    Rev 1.47   13 Jan 1992 17:21:26   john
** Added code to check for valid symbol descriptors.
** Added code to add variable lifetime information.
** 
**    Rev 1.46   08 Jan 1992 16:18:54   john
** Member count was being initialized incorrectly.
** 
**    Rev 1.45   08 Jan 1992 11:27:24   john
** Added new commands.  Increased command count
** 
**    Rev 1.44   07 Jan 1992 09:42:34   john
** Previous code fix didn't work
** 
**    Rev 1.43   06 Jan 1992 16:56:16   john
** SymAddGetModuleName was not stripping the leading chars from the
** module name properly.
** 
**    Rev 1.42   06 Jan 1992 16:02:48   john
** New public vars were being added to the wrong block
** 
**    Rev 1.41   03 Jan 1992 09:22:04   john
** Fixed SymAddFuncOpen and SymAddModuleOpen to correctly set up
** the symbol table context.  The code only worked the initial time
** it was called.  Subsequent calls caused incorrect operation.
** 
**    Rev 1.40   02 Jan 1992 12:01:56   john
** SymAddLoadStart now checks to see if an on demand load is being
** performed.  If it is then it checks to make sure the filename
** and timestamp of the load module are correct.  It then sets up
** preload state.
** If this is not an on demand load it makes sure no symbols are
** loaded and then sets up preload state.
** 
**    Rev 1.39   20 Dec 1991 09:22:02   john
** Fixed symaddtypeheader to fill in the name offset field
** correctly.
** Made changes to make symaddfuncopen to correctly set up the
** symbol table state variables.
** 
**    Rev 1.38   18 Dec 1991 11:19:04   john
** Needed to set the isValidAddr flag to true when a global vars 
** address was updated.
** 
**    Rev 1.37   18 Dec 1991 09:38:10   john
** Added return code to PushSymStack
** 
**    Rev 1.36   17 Dec 1991 16:12:10   john
** Changed symaddmodulecreate to pass back a descriptor to the
** module just created.  This is used for adding line numbers.
** 
**    Rev 1.35   16 Dec 1991 17:17:48   john
** Removed parameter that wasn't going to be used from
** SymAddModuleCreate.
** Created function to add a module path reference to an existing
** module symbol entry.
** 
**    Rev 1.34   16 Dec 1991 15:15:06   john
** Made changes to SymAddModuleOpen to support on demand loading.
** 
**    Rev 1.33   16 Dec 1991 11:39:16   brucea
** Inside SymAddLoadEnd, added call to SortAllByAddrTable
** 
**    Rev 1.32   16 Dec 1991 09:20:26   john
** Fixed SymAddSymbolSetAdrr.  A valid end address was only being
** set if there was a valid start address.
** 
**    Rev 1.31   13 Dec 1991 14:30:30   john
** Added code to update the max/min addresses of the last symbols BASE.
** 
**    Rev 1.30   13 Dec 1991 12:24:14   brucea
** Added global var: loadFilename to hold loaded filename
** Added SymAddGetModuleName
** SymAddLoadStart: added copying of filename into loadFilename
** SymAddModuleInvalidate: changed return to ER_NOT_IMPLEMENTED
** 
**    Rev 1.29   12 Dec 1991 17:55:02   john
** Changed how modulereference gets filled in
** 
**    Rev 1.28   12 Dec 1991 16:16:34   john
** Fixed SymAddSymbolSetAddr
** 
**    Rev 1.27   09 Dec 1991 12:06:24   john
** Made changes necessary to add another CLI command.
** Added code to correctly re-initialize the symbol table after all 
** symbols have been deleted.
** 
**    Rev 1.26   05 Dec 1991 15:59:10   john
** Fixed bug in SymAddVar that improperly checked for duplicate
** global names.
** Implemented code for LIVING registers types.
** 
**    Rev 1.25   02 Dec 1991 14:53:52   john
** removed functions that are not currently supported
** 
**    Rev 1.24   02 Dec 1991 14:37:58   john
** Integrated changes brought about by the address handling modifications.
** 
**    Rev 1.23   02 Dec 1991 11:27:00   brucea
** Removed SymAddCloseLoad
** 
**    Rev 1.22   02 Dec 1991 10:19:00   john
** Merged branches 1.21.1 and 1.21.2
** 
**    Rev 1.21.2.1   27 Nov 1991 16:14:06   brucea
** Changed LOGICAL_ to OFFSET_
** removed unimplemented functions
** name change: startInfo to startAddrInfo, endInfo to endAddrInfo
** added code to support LOCKED_REG type
** 
**    Rev 1.21.1.5   27 Nov 1991 12:57:46   john
** Added real code to SymAddStartLoad.
** Added code to SymAddModuleOpen.
** Created SymAddFuncOpen.
** 
**    Rev 1.21.1.4   25 Nov 1991 17:13:36   john
** Fixed check for null string
** 
**    Rev 1.21.1.3   25 Nov 1991 14:09:08   john
** Added a "size" field to auto-variables.  This removes the need
** for a call to get the variables size from its type header.
** 
**    Rev 1.21.1.2   21 Nov 1991 16:18:38   john
** Fixed the code that determined if there is a name was being added
** to the func/block.  Now if funcName points to a 0 an unnamed block
** is created.
** 
**    Rev 1.21.1.1   21 Nov 1991 15:08:46   john
** Added SymAddVarPublic and SymAddLabelPublic to handle adding
** public symbols differently than local symbols.
** Removed SymAddBlockxxx.  We are using SymAddFuncxxx to create
** unnamed blocks.
** Added the code to SymAddTypeBitfield, SymAddTypeTypeIndex.
** Made fixes in SymAddVar to handle variable addresses better.
** 
** 
**    Rev 1.21   18 Nov 1991 20:31:30   brucea
** Removed RETCODE err; from SymAddSymbolSetAddr
** Added isConstant and isValidAddr to SymAddVar and fixed accesses
** Removed (storageClass == STATIC_VAR_CLASS) from check to
**    add var to global hash table because a static var
**    is NOT globally visible
** 
**    Rev 1.20   15 Nov 1991 13:51:42   john
** - The COMMON_SYMBOL_HEADER structure changed.  All the variables
**   referencing this structure were changed to comply.
** - Added new code to handle most of the variable types in
**   SymAddVar.  This routine was not complete because complex types
**   had not been completed.
** - Added the code for SymAddSymbolSetAddr.
** 
**    Rev 1.19   13 Nov 1991 16:09:30   john
** Added SymAddTypeEnum code.
** Removed all calls to UpdateMAUSize because this info is added
** when the type header is created.
** 
**    Rev 1.18   11 Nov 1991 19:02:06   brucea
** Removed SymAddLinenum
** 
**    Rev 1.17   11 Nov 1991 17:43:04   john
** added code for struct and C array types
** 
**    Rev 1.16   11 Nov 1991 15:12:26   john
** Added real code to some of the routines to add type info.
** This code has not been tested.
** 
**    Rev 1.15   08 Nov 1991 13:50:12   john
** Moved InitBasicTypes to typetbl.cpp
** 
**    Rev 1.14   07 Nov 1991 13:51:44   john
** Stubbed out many SymAdd routines
** 
**    Rev 1.13   05 Nov 1991 17:23:08   brucea
** Fixed up AddOrdinalValue
** Changed the initialization of st to store 0 in the first location
** 
**    Rev 1.12   04 Nov 1991 16:01:44   john
** Variable names weren't being put into the global hash table
** if they were global.
** 
**    Rev 1.11   01 Nov 1991 17:11:46   john
** Matched functions to their prototypes
** 
**    Rev 1.10   31 Oct 1991 17:45:16   brucea
** Made SymAddFuncCreate and SymAddModuleCreate compatible with
** reference params and additional params 
** 
**    Rev 1.9   31 Oct 1991 16:56:48   john
** Made changes to reflect new hash table interface.
** Needed to clear the variable entry to make sure it is in a known
** state.
** 
**    Rev 1.8   30 Oct 1991 15:57:02   john
** Added stub code for the loader.
** Removed initialization code and moved it to LIBMAIN.
** 
**    Rev 1.7   24 Oct 1991 17:58:12   john
** Fixed the code that handles module name collision.  It was 
** inserting a null in the middle of the module name.
** 
**    Rev 1.6   23 Oct 1991 17:11:58   john
** Removed EXPORT from functions that will not be exportable beyond
** the DLL.
** 
**    Rev 1.5   17 Oct 1991 10:08:38   john
** Removed an unnecessary pointer from SymAddBaseCreate.
** Added error code for duplicate name collisions in the hash table.
** Modified the module name fixup code as a cleanup pass.
** 
**    Rev 1.4   11 Oct 1991 15:39:32   john
** Added hash table routines back in
** 
**    Rev 1.3   11 Oct 1991 15:06:38   brucea
** Many changes: made BaseSymbol a class; all base calls go through different
** calls.  Fixed bug in ht initialization.
** 
**    Rev 1.2   04 Oct 1991 14:49:28   john
** made changes suggested after a code review
** 
**    Rev 1.1   03 Oct 1991 16:46:16   john
** symblsvr.h changed a typedef
** 
**    Rev 1.0   03 Oct 1991 11:43:10   john
** Initial revision.
**
**  $Header:   S:/tbird/arcppc/symbol/symadd.cpv   1.4   31 Mar 1998 12:00:36   Winky  $
**
**  Copyright (C) 1991 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#ifndef __MEM_H 
#include <mem.h>
#endif

#ifndef _BASETBL_
#include "basetbl.h"
#endif

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _BYADRTBL_
#include "byadrtbl.h"
#endif

#ifndef _ENLIB_
#include "enlib.h"
#endif

#ifndef _EVENTS_
#include "events.h"
#endif

#ifndef _HASHTBL_
#include "hashtbl.h"
#endif

#ifndef _INDEXTBL_
#include "indextbl.h"
#endif

#ifndef _MEMMANAG_
#include "memmanag.h"
#endif

#ifndef _MEMPOOL_
#include "mempool.h"
#endif

#ifndef _ORDTBL_
#include "ordtbl.h"
#endif

#ifndef __STRING_H
#include <string.h>
#endif

#ifndef _SYMBLSVR_
#include "symblsvr.h"
#endif

#ifndef _SYMELF_
#include "symelf.h"
#endif

#ifndef _SYMADD_
#include "symadd.h"
#endif

#ifndef _SYMERROR_
#include "symerror.h"
#endif

#ifndef _SYMUTIL_
#include "symutil.h"
#endif

#ifndef _TYPETBL_
#include "typetbl.h"
#endif

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

extern MemPool st;         // symbol table ;
extern BaseIndexTable bit;
extern TypeTable tt;       // type table ;
extern IndexTable typit;   // type index table ;

extern VOID AdlookupResetCacheVars(VOID);

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

#define SYM_STACK_SIZE 32
#define SYM_STACK_EMPTY -1

PRIVATE TABLE_OFFSET lastLabel;
PRIVATE TABLE_OFFSET lastOpened;
PRIVATE TABLE_OFFSET lastVariable;

PRIVATE TABLE_OFFSET lastPublicLabel;     // used for adding public labels
PRIVATE TABLE_OFFSET lastPublicVariable;  //  "                     vars

PRIVATE BOOLEAN      moduleOpen;
PRIVATE SYM_ACTION   prevAction;
PRIVATE TABLE_OFFSET prevSym;
PRIVATE TABLE_OFFSET currentOpenContext;     // holds mod, func, unnamed block
PRIVATE TABLE_OFFSET symStack[SYM_STACK_SIZE];
PRIVATE S8           topSymStack;

// used to transfer SymAddLoadStart load type to SymAddLoadEnd for
// the type of event notification: initial load or on-demand load
PRIVATE BOOLEAN onDemandState = FALSE;

OrdinalTable ot;     // ordinal table ;
HashTable ht;        // hash table of global names ;

U8 loadFilename[MAX_SYMNAME_LENGTH];
TIMESTAMP_TYPE loadTimestamp;
TABLE_OFFSET rootOffset;

//---------------------------------------------------------------------------
// Table to collect symbol statistics
U32 symbolStat[MAX_SYM_TYPE];
TABLE_OFFSET lastModuleLoaded;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

RETCODE AddOrdinalValue(TABLE_OFFSET offset);
VOID    ClearEntry(VOID *entry, U32 entrySize);
RETCODE PushSymStack(TABLE_OFFSET stackEntry);
RETCODE PopSymStack(TABLE_OFFSET &stackEntry);
RETCODE UpdateBlockInfo(TABLE_OFFSET symbolOff,SYM_ACTION action);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

/****************************************************************************
**
**  AddOrdinalValue
**
**  Description:
**     Puts the ordinal value into the symbol table entry and adds it to the
**     ordinal table.
**     
**  Parameters:
**     input:
**        offset: the offset of the symbol
**        
**     output:
**        none:
**        (error): if value couldn't be put into ordinal table
**
*****************************************************************************/
RETCODE AddOrdinalValue(TABLE_OFFSET offset) {

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *block;
   ORDINAL_INDEX ordinalValue;

   // get the ordinal value
   if ((err = ot.AddSymOffsetToOT(offset, ordinalValue)) == SUCCESS)  {
      // fill in the ordinal value of this symbol ;
      block = (COMMON_SYMBOL_HEADER HUGE*)st.GetHugeDataPtr(offset);
      block->ordinalVal = ordinalValue;
      }
   return err;
}


/****************************************************************************
**
**  ClearEntry
**
**  Description:
**     Zeroes out a symbol entry structure.  When some symbols are created
**     they may not be immediately filled in.  This routine is called to 
**     make sure these symbols don't have garbage values in them.
**     
**  Parameters:
**     input:
**        *entry: A pointer to the symbol structure to be cleared
**        entrySize: The size of the entry in BYTES.
**     output:
**        none:
**
*****************************************************************************/
VOID ClearEntry(VOID *entry, U32 entrySize) {
   U32 i;

   i = entrySize-1;
   while(i--) {
      *((U8 *)entry) = 0;
      ((U8 *)entry)++;
   }
}


//--------------------------------------------------------------------------
// SymInitialize
//--------------------------------------------------------------------------
RETCODE EXPORT SymInitialize()  {

   RETCODE err;

   if ((err = InitSymTable()) != GOOD) return err;
   return tt.InitBasicTypes();
} // end of SymInitialize

//--------------------------------------------------------------------------
// InitSymTable
//--------------------------------------------------------------------------
RETCODE InitSymTable(VOID) {
   
   SYM_TYPE_MODULE HUGE *initMod;
   TABLE_OFFSET nameOffset;
   RETCODE err;
   U8 temp;

// initialize ht - the hash table
   if ((err = ht.InitOrExtendTable(GMEM_ZEROINIT)) != SUCCESS) {
      return err;
      }
   ht.SetHashTableSize();       // adjust size for hash function fit

// init cache variables
   BasetblResetCacheVars();

   AdlookupResetCacheVars();

// initialize PRIVATE vars in this module
   lastLabel = 0L;
   lastVariable = 0L;
   lastPublicLabel = 0L;
   lastPublicVariable = 0L;

// initialize the previous action for use by UpdateBlockInfo ;
   prevAction = SYM_OPEN;

   // initialize the NULL table entry in the symbol table to 0; this
   // means that if a string pointer (offset) is 0, the string length
   // is 0
   temp = 0;
   if((err = st.PutBytes(&temp, 1, nameOffset)) != GOOD) return err;

   // put the name of the root module into the symbol pool
   if((err = st.PutString((LPSTR)"ROOT",nameOffset)) != GOOD) return err;

   // initialize root symbol entry
   if((err = st.AllocBytes(sizeof(SYM_TYPE_MODULE),
      rootOffset)) != GOOD) return err;

   initMod = (SYM_TYPE_MODULE HUGE*)st.GetHugeDataPtr(rootOffset);

   // clear all the entries in the module to zero ;
   ClearEntry(initMod,sizeof(SYM_TYPE_MODULE));
   initMod->symHeader.symHeader.typeIndex.symType = SYM_ROOT;
   initMod->symHeader.symHeader.symbolNameOffset = nameOffset;

   // fill in the ordinal value of the root symbol ;
   if((err = AddOrdinalValue(rootOffset)) != GOOD) return err;

   // Save the offset of the previous symbol we were dealing with.
   // This will be used for manipulating the symbol pool later
   prevSym = currentOpenContext = rootOffset;

   // Save the offset of the module/block/function that was opened last ;
   lastOpened = rootOffset;

   // Initialize and save the offset on a stack.  The mod/blk/func will ;
   // nest and we will want to keep track of the order they were nested ;
   topSymStack = SYM_STACK_EMPTY;
   if ((err = PushSymStack(rootOffset)) != GOOD) return err;
   moduleOpen = FALSE;

   // Clear all symbol statistics - all entries equals zero
   memset(symbolStat, 0, sizeof(symbolStat));
   lastModuleLoaded = 0L;
   
   return GOOD;
}

/****************************************************************************
**
**  PopSymStack
**
**  Description:
**     Pop the offset of the topmost nested block off the stack
**     
**  Parameters:
**     input:
**        none:
**     output:
**        none:
**        (returns): offset of new top of stack block
**
*****************************************************************************/
RETCODE PopSymStack(TABLE_OFFSET &stackEntry) {
   
   if(topSymStack == -1)
      return ER_SYMBOL_STACK_EMPTY;
   stackEntry = symStack[topSymStack--];
   return GOOD;
}

/****************************************************************************
**
**  PushSymStack
**
**  Description:
**     The symbol stack is used to store symbol offsets.  The offsets 
**     are saved to indicate the current nesting level of open modules,
**     blocks, and functions.
**     
**  Parameters:
**     input:
**        stackEntry:  the function offset to be stored
**     output:
**        none:
**        (error): if stack is full
**
*****************************************************************************/
RETCODE PushSymStack(TABLE_OFFSET stackEntry) {
   
   if(topSymStack >= SYM_STACK_SIZE)
      return ER_SYM_STACK_FULL;
   symStack[++topSymStack] = stackEntry;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddBaseCreate
//
// Pseudo-code
//    First checks for already existing or out-of-bounds baseIndex.
//    Then, executes the "new" operator for BaseSymbol;
//       if error, returns error code
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddBaseCreate(LPSTR baseName, BASE_INDEX baseIndex,
                 BASE_ADDRESS baseAddress, BASE_TYPE baseTypeParam)  {

   RETCODE err;
   TABLE_OFFSET dummy;
   
   // check for validity of baseIndex; should not yet exist
   err = bit.GetOffset(baseIndex, dummy);
   if (err == ER_INDEX_OUT_OF_BOUNDS) return err;
   if (err == SUCCESS) return ER_INDEX_ALREADY_EXISTS;
   
   // index not in table, create new base and put its index into <bit>
   new BaseSymbol(baseName, baseIndex, baseAddress,
                            baseTypeParam, err);
   return err;
}

//--------------------------------------------------------------------------
// SymAddBaseSetAddr
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddBaseSetAddr(BASE_INDEX baseIndex,
                                 BASE_ADDRESS baseAddress) {

   return BaseSetAddr(baseIndex, baseAddress);
}

//--------------------------------------------------------------------------
// SymAddFuncCreate
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddFuncCreate(LPSTR funcName,U16 baseIndex,FUNC_CLASS funcClass,
	       U32 stackSize, OFFSET_ADDR_RANGE_TYPE *codeAddrRange,U32 typeIndex)
{
   SYM_TYPE_FUNCTION HUGE *function;
   TABLE_OFFSET nameOffset;
   RETCODE err;
   TABLE_OFFSET funcOffset, baseOffset;
   BOOLEAN duplicateName;
   SYM_TYPE_TYPE symType = SYM_FUNCTION;
   
   // NOTES: 09/20/93 - Nghia
   // If ther return type 'typeIndex is undefined when create the function then
   // its type might be a forward reference type.  Eventually, it has to
   // resolve somehow, or else the compiler should caught that and report
   // error.  DO NOT NEED TO CHECK FOR TYPE INDEX EXISTING.
   // make sure the base exist 
   if ((err = bit.GetOffset(baseIndex, baseOffset)) != GOOD) return err;
   
   lastLabel=lastVariable=0;

   // get memory for the function in the symbol pool
   if((err = st.AllocBytes(sizeof(SYM_TYPE_FUNCTION), funcOffset)) 
      != GOOD) return err;

   // if the name doesn't exist then this is an unnamed block ;
   if (funcName[0]) {
      if((err = st.PutString(funcName,nameOffset)) != GOOD) return err;
   } else {
      nameOffset = 0;
   }
   
   // get pointer
   function = (SYM_TYPE_FUNCTION HUGE *)st.GetHugeDataPtr(funcOffset);
   ClearEntry(function,sizeof(SYM_TYPE_FUNCTION));
   
   // initialize the rest of the function entry ;
   function->symHeader.symHeader.symbolNameOffset = nameOffset;
   
   // if there is not a name offset then this is a block symbol
   // the default is a function symbol
   if (!nameOffset)
      symType = SYM_BLOCK;     

   function->symHeader.symHeader.typeIndex.symType = symType;  
   function->symHeader.symHeader.typeIndex.baseIndex = baseIndex;
   function->symHeader.symHeader.beginAddrInfo.startAddr =
      codeAddrRange->offsetStartAddr;
   function->symHeader.symHeader.endAddrInfo.endAddr =
      codeAddrRange->offsetEndAddr;
   function->funcClass  = funcClass;
   function->stackSpace = stackSize;
   function->typeIndex  = typeIndex;

   if(funcClass==FUNC_GLOBAL) {
      if((err=ht.PutName(funcOffset,duplicateName)) != GOOD) return err;
      if(duplicateName)
         return ER_DUPLICATE_GLOBAL_NAME;
      // IMPORTANT: Nghia 02/17/94
      // Need to dereference the "function" again before use it, or else
      // It might crash the symbol - ReAlloc bug
   }
   
   // fill in the ordinal value ;
   if((err = AddOrdinalValue(funcOffset)) != GOOD) return err;  
   if((err = UpdateBlockInfo(funcOffset,SYM_OPEN)) != GOOD) return err;
   
   // update the base for this symbol ;
   if ((err = AddAddrToByAddrTable(baseIndex, funcOffset,
                                   codeAddrRange->offsetStartAddr,
                                   codeAddrRange->offsetEndAddr))
      != GOOD) return err;
   // Tally the function symbol   
   symbolStat[symType]++;

   return GOOD;
}  // end of SymAddFuncCreate


//--------------------------------------------------------------------------
// SymAddFuncClose
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddFuncClose(VOID) {
   TABLE_OFFSET offset = 0;
   RETCODE err, firstErr = GOOD;

   firstErr = UpdateBlockInfo(offset,SYM_CLOSE);
   
   err = SymGetEndList(currentOpenContext, SYM_LABEL, &lastLabel);
   if (GOOD == firstErr)
      firstErr = err;
   err = SymGetEndList(currentOpenContext, SYM_LOCAL_VAR, &lastVariable);
   if (GOOD == firstErr)
      firstErr = err;
   return firstErr;
}  // end of SymAddFuncClose


//--------------------------------------------------------------------------
// SymAddFuncOpen
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddFuncOpen(LPSTR funcName) {

   COMMON_SYMBOL_HEADER HUGE *symPtr;
   SYM_DESCRIPTOR tmpOffset;
   SYM_TYPE_TYPE  symType;
   RETCODE        err;
   U8             name[MAX_SYMNAME_LENGTH];
   
   if (prevAction == SYM_OPEN) {
      // the previously opened/changed symbol should be a module symbol
      symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(prevSym);
      if (((symPtr->typeIndex.symType) & 0xF) != SYM_MODULE) 
         return ER_SYMBOL_NOT_A_MODULE;
   
      // get module child offset
      if ((err = SymGetSymbolChild(prevSym, &symType, &tmpOffset)) != GOOD) 
         return err;
   
      if (NULL_SYMBOL == tmpOffset)
         return ER_SYMBOL_HAS_NO_CHILD;

      // push the module offset onto the context stack.  This should be
      // the functions parent.
      if ((err = PushSymStack(prevSym)) != GOOD)
         return err;
   } else {
      // the previously accessed symbol was a function and the next function
      // to be accessed is the sibling of the previous function.
      if((err = SymGetSymbolSibling(prevSym, &symType, &tmpOffset)) != GOOD)
         return err;
   }
   if (NULL_SYMBOL == tmpOffset)  // don't allow access if 0; otherwise UAEs
      return ER_SYMBOL_HAS_NO_CHILD;
   do {
      symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(tmpOffset);
      st.GetString(symPtr->symbolNameOffset, name);
      if ( !strcmp( (S8 *) funcName, (S8 *) name))
         break;
      if (( err = SymGetSymbolSibling(tmpOffset, &symType, &tmpOffset))
         != GOOD) return err;
   } while ( tmpOffset );
   
   if (!tmpOffset)
      return ER_SYMBOL_NOT_FOUND;

   // set up the current context ;
   prevSym = lastOpened = currentOpenContext = tmpOffset;
   prevAction = SYM_OPEN;
   
   // set the lastlabel and lastvariable values to the end of the var/label ;
   // list. ;
   if ((err = SymGetEndList(tmpOffset, SYM_LABEL, &lastLabel)) != GOOD)
      return err;
   
   if ((err = SymGetEndList(tmpOffset, SYM_LOCAL_VAR, &lastVariable)) 
      != GOOD) return err;
   
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddGetModuleName
//
// Purpose: Single, isolated call to get the name string of a module,
//          minus the header bytes
//
// Input parameters: module offset
//
// Output Parameters: modName.  Code modifies pointer after name put into
//                    string.
//--------------------------------------------------------------------------
RETCODE
SymAddGetModuleName(SYM_DESCRIPTOR module, LPSTR modName)  {

   SYM_TYPE_MODULE HUGE *modPtr;
   S8 *from = modName+2;
   U8 length;

   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(module)) return ER_INVALID_SYM_DESCRIPTOR;

   modPtr = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(module);
   if (modPtr->symHeader.symHeader.symbolNameOffset == NULL_SYMBOL)
      return ER_STRING_LENGTH_ZERO;
   st.GetString(modPtr->symHeader.symHeader.symbolNameOffset,
                (LPU8)modName);
   // shift the module name left over the two prepended characters in the ;
   // module names that makes them unique ;
   length = strlen(modName) - 2;
   do {
      *modName++ = *from++;
   } while (length--);
   return SUCCESS;
   } // end of SymAddGetModuleName


//--------------------------------------------------------------------------
// SymAddLabel
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddLabel(LPSTR labelName, BASE_INDEX baseIndex,
                           OFFSET_ADDR_TYPE addr) {

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *labelSym;
   TABLE_OFFSET nameOffset,labelOffset,baseOffset;
   HPU8 label;

   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD) return err;

   // get memory for the label in the symbol memory pool ;
   if((err = st.AllocBytes(sizeof(COMMON_SYMBOL_HEADER),
      labelOffset)) != GOOD) return err;
   if((err = st.PutString(labelName,nameOffset)) != GOOD) return err;

   labelSym = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(labelOffset);

   // fill in the label data ;
   labelSym->typeIndex.symType = SYM_LABEL;
   labelSym->typeIndex.baseIndex = baseIndex;
   labelSym->symbolNameOffset = nameOffset;
   labelSym->symParentOffset = currentOpenContext;
   labelSym->symSiblingOffset = 0;
   labelSym->beginAddrInfo.startAddr = addr;
   labelSym->endAddrInfo.endAddr = addr+1;

   // if there was a label loaded previously in this block then its sibling ;
   // pointer points to this label
   if(lastLabel) {
      label = st.GetHugeDataPtr(lastLabel);
      ((COMMON_SYMBOL_HEADER *)label)->symSiblingOffset = labelOffset;
   } else {
      // if this is the first label loaded for this block then we want ;
      // that module/func/blocks label list pointer pointing to this label ;
      label = st.GetHugeDataPtr(currentOpenContext);
      ((COMMON_BLOCK_HEADER *)label)->list.labelListOffset = labelOffset;
   }
   lastLabel = labelOffset;
   
   // fill in the ordinal value of this symbol ;
   if((err = AddOrdinalValue(labelOffset)) != GOOD) return err;
   
   // update the base for this symbol and add it to the by-address table
   if ((err = AddAddrToByAddrTable(baseIndex, labelOffset, addr, addr+1))
      != GOOD) return err;
      
   // tally the symbol label     
   symbolStat[SYM_LABEL]++;
   
   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddLabelPublic
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddLabelPublic(LPSTR labelName, BASE_INDEX baseIndex,
                           OFFSET_ADDR_TYPE addr) {

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *labelSym;
   TABLE_OFFSET nameOffset,labelOffset,baseOffset;
   HPU8 label;
   U8 misses;
   BOOLEAN duplicateName;

   // make sure the base exists for the symbol ;
   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD) return err;
   
   // make sure there isn't a duplicate name in the global name table ;
   if((err = ht.LookupName(labelName, labelOffset, misses)) != GOOD)
      return err;
   
   if (labelOffset)
      return ER_PUBLIC_IGNORED;
         

   // get memory for the label in the symbol memory pool ;
   if((err = st.AllocBytes(sizeof(COMMON_SYMBOL_HEADER),
      labelOffset)) != GOOD) return err;
   if((err = st.PutString(labelName,nameOffset)) != GOOD) return err;

   labelSym = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(labelOffset);

   // fill in the label data ;
   labelSym->typeIndex.symType = SYM_PUBLIC_LABEL;
   labelSym->typeIndex.baseIndex = baseIndex;
   labelSym->symbolNameOffset = nameOffset;
   labelSym->symParentOffset = rootOffset;
   labelSym->symSiblingOffset = 0;
   labelSym->beginAddrInfo.startAddr = addr;
   labelSym->endAddrInfo.endAddr = addr;

   // if there were any public labels loaded previously, then its sibling ;
   // pointer points to this label
   if(lastPublicLabel) {
      label = st.GetHugeDataPtr(lastPublicLabel);
      ((COMMON_SYMBOL_HEADER *)label)->symSiblingOffset = labelOffset;
   } else {
      // first public label being loaded; chain off root symbol label linked
      // list
      label = st.GetHugeDataPtr(rootOffset);
      ((COMMON_BLOCK_HEADER *)label)->list.labelListOffset = labelOffset;
   }
   lastPublicLabel = labelOffset;  // save away for next time thru
   
   // put the label's name into the global hash table ;
   if ((err = ht.PutName(labelOffset,duplicateName)) != GOOD)
      return err;
   if(duplicateName) // should never be a duplicate, but leave anyway
      return ER_DUPLICATE_GLOBAL_NAME;
      
   // fill in the ordinal value of this symbol ;
   if((err = AddOrdinalValue(labelOffset)) != GOOD) return err;
   
   // update the base for this symbol and add it to the by-address table
   if ((err = AddAddrToByAddrTable(baseIndex, labelOffset, addr, addr))
      != GOOD) return err;

   // tally the symbol
   symbolStat[SYM_PUBLIC_LABEL]++;
   
   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddLoadEnd
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddLoadEnd(VOID) {
   RETCODE err;
   TABLE_OFFSET offset = 0;
   
   if ((err = UpdateBlockInfo(offset,SYM_CLOSE)) != GOOD) return err;
   if ((err = SortAllByAddressTables()) != GOOD) return err;
   
   // notify interested parties; distinguish on-demand from initial load
   if (onDemandState) {
      if((err = EnlEventNotify(EVENT_SYMBOL_ONDEMAND_LOAD)) != GOOD)
         return err;
   } else {
      if((err = EnlEventNotify(EVENT_SYMBOL_INIT_LOAD)) != GOOD)
         return err;
   }
   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddLoadStart
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddLoadStart(LPSTR filename, BOOLEAN onDemand, TIMESTAMP_TYPE *timestamp)
{
  
   COMMON_BLOCK_HEADER HUGE *rootPtr;
   
   if (onDemand) { // called to loaded linenums and locals for existing module
      if (strcmp((S8 *)loadFilename, filename)) {
         return ER_LOADFILES_DONT_MATCH;
      }
      
      // setup basic state info. ;
      prevSym = lastOpened = currentOpenContext = rootOffset;
      prevAction = SYM_OPEN;

      // compare timestamps.  if they don't match then all of the file ;
      // offsets stored in the symbol table are invalid. ;
      if (UtilCmpTimestamp(timestamp, &loadTimestamp))
	 return ER_TIMESTAMPS_DONT_MATCH;
   } else {  // called to load new set of symbols
      rootPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(rootOffset);
      // NOTES: Nghia - 10/20/93
      // If lastOpened > rootOffset then table had symbols in it.
      if ( (lastOpened > rootOffset) ||
           (rootPtr->child) || (rootPtr->list.varListOffset) || 
           (rootPtr->list.labelListOffset) || 
           (rootPtr->list.constListOffset) ||
           (rootPtr->list.miscListOffset)  ||
           bit.GetEntryCount()) {
         return ER_SYMBOLS_LOADED;
      }
      // setup basic state info. ;
      prevSym = lastOpened = currentOpenContext = rootOffset;
      prevAction = SYM_OPEN;
      strcpy((LPSTR)loadFilename, filename);
      loadTimestamp = *timestamp;
   }
   // only if load is successful should the state flag be set
   onDemandState = onDemand;

   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddModuleClose
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddModuleClose(BOOLEAN localsLoaded) {

   TABLE_OFFSET         offset = 0;
   RETCODE              err, firstErr = GOOD;
   SYM_TYPE_MODULE HUGE *modPtr;

   firstErr = UpdateBlockInfo(offset,SYM_CLOSE);
   moduleOpen = FALSE;
   
   if (localsLoaded) {
      modPtr = (SYM_TYPE_MODULE *)st.GetHugeDataPtr(currentOpenContext);
      modPtr->fileOffset = SYMBOLS_LOADED;
   }
   // get the end of the label/variable lists of the root.  This needs ;
   // to be done so public labels and vars can be added properly. ;
   err = SymGetEndList(currentOpenContext, SYM_LABEL, &lastLabel);
   if (GOOD == firstErr)
      firstErr = err;
   err = SymGetEndList(currentOpenContext, SYM_LOCAL_VAR, &lastVariable);
   if (GOOD == firstErr)
      firstErr = err;
   
   return firstErr;
}  // end of SymAddModuleClose


//--------------------------------------------------------------------------
// SymAddModuleCreate
//--------------------------------------------------------------------------
RETCODE EXPORT
SymAddModuleCreate(LPSTR                   moduleName,
		   BASE_INDEX              baseIndex,
                   OFFSET_ADDR_RANGE_TYPE *codeAddrRange,
                   U32                     fileOffset,
		   BOOLEAN                 onDemand,
		   SYM_DESCRIPTOR         *moduleDescriptor,
		   TIMESTAMP_TYPE         *timestamp) {

   SYM_TYPE_MODULE HUGE *module;
   TABLE_OFFSET          nameOffset;
   RETCODE               err;
   BOOLEAN               duplicateName;
   TABLE_OFFSET          moduleOffset, baseOffset;
   U8                    tmpArray[MAX_SYMNAME_LENGTH];
   HPU8                  hpNamePtr;
   U8                    i;

   if(moduleOpen)
      return ER_MODULE_ALREADY_OPEN;
   moduleOpen = TRUE;

   // make sure the base exists ;
   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD) return err;

   lastLabel = lastVariable = 0;

   // check module name collision here and then handle;
   i=0x01;     // keep track of how many times we try to prepend a character ;
               // to the module name. ;
   // prepend an 0101 to the module name
   sprintf((LPSTR)tmpArray,(LPSTR)"%c%c%s",0x1,0x1,moduleName);

   // allocate memory in symbol pool and get pointer to it
   if((err = st.AllocBytes(sizeof(SYM_TYPE_MODULE),
      moduleOffset)) != GOOD) return err;
   
   module = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(moduleOffset);
   // clear the module since many of the final values are zero ;
   ClearEntry(module, sizeof(SYM_TYPE_MODULE));

   // Need to put the mangled name into the symbol table since this ;
   // is what the hash table uses to find a module name ;
   if ((err = st.PutString((LPSTR)tmpArray, nameOffset)) != GOOD)
      return err;
   
   // NOTE: 02/17/94 - Nghia
   // BUG in GlobalReAlloc that might trash module pointer
   module = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(moduleOffset);

   // initialize module name entry ;
   module->symHeader.symHeader.symbolNameOffset = nameOffset;

   // now get pointer to name string
   hpNamePtr = st.GetHugeDataPtr(nameOffset);
   while (TRUE) {
      // put the module offset (indirectly the name) into the name hash table
      if ((err = ht.PutName(moduleOffset, duplicateName)) != GOOD)
         return err;
      if (!duplicateName)
         break;

      if (i < 0xff) {
         return ER_DUPLICATE_GLOBAL_NAME;
      }
      i++;
      // modify name each time thru loop when duplicate found
      hpNamePtr[1] = i;  // insert in second byte of name header (01xx)
   }
   
   // NOTE: 02/17/94 - Nghia
   // BUG in symbol table. GlobalReAlloc() might wipe out the value of
   // module - Need to dereference again just in case
   module = (SYM_TYPE_MODULE HUGE *)st.GetHugeDataPtr(moduleOffset);
   
   // initialize the rest of the module entry ;
   module->symHeader.symHeader.typeIndex.symType = SYM_MODULE;
   module->symHeader.symHeader.typeIndex.baseIndex = baseIndex;
   module->symHeader.symHeader.beginAddrInfo.startAddr =
      codeAddrRange->offsetStartAddr;

   module->symHeader.symHeader.endAddrInfo.endAddr =
      codeAddrRange->offsetEndAddr;
   
   module->timestamp.year = timestamp->year;
   module->timestamp.month = timestamp->month;
   module->timestamp.day = timestamp->day;
   module->timestamp.hour = timestamp->hour;
   module->timestamp.minute = timestamp->minute;
   module->timestamp.second = timestamp->second;
   //module->typeDelta = typeDelta;
   if (onDemand) {
      module->fileOffset = fileOffset;  // more to come
   } else {
      module->fileOffset = SYMBOLS_LOADED;       // defined in symutil.h
   }
   // fill in ordinal value ;
   if((err = AddOrdinalValue(moduleOffset)) != GOOD)
      return err;

   if((err = UpdateBlockInfo(moduleOffset,SYM_OPEN)) != GOOD)
      return err;

   // update the base for this symbol and add it to the by-address table
   if ((err = AddAddrToByAddrTable(baseIndex, moduleOffset,
                                   codeAddrRange->offsetStartAddr,
                                   codeAddrRange->offsetEndAddr))
      != GOOD)
      return err;
   
   *moduleDescriptor = moduleOffset;

   // tally the module symbol and save the lastModuleLoaded for progress
   // indicator
   symbolStat[SYM_MODULE]++;
   lastModuleLoaded = moduleOffset;
   
   return GOOD;
}  // end of SymAddModuleCreate

//--------------------------------------------------------------------------
// SymAddModuleOpen
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddModuleOpen(LPSTR moduleName, LPSTR moduleReference,
                                U32 *fileOffset, U32 *typeDelta) {
   RETCODE err;
   TABLE_OFFSET moduleOffset; /* Module Descriptor */
   
   if ((err = SymGetModuleDesc(moduleName, moduleReference, &moduleOffset))
         != GOOD)
      return(err);
   return(SymAddModuleOpenByDesc(moduleOffset, fileOffset, typeDelta));
}

//--------------------------------------------------------------------------
// SymAddModuleOpenByDesc
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddModuleOpenByDesc(SYM_DESCRIPTOR moduleDesc,
      U32 *fileOffset, U32 *typeDelta) {

   TABLE_OFFSET moduleOffset = moduleDesc;
   SYM_TYPE_MODULE HUGE *modPtr;
   RETCODE err;

   if (prevAction == SYM_OPEN) {
      prevSym = lastOpened = currentOpenContext = moduleOffset;
      // when the final close call is made the symbol state stack will have;
      // an entry popped off.  So push the root offset onto the stack. ;
      if((err = PushSymStack(rootOffset)) != GOOD)
         return err;
   } else {
      lastOpened = moduleOffset;
      currentOpenContext = moduleOffset;
   }
   prevAction = SYM_OPEN;
   
   // set the lastlabel and lastvariable values to the end of the var/label ;
   // list. ;
   if ((err = SymGetEndList(moduleOffset, SYM_LABEL, &lastLabel)) != GOOD)
      return err;
   
   if ((err = SymGetEndList(moduleOffset, SYM_LOCAL_VAR, &lastVariable)) 
      != GOOD)
      return err;
   
   // get the file descriptor ;
   modPtr = (SYM_TYPE_MODULE HUGE *) st.GetHugeDataPtr(moduleOffset);
   *fileOffset = modPtr->fileOffset;
   // get the typeDelta ;
   *typeDelta = modPtr->typeDelta;
   
   moduleOpen = TRUE;
   
   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddModuleReference
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddModuleReference(SYM_DESCRIPTOR moduleDescriptor, 
                                     LPSTR moduleReference) {
   RETCODE err;
   SYM_TYPE_MODULE HUGE *modPtr;
   TABLE_OFFSET nameOffset;

   // make sure we have something to add
   if (!*moduleReference)
      return ER_NAME_NOT_ADDED;
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(moduleDescriptor)) 
      return ER_INVALID_SYM_DESCRIPTOR;

   modPtr = (SYM_TYPE_MODULE HUGE *) st.GetHugeDataPtr(moduleDescriptor);
   if (((modPtr->symHeader.symHeader.typeIndex.symType) & 0xF) != SYM_MODULE)
      return ER_SYMBOL_NOT_A_MODULE;
   
   if((err = st.PutString(moduleReference,nameOffset)) != GOOD) 
      return err;
   
   // NOTES: Nghia - 10/20/93
   // BUG in symbol table.  When st.PutString() extends the table size,
   // GlobalReAlloc() wiped out modPtr old value.  Which caused a UAE.
   // TEST: load Tandberg\t2.abs nodemand.
   // SOLUTION: Update the modPtr in case table is changed.
   //
   modPtr = (SYM_TYPE_MODULE HUGE *) st.GetHugeDataPtr(moduleDescriptor);
   modPtr->srcFilenameOffset = nameOffset;
   return GOOD;
}  // end of SymAddModuleReference


//--------------------------------------------------------------------------
// SymAddSymbolSetAddr
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddSymbolSetAddr(QUAL_ADDR_RANGE_TYPE *qualAddrRange) {

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *symPtr;
   BaseSymbol HUGE *basePtr;
   SYM_DESCRIPTOR baseOffset;
   U8             tmpSymType;
   
   // prevSym is actually the current open context ;
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(prevSym);

   tmpSymType = (symPtr->typeIndex.symType) & 0xF;
   switch (tmpSymType) {
      case SYM_FUNCTION:
      case SYM_BLOCK:
      case SYM_MODULE:
         break;  // valid cases

      default:
         return ER_SYMBOL_NOT_A_FUNCTION;
   }
   if (qualAddrRange->startValid)
      symPtr->beginAddrInfo.startAddr = qualAddrRange->startAddr;
   if (qualAddrRange->endValid)
      symPtr->endAddrInfo.endAddr = qualAddrRange->endAddr;
   if (!(qualAddrRange->startValid || qualAddrRange->endValid))
      return ER_NO_VALID_ADDRESS;
   
   // update the base address range.  This can only be done for code bases ;
   // here. ;
   if ((err = bit.GetOffset(symPtr->typeIndex.baseIndex, baseOffset)) != GOOD)
      return err;
   basePtr = (BaseSymbol HUGE *)st.GetHugeDataPtr(baseOffset);
   basePtr->UpdateAddrVars(qualAddrRange->startAddr, qualAddrRange->endAddr);

   return GOOD;
}

//--------------------------------------------------------------------------
// SymSetSymbolAddrByDesc
//--------------------------------------------------------------------------
RETCODE EXPORT SymSetSymbolAddrByDesc(SYM_DESCRIPTOR symDesc,
                                      OFFSET_ADDR_RANGE_TYPE *addrRange) {

   RETCODE err;
   COMMON_SYMBOL_HEADER HUGE *symPtr;
   BaseSymbol HUGE *basePtr;
   SYM_DESCRIPTOR baseOffset;
   U8             tmpSymType;

   if (!addrRange ||
       !(addrRange->offsetStartAddr || addrRange->offsetEndAddr))
      return ER_NO_VALID_ADDRESS;
  
   // Get symbol storage structure of the input symDesc 
   if (!symDesc) return ER_INVALID_SYM_DESCRIPTOR;
   symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(symDesc);
   if (!symPtr) return ER_INVALID_SYM_DESCRIPTOR;
   
   tmpSymType = (symPtr->typeIndex.symType) & 0xF;
   switch (tmpSymType) {
      case SYM_FUNCTION:
      case SYM_BLOCK:
      case SYM_MODULE:
         break;  // valid cases to update address
      default:
         return ER_INVALID_SYM_DESCRIPTOR;
   }
   
   // update the symbol address range
   symPtr->beginAddrInfo.startAddr = addrRange->offsetStartAddr;
   symPtr->endAddrInfo.endAddr = addrRange->offsetEndAddr;
   
   // update the base address range.  This can only be done for code bases 
   // here
   if ((err = bit.GetOffset(symPtr->typeIndex.baseIndex, baseOffset)) != GOOD)
      return err;
   basePtr = (BaseSymbol HUGE *)st.GetHugeDataPtr(baseOffset);
   basePtr->UpdateAddrVars(addrRange->offsetStartAddr,
                           addrRange->offsetEndAddr);
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeBitfield
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeBitfield(TYPE_INDEX typeIndex,
                                  TYPE_BITFIELD_STRUCT *bitfieldStruct) {
   RETCODE err;
   TABLE_OFFSET offset;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   
   if ((err = tt.PutBytes((U8 *)bitfieldStruct, sizeof(TYPE_BITFIELD_STRUCT),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_BITFIELD_STRUCT))) != GOOD) 
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddTypeCArray
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeCArray(TYPE_INDEX typeIndex,
                                TYPE_Z_STRUCT *cArrayStruct) {
   RETCODE err;
   TABLE_OFFSET offset;
   
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   
   if ((err = tt.PutBytes((U8 *)cArrayStruct, sizeof(TYPE_Z_STRUCT),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_Z_STRUCT))) != GOOD) 
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeEnum
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeEnum(TYPE_INDEX typeIndex, U32 enumValue,
                              LPSTR enumName) {
   RETCODE err;
   TABLE_OFFSET offset;
   ENUM_TYPE_STRUCT enumStruct;
   
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   
   if ((err = st.PutString(enumName, offset)) != GOOD) return err;
   
   enumStruct.enumValue = enumValue;
   enumStruct.enumName = offset;
   
   if ((err = tt.PutBytes((U8 *)&enumStruct, sizeof(ENUM_TYPE_STRUCT),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(ENUM_TYPE_STRUCT))) != GOOD) 
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}
//--------------------------------------------------------------------------
// SymAddTypeFunc
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeFunc(TYPE_INDEX typeIndex, U32 attribute,
               U8 frameType, U32 pushMask, TYPE_INDEX returnType,
               U8 argCount, U8 level, LPSTR fatherName) {
   
   FUNC_TYPE_HEADER funcTypeHeader;
   TABLE_OFFSET nameOffset,typeOffset;
   RETCODE err;

   // check to make sure the type index matches the index of the last ;
   // type header created. ;
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   // put the type name into the symbol table, if it exists ;
   if (fatherName[0]) {
      if ((err = st.PutString(fatherName,nameOffset)) != GOOD) return err;
   } else {
      nameOffset = NULL_SYMBOL;
   }

   funcTypeHeader.attribute = attribute;
   funcTypeHeader.frameType = frameType;
   funcTypeHeader.pushMask = pushMask;
   funcTypeHeader.returnType = returnType;
   funcTypeHeader.argCount = argCount;
   funcTypeHeader.level = level;
   funcTypeHeader.fatherName = nameOffset;

   // put the function info into the type table. ;
   if ((err = tt.PutBytes((U8 *)&funcTypeHeader, sizeof(FUNC_TYPE_HEADER),
      typeOffset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(FUNC_TYPE_HEADER))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;
   
   
   return GOOD;
}


//--------------------------------------------------------------------------
// SymAddTypeFuncParam
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeFuncParam(TYPE_INDEX typeIndex,
                                   TYPE_INDEX paramTypeIndex) {

   RETCODE err;
   TABLE_OFFSET typeOffset;
   
   // check to make sure the type index matches the index of the last ;
   // type header created. ;
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   
   if ((err = tt.PutBytes((U8 *)&paramTypeIndex, sizeof(TYPE_INDEX), 
      typeOffset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_INDEX))) != GOOD) return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;
   
   return GOOD;
}
//--------------------------------------------------------------------------
// SymAddTypeHeader
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeHeader(TYPE_INDEX typeIndex,
                                TYPE_HEADER_TYPE *typeHeader) {
   RETCODE err;
   TYPE_HEADER_TYPE2 typeHdr;
   TABLE_OFFSET nameOffset = 0;
   typeHdr.typeChoice = typeHeader->typeChoice;
   
   if (typeHdr.typeChoice == SIMPLE_TYPE_CLASS) 
      typeHdr.t.simpleType = typeHeader->t.simpleType;
   else 
      typeHdr.t.complexType = typeHeader->t.complexType;

   // NOTES: 09/15/93 - Nghia
   // Fill in the size of MAU if known, otherwise wait to calculate the
   // sizeInMAUs of this type until it's get access by someone.
   // This way forward reference type will never need to know the sizeInMAUs
   // of its type before hand.
   typeHdr.sizeCalculated = typeHeader->sizeCalculated;
   if (typeHdr.sizeCalculated) 
      typeHdr.sizeInMAUs = typeHeader->sizeInMAUs;
   else
      typeHdr.sizeInMAUs = 0L;
   
   typeHdr.recordSize = sizeof(TYPE_HEADER_TYPE2);
   // set member count to 0; the first member added will bump it to the
   // valid value of 1.
   typeHdr.memberCount = 0;    
   
   // put the header name if it exists ;
   if(typeHeader->typeName[0]) {
      if ((err = st.PutString(typeHeader->typeName,nameOffset)) != GOOD) 
         return err;
   }
   typeHdr.typeName = nameOffset;
   typeHdr.dirty = typeHeader->dirty;
   if ((err = tt.PutHeader((U8 *)&typeHdr,typeHdr.recordSize,typeIndex))
      != GOOD) return err;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeOverwriteSize
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeOverwriteSize(U8 typeIndex, U8 typeMAUSize) {
   RETCODE err;
   TYPE_HEADER_TYPE2 HUGE *typePtr;
   TABLE_OFFSET typeOffset;

   if((err = typit.GetOffset(typeIndex,typeOffset)) != GOOD) return err;
   typePtr = (TYPE_HEADER_TYPE2 HUGE *) tt.GetHugeDataPtr(typeOffset);
   typePtr->sizeInMAUs = typeMAUSize; 
   typePtr->sizeCalculated = TRUE;
   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypePointerTypeIndex
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypePointerTypeIndex(TYPE_INDEX typeIndex,       
                                          TYPE_INDEX pointerTypeIndex) {
   RETCODE err;
   TABLE_OFFSET offset;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = tt.PutBytes((U8 *)&pointerTypeIndex, sizeof(TYPE_INDEX),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_INDEX))) != GOOD) return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}
//--------------------------------------------------------------------------
// SymAddTypeReferenceTypeIndex --Hera 2/9/98
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeReferenceTypeIndex(TYPE_INDEX typeIndex,       
                                          TYPE_INDEX referenceTypeIndex) {
   RETCODE err;
   TABLE_OFFSET offset;

   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;

   if ((err = tt.PutBytes((U8 *)&referenceTypeIndex, sizeof(TYPE_INDEX),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_INDEX))) != GOOD) return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}
//--------------------------------------------------------------------------
// SymAddTypeClass
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeClass(TYPE_INDEX typeIndex,
                                     TYPE_C_STRUCT *cls) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_STRUCT_HEADER clsHdr;
   
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   
   if ((err = st.PutString(cls->name,offset)) != GOOD) return err;
   
   clsHdr.nameOffset = offset;
   clsHdr.typeIndex = cls->typeIndex;
   clsHdr.offset = cls->offset;
   
   if ((err = tt.PutBytes((U8 *)&clsHdr, sizeof(TYPE_CLASS_HEADER),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_CLASS_HEADER))) != GOOD)
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeStructUnion
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeStructUnion(TYPE_INDEX typeIndex,
                                     TYPE_S_U_STRUCT *structOrUnion) {
   RETCODE err;
   TABLE_OFFSET offset;
   TYPE_STRUCT_HEADER structHdr;
   
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   
   if ((err = st.PutString(structOrUnion->name,offset)) != GOOD) return err;
   
   structHdr.nameOffset = offset;
   structHdr.typeIndex = structOrUnion->typeIndex;
   structHdr.offset = structOrUnion->offset;
   
   if ((err = tt.PutBytes((U8 *)&structHdr, sizeof(TYPE_STRUCT_HEADER),
      offset)) != GOOD) return err;
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_STRUCT_HEADER))) != GOOD) 
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddTypeTypeIndex
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddTypeTypeIndex(TYPE_INDEX typeIndex,       
                                   TYPE_INDEX typeTypeIndex) {
   RETCODE err;
   TABLE_OFFSET offset;

   
   if (typeIndex != tt.GetTypeIndex())
      return ER_TYPE_IDXS_DONT_MATCH;
   
   if ((err = tt.PutBytes((U8 *)&typeTypeIndex, sizeof(TYPE_INDEX),
      offset)) != GOOD) return err;
   // NOTES: 09/15/93 - Nghia
   // Update record size with sizeof(TYPE_INDEX) only,
   // not sizeof(TYPE_STRUCT_HEADER) which is way too big
   if ((err = tt.UpdateRecordSize(sizeof(TYPE_INDEX))) != GOOD) 
      return err;
   if ((err = tt.IncrementMemberCount()) != GOOD) return err;

   return GOOD;
}

//--------------------------------------------------------------------------
// SymAddVar
//
// NOTES: variable size is held in variable symbol record; i.e. it does not
//        have to be extracted from the type field
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddVar(LPSTR              varName,
                         BASE_INDEX         baseIndex, 
                         TYPE_INDEX         typeIndex,
                         VAR_STORAGE_CLASS  storageClass,
                         VAR_REGISTER_CLASS registerClass,
                         ADD_VAR_ADDR_UNION FAR *varAddr,
                         BOOLEAN            isConstant,
                         BOOLEAN            isValidAddr,
                         SYM_DESCRIPTOR FAR *varDesc) {

   RETCODE                err;
   TABLE_OFFSET           nameOffset,varOffset,baseOffset,typeOffset;
   HPU8                   var;
   BOOLEAN                duplicateName = FALSE;
   U16                    allocSize;
   SYM_TYPE_VARIABLE HUGE *varSym;
   TYPE_HEADER_TYPE2 HUGE *typeHeader;
   VAR_BASED_VAR HUGE     *basedPtr;
   AUTO_VAR_OFFSET HUGE   *autoVarPtr;
   SYM_LIFETIME_START_INFO HUGE *lifetimePtr;
   SYM_TYPE_TYPE          tmpSymType;
   U8                     misses;

   // check to make sure the type index and base index exist;
   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD)
      return err;
   if((err = typit.GetOffset(typeIndex,typeOffset)) != GOOD)
      return err;

   if ((storageClass == GLOBAL_VAR_CLASS) || 
      (storageClass == UNKNOWN_VAR_CLASS)) {
      // find out if the variable name already exists. ;
      if ((err = ht.LookupName(varName, varOffset, misses)) != GOOD) 
         return err;
      if (varOffset)
         return ER_DUPLICATE_GLOBAL_NAME;
   }
   // trap on items not implemented yet ;
   if (( registerClass == SHADOW_REG ) ||
      ( (registerClass != NOT_REG) && (storageClass == BASED_VAR_CLASS)))
      return ER_NOT_IMPLEMENTED;

   if((err = st.PutString(varName,nameOffset)) != GOOD)
      return err;

   // get memory for the variable in the symbol pool ;
   switch (registerClass) {
      case NOT_REG:
         if (storageClass != BASED_VAR_CLASS) {
            allocSize = sizeof(SYM_TYPE_VARIABLE);
         } else {
            allocSize = sizeof(SYM_TYPE_VARIABLE) + sizeof(VAR_BASED_VAR);
         }
         break;
      case LIVING_REG:
         allocSize = sizeof(SYM_LIFETIME_START_INFO) + 
            sizeof(SYM_TYPE_VARIABLE);
         break;
      case SHADOW_REG:
         // @@ !!! this is a dummy value ;
         allocSize = sizeof(SYM_TYPE_VARIABLE);
         break;
      case LOCKED_REG:
         allocSize = sizeof(AUTO_VAR_OFFSET) + sizeof(SYM_TYPE_VARIABLE) +
                     sizeof(SYM_LIFETIME_START_INFO);
         break;
   }

   // allocate the number of bytes just calculated. ;
   if((err = st.AllocBytes(allocSize, varOffset)) != GOOD)
      return err;

   varSym = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(varOffset);
   ClearEntry(varSym, sizeof(SYM_TYPE_VARIABLE));
   
   // put the offset of the symbol name into the variable entry ;
   // before it gets put into the global hash table. ;
   varSym->symHeader.symbolNameOffset = nameOffset;

   // an unknown var is considered a global; put either into hash table
   if ((storageClass == GLOBAL_VAR_CLASS) ||
                        (storageClass == UNKNOWN_VAR_CLASS)) {     
      varSym->symHeader.typeIndex.symType = SYM_GLOBAL_VAR;
      if((err = ht.PutName(varOffset,duplicateName)) != GOOD)
         return err;
      // this should never happen, but leave it anyway. ;
      if(duplicateName)
         return ER_DUPLICATE_GLOBAL_NAME;
   } 
   else {
      varSym->symHeader.typeIndex.symType = SYM_LOCAL_VAR;
   }

   // NOTE: 02/17/94 - Nghia
   // BUG in GlobalReAlloc() that trash pointer
   varSym = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(varOffset);
   
   // save the type of symbol for tally
   tmpSymType = varSym->symHeader.typeIndex.symType;
   
   varSym->symHeader.typeIndex.baseIndex = baseIndex;
   varSym->symHeader.symParentOffset = currentOpenContext;
   varSym->symHeader.symSiblingOffset = 0;
   
   typeHeader = (TYPE_HEADER_TYPE2 HUGE *)tt.GetHugeDataPtr(typeOffset);

   // store the address info of the register using the storageClass and ;
   // the registerClass of the variable.  Make sure the address is valid. ;
   if (isValidAddr) {
      if (registerClass == NOT_REG) {
         switch (storageClass) {
            case STATIC_VAR_CLASS:
            case UNKNOWN_VAR_CLASS:
            case GLOBAL_VAR_CLASS:
               varSym->symHeader.beginAddrInfo.startAddr =
                  varAddr->fixedAddr;
               if (typeHeader->sizeInMAUs == 0L) {
                  // !!! should isValidAddr be set to FALSE if the
                  // MAU size is 0???
                  // a size of 0 is not represented by the address start-end
                  // structure.  Set end equal to start for this case anyway
                  varSym->symHeader.endAddrInfo.endAddr =
                  varSym->symHeader.beginAddrInfo.startAddr;
               } else {
                  varSym->symHeader.endAddrInfo.endAddr =
                     varSym->symHeader.beginAddrInfo.startAddr + 
                     typeHeader->sizeInMAUs - 1;
                  break;
               }

            case AUTO_VAR_CLASS:
               varSym->symHeader.beginAddrInfo.autoVarOffset =
                  varAddr->autoVar;
               varSym->symHeader.endAddrInfo.varSize = typeHeader->sizeInMAUs;
            break;

            case BASED_VAR_CLASS:
               // based variables have a separate structure to hold data;
               varSym->symHeader.beginAddrInfo.startAddr = 0L;
               varSym->symHeader.endAddrInfo.varSize = typeHeader->sizeInMAUs;

               // get a pointer to the memory just below the common header ;
               basedPtr = (VAR_BASED_VAR HUGE *)st.GetHugeDataPtr(varOffset +
                  sizeof(SYM_TYPE_VARIABLE));
               basedPtr->offsetVal = varAddr->basedVar.offsetVal;
               basedPtr->controlNum = varAddr->basedVar.controlNum;
               basedPtr->publicLocal = varAddr->basedVar.publicLocal;
               basedPtr->memorySpace = varAddr->basedVar.memorySpace;
               basedPtr->baseSize = varAddr->basedVar.baseSize;
            break;

            default:
               return ER_STORAGE_CLASS_UNKNOWN;
         }
      } else {
         if (registerClass == LOCKED_REG) {

            // store the "address" ;
            varSym->symHeader.beginAddrInfo.registerIndex =
               varAddr->lockedReg.regIndex;
            varSym->symHeader.endAddrInfo.varSize = 
               typeHeader->sizeInMAUs;
            
            // the additional frame offset (autoVarOffset) must be ;
            // placed in separate space after the standard variable ;
            //data (like based variable) ;
            autoVarPtr = (AUTO_VAR_OFFSET HUGE *)st.GetHugeDataPtr(varOffset +
               sizeof(SYM_TYPE_VARIABLE));
            *autoVarPtr = varAddr->lockedReg.autoVarOffset;
            
            lifetimePtr = (SYM_LIFETIME_START_INFO HUGE *)
               st.GetHugeDataPtr(varOffset + sizeof(SYM_TYPE_VARIABLE) +
               sizeof(AUTO_VAR_OFFSET));
            lifetimePtr->firstEntry = NULL_SYMBOL;
            lifetimePtr->lastEntry = NULL_SYMBOL;

         } else if (registerClass == LIVING_REG) {
            // store away the "address" ;
            varSym->symHeader.beginAddrInfo.registerIndex =
               varAddr->registerIndex;
            varSym->symHeader.endAddrInfo.varSize = 
               typeHeader->sizeInMAUs;

            lifetimePtr = (SYM_LIFETIME_START_INFO HUGE *)
               st.GetHugeDataPtr(varOffset + sizeof(SYM_TYPE_VARIABLE));
            lifetimePtr->firstEntry = NULL_SYMBOL;
            lifetimePtr->lastEntry = NULL_SYMBOL;

         } else {
            // this should never happen.  See above. ;
            return ER_NOT_IMPLEMENTED;
         }
      }
   } // end isValidAddr ;

   varSym->typeIndex = typeIndex;
   varSym->storageClass = storageClass;
   varSym->registerClass = registerClass;
   varSym->isConstant = isConstant;    /* indicates a const var or not */
   varSym->isValidAddr = isValidAddr;  /* sets flag for valid addr or not */

   // fill in the ordinal value of this symbol ;
   if((err = AddOrdinalValue(varOffset)) != GOOD)
      return err;

   // if there was a var loaded previously in this block then its sibling ;
   // pointer points to this variable
   if(lastVariable) {
      var = st.GetHugeDataPtr(lastVariable);
      ((SYM_TYPE_VARIABLE *)var)->symHeader.symSiblingOffset = varOffset;
   } else {
      // if this is the first variable loaded for this block then we want ;
      // that module/func/blocks var list pointer pointing to this variable ;
      var = st.GetHugeDataPtr(currentOpenContext);
      ((COMMON_BLOCK_HEADER *)var)->list.varListOffset = varOffset;
   }
   // update the base for this symbol and add it to the by-address table ;
   // if it is static/global/unknown and the address given is valid.;
   if (((storageClass == STATIC_VAR_CLASS) ||
      (storageClass == GLOBAL_VAR_CLASS) ||
      (storageClass == UNKNOWN_VAR_CLASS)) && isValidAddr ) {
      if ((err = AddAddrToByAddrTable(baseIndex, varOffset,
         varSym->symHeader.beginAddrInfo.startAddr,
         varSym->symHeader.endAddrInfo.endAddr))
         != GOOD)
         return err;
   }
   lastVariable = varOffset;

   // return a descriptor to the variable.  In this case it is the offset ;
   // into the global symbol table. ;
   *varDesc = varOffset;

   // tally the symbol
   symbolStat[tmpSymType]++;
   
   return GOOD;
}  // end of SymAddVar


//--------------------------------------------------------------------------
// SymAddVarPublic
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddVarPublic(LPSTR varName, BASE_INDEX baseIndex,
                               TYPE_INDEX typeIndex, 
                               OFFSET_ADDR_TYPE varAddr) {

   COMMON_SYMBOL_HEADER HUGE *symPtr;
   RETCODE            err;
   TABLE_OFFSET       varOffset,baseOffset,typeOffset;
   U8                 misses;
   SYM_TYPE_VARIABLE  HUGE *varSym;
   SYM_TYPE_VARIABLE  HUGE *varAccessPtr;
   VAR_STORAGE_CLASS  storageClass;
   TYPE_HEADER_TYPE2  HUGE *typeHeader;
   TABLE_OFFSET       nameOffset;
   BOOLEAN            duplicateName;
   U8                 tmpSymType;

   // check to make sure the type index and base index exist;
   if((err = bit.GetOffset(baseIndex,baseOffset)) != GOOD) return err;
   if((err = typit.GetOffset(typeIndex,typeOffset)) != GOOD) return err;

   // find out if the variable name already exists. ;
   if ((err = ht.LookupName(varName, varOffset, misses)) != GOOD) return err;
   if (varOffset) {
      symPtr = (COMMON_SYMBOL_HEADER HUGE *)st.GetHugeDataPtr(varOffset);
      tmpSymType = (symPtr->typeIndex.symType) & 0xF;
      if (!((tmpSymType == SYM_GLOBAL_VAR) || 
           (tmpSymType == SYM_PUBLIC_VAR) ||
           (tmpSymType == SYM_PUBLIC_LABEL) ||
           (tmpSymType == SYM_PUBLIC_UNKNOWN))) {
         return ER_NOT_A_VARIABLE;
      } else {
         varSym = (SYM_TYPE_VARIABLE *)symPtr;
         if (varSym->isValidAddr) 
            return ER_PUBLIC_IGNORED;
         else {
            // fill in the address and return ;
            // must get valid type index from variable record
            typeIndex = varSym->typeIndex;
            if ((err = typit.GetOffset(typeIndex,typeOffset)) != GOOD) 
               return err;
            
            // update the base index for the public symbol ;
            varSym->symHeader.typeIndex.baseIndex = baseIndex;
            
            // update the address for the existing public symbol ;
            typeHeader = (TYPE_HEADER_TYPE2 HUGE *)
               tt.GetHugeDataPtr(typeOffset);
            if (varSym->registerClass == NOT_REG) {
               storageClass = varSym->storageClass;
               switch (storageClass) {
                  case STATIC_VAR_CLASS:
                  case UNKNOWN_VAR_CLASS:
                  case GLOBAL_VAR_CLASS:
                     varSym->symHeader.beginAddrInfo.startAddr = varAddr;

                     // !!! should isValidAddr be set to FALSE if the
                     // MAU size is 0???
                     // enter end address.  Points to last byte of var
                     // which equals startAddr + sizeInMAUs - 1.
                     // If size is zero, set to start address
                     if (typeHeader->sizeInMAUs == 0) {
                        varSym->symHeader.endAddrInfo.endAddr = 
                        varSym->symHeader.beginAddrInfo.startAddr;
                     } else {
                        varSym->symHeader.endAddrInfo.endAddr = 
                        varSym->symHeader.beginAddrInfo.startAddr + 
                        (typeHeader->sizeInMAUs - 1);
                     };
                     varSym->isValidAddr = TRUE;
                     // now add to by-address-table
                     if ((err = AddAddrToByAddrTable(
                                   baseIndex,
                                   varOffset,
                                   varSym->symHeader.beginAddrInfo.startAddr,
                                   varSym->symHeader.endAddrInfo.endAddr))
                        != GOOD) return err;
                  break;
               default:
                  return ER_STORAGE_CLASS_UNKNOWN;
               }
            } else {
               return ER_SYM_REG_VAR_NOT_ALLOWED;
            }  // end of varPtr->registerClass ;
            return ER_ADDRESS_UPDATED;
         }
      }
   } else {  // variable not already loaded; chain off root directory as
             // a public variable
      if((err = st.PutString(varName,nameOffset)) != GOOD) return err;
      if((err = st.AllocBytes(sizeof(SYM_TYPE_VARIABLE), varOffset))
         != GOOD) return err;
      
      // NOTE: 02/17/94 - Nghia
      // BUG in GlobalReAlloc() that might trash the varSym pointer
      varSym = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(varOffset);
      ClearEntry(varSym, sizeof(SYM_TYPE_VARIABLE));

      varSym->symHeader.typeIndex.symType = SYM_PUBLIC_VAR;
      varSym->symHeader.typeIndex.baseIndex = baseIndex;
      varSym->symHeader.symbolNameOffset = nameOffset;
      varSym->symHeader.symParentOffset = rootOffset;
      varSym->symHeader.symSiblingOffset = 0;
   
      typeHeader = (TYPE_HEADER_TYPE2 HUGE *)tt.GetHugeDataPtr(typeOffset);
      varSym->symHeader.beginAddrInfo.startAddr = varAddr;
      if (typeHeader->sizeInMAUs == 0L) {
         // !!! should isValidAddr be set to FALSE if the
         // MAU size is 0???
         // a size of 0 is not represented by the address start-end
         // structure.  Set end equal to start for this case anyway
         varSym->symHeader.endAddrInfo.endAddr =
         varSym->symHeader.beginAddrInfo.startAddr;
      } else {
         varSym->symHeader.endAddrInfo.endAddr =
            varSym->symHeader.beginAddrInfo.startAddr + 
            typeHeader->sizeInMAUs - 1;
      }
      varSym->typeIndex =     typeIndex;
      varSym->storageClass =  UNKNOWN_VAR_CLASS;
      varSym->registerClass = NOT_REG;
      varSym->isConstant =    FALSE;
      varSym->isValidAddr =   TRUE;

      // if there were any public vars loaded previously, its sibling
      // pointer points to this variable
      if(lastPublicVariable) {
         varAccessPtr =
            (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(lastPublicVariable);
         ((SYM_TYPE_VARIABLE *)varAccessPtr)->symHeader.symSiblingOffset =
            varOffset;
      } else {
         // first public variable; chain off root symbol var linked list
         varAccessPtr =
            (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(rootOffset);
         ((COMMON_BLOCK_HEADER *)varAccessPtr)->list.varListOffset =
            varOffset;
      }   
      lastPublicVariable = varOffset;  // save away for next time thru

      // put the public var name into the global hash table ;
      if((err = ht.PutName(varOffset,duplicateName)) != GOOD) return err;
      if(duplicateName) // should never be a duplicate, but leave anyway
         return ER_DUPLICATE_GLOBAL_NAME;


      // NOTE: 02/17/94 - Nghia
      // BUG in GlobalReAlloc() that might trash the varSym pointer
      varSym = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(varOffset);

      if (GOOD != (err =
         AddAddrToByAddrTable(baseIndex,
                              varOffset,
                              varSym->symHeader.beginAddrInfo.startAddr,
                              varSym->symHeader.endAddrInfo.endAddr)))
	 return err;

      // fill in the ordinal value of this symbol ;
      if((err = AddOrdinalValue(varOffset)) != GOOD) return err;

      // tally variable symbol
      symbolStat[varSym->symHeader.typeIndex.symType]++;
   }
   return GOOD;
}  // end of SymAddVarPublic


//--------------------------------------------------------------------------
// SymAddVarLifetimeInfo
//--------------------------------------------------------------------------
RETCODE EXPORT SymAddVarLifetimeInfo(SYM_DESCRIPTOR variable,
                                     VAR_LIFETIME_INFO *lifetimeVarInfo) {
   RETCODE                      err;
   SYM_TYPE_VARIABLE HUGE       *varPtr;
   SYM_LIFETIME_START_INFO HUGE *lifetimeStartPtr;
   SYM_LIFETIME_INFO HUGE       *lifetimePtr;
   TABLE_OFFSET                 lifetimeOffset, lifetimeStartOffset;
   U8                           tmpSymType;
   
   // make sure the symbol descriptor is ok
   if (!UtilIsValidSymDescriptor(variable))
      return ER_INVALID_SYM_DESCRIPTOR;

   // make sure this is a variable symbol ;
   varPtr = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(variable);
   tmpSymType = (varPtr->symHeader.typeIndex.symType) & 0xF;
   if (!((tmpSymType == SYM_GLOBAL_VAR) ||
        (tmpSymType == SYM_LOCAL_VAR)  ||
        (tmpSymType == SYM_PUBLIC_VAR) ||
        (tmpSymType == SYM_PUBLIC_UNKNOWN))) {
      return ER_NOT_A_VARIABLE;
   }
   if (varPtr->registerClass == NOT_REG)
      return ER_NO_LIFETIME_INFO;
   
   // allocate the memory for the new lifetime info. ;
   if ((err = st.AllocBytes(sizeof(SYM_LIFETIME_INFO), lifetimeOffset))
      != GOOD) return err;
   
   // NOTES: Nghia - 10/20/93
   // BUG in symbol table.  When st.AllocsBytes() extends the table size,
   // GlobalReAlloc() wiped out varPtr old value.  Which caused a UAE.
   // Update the old varPtr.
   varPtr = (SYM_TYPE_VARIABLE HUGE *)st.GetHugeDataPtr(variable);
   
   switch (varPtr->registerClass) {
      case LOCKED_REG:
         lifetimeStartOffset = variable + sizeof(AUTO_VAR_OFFSET) +
            sizeof(SYM_TYPE_VARIABLE);
         break;

      case LIVING_REG:
         lifetimeStartOffset = variable + sizeof(SYM_TYPE_VARIABLE);
         break;

      case SHADOW_REG:
         return ER_NOT_IMPLEMENTED;

      default:
         return ER_NOT_IMPLEMENTED;
   }
   lifetimeStartPtr = (SYM_LIFETIME_START_INFO HUGE *)
      st.GetHugeDataPtr(lifetimeStartOffset);
   
   if (NULL_SYMBOL == lifetimeStartPtr->lastEntry) {
      lifetimeStartPtr->firstEntry = lifetimeOffset;
   } else {
      // fill in the link to the new lifetime info. ;
      lifetimePtr = (SYM_LIFETIME_INFO HUGE *) 
                    st.GetHugeDataPtr(lifetimeStartPtr->lastEntry);
      lifetimePtr->nextLifetimeInfo = lifetimeOffset;
   }
   // fix up the pointer to the last lifetime info added. ;
   lifetimeStartPtr->lastEntry = lifetimeOffset;
   
   // fill in the new lifetime info. ;
   lifetimePtr = (SYM_LIFETIME_INFO HUGE *) st.GetHugeDataPtr(lifetimeOffset);
   
   lifetimePtr->lifetimeInfo.lifetimeAddr = lifetimeVarInfo->lifetimeAddr;
   lifetimePtr->lifetimeInfo.lifetimeClass = lifetimeVarInfo->lifetimeClass;
   lifetimePtr->nextLifetimeInfo = NULL_SYMBOL;
   
   return GOOD;
}


/****************************************************************************
**
**  UpdateBlockInfo
**
**  Description:
**     This function updates all of the pointers associated with the
**     currently open block/function/module symbols.  It performs 
**     different actions based upon what the current action is 
**     (opening/closing a symbol) and what the previous symbol action 
**     was.  Using this information the symbol stack will be modified,
**     symbol pointers will be filled in, etc...
**     
**  Parameters:
**     input:
**        symbolOff:  The offset into the symbol memory pool of the symbol
**                    to be modified.  (NULL on a CLOSE symbol command)
**        action: The current action to be performed on the symbol table.
**                ie. OPEN a symbol, or CLOSE a symbol.
**     output:
**        none:
**        (returns): error code
**
*****************************************************************************/

/****************************************************************************
**
**    UpdateBlockInfo: Theory of Operation
**
**    The UpdateBlockInfo function is implemented using a state machine.
**    The state machine uses the previous open/close action along with the
**    current open/close action to decide the function to be performed.
**    These functions are:
**       previous action      current action    function performed
**------------------------------------------------------------------------
**       OPEN_SYMBOL          OPEN_SYMBOL       we are creating a child 
**                                              symbol to the last symbol
**                                              that was created.
**       OPEN_SYMBOL          CLOSE_SYMBOL      we are closing the current
**                                              symbol (either a child or
**                                              a sibling symbol).
**       CLOSE_SYMBOL         OPEN_SYMBOL       we are creating a sibling
**                                              symbol to the last symbol
**                                              that was created.
**       CLOSE_SYMBOL         CLOSE_SYMBOL      we are popping back to the
**                                              parent of the last symbol 
**                                              created.
**
**    At each of these actions are performed the parent/child/sibling 
**    pointers that are known are filled in.  (ie. if we are creating a 
**    child symbol, then the parent symbols child pointer (got that?) is
**    filled in with the address of the child symbol.  Likewise, the child
**    symbols parent pointer is filled in with the address of the parent
**    symbol.)  In the cases where the symbol is being closed, no pointers
**    are filled in and only the next symbol we will deal with is operated
**    upon.
**
************************************************************************/
RETCODE UpdateBlockInfo(TABLE_OFFSET symbolOff,SYM_ACTION action) {
   
   TABLE_OFFSET symbol;
   COMMON_BLOCK_HEADER HUGE *prevSymPtr;
   COMMON_BLOCK_HEADER HUGE *curSymPtr;
   
   if(action ==SYM_OPEN) {
      symbol = lastOpened = symbolOff;
      curSymPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(symbol);
      prevSymPtr = (COMMON_BLOCK_HEADER HUGE *)st.GetHugeDataPtr(prevSym);
   }
      

// determine what action to take based upon the last OPEN/CLOSE operation. ;
// the initial value is defined before creating the ROOT entry in ;
// InitSymTable ;
   switch (prevAction) {
      case SYM_OPEN:
         switch (action) {
            case SYM_OPEN:
               prevSymPtr->child = currentOpenContext = symbol;
               curSymPtr->symHeader.symParentOffset = prevSym;
               PushSymStack(prevSym);
               break;

            case SYM_CLOSE:
               symbol = lastOpened;
               currentOpenContext = symStack[topSymStack];
               break;

            default:
               return ER_UPDATE_BLOCK_FAIL; // this error should never occur
         }
         break;  //prevAction SYM_OPEN

      case SYM_CLOSE:
         switch (action) {
            case SYM_OPEN:
               curSymPtr->symHeader.symParentOffset = 
                  prevSymPtr->symHeader.symParentOffset;
               prevSymPtr->symHeader.symSiblingOffset = symbol;
               currentOpenContext = symbol;
               break;

            case SYM_CLOSE:
               PopSymStack(symbol); // pass by reference
               currentOpenContext = symbol;
               break;

            default:
	       return ER_UPDATE_BLOCK_FAIL; // this error should never occur
         }
         break;  //prevAction SYM_CLOSE

      default:
         return ER_UPDATE_BLOCK_FAIL; // this error should never occur ;
   }
   prevSym = symbol;
   prevAction = action;
   return GOOD;
}

/******************************************************************
*  For C++, modify the relationship between modules and functions *
*                                                                 *
*******************************************************************/
RETCODE EXPORT SymModifyRelation(){
   SYM_DESCRIPTOR moduleDesc,funcDesc;
   HPU8 modPtr,funcPtr;
   SYM_TYPE_TYPE symType;
   RETCODE err = GOOD;

   if((err = SymGetModuleListHead(&moduleDesc)) != GOOD)
      return(err);
   while (moduleDesc){
      U32 mstartaddr, mendaddr;

      modPtr = st.GetHugeDataPtr(moduleDesc);
      mstartaddr = ((COMMON_SYMBOL_HEADER HUGE*)modPtr)->beginAddrInfo.startAddr;
      mendaddr = ((COMMON_SYMBOL_HEADER HUGE*)modPtr)->endAddrInfo.endAddr;
      if((err = SymGetSymbolChild(moduleDesc, &symType, &funcDesc)) != GOOD)
         return(err);
      while (funcDesc) {
	 U32 startaddr, endaddr;
	 SYM_DESCRIPTOR newmoduleDesc;

	 funcPtr = st.GetHugeDataPtr(funcDesc);
	 startaddr = ((COMMON_SYMBOL_HEADER HUGE*)funcPtr)->beginAddrInfo.startAddr;
	 endaddr = ((COMMON_SYMBOL_HEADER HUGE*)funcPtr)->endAddrInfo.endAddr;
	 if (startaddr >= mstartaddr && endaddr <= mendaddr) break;
	 else {
	     U32 mstarttmp,mendtmp;
	    if ((err = SymGetModuleListHead(&newmoduleDesc)) != GOOD)
               return(err);
	    //SymGetSymbolSibling(moduleDesc,&symType,&newmoduleDesc);	    
	    while (newmoduleDesc) {
	       modPtr = st.GetHugeDataPtr(newmoduleDesc);
	       mstarttmp = ((COMMON_SYMBOL_HEADER HUGE*)modPtr)->beginAddrInfo.startAddr;
	       mendtmp = ((COMMON_SYMBOL_HEADER HUGE*)modPtr)->endAddrInfo.endAddr;
	       if (startaddr >= mstarttmp && endaddr <= mendtmp){
		  ((COMMON_SYMBOL_HEADER HUGE*)funcPtr)->symParentOffset = newmoduleDesc;
	          break;
               }
	       else
		  SymGetSymbolSibling(newmoduleDesc,&symType,&newmoduleDesc);
	    }	    
	 }
	 SymGetSymbolSibling(funcDesc,&symType,&funcDesc);
      }
      SymGetSymbolSibling(moduleDesc,&symType,&moduleDesc);
   }
   return(err);
}
               
	        
      
/******************************** E O F ***********************************/
