Clean up label generation

Only check for localness when we already know we have a local
This commit is contained in:
ISSOtm
2020-10-03 21:33:30 +02:00
parent f53ad359a6
commit 2e3db9d56a
8 changed files with 161 additions and 129 deletions

View File

@@ -34,7 +34,6 @@ struct Symbol {
enum SymbolType type;
bool isExported; /* Whether the symbol is to be exported */
bool isBuiltin; /* Whether the symbol is a built-in */
struct Symbol const *scope;
struct Section *section;
char fileName[_MAX_PATH + 1]; /* File where the symbol was defined. */
uint32_t fileLine; /* Line where the symbol was defined. */
@@ -109,8 +108,8 @@ void sym_ForEach(void (*func)(struct Symbol *, void *), void *arg);
int32_t sym_GetValue(struct Symbol const *sym);
void sym_SetExportAll(bool set);
struct Symbol *sym_AddLocalReloc(char const *symName);
struct Symbol *sym_AddReloc(char const *symName);
struct Symbol *sym_AddLocalLabel(char const *symName);
struct Symbol *sym_AddLabel(char const *symName);
void sym_Export(char const *symName);
struct Symbol *sym_AddEqu(char const *symName, int32_t value);
struct Symbol *sym_AddSet(char const *symName, int32_t value);
@@ -125,7 +124,7 @@ void sym_Purge(char const *symName);
void sym_Init(void);
/* Functions to save and restore the current symbol scope. */
struct Symbol *sym_GetCurrentSymbolScope(void);
void sym_SetCurrentSymbolScope(struct Symbol *newScope);
char const *sym_GetCurrentSymbolScope(void);
void sym_SetCurrentSymbolScope(char const *newScope);
#endif /* RGBDS_SYMBOL_H */

View File

@@ -562,8 +562,6 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
%left NEG /* negation -- unary minus */
%token <tzSym> T_LABEL
%type <tzSym> scoped_label
%type <tzSym> scoped_label_bare
%token <tzSym> T_ID
%token <tzSym> T_LOCAL_ID
%type <tzSym> scoped_id
@@ -674,41 +672,28 @@ line : label
| pseudoop
;
scoped_label_bare : T_LABEL {
warning(WARNING_OBSOLETE, "Non-local labels without a colon are deprecated\n");
strcpy($$, $1);
}
| T_LOCAL_ID {
strcpy($$, $1);
}
;
scoped_label : T_LABEL ':' {
strcpy($$, $1);
}
| T_LOCAL_ID ':' {
strcpy($$, $1);
}
;
scoped_id : T_ID | T_LOCAL_ID ;
label : /* empty */
| scoped_label_bare {
if ($1[0] == '.')
sym_AddLocalReloc($1);
else
sym_AddReloc($1);
| T_LOCAL_ID {
sym_AddLocalLabel($1);
}
| scoped_label {
if ($1[0] == '.')
sym_AddLocalReloc($1);
else
sym_AddReloc($1);
| T_LABEL {
warning(WARNING_OBSOLETE, "Non-local labels without a colon are deprecated\n");
sym_AddLabel($1);
}
| scoped_label ':' {
if ($1[0] == '.')
sym_AddLocalReloc($1);
else
sym_AddReloc($1);
| T_LOCAL_ID ':' {
sym_AddLocalLabel($1);
}
| T_LABEL ':' {
sym_AddLabel($1);
}
| T_LOCAL_ID ':' ':' {
sym_AddLocalLabel($1);
sym_Export($1);
}
| T_LABEL ':' ':' {
sym_AddLabel($1);
sym_Export($1);
}
;

View File

@@ -17,13 +17,13 @@
#include "platform.h" // strdup
struct SectionStackEntry {
struct Section *pSection;
struct Symbol *pScope; /* Section's symbol scope */
struct Section *section;
char const *scope; /* Section's symbol scope */
uint32_t offset;
struct SectionStackEntry *next;
};
struct SectionStackEntry *pSectionStack;
struct SectionStackEntry *sectionStack;
uint32_t curOffset; /* Offset into the current section (see sect_GetSymbolOffset) */
static struct Section *currentLoadSection = NULL;
uint32_t loadOffset; /* The offset of the LOAD section within its parent */
@@ -774,23 +774,21 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
*/
void out_PushSection(void)
{
struct SectionStackEntry *sect;
struct SectionStackEntry *sect = malloc(sizeof(*sect));
sect = malloc(sizeof(struct SectionStackEntry));
if (sect == NULL)
fatalerror("No memory for section stack: %s<\n", strerror(errno));
sect->pSection = pCurrentSection;
sect->pScope = sym_GetCurrentSymbolScope();
fatalerror("No memory for section stack: %s\n", strerror(errno));
sect->section = pCurrentSection;
sect->scope = sym_GetCurrentSymbolScope();
sect->offset = curOffset;
sect->next = pSectionStack;
pSectionStack = sect;
sect->next = sectionStack;
sectionStack = sect;
/* TODO: maybe set current section to NULL? */
}
void out_PopSection(void)
{
if (pSectionStack == NULL)
if (!sectionStack)
fatalerror("No entries in the section stack\n");
if (currentLoadSection)
@@ -798,12 +796,12 @@ void out_PopSection(void)
struct SectionStackEntry *sect;
sect = pSectionStack;
sect = sectionStack;
changeSection();
pCurrentSection = sect->pSection;
sym_SetCurrentSymbolScope(sect->pScope);
pCurrentSection = sect->section;
sym_SetCurrentSymbolScope(sect->scope);
curOffset = sect->offset;
pSectionStack = sect->next;
sectionStack = sect->next;
free(sect);
}

View File

@@ -36,7 +36,7 @@
HashMap symbols;
static struct Symbol *symbolScope; /* Current section symbol scope */
static char const *labelScope; /* Current section's label scope */
static struct Symbol *PCSymbol;
static char savedTIME[256];
static char savedDATE[256];
@@ -133,7 +133,6 @@ static struct Symbol *createsymbol(char const *s)
symbol->isExported = false;
symbol->isBuiltin = false;
symbol->scope = NULL;
symbol->section = NULL;
updateSymbolFilename(symbol);
symbol->ID = -1;
@@ -148,19 +147,20 @@ static struct Symbol *createsymbol(char const *s)
* the name with the parent symbol's name.
*/
static void fullSymbolName(char *output, size_t outputSize,
char const *localName, const struct Symbol *scope)
char const *localName, char const *scopeName)
{
const struct Symbol *parent = scope->scope ? scope->scope : scope;
int n = snprintf(output, outputSize, "%s%s", parent->name, localName);
int ret = snprintf(output, outputSize, "%s%s", scopeName, localName);
if (n >= (int)outputSize)
fatalerror("Symbol name is too long: '%s%s'\n", parent->name, localName);
if (ret < 0)
fatalerror("snprintf error when expanding symbol name: %s", strerror(errno));
else if ((size_t)ret >= outputSize)
fatalerror("Symbol name is too long: '%s%s'\n", scopeName, localName);
}
/*
* Find a symbol by name and scope
*/
static struct Symbol *findsymbol(char const *s, struct Symbol const *scope)
static struct Symbol *findsymbol(char const *s, char const *scope)
{
char fullname[MAXSYMLEN + 1];
@@ -182,7 +182,7 @@ static struct Symbol *findsymbol(char const *s, struct Symbol const *scope)
*/
struct Symbol *sym_FindSymbol(char const *symName)
{
return findsymbol(symName, symName[0] == '.' ? symbolScope : NULL);
return findsymbol(symName, symName[0] == '.' ? labelScope : NULL);
}
static inline bool isReferenced(struct Symbol const *sym)
@@ -195,8 +195,7 @@ static inline bool isReferenced(struct Symbol const *sym)
*/
void sym_Purge(char const *symName)
{
struct Symbol *scope = symName[0] == '.' ? symbolScope : NULL;
struct Symbol *symbol = findsymbol(symName, scope);
struct Symbol *symbol = sym_FindSymbol(symName);
if (!symbol) {
error("'%s' not defined\n", symName);
@@ -205,6 +204,10 @@ void sym_Purge(char const *symName)
} else if (isReferenced(symbol)) {
error("Symbol \"%s\" is referenced and thus cannot be purged\n", symName);
} else {
/* Do not keep a reference to the label's name after purging it */
if (symbol->name == labelScope)
labelScope = NULL;
hash_RemoveElement(symbols, symbol->name);
if (symbol->type == SYM_MACRO)
free(symbol->macro);
@@ -261,14 +264,14 @@ uint32_t sym_GetDefinedValue(char const *s)
return 0;
}
struct Symbol *sym_GetCurrentSymbolScope(void)
char const *sym_GetCurrentSymbolScope(void)
{
return symbolScope;
return labelScope;
}
void sym_SetCurrentSymbolScope(struct Symbol *newScope)
void sym_SetCurrentSymbolScope(char const *newScope)
{
symbolScope = newScope;
labelScope = newScope;
}
/*
@@ -358,74 +361,94 @@ struct Symbol *sym_AddSet(char const *symName, int32_t value)
}
/*
* Add a local (.name) relocatable symbol
* Add a label (aka "relocatable symbol")
* @param name The label's full name (so `.name` is invalid)
* @return The created symbol
*/
struct Symbol *sym_AddLocalReloc(char const *symName)
static struct Symbol *addSectionlessLabel(char const *name)
{
if (!symbolScope) {
error("Local label '%s' in main scope\n", symName);
assert(name[0] != '.'); /* The symbol name must have been expanded prior */
struct Symbol *sym = findsymbol(name, NULL); /* Due to this, don't look for expansions */
if (!sym) {
sym = createsymbol(name);
} else if (sym_IsDefined(sym)) {
error("'%s' already defined in %s(%" PRIu32 ")\n",
name, sym->fileName, sym->fileLine);
return NULL;
}
/* If the symbol already exists as a ref, just "take over" it */
sym->type = SYM_LABEL;
sym->callback = NULL;
sym->value = sect_GetSymbolOffset();
if (exportall)
sym->isExported = true;
sym->section = sect_GetSymbolSection();
updateSymbolFilename(sym);
return sym;
}
static struct Symbol *addLabel(char const *name)
{
struct Symbol *sym = addSectionlessLabel(name);
if (sym && !sym->section)
error("Label \"%s\" created outside of a SECTION\n", name);
return sym;
}
/*
* Add a local (.name or Parent.name) relocatable symbol
*/
struct Symbol *sym_AddLocalLabel(char const *name)
{
if (!labelScope) {
error("Local label '%s' in main scope\n", name);
return NULL;
}
char fullname[MAXSYMLEN + 1];
fullSymbolName(fullname, sizeof(fullname), symName, symbolScope);
return sym_AddReloc(fullname);
if (name[0] == '.') {
/* If symbol is of the form `.name`, expand to the full `Parent.name` name */
fullSymbolName(fullname, sizeof(fullname), name, labelScope);
name = fullname; /* Use the expanded name instead */
} else {
size_t i = 0;
/* Otherwise, check that `Parent` is in fact the current scope */
while (labelScope[i] && name[i] == labelScope[i])
i++;
/* Assuming no dots in `labelScope` */
assert(strchr(&name[i], '.')); /* There should be at least one dot, though */
size_t parentLen = i + (strchr(&name[i], '.') - name);
/*
* Check that `labelScope[i]` ended the check, guaranteeing that `name` is at least
* as long, and then that this was the entirety of the `Parent` part of `name`.
*/
if (labelScope[i] != '\0' || name[i] != '.')
error("Not currently in the scope of '%.*s'\n", parentLen, name);
if (strchr(&name[parentLen + 1], '.')) /* There will at least be a terminator */
fatalerror("'%s' is a nonsensical reference to a nested local label\n",
name);
}
return addLabel(name);
}
/*
* Add a relocatable symbol
*/
struct Symbol *sym_AddReloc(char const *symName)
struct Symbol *sym_AddLabel(char const *name)
{
struct Symbol const *scope = NULL;
char *localPtr = strchr(symName, '.');
if (localPtr != NULL) {
if (!symbolScope) {
error("Local label in main scope\n");
return NULL;
}
scope = symbolScope->scope ? symbolScope->scope : symbolScope;
uint32_t parentLen = localPtr - symName;
if (strchr(localPtr + 1, '.') != NULL)
fatalerror("'%s' is a nonsensical reference to a nested local symbol\n",
symName);
else if (strlen(scope->name) != parentLen
|| strncmp(symName, scope->name, parentLen) != 0)
error("Not currently in the scope of '%.*s'\n", parentLen, symName);
}
struct Symbol *sym = findsymbol(symName, scope);
if (!sym)
sym = createsymbol(symName);
else if (sym_IsDefined(sym))
error("'%s' already defined in %s(%" PRIu32 ")\n",
symName, sym->fileName, sym->fileLine);
/* If the symbol already exists as a ref, just "take over" it */
sym->type = SYM_LABEL;
sym->callback = NULL;
sym->value = sect_GetSymbolOffset();
if (exportall)
sym->isExported = true;
sym->scope = scope;
sym->section = sect_GetSymbolSection();
/* Labels need to be assigned a section, except PC */
if (!sym->section && strcmp(symName, "@"))
error("Label \"%s\" created outside of a SECTION\n", symName);
updateSymbolFilename(sym);
struct Symbol *sym = addLabel(name);
/* Set the symbol as the new scope */
/* TODO: don't do this for local labels */
symbolScope = findsymbol(symName, scope);
return symbolScope;
if (sym)
labelScope = sym->name;
return sym;
}
/*
@@ -471,19 +494,16 @@ struct Symbol *sym_Ref(char const *symName)
if (nsym == NULL) {
char fullname[MAXSYMLEN + 1];
struct Symbol const *scope = NULL;
if (symName[0] == '.') {
if (!symbolScope)
if (!labelScope)
fatalerror("Local label reference '%s' in main scope\n", symName);
scope = symbolScope->scope ? symbolScope->scope : symbolScope;
fullSymbolName(fullname, sizeof(fullname), symName, symbolScope);
fullSymbolName(fullname, sizeof(fullname), symName, labelScope);
symName = fullname;
}
nsym = createsymbol(symName);
nsym->type = SYM_REF;
nsym->scope = scope;
}
return nsym;
@@ -516,7 +536,7 @@ void sym_Init(void)
struct Symbol *_NARGSymbol = sym_AddEqu("_NARG", 0);
struct Symbol *__LINE__Symbol = sym_AddEqu("__LINE__", 0);
PCSymbol = sym_AddReloc("@"),
PCSymbol = addSectionlessLabel("@");
PCSymbol->isBuiltin = true;
PCSymbol->callback = CallbackPC;
_NARGSymbol->isBuiltin = true;
@@ -571,7 +591,7 @@ void sym_Init(void)
addString("__UTC_SECOND__", removeLeadingZeros(savedSECOND));
#undef addString
symbolScope = NULL;
labelScope = NULL;
math_DefinePI();
}

View File

@@ -1,5 +1,5 @@
ERROR: label-macro-arg.asm(44) -> label-macro-arg.asm::test_char(31):
Local label in main scope
Local label 'sizeof_.something' in main scope
while expanding symbol "VAR_DEF"
ERROR: label-macro-arg.asm(44) -> label-macro-arg.asm::test_char(31):
syntax error

21
test/asm/sym-scope.asm Normal file
View File

@@ -0,0 +1,21 @@
SECTION "Scopes", ROM0
; Neither of these should be created
.tooSoon
Nice.try
Parent:
.loc
dw Parent.loc ; This is what it should expand to
Parent.explicit
dw .explicit ; This should expand to the above
; None of the two locals below should manage to be created, being in the wrong scopes
; Note however that `Parentheses` begins with `Parent`, which string checks may fail to handle
Parentheses.check
Parentheses:
Parent.check

9
test/asm/sym-scope.err Normal file
View File

@@ -0,0 +1,9 @@
ERROR: sym-scope.asm(4):
Local label '.tooSoon' in main scope
ERROR: sym-scope.asm(5):
Local label 'Nice.try' in main scope
ERROR: sym-scope.asm(17):
Not currently in the scope of 'Parentheses.check'
ERROR: sym-scope.asm(21):
Not currently in the scope of 'Parent.check'
error: Assembly aborted (4 errors)!

0
test/asm/sym-scope.out Normal file
View File