shithub: rgbds

Download patch

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)!