diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index 7deb39c1b..d93976101 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -735,6 +735,14 @@ static void DoInclude (void) +static void DoInitializer (void) +/* Export a symbol as initializer */ +{ + ExportImport (SymInitializer, 0); +} + + + static void DoInvalid (void) /* Handle a token that is invalid here, since it should have been handled on * a much lower level of the expression hierarchy. Getting this sort of token @@ -1179,6 +1187,7 @@ static CtrlDesc CtrlCmdTab [] = { { ccNone, DoImportZP }, { ccNone, DoIncBin }, { ccNone, DoInclude }, + { ccNone, DoInitializer }, { ccNone, DoInvalid }, /* .LEFT */ { ccNone, DoLineCont }, { ccNone, DoList }, diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c index fb5212a3c..b14a974d6 100644 --- a/src/ca65/scanner.c +++ b/src/ca65/scanner.c @@ -182,6 +182,7 @@ struct DotKeyword { { "IMPORTZP", TOK_IMPORTZP }, { "INCBIN", TOK_INCBIN }, { "INCLUDE", TOK_INCLUDE }, + { "INITIALIZER", TOK_INITIALIZER }, { "LEFT", TOK_LEFT }, { "LINECONT", TOK_LINECONT }, { "LIST", TOK_LIST }, diff --git a/src/ca65/scanner.h b/src/ca65/scanner.h index 91ca49a27..0849eb529 100644 --- a/src/ca65/scanner.h +++ b/src/ca65/scanner.h @@ -165,6 +165,7 @@ enum Token { TOK_IMPORTZP, TOK_INCBIN, TOK_INCLUDE, + TOK_INITIALIZER, TOK_LEFT, TOK_LINECONT, TOK_LIST, diff --git a/src/ca65/symtab.c b/src/ca65/symtab.c index 12d9a4745..f43b4c7b1 100644 --- a/src/ca65/symtab.c +++ b/src/ca65/symtab.c @@ -63,8 +63,9 @@ #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_INITIALIZER 0x0020 /* Exported initializer */ +#define SF_ZP 0x0040 /* Declared as zeropage symbol */ +#define SF_ABS 0x0080 /* Declared as absolute symbol */ #define SF_INDEXED 0x0800 /* Index is valid */ #define SF_CONST 0x1000 /* The symbol has a constant value */ #define SF_MULTDEF 0x2000 /* Multiply defined symbol */ @@ -81,8 +82,6 @@ #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 */ @@ -116,6 +115,12 @@ struct SymTable_ { +/* 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 */ @@ -354,10 +359,8 @@ static SymEntry* SymFindAny (SymTable* Tab, const char* Name) static SymEntry* SymRefInternal (SymTable* Table, const char* Name) /* Search for the symbol in the given table and return it */ { - SymEntry* S; - /* Try to find the symbol, create a new one if the symbol does not exist */ - S = SymFind (Table, Name, 1); + SymEntry* S = SymFind (Table, Name, SF_ALLOC_NEW); /* Mark the symbol as referenced */ S->Flags |= SF_REFERENCED; @@ -396,10 +399,8 @@ void SymLeaveLevel (void) void SymDef (const char* Name, ExprNode* Expr, int ZP) /* Define a new symbol */ { - SymEntry* S; - /* Do we have such a symbol? */ - S = SymFind (SymTab, Name, 1); + 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); @@ -473,7 +474,7 @@ void SymImport (const char* Name, int ZP) } /* Do we have such a symbol? */ - S = SymFind (SymTab, Name, 1); + S = SymFind (SymTab, Name, SF_ALLOC_NEW); if (S->Flags & SF_DEFINED) { Error (ERR_SYM_ALREADY_DEFINED, Name); S->Flags |= SF_MULTDEF; @@ -516,7 +517,7 @@ void SymExport (const char* Name, int ZP) } /* Do we have such a symbol? */ - S = SymFind (SymTab, Name, 1); + 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); @@ -556,7 +557,7 @@ void SymGlobal (const char* Name, int ZP) } /* Search for this symbol, create a new entry if needed */ - S = SymFind (SymTab, Name, 1); + 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. */ @@ -576,6 +577,49 @@ void SymGlobal (const char* Name, int ZP) +void SymInitializer (const char* Name, int ZP) +/* 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. + */ +{ + SymEntry* S; + + /* Check the ZP parameter */ + CHECK (ZP == 0); + + /* 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); + 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 ((S->Flags & SF_ZP) != 0) { + Error (ERR_SYM_REDECL_MISMATCH); + } + S->Flags &= ~SF_GLOBAL; + } + + /* Set the symbol data */ + S->Flags |= SF_EXPORT | SF_INITIALIZER | SF_REFERENCED; +} + + + int SymIsDef (const char* Name) /* Return true if the given symbol is already defined */ { @@ -1030,20 +1074,30 @@ void WriteExports (void) /* Check if the symbol is const */ ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR; - /* Write the type */ - if (S->Flags & SF_ZP) { - ObjWrite8 (EXP_ZP | ExprMask); - } else { - ObjWrite8 (EXP_ABS | ExprMask); + /* Add zeropage/abs bits */ + ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS; + + /* Add the initializer bits */ + if (S->Flags & SF_INITIALIZER) { + ExprMask |= EXP_INITIALIZER; } + + /* Write the type */ + ObjWrite8 (ExprMask); + + /* Write the name */ ObjWriteStr (S->Name); - if (ExprMask == EXP_CONST) { + + /* 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; diff --git a/src/ca65/symtab.h b/src/ca65/symtab.h index 9176bc702..6c5642b27 100644 --- a/src/ca65/symtab.h +++ b/src/ca65/symtab.h @@ -42,7 +42,7 @@ /* common */ #include "exprdefs.h" - + /* ca65 */ #include "symentry.h" @@ -86,6 +86,14 @@ void SymGlobal (const char* Name, int ZP); * either imported or exported. */ +void SymInitializer (const char* Name, int ZP); +/* 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. + */ + int SymIsConst (SymEntry* Sym); /* Return true if the given symbol has a constant value */ @@ -145,4 +153,4 @@ void WriteDbgSyms (void); - + diff --git a/src/od65/dump.c b/src/od65/dump.c index b9bf7f122..a4413df96 100644 --- a/src/od65/dump.c +++ b/src/od65/dump.c @@ -33,6 +33,7 @@ +#include #include /* common */ @@ -536,7 +537,7 @@ void DumpObjExports (FILE* F, unsigned long Offset) unsigned long Value = 0; int HaveValue; - const char* TypeDesc; + char TypeDesc[128]; /* Read the data for one export */ unsigned char Type = Read8 (F); @@ -552,12 +553,17 @@ void DumpObjExports (FILE* F, unsigned long Offset) ReadFilePos (F, &Pos); /* Get a description for the type */ - switch (Type) { - case EXP_ABS|EXP_CONST: TypeDesc = "EXP_ABS,EXP_CONST"; break; - case EXP_ZP|EXP_CONST: TypeDesc = "EXP_ZP,EXP_CONST"; break; - case EXP_ABS|EXP_EXPR: TypeDesc = "EXP_ABS,EXP_EXPR"; break; - case EXP_ZP|EXP_EXPR: TypeDesc = "EXP_ZP,EXP_EXPR"; break; - default: TypeDesc = "EXP_UNKNOWN"; break; + TypeDesc[0] = '\0'; + switch (Type & EXP_MASK_SIZE) { + case EXP_ABS: strcat (TypeDesc, "EXP_ABS"); break; + case EXP_ZP: strcat (TypeDesc, "EXP_ZP"); break; + } + switch (Type & EXP_MASK_VAL) { + case EXP_CONST: strcat (TypeDesc, ",EXP_CONST"); break; + case EXP_EXPR: strcat (TypeDesc, ",EXP_EXPR"); break; + } + if (Type & EXP_INITIALIZER) { + strcat (TypeDesc, ",EXP_INITIALIZER"); } /* Print the header */