shithub: rgbds

Download patch

ref: fd02ffb7bd6e41d310dd1c6f0652fcee82152437
parent: 62ecdce0b0db976894f88336f1fa7f257a77e950
author: ISSOtm <[email protected]>
date: Sun Aug 16 09:33:06 EDT 2020

Implement __FILE__ symbol

Also clean up built-in symbol creation
This is not great, but currently okay.
Should be fixed later, like the rest...

--- a/include/asm/fstack.h
+++ b/include/asm/fstack.h
@@ -58,6 +58,7 @@
 
 void fstk_Dump(void);
 char *fstk_DumpToStr(void);
+char const *fstk_GetFileName(void);
 uint32_t fstk_GetLine(void);
 
 void fstk_Init(char *mainPath, uint32_t maxRecursionDepth);
--- a/include/asm/symbol.h
+++ b/include/asm/symbol.h
@@ -38,15 +38,20 @@
 	char fileName[_MAX_PATH + 1]; /* File where the symbol was defined. */
 	uint32_t fileLine; /* Line where the symbol was defined. */
 
+	bool hasCallback;
 	union {
-		struct { /* If sym_IsNumeric */
+		union { /* Otherwise */
+			/* If sym_IsNumeric */
 			int32_t value;
-			int32_t (*callback)(void);
+			int32_t (*numCallback)(void);
+			/* For SYM_MACRO */
+			struct {
+				size_t macroSize;
+				char *macro;
+			};
+			/* For SYM_EQUS, TODO: separate "base" fields from SYM_MACRO */
+			char const *(*strCallback)(void); /* For SYM_EQUS */
 		};
-		struct { /* For SYM_MACRO */
-			size_t macroSize;
-			char *macro;
-		};
 	};
 
 	uint32_t ID; /* ID of the symbol in the object file (-1 if none) */
@@ -101,6 +106,8 @@
  */
 static inline char const *sym_GetStringValue(struct Symbol const *sym)
 {
+	if (sym->hasCallback)
+		return sym->strCallback();
 	return sym->macro;
 }
 
--- a/src/asm/fstack.c
+++ b/src/asm/fstack.c
@@ -229,8 +229,8 @@
 
 	newContext(0);
 	/* Line minus 1 because buffer begins with a newline */
-	contextStack->lexerState = lexer_OpenFileView(macro->macro,
-						      macro->macroSize, macro->fileLine - 1);
+	contextStack->lexerState = lexer_OpenFileView(macro->macro, macro->macroSize,
+						      macro->fileLine - 1);
 	if (!contextStack->lexerState)
 		fatalerror("Failed to set up lexer for macro invocation\n");
 	lexer_SetStateAtEOL(contextStack->lexerState);
@@ -305,6 +305,11 @@
 	dumpToStream(stream);
 	fclose(stream);
 	return str;
+}
+
+char const *fstk_GetFileName(void)
+{
+	return contextStack->fileName;
 }
 
 uint32_t fstk_GetLine(void)
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -85,6 +85,45 @@
 	return lexer_GetLineNo();
 }
 
+static char const *Callback__FILE__(void)
+{
+	/*
+	 * FIXME: this is dangerous, and here's why this is CURRENTLY okay. It's still bad, fix it.
+	 * There are only two call sites for this; one copies the contents directly, the other is
+	 * EQUS expansions, which cannot straddle file boundaries. So this should be fine.
+	 */
+	static char *buf = NULL;
+	static size_t bufsize = 0;
+	char const *fileName = fstk_GetFileName();
+	size_t j = 1;
+
+	/* TODO: is there a way for a file name to be empty? */
+	assert(strlen(fileName) != 0);
+	/* The assertion above ensures the loop runs at least once */
+	for (size_t i = 0; fileName[i]; i++, j++) {
+		/* Account for the extra backslash inserted below */
+		if (fileName[i] == '"')
+			j++;
+		/* Ensure there will be enough room; DO NOT PRINT ANYTHING ABOVE THIS!! */
+		if (j + 2 >= bufsize) { /* Always keep room for 2 tail chars */
+			bufsize = bufsize ? bufsize * 2 : 64;
+			buf = realloc(buf, bufsize);
+			if (!buf)
+				fatalerror("Failed to grow buffer for file name: %s\n",
+					   strerror(errno));
+		}
+		/* Escape quotes, since we're returning a string */
+		if (fileName[i] == '"')
+			buf[j - 1] = '\\';
+		buf[j] = fileName[i];
+	}
+	/* Write everything after the loop, to ensure everything has been allocated */
+	buf[0] = '"';
+	buf[j++] = '"';
+	buf[j] = '\0';
+	return buf;
+}
+
 static int32_t CallbackPC(void)
 {
 	struct Section const *section = sect_GetSymbolSection();
@@ -97,8 +136,8 @@
  */
 int32_t sym_GetValue(struct Symbol const *sym)
 {
-	if (sym_IsNumeric(sym) && sym->callback)
-		return sym->callback();
+	if (sym_IsNumeric(sym) && sym->hasCallback)
+		return sym->numCallback();
 
 	if (sym->type == SYM_LABEL)
 		/* TODO: do not use section's org directly */
@@ -113,9 +152,8 @@
 static void updateSymbolFilename(struct Symbol *sym)
 {
 	if (snprintf(sym->fileName, _MAX_PATH + 1, "%s",
-		     lexer_GetFileName()) > _MAX_PATH)
-		fatalerror("%s: File name is too long: '%s'\n", __func__,
-			   lexer_GetFileName());
+		     fstk_GetFileName()) > _MAX_PATH)
+		fatalerror("%s: File name is too long: '%s'\n", __func__, fstk_GetFileName());
 	sym->fileLine = fstk_GetLine();
 }
 
@@ -134,6 +172,7 @@
 
 	symbol->isExported = false;
 	symbol->isBuiltin = false;
+	symbol->hasCallback = false;
 	symbol->section = NULL;
 	updateSymbolFilename(symbol);
 	symbol->ID = -1;
@@ -310,7 +349,6 @@
 	struct Symbol *sym = createNonrelocSymbol(symName);
 
 	sym->type = SYM_EQU;
-	sym->callback = NULL;
 	sym->value = value;
 
 	return sym;
@@ -364,7 +402,6 @@
 		updateSymbolFilename(sym);
 
 	sym->type = SYM_SET;
-	sym->callback = NULL;
 	sym->value = value;
 
 	return sym;
@@ -375,7 +412,7 @@
  * @param name The label's full name (so `.name` is invalid)
  * @return The created symbol
  */
-static struct Symbol *addSectionlessLabel(char const *name)
+static struct Symbol *addLabel(char const *name)
 {
 	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 */
@@ -389,7 +426,6 @@
 	}
 	/* 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;
@@ -396,13 +432,6 @@
 	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;
@@ -538,21 +567,35 @@
 	return ptr;
 }
 
+static inline struct Symbol *createBuiltinSymbol(char const *name)
+{
+	struct Symbol *sym = createsymbol(name);
+
+	sym->isBuiltin = true;
+	sym->hasCallback = true;
+	strcpy(sym->fileName, "<builtin>");
+	sym->fileLine = 0;
+	return sym;
+}
 /*
  * Initialize the symboltable
  */
 void sym_Init(void)
 {
-	struct Symbol *_NARGSymbol = sym_AddEqu("_NARG", 0);
-	struct Symbol *__LINE__Symbol = sym_AddEqu("__LINE__", 0);
+	PCSymbol = createBuiltinSymbol("@");
+	struct Symbol *_NARGSymbol = createBuiltinSymbol("_NARG");
+	struct Symbol *__LINE__Symbol = createBuiltinSymbol("__LINE__");
+	struct Symbol *__FILE__Symbol = createBuiltinSymbol("__FILE__");
 
-	PCSymbol = addSectionlessLabel("@");
-	PCSymbol->isBuiltin = true;
-	PCSymbol->callback = CallbackPC;
-	_NARGSymbol->isBuiltin = true;
-	_NARGSymbol->callback = Callback_NARG;
-	__LINE__Symbol->isBuiltin = true;
-	__LINE__Symbol->callback = Callback__LINE__;
+	PCSymbol->type = SYM_LABEL;
+	PCSymbol->section = NULL;
+	PCSymbol->numCallback = CallbackPC;
+	_NARGSymbol->type = SYM_EQU;
+	_NARGSymbol->numCallback = Callback_NARG;
+	__LINE__Symbol->type = SYM_EQU;
+	__LINE__Symbol->numCallback = Callback__LINE__;
+	__FILE__Symbol->type = SYM_EQUS;
+	__FILE__Symbol->strCallback = Callback__FILE__;
 	sym_AddSet("_RS", 0)->isBuiltin = true;
 
 	sym_AddEqu("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR)->isBuiltin = true;
--- a/test/asm/file-sym.out
+++ b/test/asm/file-sym.out
@@ -1,1 +1,1 @@
-"test/asm/file-sym.asm"
+"file-sym.asm"