shithub: rgbds

Download patch

ref: 62d820c2612ecf8f51d71b0ec4a1d9862d9908f6
parent: ff2321a8ce30c6d0af0e38b0383361b8841914a2
parent: a53d795361fc63a07e54aa23d104a9d073370734
author: Antonio Niño Díaz <[email protected]>
date: Mon Jun 12 17:46:32 EDT 2017

Merge pull request #181 from Ben10do/reference-local-symbols

Allow local labels to be referenced (and exported)

Signed-off-by: Antonio Niño Díaz <[email protected]>

--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -587,7 +587,11 @@
 		else
 			sym_AddReloc($1);
 	} | T_LABEL ':' ':' {
-		sym_AddReloc($1);
+		if ($1[0] == '.') {
+			sym_AddLocalReloc($1);
+		} else {
+			sym_AddReloc($1);
+		}
 		sym_Export($1);
 	};
 
--- a/src/asm/globlex.c
+++ b/src/asm/globlex.c
@@ -475,6 +475,7 @@
 	lex_FloatAddSecondRange(id, '\\', '\\');
 	lex_FloatAddSecondRange(id, '@', '@');
 	lex_FloatAddSecondRange(id, '#', '#');
+	lex_FloatAddRange(id, '.', '.');
 	lex_FloatAddRange(id, 'a', 'z');
 	lex_FloatAddRange(id, 'A', 'Z');
 	lex_FloatAddRange(id, '0', '9');
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -260,11 +260,7 @@
 		sectid = -1;
 		type = SYM_IMPORT;
 	} else {
-		if (pSym->nType & SYMF_LOCAL) {
-			strcpy(symname, pSym->pScope->tzName);
-			strcat(symname, pSym->tzName);
-		} else
-			strcpy(symname, pSym->tzName);
+		strcpy(symname, pSym->tzName);
 
 		if (pSym->nType & SYMF_EXPORT) {
 			/* Symbol should be exported */
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -114,26 +114,16 @@
 		return (NULL);
 	}
 }
+
 /*
- * Find a symbol by name and scope
+ * Creates the full name of a local symbol in a given scope, by prepending
+ * the name with the parent symbol's name.
  */
-struct sSymbol *
-findsymbol(char *s, struct sSymbol * scope)
+size_t
+fullSymbolName(char *output, size_t outputSize, char *localName, struct sSymbol *scope)
 {
-	struct sSymbol **ppsym;
-	SLONG hash;
-
-	hash = calchash(s);
-	ppsym = &(tHashedSymbols[hash]);
-
-	while ((*ppsym) != NULL) {
-		if ((strcmp(s, (*ppsym)->tzName) == 0)
-		    && ((*ppsym)->pScope == scope)) {
-			return (*ppsym);
-		} else
-			ppsym = &((*ppsym)->pNext);
-	}
-	return (NULL);
+	struct sSymbol *parent = scope->pScope ? scope->pScope : scope;
+	return snprintf(output, outputSize, "%s%s", parent->tzName, localName);
 }
 
 /*
@@ -144,13 +134,25 @@
 {
 	struct sSymbol **ppsym;
 	SLONG hash;
+	char fullname[MAXSYMLEN + 1];
+		
+	if (s[0] == '.' && scope) {
+		fullSymbolName(fullname, sizeof(fullname), s, scope);
+		s = fullname;
+	}
+	
+	char *seperator;
+	if ((seperator = strchr(s, '.'))) {
+		if (strchr(seperator + 1, '.')) {
+			fatalerror("'%s' is a nonsensical reference to a nested local symbol", s);
+		}
+	}
 
 	hash = calchash(s);
 	ppsym = &(tHashedSymbols[hash]);
 
 	while ((*ppsym) != NULL) {
-		if ((strcmp(s, (*ppsym)->tzName) == 0)
-		    && ((*ppsym)->pScope == scope)) {
+		if ((strcmp(s, (*ppsym)->tzName) == 0)) {
 			return (ppsym);
 		} else
 			ppsym = &((*ppsym)->pNext);
@@ -162,6 +164,16 @@
  * Find a symbol by name and scope
  */
 struct sSymbol *
+findsymbol(char *s, struct sSymbol * scope)
+{
+	struct sSymbol **ppsym = findpsymbol(s, scope);
+	return ppsym ? *ppsym : NULL;
+}
+
+/*
+ * Find a symbol by name and scope
+ */
+struct sSymbol *
 sym_FindSymbol(char *tzName)
 {
 	struct sSymbol *pscope;
@@ -593,31 +605,17 @@
 void
 sym_AddLocalReloc(char *tzSym)
 {
-	if ((nPass == 1)
-	    || ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
-		/* only add local reloc symbols in pass 1 */
-		struct sSymbol *nsym;
-
-		if (pScope) {
-			if ((nsym = findsymbol(tzSym, pScope)) != NULL) {
-				if (nsym->nType & SYMF_DEFINED) {
-					yyerror("'%s' already defined", tzSym);
-				}
-			} else
-				nsym = createsymbol(tzSym);
-
-			if (nsym) {
-				nsym->nValue = nPC;
-				nsym->nType |=
-				    SYMF_RELOC | SYMF_LOCAL | SYMF_DEFINED;
-				if (exportall) {
-				   nsym->nType |= SYMF_EXPORT;
-				}
-				nsym->pScope = pScope;
-				nsym->pSection = pCurrentSection;
-			}
-		} else
-			fatalerror("Local label in main scope");
+	if (pScope) {
+		if (strlen(tzSym) + strlen(pScope->tzName) > MAXSYMLEN) {
+			fatalerror("Symbol too long");
+		}
+		
+		char fullname[MAXSYMLEN + 1];
+		fullSymbolName(fullname, sizeof(fullname), tzSym, pScope);
+		sym_AddReloc(fullname);
+		
+	} else {
+		fatalerror("Local label in main scope");
 	}
 }
 
@@ -627,12 +625,32 @@
 void
 sym_AddReloc(char *tzSym)
 {
+	struct sSymbol* scope = NULL;
+	
 	if ((nPass == 1)
 	    || ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
 		/* only add reloc symbols in pass 1 */
 		struct sSymbol *nsym;
+		char *localPtr = NULL;
+		
+		if ((localPtr = strchr(tzSym, '.')) != NULL) {			
+			if (!pScope) {
+				fatalerror("Local label in main scope");
+			}
+			
+			struct sSymbol *parent = pScope->pScope ? pScope->pScope : pScope;
+			int parentLen = localPtr - tzSym;
+			
+			if (strchr(localPtr + 1, '.') != NULL) {
+				fatalerror("'%s' is a nonsensical reference to a nested local symbol", tzSym);
+			} else if (strlen(parent->tzName) != parentLen || strncmp(tzSym, parent->tzName, parentLen) != 0) {
+				yyerror("Not currently in the scope of '%.*s'", parentLen, tzSym);
+			}
+			
+			scope = parent;
+		}
 
-		if ((nsym = findsymbol(tzSym, NULL)) != NULL) {
+		if ((nsym = findsymbol(tzSym, scope)) != NULL) {
 			if (nsym->nType & SYMF_DEFINED) {
 				yyerror("'%s' already defined", tzSym);
 			}
@@ -642,14 +660,17 @@
 		if (nsym) {
 			nsym->nValue = nPC;
 			nsym->nType |= SYMF_RELOC | SYMF_DEFINED;
+			if (localPtr) {
+				nsym->nType |= SYMF_LOCAL;
+			}
 			if (exportall) {
 			   nsym->nType |= SYMF_EXPORT;
 			}
-			nsym->pScope = NULL;
+			nsym->pScope = scope;
 			nsym->pSection = pCurrentSection;
 		}
 	}
-	pScope = findsymbol(tzSym, NULL);
+	pScope = findsymbol(tzSym, scope);
 }
 
 /*
@@ -705,7 +726,7 @@
 		/* only export symbols in pass 1 */
 		struct sSymbol *nsym;
 
-		if ((nsym = findsymbol(tzSym, 0)) == NULL)
+		if ((nsym = sym_FindSymbol(tzSym)) == NULL)
 			nsym = createsymbol(tzSym);
 
 		if (nsym)
@@ -713,7 +734,7 @@
 	} else {
 		struct sSymbol *nsym;
 
-		if ((nsym = findsymbol(tzSym, 0)) != NULL) {
+		if ((nsym = sym_FindSymbol(tzSym)) != NULL) {
 			if (nsym->nType & SYMF_DEFINED)
 				return;
 		}
@@ -732,7 +753,7 @@
 		/* only globalize symbols in pass 2 */
 		struct sSymbol *nsym;
 
-		nsym = findsymbol(tzSym, 0);
+		nsym = sym_FindSymbol(tzSym);
 
 		if ((nsym == NULL) || ((nsym->nType & SYMF_DEFINED) == 0)) {
 			if (nsym == NULL)
--- /dev/null
+++ b/test/asm/local-wrong-parent.asm
@@ -1,0 +1,6 @@
+SECTION "sec", ROM0
+
+Parent:
+	db 0
+WrongParent.child
+	db 0
--- /dev/null
+++ b/test/asm/local-wrong-parent.out
@@ -1,0 +1,3 @@
+ERROR: local-wrong-parent.asm(5):
+	Not currently in the scope of 'WrongParent'
+error: Assembly aborted in pass 1 (1 errors)!
--- /dev/null
+++ b/test/asm/remote-local-explicit.asm
@@ -1,0 +1,7 @@
+SECTION "sec", ROM0
+
+Parent:
+Parent.child::
+	db 0
+NotParent:
+	dw Parent.child
--- /dev/null
+++ b/test/asm/remote-local-noexist.asm
@@ -1,0 +1,7 @@
+SECTION "sec", ROM0
+
+Parent:
+.child:
+	db 0
+NotParent:
+	dw Parent.child.fail
--- /dev/null
+++ b/test/asm/remote-local-noexist.out
@@ -1,0 +1,2 @@
+ERROR: remote-local-noexist.asm(7):
+	'Parent.child.fail' is a nonsensical reference to a nested local symbol
--- /dev/null
+++ b/test/asm/remote-local.asm
@@ -1,0 +1,7 @@
+SECTION "sec", ROM0
+
+Parent:
+.child:
+	db 0
+NotParent:
+	dw Parent.child