ref: 2e3db9d56ac9ebd6daee9d411764c5011dc2242a
parent: f53ad359a64472dc9d4e0b51b603040c943cb8eb
author: ISSOtm <[email protected]>
date: Sat Oct 3 17:33:30 EDT 2020
Clean up label generation Only check for localness when we already know we have a local
--- a/include/asm/symbol.h
+++ b/include/asm/symbol.h
@@ -34,7 +34,6 @@
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 @@
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_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 */
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -562,8 +562,6 @@
%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 @@
| pseudoop
;
-scoped_label_bare : T_LABEL {
- warning(WARNING_OBSOLETE, "Non-local labels without a colon are deprecated\n");
- strcpy($$, $1);
- }
+scoped_id : T_ID | T_LOCAL_ID ;
+
+label : /* empty */
| T_LOCAL_ID {
- strcpy($$, $1);
+ sym_AddLocalLabel($1);
}
-;
-scoped_label : T_LABEL ':' {
- strcpy($$, $1);
+ | T_LABEL {
+ warning(WARNING_OBSOLETE, "Non-local labels without a colon are deprecated\n");
+ sym_AddLabel($1);
}
| T_LOCAL_ID ':' {
- strcpy($$, $1);
+ sym_AddLocalLabel($1);
}
-;
-scoped_id : T_ID | T_LOCAL_ID ;
-
-label : /* empty */
- | scoped_label_bare {
- if ($1[0] == '.')
- sym_AddLocalReloc($1);
- else
- sym_AddReloc($1);
+ | T_LABEL ':' {
+ sym_AddLabel($1);
}
- | scoped_label {
- if ($1[0] == '.')
- sym_AddLocalReloc($1);
- else
- sym_AddReloc($1);
+ | T_LOCAL_ID ':' ':' {
+ sym_AddLocalLabel($1);
+ sym_Export($1);
}
- | scoped_label ':' {
- if ($1[0] == '.')
- sym_AddLocalReloc($1);
- else
- sym_AddReloc($1);
+ | T_LABEL ':' ':' {
+ sym_AddLabel($1);
sym_Export($1);
}
;
--- a/src/asm/section.c
+++ b/src/asm/section.c
@@ -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_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 @@
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);
}
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -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 @@
symbol->isExported = false;
symbol->isBuiltin = false;
- symbol->scope = NULL;
symbol->section = NULL;
updateSymbolFilename(symbol);
symbol->ID = -1;
@@ -148,19 +147,20 @@
* 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 @@
*/
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 @@
*/
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 @@
} 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 @@
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 @@
}
/*
- * 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);
- char fullname[MAXSYMLEN + 1];
+ return sym;
+}
- fullSymbolName(fullname, sizeof(fullname), symName, symbolScope);
- return sym_AddReloc(fullname);
+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 relocatable symbol
+ * Add a local (.name or Parent.name) relocatable symbol
*/
-struct Symbol *sym_AddReloc(char const *symName)
+struct Symbol *sym_AddLocalLabel(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);
+ if (!labelScope) {
+ error("Local label '%s' in main scope\n", name);
+ return NULL;
}
- struct Symbol *sym = findsymbol(symName, scope);
+ char fullname[MAXSYMLEN + 1];
- 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 */
+ 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;
- sym->type = SYM_LABEL;
- sym->callback = NULL;
- sym->value = sect_GetSymbolOffset();
+ /* 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);
- if (exportall)
- sym->isExported = true;
+ /*
+ * 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);
+ }
- 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);
+ return addLabel(name);
+}
- updateSymbolFilename(sym);
+/*
+ * Add a relocatable symbol
+ */
+struct Symbol *sym_AddLabel(char const *name)
+{
+ 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 @@
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 @@
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 @@
addString("__UTC_SECOND__", removeLeadingZeros(savedSECOND));
#undef addString
- symbolScope = NULL;
+ labelScope = NULL;
math_DefinePI();
}
--- a/test/asm/label-macro-arg.err
+++ b/test/asm/label-macro-arg.err
@@ -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
--- /dev/null
+++ b/test/asm/sym-scope.asm
@@ -1,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
--- /dev/null
+++ b/test/asm/sym-scope.err
@@ -1,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)!