#include "objfile.h"
#include "scanner.h"
#include "segment.h"
+#include "sizeof.h"
#include "spool.h"
+#include "studyexpr.h"
#include "symtab.h"
/* Combined symbol entry flags used within this module */
#define SF_UNDEFMASK (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
#define SF_UNDEFVAL (SF_REFERENCED)
-#define SF_DBGINFOMASK (SF_UNUSED | SF_DEFINED | SF_EXPORT | SF_IMPORT)
+#define SF_DBGINFOMASK (SF_UNUSED | SF_DEFINED | SF_IMPORT)
#define SF_DBGINFOVAL (SF_DEFINED)
/* Symbol tables */
S->Left = 0;
S->Right = 0;
S->Childs = 0;
+ S->SegRanges = AUTO_COLLECTION_INITIALIZER;
S->Flags = ST_NONE;
S->AddrSize = ADDR_SIZE_DEFAULT;
S->Type = ST_UNDEF;
CurrentScope->Flags |= ST_DEFINED;
CurrentScope->AddrSize = AddrSize;
CurrentScope->Type = Type;
+
+ /* If this is a scope that allows to emit data into segments, add segment
+ * ranges for all currently existing segments. Doing this for just a few
+ * scope types is not really necessary but an optimization, because it
+ * does not allocate memory for useless data (unhandled types here don't
+ * occupy space in any segment).
+ */
+ if (CurrentScope->Type <= ST_SCOPE_HAS_DATA) {
+ AddSegRanges (&CurrentScope->SegRanges);
+ }
}
void SymLeaveLevel (void)
/* Leave the current lexical level */
{
+ /* Close the segment ranges. We don't care about the scope type here,
+ * since types without segment ranges will just have an empty list.
+ */
+ CloseSegRanges (&CurrentScope->SegRanges);
+
+ /* If we have segment ranges, the first one is the segment that was
+ * active, when the scope was opened. Set the size of the scope to the
+ * number of data bytes emitted into this segment.
+ */
+ if (CollCount (&CurrentScope->SegRanges) > 0) {
+ const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0);
+ DefSizeOfScope (CurrentScope, GetSegRangeSize (R));
+ }
+
+ /* Leave the scope */
CurrentScope = CurrentScope->Parent;
}
-SymEntry* SymFindLocal (const char* Name, int AllocNew)
+SymEntry* SymFindLocal (SymEntry* Parent, const char* Name, int AllocNew)
/* Find a cheap local symbol. 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.
int Cmp;
/* Local symbol, get the table */
- if (!SymLast) {
+ if (!Parent) {
/* No last global, so there's no local table */
Error ("No preceeding global symbol");
if (AllocNew) {
- return NewSymEntry (Name);
+ return NewSymEntry (Name, SF_LOCAL);
} else {
return 0;
}
}
/* Search for the symbol if we have a table */
- Cmp = SymSearchTree (SymLast->Locals, Name, &S);
+ Cmp = SymSearchTree (Parent->Locals, Name, &S);
/* If we found an entry, return it */
if (Cmp == 0) {
if (AllocNew) {
/* Otherwise create a new entry, insert and return it */
- SymEntry* N = NewSymEntry (Name);
+ SymEntry* N = NewSymEntry (Name, SF_LOCAL);
if (S == 0) {
- SymLast->Locals = N;
+ Parent->Locals = N;
} else if (Cmp < 0) {
S->Left = N;
} else {
if (AllocNew) {
/* Otherwise create a new entry, insert and return it */
- SymEntry* N = NewSymEntry (Name);
+ SymEntry* N = NewSymEntry (Name, SF_NONE);
if (S == 0) {
Scope->Table[Hash] = N;
} else if (Cmp < 0) {
-static SymEntry* SymFindAny (SymTable* Scope, const char* Name)
+SymEntry* SymFindAny (SymTable* Scope, const char* Name)
/* Find a symbol in the given or any of its parent scopes. The function will
* never create a new symbol, since this can only be done in one specific
* scope.
Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
if (Sym) {
/* Found, return it */
- return Sym;
- } else {
- /* Not found, search in the parent scope, if we have one */
- Scope = Scope->Parent;
+ break;
}
- } while (Sym == 0 && Scope != 0);
-
- /* Not found */
- return 0;
-}
-
-
-int SymIsZP (SymEntry* S)
-/* Return true if the symbol is explicitly marked as zeropage symbol */
-{
- /* 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 (!IsLocalNameId (S->Name) && (S->Flags & (SF_DEFINED | SF_IMPORT)) == 0 &&
- S->SymTab->Parent != 0) {
+ /* Not found, search in the parent scope, if we have one */
+ Scope = Scope->Parent;
- /* Try to find a symbol with the same name in the enclosing scope */
- SymEntry* E = SymFindAny (S->SymTab->Parent, GetString (S->Name));
-
- /* If we found one, use the ZP flag */
- if (E && E->AddrSize == ADDR_SIZE_ZP) {
- S->AddrSize = ADDR_SIZE_ZP;
- }
- }
+ } while (Sym == 0 && Scope != 0);
- /* Check the ZP flag */
- return (S->AddrSize == ADDR_SIZE_ZP);
+ /* Return the result */
+ return Sym;
}
* 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->Parent;
- while (Tab) {
- Sym = SymFindAny (Tab, GetString (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->Parent;
- }
- } else {
- /* No symbol found */
- break;
- }
- }
+ SymTable* Tab = GetSymParentScope (S);
+ while (Tab) {
+ Sym = SymFind (Tab, GetString (S->Name), SYM_FIND_EXISTING);
+ if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) {
+ /* We've found a symbol in a higher level that is
+ * either defined in the source, or an import.
+ */
+ break;
+ }
+ /* No matching symbol found in this level. Look further */
+ Tab = Tab->Parent;
}
if (Sym) {
if (S->Flags & SF_GLOBAL) {
S->Flags &= ~SF_GLOBAL;
if (S->Flags & SF_DEFINED) {
- S->Flags |= SF_EXPORT;
+ S->Flags |= SF_EXPORT;
} else {
- S->Flags |= SF_IMPORT;
+ S->Flags |= SF_IMPORT;
}
}
S = S->List;
}
- /* Second pass: Walk again through the symbols. Ignore undefined's, since
- * we handled them in the last pass, and ignore unused symbols, since
- * we handled them in the last pass, too.
+ /* Second pass: Walk again through the symbols. Count exports and imports
+ * and set address sizes where this has not happened before. Ignore
+ * undefined's, since we handled them in the last pass, and ignore unused
+ * symbols, since we handled them in the last pass, too.
*/
S = SymList;
while (S) {
if ((S->Flags & SF_UNUSED) == 0 &&
(S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
+
+ /* Check for defined symbols that were never referenced */
if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
- /* Symbol was defined but never referenced */
PWarning (&S->Pos, 2,
"Symbol `%s' is defined but never used",
GetString (S->Name));
}
+
+ /* Assign an index to all imports */
if (S->Flags & SF_IMPORT) {
if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
/* Imported symbol is not referenced */
S->Flags |= SF_INDEXED;
}
}
+
+ /* Assign an index to all exports */
if (S->Flags & SF_EXPORT) {
/* Give the export an index, count exports */
S->Index = ExportCount++;
S->Flags |= SF_INDEXED;
}
+
+ /* If the symbol is defined but has an unknown address size,
+ * recalculate it.
+ */
+ if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) {
+ ExprDesc ED;
+ ED_Init (&ED);
+ StudyExpr (S->Expr, &ED);
+ S->AddrSize = ED.AddrSize;
+ ED_Done (&ED);
+ }
}
/* Next symbol */
ObjWrite32 (ConstVal);
} else {
/* Expression involved */
- WriteExpr (S->V.Expr);
+ WriteExpr (S->Expr);
}
/* Write the source file position */
ObjWrite32 (ConstVal);
} else {
/* Expression involved */
- WriteExpr (S->V.Expr);
+ WriteExpr (S->Expr);
}
/* Write the source file position */