"Syntax error",
"Symbol `%s' is already defined",
"Undefined symbol `%s'",
- "Symbol `%s' is marked as import",
- "Symbol `%s' is marked as export",
+ "Symbol `%s' is already marked as import",
+ "Symbol `%s' is already marked as export",
"Exported symbol `%s' is undefined",
"Exported values must be constant",
".IF nesting too deep",
/* common */
#include "bitops.h"
#include "check.h"
+#include "symdefs.h"
#include "tgttrans.h"
/* ca65 */
if (Tok != TOK_STRCON) {
ErrorSkip (ERR_STRCON_EXPECTED);
} else {
- strcpy (Name, SVal);
- NextTok ();
- NewInputFile (Name);
+ strcpy (Name, SVal);
+ NextTok ();
+ NewInputFile (Name);
}
}
static void DoInitializer (void)
/* Export a symbol as initializer */
{
- ExportImport (SymInitializer, 0);
+ char Name [sizeof (SVal)];
+ long Val;
+
+ /* Symbol name follows */
+ if (Tok != TOK_IDENT) {
+ ErrorSkip (ERR_IDENT_EXPECTED);
+ return;
+ }
+ strcpy (Name, SVal);
+ NextTok ();
+
+ /* Optional initializer value */
+ if (Tok == TOK_COMMA) {
+ /* Initializer value follows */
+ NextTok ();
+ Val = ConstExpression ();
+ if (Val < EXP_INIT_MIN || Val > EXP_INIT_MAX) {
+ /* Value out of range */
+ Error (ERR_RANGE);
+ return;
+ }
+ } else {
+ /* Use the default initializer value */
+ Val = EXP_INIT_DEF;
+ }
+
+ /* Define the symbol */
+ SymInitializer (Name, (unsigned) Val);
}
long Val; /* Value (if CONST set) */
SymEntry* Sym; /* Symbol (if trampoline entry) */
} V;
+ unsigned char InitVal; /* Initializer value */
char Name [1]; /* Dynamic allocation */
};
S = xmalloc (sizeof (SymEntry) + Len);
/* Initialize the entry */
- S->Left = 0;
- S->Right = 0;
- S->Locals = 0;
- S->SymTab = 0;
- S->Flags = 0;
- S->V.Expr = 0;
- S->Pos = CurPos;
+ S->Left = 0;
+ S->Right = 0;
+ S->Locals = 0;
+ S->SymTab = 0;
+ S->Pos = CurPos;
+ S->Flags = 0;
+ S->V.Expr = 0;
+ S->InitVal = 0;
memcpy (S->Name, Name, Len+1);
/* Insert it into the list of all entries */
}
if (S->Flags & SF_EXPORT) {
/* The symbol is already marked as exported symbol */
- Error (ERR_SYM_ALREADY_EXPORT);
+ Error (ERR_SYM_ALREADY_EXPORT, Name);
return;
}
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);
+ Error (ERR_SYM_ALREADY_IMPORT, Name);
return;
}
-void SymInitializer (const char* Name, int ZP)
+void SymInitializer (const char* Name, unsigned InitVal)
/* Mark the given symbol as an initializer. This will also mark the symbol as
- * an export. Initializers may never be zero page symbols, the ZP parameter
- * is supplied to make the prototype the same as the other functions (this
- * is used in pseudo.c). Passing something else but zero as ZP argument will
- * trigger an internal error.
+ * an export. Initializers may never be zero page symbols.
*/
{
SymEntry* S;
- /* Check the ZP parameter */
- CHECK (ZP == 0);
+ /* Check the InitVal parameter */
+ CHECK (InitVal >= EXP_INIT_MIN && InitVal <= EXP_INIT_MAX);
/* Don't accept local symbols */
if (IsLocal (Name)) {
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);
+ 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 the symbol is marked as global, silently remove the global flag */
if (S->Flags & SF_GLOBAL) {
- if ((S->Flags & SF_ZP) != 0) {
- Error (ERR_SYM_REDECL_MISMATCH);
- }
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);
+ }
+
+ /* If the symbol was already declared as an initializer, check if the new
+ * initializer value is the same as the old one.
+ */
+ if (S->Flags & SF_INITIALIZER) {
+ if (S->InitVal != InitVal) {
+ Error (ERR_SYM_REDECL_MISMATCH);
+ }
+ }
+ S->InitVal = InitVal;
+
/* Set the symbol data */
S->Flags |= SF_EXPORT | SF_INITIALIZER | SF_REFERENCED;
}
{
SymEntry* S = SymFindAny (SymTab, Name);
return S != 0 && (S->Flags & SF_REFERENCED) != 0;
-}
+}
/* Add the initializer bits */
if (S->Flags & SF_INITIALIZER) {
- ExprMask |= EXP_INIT;
+ ExprMask |= S->InitVal;
}
/* Write the type */
/* Add the initializer bits */
if (S->Flags & SF_INITIALIZER) {
- ExprMask |= EXP_INIT;
+ ExprMask |= S->InitVal;
}
/* Write the type */
* either imported or exported.
*/
-void SymInitializer (const char* Name, int ZP);
+void SymInitializer (const char* Name, unsigned InitVal);
/* Mark the given symbol as an initializer. This will also mark the symbol as
- * an export. Initializers may never be zero page symbols, the ZP parameter
- * is supplied to make the prototype the same as the other functions (this
- * is used in pseudo.c). Passing something else but zero as ZP argument will
- * trigger an internal error.
+ * an export. Initializers may never be zero page symbols.
*/
int SymIsConst (SymEntry* Sym);
/* Import size */
-#define IMP_ABS 0x00 /* Import as normal value */
-#define IMP_ZP 0x01 /* Import as zero page symbol */
-#define IMP_MASK_SIZE 0x01 /* Size mask */
+#define IMP_ABS 0x00 /* Import as normal value */
+#define IMP_ZP 0x01 /* Import as zero page symbol */
+#define IMP_MASK_SIZE 0x01 /* Size mask */
-#define IS_IMP_ABS(x) (((x) & IMP_MASK_SIZE) == IMP_ABS)
-#define IS_IMP_ZP(x) (((x) & IMP_MASK_SIZE) == IMP_ZP)
+#define IS_IMP_ABS(x) (((x) & IMP_MASK_SIZE) == IMP_ABS)
+#define IS_IMP_ZP(x) (((x) & IMP_MASK_SIZE) == IMP_ZP)
/* Export size */
-#define EXP_ABS 0x00 /* Export as normal value */
-#define EXP_ZP 0x01 /* Export as zero page value */
-#define EXP_MASK_SIZE 0x01 /* Size mask */
+#define EXP_ABS 0x00 /* Export as normal value */
+#define EXP_ZP 0x20 /* Export as zero page value */
+#define EXP_MASK_SIZE 0x20 /* Size mask */
#define IS_EXP_ABS(x) (((x) & EXP_MASK_SIZE) == EXP_ABS)
-#define IS_EXP_ZP(x) (((x) & EXP_MASK_SIZE) == EXP_ZP)
+#define IS_EXP_ZP(x) (((x) & EXP_MASK_SIZE) == EXP_ZP)
/* Export value type */
-#define EXP_CONST 0x00 /* Mask bit for const values */
-#define EXP_EXPR 0x02 /* Mask bit for expr values */
-#define EXP_MASK_VAL 0x02 /* Value mask */
+#define EXP_CONST 0x00 /* Mask bit for const values */
+#define EXP_EXPR 0x40 /* Mask bit for expr values */
+#define EXP_MASK_VAL 0x40 /* Value mask */
#define IS_EXP_CONST(x) (((x) & EXP_MASK_VAL) == EXP_CONST)
#define IS_EXP_EXPR(x) (((x) & EXP_MASK_VAL) == EXP_EXPR)
/* Export initializer flag */
-#define EXP_INIT 0x04 /* Mask bit for initializer export */
-#define EXP_MASK_INIT 0x04 /* Value mask */
+#define EXP_INIT_MIN 0x01 /* Minimum value */
+#define EXP_INIT_MAX 0x1F /* Maximum value */
+#define EXP_INIT_DEF 0x18 /* Default value */
+#define EXP_MASK_INIT 0x1F /* Initializer value mask */
-#define IS_EXP_INIT(x) (((x) & EXP_MASK_INIT) == EXP_INIT)
+#define IS_EXP_INIT(x) (((x) & EXP_MASK_INIT) != 0)
+#define GET_EXP_INIT_VAL(x) ((x) & EXP_MASK_INIT)
D->Name = ReadStr (F);
/* Read the value */
- if (Type & EXP_EXPR) {
+ if (IS_EXP_EXPR (Type)) {
D->Expr = ReadExpr (F, O);
} else {
D->Expr = LiteralExpr (Read32 (F), O);
/* common */
#include "check.h"
+#include "coll.h"
#include "hashstr.h"
#include "symdefs.h"
#include "xmalloc.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/* Hash table */
-#define HASHTAB_SIZE 4081
-static Export* HashTab [HASHTAB_SIZE];
+#define HASHTAB_SIZE 4081
+static Export* HashTab [HASHTAB_SIZE];
/* Import management variables */
-static unsigned ImpCount = 0; /* Import count */
-static unsigned ImpOpen = 0; /* Count of open imports */
+static unsigned ImpCount = 0; /* Import count */
+static unsigned ImpOpen = 0; /* Count of open imports */
/* Export management variables */
-static unsigned ExpCount = 0; /* Export count */
-static Export** ExpPool = 0; /* Exports array */
+static unsigned ExpCount = 0; /* Export count */
+static Export** ExpPool = 0; /* Exports array */
/* Defines for the flags in Export */
-#define EXP_USERMARK 0x0001
+#define EXP_USERMARK 0x0001
+
+/* List of all exports that are also initializers */
+static Collection Initializers = STATIC_COLLECTION_INITIALIZER;
Import* Imp;
unsigned HashVal;
+ /* If this is an initializer, insert it into the initializer list */
+ if (IS_EXP_INIT (E->Type)) {
+ CollAppend (&Initializers, E);
+ }
+
/* Create a hash value for the given name */
HashVal = HashStr (E->Name) % HASHTAB_SIZE;
do {
if (strcmp (L->Name, E->Name) == 0) {
/* This may be an unresolved external */
- if (L->Expr == 0) {
+ if (L->Expr == 0) {
/* This *is* an unresolved external */
E->Next = L->Next;
E->Name = ReadStr (F);
/* Read the value */
- if (Type & EXP_EXPR) {
+ if (IS_EXP_EXPR (Type)) {
E->Expr = ReadExpr (F, O);
} else {
E->Expr = LiteralExpr (Read32 (F), O);
-static void CheckSymType (Export* E)
+static void CheckSymType (const Export* E)
/* Check the types for one export */
{
/* External with matching imports */
Import* Imp = E->ImpList;
- int ZP = (E->Type & EXP_ZP) != 0;
+ int ZP = IS_EXP_ZP (E->Type);
while (Imp) {
- if (ZP != ((Imp->Type & IMP_ZP) != 0)) {
+ if (ZP != IS_IMP_ZP (Imp->Type)) {
/* Export is ZP, import is abs or the other way round */
if (E->Obj) {
- /* User defined export */
- Warning ("Type mismatch for `%s', export in "
+ /* User defined export */
+ Warning ("Type mismatch for `%s', export in "
"%s(%lu), import in %s(%lu)",
E->Name, E->Obj->Files [Imp->Pos.Name],
E->Pos.Line, Imp->Obj->Files [Imp->Pos.Name],
/* Print all open imports */
for (I = 0; I < ExpCount; ++I) {
- Export* E = ExpPool [I];
+ const Export* E = ExpPool [I];
if (E->Expr != 0 && E->ImpCount > 0) {
/* External with matching imports */
CheckSymType (E);
/* Print all exports */
Count = 0;
for (I = 0; I < ExpCount; ++I) {
- Export* E = ExpPool [I];
+ const Export* E = ExpPool [I];
/* Print unreferenced symbols only if explictly requested */
if (VerboseMap || E->ImpCount > 0) {
fprintf (F,
- "%-25s %06lX %c%c ",
- E->Name,
- GetExportVal (E),
- E->ImpCount? 'R' : ' ',
- (E->Type & EXP_ZP)? 'Z' : ' ');
+ "%-25s %06lX %c%c%c ",
+ E->Name,
+ GetExportVal (E),
+ E->ImpCount? 'R' : ' ',
+ IS_EXP_ZP (E->Type)? 'Z' : ' ',
+ IS_EXP_INIT (E->Type)? 'I' : ' ');
if (++Count == 2) {
- Count = 0;
- fprintf (F, "\n");
+ Count = 0;
+ fprintf (F, "\n");
}
}
}
/* Print an import map to the given file */
{
unsigned I;
- Import* Imp;
+ const Import* Imp;
/* Loop over all exports */
for (I = 0; I < ExpCount; ++I) {
/* Get the export */
- Export* Exp = ExpPool [I];
+ const Export* Exp = ExpPool [I];
/* Print the symbol only if there are imports, or if a verbose map
* file is requested.
/* Print the export */
fprintf (F,
- "%s (%s):\n",
- Exp->Name,
- ObjName);
+ "%s (%s):\n",
+ Exp->Name,
+ ObjName);
/* Print all imports for this symbol */
Imp = Exp->ImpList;
while (Imp) {
- /* Print the import */
- fprintf (F,
- " %-25s %s(%lu)\n",
- Imp->Obj->Name,
- Imp->Obj->Files [Imp->Pos.Name],
- Imp->Pos.Line);
+ /* Print the import */
+ fprintf (F,
+ " %-25s %s(%lu)\n",
+ Imp->Obj->Name,
+ Imp->Obj->Files [Imp->Pos.Name],
+ Imp->Pos.Line);
- /* Next import */
- Imp = Imp->Next;
+ /* Next import */
+ Imp = Imp->Next;
}
}
}
/* Print all exports */
for (I = 0; I < ExpCount; ++I) {
- Export* E = ExpPool [I];
+ const Export* E = ExpPool [I];
fprintf (F, "al %06lX .%s\n", GetExportVal (E), E->Name);
}
}
case EXP_EXPR: strcat (TypeDesc, ",EXP_EXPR"); break;
}
if (IS_EXP_INIT (Flags)) {
- strcat (TypeDesc, ",EXP_INIT");
+ sprintf (TypeDesc+strlen(TypeDesc), ",EXP_INIT=%u", GET_EXP_INIT_VAL(Flags));
}
/* Return the result */