1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-28 19:29:53 +00:00
cc65/src/ca65/symtab.c

1246 lines
32 KiB
C
Raw Normal View History

/*****************************************************************************/
/* */
/* symtab.c */
/* */
/* Symbol table for the ca65 macroassembler */
/* */
/* */
/* */
/* (C) 1998-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <string.h>
/* common */
#include "cddefs.h"
#include "check.h"
#include "hashstr.h"
#include "symdefs.h"
#include "xmalloc.h"
/* ca65 */
#include "global.h"
#include "error.h"
#include "expr.h"
#include "objfile.h"
#include "scanner.h"
#include "symtab.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Bits for the Flags value in SymEntry */
#define SF_USER 0x0001 /* User bit */
#define SF_TRAMPOLINE 0x0002 /* Trampoline entry */
#define SF_EXPORT 0x0004 /* Export this symbol */
#define SF_IMPORT 0x0008 /* Import this symbol */
#define SF_GLOBAL 0x0010 /* Global symbol */
#define SF_ZP 0x0020 /* Declared as zeropage symbol */
#define SF_ABS 0x0040 /* Declared as absolute symbol */
#define SF_LABEL 0x0080 /* Used as a label */
#define SF_INDEXED 0x0800 /* Index is valid */
#define SF_CONST 0x1000 /* The symbol has a constant value */
#define SF_MULTDEF 0x2000 /* Multiply defined symbol */
#define SF_DEFINED 0x4000 /* Defined */
#define SF_REFERENCED 0x8000 /* Referenced */
/* Combined stuff */
#define SF_UNDEFMASK (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
#define SF_UNDEFVAL (SF_REFERENCED)
#define SF_IMPMASK (SF_TRAMPOLINE | SF_IMPORT | SF_REFERENCED)
#define SF_IMPVAL (SF_IMPORT | SF_REFERENCED)
#define SF_EXPMASK (SF_TRAMPOLINE | SF_EXPORT)
#define SF_EXPVAL (SF_EXPORT)
#define SF_DBGINFOMASK (SF_TRAMPOLINE | SF_DEFINED | SF_EXPORT | SF_IMPORT)
#define SF_DBGINFOVAL (SF_DEFINED)
/* Structure of a symbol table entry */
struct SymEntry {
SymEntry* Left; /* Lexically smaller entry */
SymEntry* Right; /* Lexically larger entry */
SymEntry* List; /* List of all entries */
SymEntry* Locals; /* Root of subtree for local symbols */
struct SymTable* SymTab; /* Table this symbol is in, 0 for locals */
FilePos Pos; /* File position for this symbol */
unsigned Flags; /* Symbol flags */
unsigned Index; /* Index of import/export entries */
union {
struct ExprNode* Expr; /* Expression if CONST not set */
long Val; /* Value (if CONST set) */
SymEntry* Sym; /* Symbol (if trampoline entry) */
} V;
unsigned char ConDesPrio[CD_TYPE_COUNT]; /* ConDes priorities... */
/* ...actually value+1 (used as flag) */
char Name [1]; /* Dynamic allocation */
};
/* Definitions for the hash table */
#define MAIN_HASHTAB_SIZE 213
#define SUB_HASHTAB_SIZE 53
typedef struct SymTable SymTable;
struct SymTable {
unsigned TableSlots; /* Number of hash table slots */
unsigned TableEntries; /* Number of entries in the table */
SymTable* BackLink; /* Link to enclosing scope if any */
SymEntry* Table [1]; /* Dynamic allocation */
};
/* Arguments for SymFind */
#define SF_FIND_EXISTING 0
#define SF_ALLOC_NEW 1
/* Symbol table variables */
static SymEntry* SymList = 0; /* List of all symbol table entries */
static SymEntry* SymLast = 0; /* Pointer to last defined symbol */
static SymTable* SymTab = 0; /* Pointer to current symbol table */
static SymTable* RootTab = 0; /* Root symbol table */
static unsigned ImportCount = 0;/* Counter for import symbols */
static unsigned ExportCount = 0;/* Counter for export symbols */
/*****************************************************************************/
/* Internally used functions */
/*****************************************************************************/
static int IsLocal (const char* Name)
/* Return true if Name is the name of a local symbol */
{
return (*Name == LocalStart);
}
static SymEntry* NewSymEntry (const char* Name)
/* Allocate a symbol table entry, initialize and return it */
{
SymEntry* S;
unsigned Len;
/* Get the length of the name */
Len = strlen (Name);
/* Allocate memory */
S = xmalloc (sizeof (SymEntry) + Len);
/* Initialize the entry */
S->Left = 0;
S->Right = 0;
S->Locals = 0;
S->SymTab = 0;
S->Pos = CurPos;
S->Flags = 0;
S->V.Expr = 0;
memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
memcpy (S->Name, Name, Len+1);
/* Insert it into the list of all entries */
S->List = SymList;
SymList = S;
/* Return the initialized entry */
return S;
}
static SymTable* NewSymTable (unsigned Size)
/* Allocate a symbol table on the heap and return it */
{
SymTable* S;
/* Allocate memory */
S = xmalloc (sizeof (SymTable) + (Size-1) * sizeof (SymEntry*));
/* Set variables and clear hash table entries */
S->TableSlots = Size;
S->TableEntries = 0;
S->BackLink = 0;
while (Size--) {
S->Table [Size] = 0;
}
/* Return the prepared struct */
return S;
}
static int SearchSymTab (SymEntry* T, const char* Name, SymEntry** E)
/* Search in the given table for a name (Hash is the hash value of Name and
* is given as parameter so that it will not get calculated twice if we search
* in more than one table). If we find the symbol, the function will return 0
* and put the entry pointer into E. If we did not find the symbol, and the
* tree is empty, E is set to NULL. If the tree is not empty, E will be set to
* the last entry, and the result of the function is <0 if the entry should
* be inserted on the left side, and >0 if it should get inserted on the right
* side.
*/
{
int Cmp;
/* Is there a tree? */
if (T == 0) {
*E = 0;
return 1;
}
/* We have a table, search it */
while (1) {
/* Choose next entry */
Cmp = strcmp (Name, T->Name);
if (Cmp < 0 && T->Left) {
T = T->Left;
} else if (Cmp > 0 && T->Right) {
T = T->Right;
} else {
/* Found or end of search */
break;
}
}
/* Return the search result */
*E = T;
return Cmp;
}
/*****************************************************************************/
/* Code */
/*****************************************************************************/
static SymEntry* SymFind (SymTable* Tab, const char* Name, int AllocNew)
/* Find a new symbol table entry in the given table. If AllocNew is given and
* the entry is not found, create a new one. Return the entry found, or the
* new entry created, or - in case AllocNew is zero - return 0.
*/
{
SymEntry* S;
int Cmp;
unsigned Hash;
if (IsLocal (Name)) {
/* Local symbol, get the table */
if (!SymLast) {
/* No last global, so there's no local table */
Error (ERR_ILLEGAL_LOCAL_USE);
if (AllocNew) {
return NewSymEntry (Name);
} else {
return 0;
}
}
/* Search for the symbol if we have a table */
Cmp = SearchSymTab (SymLast->Locals, Name, &S);
/* If we found an entry, return it */
if (Cmp == 0) {
return S;
}
if (AllocNew) {
/* Otherwise create a new entry, insert and return it */
SymEntry* N = NewSymEntry (Name);
if (S == 0) {
SymLast->Locals = N;
} else if (Cmp < 0) {
S->Left = N;
} else {
S->Right = N;
}
return N;
}
} else {
/* Global symbol: Get the hash value for the name */
Hash = HashStr (Name) % Tab->TableSlots;
/* Search for the entry */
Cmp = SearchSymTab (Tab->Table [Hash], Name, &S);
/* If we found an entry, return it */
if (Cmp == 0) {
/* Check for a trampoline entry, in this case return the real
* symbol.
*/
if (S->Flags & SF_TRAMPOLINE) {
return S->V.Sym;
} else {
return S;
}
}
if (AllocNew) {
/* Otherwise create a new entry, insert and return it */
SymEntry* N = NewSymEntry (Name);
if (S == 0) {
Tab->Table [Hash] = N;
} else if (Cmp < 0) {
S->Left = N;
} else {
S->Right = N;
}
N->SymTab = Tab;
++Tab->TableEntries;
return N;
}
}
/* We did not find the entry and AllocNew is false. */
return 0;
}
static SymEntry* SymFindAny (SymTable* Tab, const char* Name)
/* Find a symbol in any table */
{
SymEntry* Sym;
do {
/* Search in the current table */
Sym = SymFind (Tab, Name, SF_FIND_EXISTING);
if (Sym) {
/* Found, return it */
return Sym;
} else {
/* Not found, search in the backlink, if we have one */
Tab = Tab->BackLink;
}
} while (Sym == 0 && Tab != 0);
/* Not found */
return 0;
}
void SymEnterLevel (void)
/* Enter a new lexical level */
{
if (RootTab == 0) {
/* Create the main symbol table */
RootTab = SymTab = NewSymTable (MAIN_HASHTAB_SIZE);
} else {
/* Create a local symbol table */
SymTable* LocalSyms;
LocalSyms = NewSymTable (SUB_HASHTAB_SIZE);
LocalSyms->BackLink = SymTab;
SymTab = LocalSyms;
}
}
void SymLeaveLevel (void)
/* Leave the current lexical level */
{
SymTab = SymTab->BackLink;
}
void SymDef (const char* Name, ExprNode* Expr, int ZP, int Label)
/* Define a new symbol */
{
/* Do we have such a symbol? */
SymEntry* S = SymFind (SymTab, Name, SF_ALLOC_NEW);
if (S->Flags & SF_IMPORT) {
/* Defined symbol is marked as imported external symbol */
Error (ERR_SYM_ALREADY_IMPORT, Name);
return;
}
if (S->Flags & SF_DEFINED) {
/* Multiple definition */
Error (ERR_SYM_ALREADY_DEFINED, Name);
S->Flags |= SF_MULTDEF;
return;
}
/* Set the symbol data */
if (IsConstExpr (Expr)) {
/* Expression is const, store the value */
S->Flags |= SF_CONST;
S->V.Val = GetExprVal (Expr);
FreeExpr (Expr);
} else {
/* Not const, store the expression */
S->V.Expr = Expr;
}
S->Flags |= SF_DEFINED;
if (ZP) {
S->Flags |= SF_ZP;
}
if (Label) {
S->Flags |= SF_LABEL;
}
/* If the symbol is a ZP symbol, check if the value is in correct range */
if (S->Flags & SF_ZP) {
/* Already marked as ZP symbol by some means */
if (!IsByteExpr (Expr)) {
Error (ERR_RANGE);
}
}
/* If this is not a local symbol, remember it as the last global one */
if (!IsLocal (Name)) {
SymLast = S;
}
}
SymEntry* SymRef (const char* Name, int Scope)
/* Search for the symbol and return it */
{
SymEntry* S;
switch (Scope) {
case SCOPE_GLOBAL: S = SymFind (RootTab, Name, SF_ALLOC_NEW); break;
case SCOPE_LOCAL: S = SymFind (SymTab, Name, SF_ALLOC_NEW); break;
/* Others are not allowed */
case SCOPE_ANY:
default:
Internal ("Invalid scope in SymRef: %d", Scope);
/* NOTREACHED */
S = 0;
}
/* Mark the symbol as referenced */
S->Flags |= SF_REFERENCED;
/* Return it */
return S;
}
void SymImport (const char* Name, int ZP)
/* Mark the given symbol as an imported symbol */
{
SymEntry* S;
/* Don't accept local symbols */
if (IsLocal (Name)) {
Error (ERR_ILLEGAL_LOCAL_USE);
return;
}
/* Do we have such a symbol? */
S = SymFind (SymTab, Name, SF_ALLOC_NEW);
if (S->Flags & SF_DEFINED) {
Error (ERR_SYM_ALREADY_DEFINED, Name);
S->Flags |= SF_MULTDEF;
return;
}
if (S->Flags & SF_EXPORT) {
/* The symbol is already marked as exported symbol */
Error (ERR_SYM_ALREADY_EXPORT, Name);
return;
}
/* If the symbol is marked as global, check the symbol size, then do
* silently remove the global flag
*/
if (S->Flags & SF_GLOBAL) {
if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
Error (ERR_SYM_REDECL_MISMATCH, Name);
}
S->Flags &= ~SF_GLOBAL;
}
/* Set the symbol data */
S->Flags |= SF_IMPORT;
if (ZP) {
S->Flags |= SF_ZP;
}
}
void SymExport (const char* Name, int ZP)
/* Mark the given symbol as an exported symbol */
{
SymEntry* S;
/* Don't accept local symbols */
if (IsLocal (Name)) {
Error (ERR_ILLEGAL_LOCAL_USE);
return;
}
/* Do we have such a symbol? */
S = SymFind (SymTab, Name, SF_ALLOC_NEW);
if (S->Flags & SF_IMPORT) {
/* The symbol is already marked as imported external symbol */
Error (ERR_SYM_ALREADY_IMPORT, Name);
return;
}
/* If the symbol is marked as global, check the symbol size, then do
* silently remove the global flag
*/
if (S->Flags & SF_GLOBAL) {
if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
Error (ERR_SYM_REDECL_MISMATCH, Name);
}
S->Flags &= ~SF_GLOBAL;
}
/* Set the symbol data */
S->Flags |= SF_EXPORT | SF_REFERENCED;
if (ZP) {
S->Flags |= SF_ZP;
}
}
void SymGlobal (const char* Name, int ZP)
/* Mark the given symbol as a global symbol, that is, as a symbol that is
* either imported or exported.
*/
{
SymEntry* S;
/* Don't accept local symbols */
if (IsLocal (Name)) {
Error (ERR_ILLEGAL_LOCAL_USE);
return;
}
/* Search for this symbol, create a new entry if needed */
S = SymFind (SymTab, Name, SF_ALLOC_NEW);
/* If the symbol is already marked as import or export, check the
* size of the definition, then bail out. */
if (S->Flags & SF_IMPORT || S->Flags & SF_EXPORT) {
if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
Error (ERR_SYM_REDECL_MISMATCH, Name);
}
return;
}
/* Mark the symbol */
S->Flags |= SF_GLOBAL;
if (ZP) {
S->Flags |= SF_ZP;
}
}
void SymConDes (const char* Name, unsigned Type, unsigned Prio)
/* Mark the given symbol as a module constructor/destructor. This will also
* mark the symbol as an export. Initializers may never be zero page symbols.
*/
{
SymEntry* S;
/* Check the parameters */
#if (CD_TYPE_MIN != 0)
CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
#else
CHECK (Type <= CD_TYPE_MAX);
#endif
CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
/* Don't accept local symbols */
if (IsLocal (Name)) {
Error (ERR_ILLEGAL_LOCAL_USE);
return;
}
/* Do we have such a symbol? */
S = SymFind (SymTab, Name, SF_ALLOC_NEW);
if (S->Flags & SF_IMPORT) {
/* The symbol is already marked as imported external symbol */
Error (ERR_SYM_ALREADY_IMPORT, Name);
return;
}
/* If the symbol is marked as global, silently remove the global flag */
if (S->Flags & SF_GLOBAL) {
S->Flags &= ~SF_GLOBAL;
}
/* Check if the symbol was not already defined as ZP symbol */
if ((S->Flags & SF_ZP) != 0) {
Error (ERR_SYM_REDECL_MISMATCH, Name);
}
/* If the symbol was already declared as a condes, check if the new
* priority value is the same as the old one.
*/
if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
if (S->ConDesPrio[Type] != Prio) {
Error (ERR_SYM_REDECL_MISMATCH, Name);
}
}
S->ConDesPrio[Type] = Prio;
/* Set the symbol data */
S->Flags |= SF_EXPORT | SF_REFERENCED;
}
int SymIsDef (const char* Name, int Scope)
/* Return true if the given symbol is already defined */
{
SymEntry* S = 0;
/* Search for the symbol */
switch (Scope) {
case SCOPE_ANY: S = SymFindAny (SymTab, Name); break;
case SCOPE_GLOBAL: S = SymFind (RootTab, Name, SF_FIND_EXISTING); break;
case SCOPE_LOCAL: S = SymFind (SymTab, Name, SF_FIND_EXISTING); break;
default: Internal ("Invalid scope in SymIsDef: %d", Scope);
}
/* Check if it's defined */
return S != 0 && (S->Flags & SF_DEFINED) != 0;
}
int SymIsRef (const char* Name, int Scope)
/* Return true if the given symbol has been referenced */
{
SymEntry* S = 0;
/* Search for the symbol */
switch (Scope) {
case SCOPE_ANY: S = SymFindAny (SymTab, Name); break;
case SCOPE_GLOBAL: S = SymFind (RootTab, Name, SF_FIND_EXISTING); break;
case SCOPE_LOCAL: S = SymFind (SymTab, Name, SF_FIND_EXISTING); break;
default: Internal ("Invalid scope in SymIsRef: %d", Scope);
}
/* Check if it's defined */
return S != 0 && (S->Flags & SF_REFERENCED) != 0;
}
int SymIsConst (SymEntry* S)
/* Return true if the given symbol has a constant value */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
/* Check for constness */
if (S->Flags & SF_CONST) {
return 1;
} else if ((S->Flags & SF_DEFINED) && IsConstExpr (S->V.Expr)) {
/* Constant expression, remember the value */
ExprNode* Expr = S->V.Expr;
S->Flags |= SF_CONST;
S->V.Val = GetExprVal (Expr);
FreeExpr (Expr);
return 1;
}
return 0;
}
int SymIsZP (SymEntry* S)
/* Return true if the symbol is explicitly marked as zeropage symbol */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
/* If the symbol is not a global symbol, was not defined before, check the
* enclosing scope for a symbol with the same name, and return the ZP
* attribute of this symbol if we find one.
*/
if (!IsLocal (S->Name) &&
(S->Flags & (SF_ZP | SF_ABS | SF_DEFINED | SF_IMPORT)) == 0 &&
S->SymTab->BackLink != 0) {
/* Try to find a symbol with the same name in the enclosing scope */
SymEntry* E = SymFindAny (S->SymTab->BackLink, S->Name);
/* If we found one, use the ZP flag */
if (E && (E->Flags & SF_ZP) != 0) {
S->Flags |= SF_ZP;
}
}
/* Check the ZP flag */
return (S->Flags & SF_ZP) != 0;
}
int SymIsImport (SymEntry* S)
/* Return true if the given symbol is marked as import */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
/* Check the import flag */
return (S->Flags & SF_IMPORT) != 0;
}
int SymHasExpr (SymEntry* S)
/* Return true if the given symbol has an associated expression */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
/* Check the expression */
return ((S->Flags & SF_DEFINED) != 0 &&
(S->Flags & SF_IMPORT) == 0 &&
(S->Flags & SF_CONST) == 0);
}
void SymFinalize (SymEntry* S)
/* Finalize a symbol expression if there is one */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
/* Check if we have an expression */
if (SymHasExpr (S)) {
S->V.Expr = FinalizeExpr (S->V.Expr);
}
}
void SymMarkUser (SymEntry* S)
/* Set a user mark on the specified symbol */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
/* Set the bit */
S->Flags |= SF_USER;
}
void SymUnmarkUser (SymEntry* S)
/* Remove a user mark from the specified symbol */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
/* Reset the bit */
S->Flags &= ~SF_USER;
}
int SymHasUserMark (SymEntry* S)
/* Return the state of the user mark for the specified symbol */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
/* Check the bit */
return (S->Flags & SF_USER) != 0;
}
long GetSymVal (SymEntry* S)
/* Return the symbol value */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
PRECONDITION ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_CONST) != 0);
return S->V.Val;
}
ExprNode* GetSymExpr (SymEntry* S)
/* Get the expression for a non-const symbol */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
PRECONDITION (S != 0 && (S->Flags & SF_CONST) == 0);
return S->V.Expr;
}
const char* GetSymName (SymEntry* S)
/* Return the name of the symbol */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
return S->Name;
}
unsigned GetSymIndex (SymEntry* S)
/* Return the symbol index for the given symbol */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
PRECONDITION (S != 0 && (S->Flags & SF_INDEXED));
return S->Index;
}
const FilePos* GetSymPos (SymEntry* S)
/* Return the position of first occurence in the source for the given symbol */
{
/* Resolve trampoline entries */
if (S->Flags & SF_TRAMPOLINE) {
S = S->V.Sym;
}
PRECONDITION (S != 0);
return &S->Pos;
}
static void SymCheckUndefined (SymEntry* S)
/* Handle an undefined symbol */
{
/* Undefined symbol. It may be...
*
* - An undefined symbol in a nested lexical level. In this
* case, search for the symbol in the higher levels and
* make the entry a trampoline entry if we find one.
*
* - If the symbol is not found, it is a real undefined symbol.
* If the AutoImport flag is set, make it an import. If the
* AutoImport flag is not set, it's an error.
*/
SymEntry* Sym = 0;
if (S->SymTab) {
/* It's a global symbol, get the higher level table */
SymTable* Tab = S->SymTab->BackLink;
while (Tab) {
Sym = SymFindAny (Tab, S->Name);
if (Sym) {
if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) {
/* We've found a symbol in a higher level that is
* either defined in the source, or an import.
*/
break;
} else {
/* The symbol found is undefined itself. Look further */
Tab = Sym->SymTab->BackLink;
}
} else {
/* No symbol found */
break;
}
}
}
if (Sym) {
/* We found the symbol in a higher level. Make S a trampoline
* symbol. Beware: We have to transfer the symbol attributes to
* the real symbol and check for any conflicts.
*/
S->Flags |= SF_TRAMPOLINE;
S->V.Sym = Sym;
/* Transfer the flags. Note: S may not be imported, since in that
* case it wouldn't be undefined.
*/
if (S->Flags & SF_EXPORT) {
if (Sym->Flags & SF_IMPORT) {
/* The symbol is already marked as imported external symbol */
PError (&S->Pos, ERR_SYM_ALREADY_IMPORT, S->Name);
}
Sym->Flags |= S->Flags & (SF_EXPORT | SF_ZP);
}
/* Transfer the referenced flag */
Sym->Flags |= (S->Flags & SF_REFERENCED);
} else {
/* The symbol is definitely undefined */
if (S->Flags & SF_EXPORT) {
/* We will not auto-import an export */
PError (&S->Pos, ERR_EXPORT_UNDEFINED, S->Name);
} else {
if (AutoImport) {
/* Mark as import, will be indexed later */
S->Flags |= SF_IMPORT;
} else {
/* Error */
PError (&S->Pos, ERR_SYM_UNDEFINED, S->Name);
}
}
}
}
void SymCheck (void)
/* Run through all symbols and check for anomalies and errors */
{
SymEntry* S;
/* Check for open lexical levels */
if (SymTab->BackLink != 0) {
Error (ERR_OPEN_PROC);
}
/* First pass: Walk through all symbols, checking for undefined's and
* changing them to trampoline symbols or make them imports.
*/
S = SymList;
while (S) {
/* If the symbol is marked as global, mark it as export, if it is
* already defined, otherwise mark it as import.
*/
if (S->Flags & SF_GLOBAL) {
S->Flags &= ~SF_GLOBAL;
if (S->Flags & SF_DEFINED) {
S->Flags |= SF_EXPORT;
} else {
S->Flags |= SF_IMPORT;
}
}
/* Handle undefined symbols */
if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
/* This is an undefined symbol. Handle it. */
SymCheckUndefined (S);
}
/* Next symbol */
S = S->List;
}
/* Second pass: Walk again through the symbols. Ignore undefined's, since
* we handled them in the last pass, and ignore trampoline symbols, since
* we handled them in the last pass, too.
*/
S = SymList;
while (S) {
if ((S->Flags & SF_TRAMPOLINE) == 0 &&
(S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
/* Symbol was defined but never referenced */
PWarning (&S->Pos, WARN_SYM_NOT_REFERENCED, S->Name);
}
if (S->Flags & SF_IMPORT) {
if ((S->Flags & SF_REFERENCED) == 0) {
/* Imported symbol is not referenced */
PWarning (&S->Pos, WARN_IMPORT_NOT_REFERENCED, S->Name);
} else {
/* Give the import an index, count imports */
S->Index = ImportCount++;
S->Flags |= SF_INDEXED;
}
}
if (S->Flags & SF_EXPORT) {
/* Give the export an index, count exports */
S->Index = ExportCount++;
S->Flags |= SF_INDEXED;
}
}
/* Next symbol */
S = S->List;
}
}
void SymDump (FILE* F)
/* Dump the symbol table */
{
SymEntry* S = SymList;
while (S) {
/* Ignore trampoline symbols */
if ((S->Flags & SF_TRAMPOLINE) != 0) {
fprintf (F,
"%-24s %s %s %s %s %s\n",
S->Name,
(S->Flags & SF_DEFINED)? "DEF" : "---",
(S->Flags & SF_REFERENCED)? "REF" : "---",
(S->Flags & SF_IMPORT)? "IMP" : "---",
(S->Flags & SF_EXPORT)? "EXP" : "---",
(S->Flags & SF_ZP)? "ZP" : "--");
}
/* Next symbol */
S = S->List;
}
}
void WriteImports (void)
/* Write the imports list to the object file */
{
SymEntry* S;
/* Tell the object file module that we're about to start the imports */
ObjStartImports ();
/* Write the import count to the list */
ObjWriteVar (ImportCount);
/* Walk throught list and write all imports to the file */
S = SymList;
while (S) {
if ((S->Flags & SF_IMPMASK) == SF_IMPVAL) {
if (S->Flags & SF_ZP) {
ObjWrite8 (IMP_ZP);
} else {
ObjWrite8 (IMP_ABS);
}
ObjWriteStr (S->Name);
ObjWritePos (&S->Pos);
}
S = S->List;
}
/* Done writing imports */
ObjEndImports ();
}
static unsigned char GetExprMask (SymEntry* S)
/* Return the expression bits for the given symbol table entry */
{
unsigned char ExprMask;
/* Check if the symbol is const */
ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
/* Add zeropage/abs bits */
ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS;
/* Add the label/equate bits */
ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
/* Return the mask */
return ExprMask;
}
void WriteExports (void)
/* Write the exports list to the object file */
{
SymEntry* S;
unsigned Type;
/* Tell the object file module that we're about to start the exports */
ObjStartExports ();
/* Write the export count to the list */
ObjWriteVar (ExportCount);
/* Walk throught list and write all exports to the file */
S = SymList;
while (S) {
if ((S->Flags & SF_EXPMASK) == SF_EXPVAL) {
unsigned char ExprMask;
/* Finalize an associated expression if we have one */
SymFinalize (S);
/* Get the expression bits */
ExprMask = GetExprMask (S);
/* Count the number of ConDes types */
for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
INC_EXP_CONDES_COUNT (ExprMask);
}
}
/* Write the type */
ObjWrite8 (ExprMask);
/* Write any ConDes declarations */
if (GET_EXP_CONDES_COUNT (ExprMask) > 0) {
for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
unsigned char Prio = S->ConDesPrio[Type];
if (Prio != CD_PRIO_NONE) {
ObjWrite8 (CD_BUILD (Type, Prio));
}
}
}
/* Write the name */
ObjWriteStr (S->Name);
/* Write the value */
if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
/* Constant value */
ObjWrite32 (S->V.Val);
} else {
/* Expression involved */
WriteExpr (S->V.Expr);
}
/* Write the source file position */
ObjWritePos (&S->Pos);
}
S = S->List;
}
/* Done writing exports */
ObjEndExports ();
}
void WriteDbgSyms (void)
/* Write a list of all symbols to the object file */
{
unsigned Count;
SymEntry* S;
/* Tell the object file module that we're about to start the debug info */
ObjStartDbgSyms ();
/* Check if debug info is requested */
if (DbgSyms) {
/* Walk through the list and count the symbols */
Count = 0;
S = SymList;
while (S) {
if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
++Count;
}
S = S->List;
}
/* Write the symbol count to the list */
ObjWriteVar (Count);
/* Walk through list and write all symbols to the file */
S = SymList;
while (S) {
if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
unsigned char ExprMask;
/* Finalize an associated expression if we have one */
SymFinalize (S);
/* Get the expression bits */
ExprMask = GetExprMask (S);
/* Write the type */
ObjWrite8 (ExprMask);
/* Write the name */
ObjWriteStr (S->Name);
/* Write the value */
if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
/* Constant value */
ObjWrite32 (S->V.Val);
} else {
/* Expression involved */
WriteExpr (S->V.Expr);
}
/* Write the source file position */
ObjWritePos (&S->Pos);
}
S = S->List;
}
} else {
/* No debug symbols */
ObjWriteVar (0);
}
/* Done writing debug symbols */
ObjEndDbgSyms ();
}