shithub: rgbds

Download patch

ref: d2bd9a23684507dbb413028770c9121e01500bb0
parent: b2c1f6122eb5ed5a9070c8cf0450f0cf826f6edd
parent: b909a5063aca9b29abe15e65eb137de0904100cc
author: Antonio Niño Díaz <antonio_nd@outlook.com>
date: Fri May 31 08:10:17 EDT 2019

Merge pull request #337 from dbrotz/one-pass

Use only one pass

--- a/include/asm/asm.h
+++ b/include/asm/asm.h
@@ -28,7 +28,6 @@
 extern int32_t nLineNo;
 extern uint32_t nTotalLines;
 extern uint32_t nPC;
-extern uint32_t nPass;
 extern uint32_t nIFDepth;
 extern bool skipElif;
 extern uint32_t nUnionDepth;
--- a/include/asm/rpn.h
+++ b/include/asm/rpn.h
@@ -18,11 +18,9 @@
 	uint32_t nRPNLength;
 	uint32_t nRPNOut;
 	uint32_t isReloc;
-	uint32_t isPCRel;
 };
 
 uint32_t rpn_isReloc(const struct Expression *expr);
-uint32_t rpn_isPCRelative(const struct Expression *expr);
 void rpn_Symbol(struct Expression *expr, char *tzSym);
 void rpn_Number(struct Expression *expr, uint32_t i);
 void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
--- a/include/asm/symbol.h
+++ b/include/asm/symbol.h
@@ -38,8 +38,8 @@
 #define SYMF_SET	0x004
 /* Symbol should be exported */
 #define SYMF_EXPORT	0x008
-/* Symbol is imported, it's value is unknown */
-#define SYMF_IMPORT	0x010
+/* Symbol referenced in RPN expression */
+#define SYMF_REF	0x010
 /* Symbol is a local symbol */
 #define SYMF_LOCAL	0x020
 /* Symbol has been defined, not only referenced */
@@ -53,8 +53,6 @@
 
 uint32_t calchash(char *s);
 void sym_SetExportAll(uint8_t set);
-void sym_PrepPass1(void);
-void sym_PrepPass2(void);
 void sym_AddLocalReloc(char *tzSym);
 void sym_AddReloc(char *tzSym);
 void sym_Export(char *tzSym);
@@ -72,7 +70,6 @@
 uint32_t sym_GetConstantValue(char *s);
 uint32_t sym_isConstant(char *s);
 struct sSymbol *sym_FindSymbol(char *tzName);
-void sym_Global(char *tzSym);
 char *sym_FindMacroArg(int32_t i);
 char *sym_GetStringValue(char *tzSym);
 void sym_UseCurrentMacroArgs(void);
@@ -79,9 +76,9 @@
 void sym_SetMacroArgID(uint32_t nMacroCount);
 uint32_t sym_isString(char *tzSym);
 void sym_AddMacro(char *tzSym);
+void sym_Ref(char *tzSym);
 void sym_ShiftCurrentMacroArgs(void);
 void sym_AddString(char *tzSym, char *tzValue);
-uint32_t sym_GetValue(char *s);
 uint32_t sym_GetDefinedValue(char *s);
 uint32_t sym_isDefined(char *tzName);
 void sym_Purge(char *tzName);
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -799,7 +799,7 @@
 ;
 
 db		: T_POP_DB constlist_8bit_entry comma constlist_8bit {
-			if ((nPass == 1) && (nListCountEmpty > 0)) {
+			if (nListCountEmpty > 0) {
 				warning("Empty entry in list of 8-bit elements (treated as 0).");
 			}
 		}
@@ -807,7 +807,7 @@
 ;
 
 dw		: T_POP_DW constlist_16bit_entry comma constlist_16bit {
-			if ((nPass == 1) && (nListCountEmpty > 0)) {
+			if (nListCountEmpty > 0) {
 				warning("Empty entry in list of 16-bit elements (treated as 0).");
 			}
 		}
@@ -815,7 +815,7 @@
 ;
 
 dl		: T_POP_DL constlist_32bit_entry comma constlist_32bit {
-			if ((nPass == 1) && (nListCountEmpty > 0)) {
+			if (nListCountEmpty > 0) {
 				warning("Empty entry in list of 32-bit elements (treated as 0).");
 			}
 		}
@@ -852,8 +852,7 @@
 			 * This is done automatically if the label isn't found
 			 * in the list of defined symbols.
 			 */
-			if (nPass == 1)
-				warning("IMPORT is a deprecated keyword with no effect: %s", $1);
+			warning("IMPORT is a deprecated keyword with no effect: %s", $1);
 		}
 ;
 
@@ -879,7 +878,7 @@
 
 global_list_entry : T_ID
 		{
-			sym_Global($1);
+			sym_Export($1);
 		}
 ;
 
@@ -929,29 +928,25 @@
 
 printt		: T_POP_PRINTT string
 		{
-			if (nPass == 1)
-				printf("%s", $2);
+			printf("%s", $2);
 		}
 ;
 
 printv		: T_POP_PRINTV const
 		{
-			if (nPass == 1)
-				printf("$%X", constexpr_GetConstantValue(&$2));
+			printf("$%X", constexpr_GetConstantValue(&$2));
 		}
 ;
 
 printi		: T_POP_PRINTI const
 		{
-			if (nPass == 1)
-				printf("%d", constexpr_GetConstantValue(&$2));
+			printf("%d", constexpr_GetConstantValue(&$2));
 		}
 ;
 
 printf		: T_POP_PRINTF const
 		{
-			if (nPass == 1)
-				math_Print(constexpr_GetConstantValue(&$2));
+			math_Print(constexpr_GetConstantValue(&$2));
 		}
 ;
 
@@ -1126,7 +1121,6 @@
 				struct Expression sTemp, sOffset;
 
 				rpn_Symbol(&sTemp, $1);
-				sTemp.nVal = sym_GetValue($1);
 
 				rpn_Number(&sOffset, nPCOffset);
 
@@ -1133,13 +1127,11 @@
 				rpn_SUB(&$$, &sTemp, &sOffset);
 			} else {
 				rpn_Symbol(&$$, $1);
-				$$.nVal = sym_GetValue($1);
 			}
 		}
 		| T_NUMBER
 		{
 			rpn_Number(&$$, $1);
-			$$.nVal = $1;
 		}
 		| string
 		{
@@ -1149,7 +1141,6 @@
 
 			free(s);
 			rpn_Number(&$$, r);
-			$$.nVal = r;
 		}
 		| T_OP_LOGICNOT relocconst %prec NEG	{ rpn_LOGNOT(&$$, &$2); }
 		| relocconst T_OP_LOGICOR relocconst	{ rpn_LOGOR(&$$, &$1, &$3); }
@@ -1179,12 +1170,10 @@
 		{
 			/* '@' is also a T_ID, it is handled here. */
 			rpn_BankSymbol(&$$, $3);
-			$$.nVal = 0;
 		}
 		| T_OP_BANK '(' string ')'
 		{
 			rpn_BankSection(&$$, $3);
-			$$.nVal = 0;
 		}
 		| T_OP_DEF {
 				oDontExpandStrings = true;
@@ -1637,8 +1626,7 @@
 		| T_Z80_JP T_MODE_HL_IND
 		{
 			out_AbsByte(0xE9);
-			if (nPass == 1)
-				warning("'JP [HL]' is obsolete, use 'JP HL' instead.");
+			warning("'JP [HL]' is obsolete, use 'JP HL' instead.");
 		}
 		| T_Z80_JP T_MODE_HL
 		{
@@ -1665,8 +1653,7 @@
 		| T_Z80_LDI T_MODE_A comma T_MODE_HL
 		{
 			out_AbsByte(0x0A | (2 << 4));
-			if (nPass == 1)
-				warning("'LDI A,HL' is obsolete, use 'LDI A,[HL]' or 'LD A,[HL+] instead.");
+			warning("'LDI A,HL' is obsolete, use 'LDI A,[HL]' or 'LD A,[HL+] instead.");
 		}
 		| T_Z80_LDI T_MODE_A comma T_MODE_HL_IND
 		{
@@ -1681,8 +1668,7 @@
 		| T_Z80_LDD T_MODE_A comma T_MODE_HL
 		{
 			out_AbsByte(0x0A | (3 << 4));
-			if (nPass == 1)
-				warning("'LDD A,HL' is obsolete, use 'LDD A,[HL]' or 'LD A,[HL-] instead.");
+			warning("'LDD A,HL' is obsolete, use 'LDD A,[HL]' or 'LD A,[HL-] instead.");
 		}
 		| T_Z80_LDD T_MODE_A comma T_MODE_HL_IND
 		{
--- a/src/asm/charmap.c
+++ b/src/asm/charmap.c
@@ -62,9 +62,6 @@
 		charmap = &globalCharmap;
 	}
 
-	if (nPass == 2)
-		return charmap->count;
-
 	if (charmap->count > MAXCHARMAPS || strlen(input) > CHARMAPLENGTH)
 		return -1;
 
--- a/src/asm/main.c
+++ b/src/asm/main.c
@@ -37,7 +37,7 @@
 
 clock_t nStartClock, nEndClock;
 int32_t nLineNo;
-uint32_t nTotalLines, nPass, nPC, nIFDepth, nUnionDepth, nErrors;
+uint32_t nTotalLines, nPC, nIFDepth, nUnionDepth, nErrors;
 bool skipElif;
 uint32_t unionStart[128], unionSize[128];
 
@@ -432,21 +432,17 @@
 	skipElif = true;
 	nUnionDepth = 0;
 	nPC = 0;
-	nPass = 1;
 	nErrors = 0;
-	sym_PrepPass1();
+	sym_Init();
 	sym_SetExportAll(CurrentOptions.exportall);
 	fstk_Init(tzMainfile);
 	opt_ParseDefines();
 
-	if (CurrentOptions.verbose)
-		printf("Pass 1...\n");
-
 	yy_set_state(LEX_STATE_NORMAL);
 	opt_SetCurrentOptions(&DefaultOptions);
 
 	if (yyparse() != 0 || nErrors != 0)
-		errx(1, "Assembly aborted in pass 1 (%ld errors)!", nErrors);
+		errx(1, "Assembly aborted (%ld errors)!", nErrors);
 
 	if (nIFDepth != 0)
 		errx(1, "Unterminated IF construct (%ld levels)!", nIFDepth);
@@ -455,27 +451,6 @@
 		errx(1, "Unterminated UNION construct (%ld levels)!",
 		     nUnionDepth);
 	}
-
-	nTotalLines = 0;
-	nLineNo = 1;
-	nIFDepth = 0;
-	skipElif = true;
-	nUnionDepth = 0;
-	nPC = 0;
-	nPass = 2;
-	nErrors = 0;
-	sym_PrepPass2();
-	out_PrepPass2();
-	fstk_Init(tzMainfile);
-	yy_set_state(LEX_STATE_NORMAL);
-	opt_SetCurrentOptions(&DefaultOptions);
-	opt_ParseDefines();
-
-	if (CurrentOptions.verbose)
-		printf("Pass 2...\n");
-
-	if (yyparse() != 0 || nErrors != 0)
-		errx(1, "Assembly aborted in pass 2 (%ld errors)!", nErrors);
 
 	double timespent;
 
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -259,37 +259,46 @@
  */
 static void writesymbol(struct sSymbol *pSym, FILE *f)
 {
-	char symname[MAXSYMLEN * 2 + 1];
 	uint32_t type;
 	uint32_t offset;
 	int32_t sectid;
 
-	if (pSym->nType & SYMF_IMPORT) {
-		/* Symbol should be imported */
-		strcpy(symname, pSym->tzName);
-		offset = 0;
-		sectid = -1;
+	if (!(pSym->nType & SYMF_DEFINED)) {
+		if (pSym->nType & SYMF_LOCAL) {
+			char *name = pSym->tzName;
+			char *localPtr = strchr(name, '.');
+
+			if (localPtr)
+				name = localPtr;
+			errx(1, "%s(%u) : '%s' not defined",
+			     pSym->tzFileName, pSym->nFileLine, name);
+		}
 		type = SYM_IMPORT;
+	} else if (pSym->nType & SYMF_EXPORT) {
+		type = SYM_EXPORT;
 	} else {
-		strcpy(symname, pSym->tzName);
+		type = SYM_LOCAL;
+	}
 
-		if (pSym->nType & SYMF_EXPORT) {
-			/* Symbol should be exported */
-			type = SYM_EXPORT;
-			offset = pSym->nValue;
-			if (pSym->nType & SYMF_CONST)
-				sectid = -1;
-			else
-				sectid = getsectid(pSym->pSection);
-		} else {
-			/* Symbol is local to this file */
-			type = SYM_LOCAL;
-			offset = pSym->nValue;
+	switch (type) {
+	case SYM_LOCAL:
+		offset = pSym->nValue;
+		sectid = getsectid(pSym->pSection);
+		break;
+	case SYM_IMPORT:
+		offset = 0;
+		sectid = -1;
+		break;
+	case SYM_EXPORT:
+		offset = pSym->nValue;
+		if (pSym->nType & SYMF_CONST)
+			sectid = -1;
+		else
 			sectid = getsectid(pSym->pSection);
-		}
+		break;
 	}
 
-	fputstring(symname, f);
+	fputstring(pSym->tzName, f);
 	fputc(type, f);
 
 	if (type != SYM_IMPORT) {
@@ -563,22 +572,6 @@
 }
 
 /*
- * Prepare for pass #2
- */
-void out_PrepPass2(void)
-{
-	struct Section *pSect;
-
-	pSect = pSectionList;
-	while (pSect) {
-		pSect->nPC = 0;
-		pSect = pSect->pNext;
-	}
-	pCurrentSection = NULL;
-	pSectionStack = NULL;
-}
-
-/*
  * Set the objectfilename
  */
 void out_SetFileName(char *s)
@@ -586,10 +579,6 @@
 	tzObjectname = s;
 	if (CurrentOptions.verbose)
 		printf("Output filename %s\n", s);
-
-	pSectionList = NULL;
-	pCurrentSection = NULL;
-	pPatchSymbols = NULL;
 }
 
 /*
@@ -636,7 +625,6 @@
 	pSect->pNext = NULL;
 	pSect->pPatches = NULL;
 	pSect->charmap = NULL;
-	pPatchSymbols = NULL;
 
 	/* It is only needed to allocate memory for ROM sections. */
 	if (secttype == SECT_ROM0 || secttype == SECT_ROMX) {
@@ -705,9 +693,7 @@
 {
 	checksectionoverflow(1);
 	b &= 0xFF;
-	if (nPass == 2)
-		pCurrentSection->tData[nPC] = b;
-
+	pCurrentSection->tData[nPC] = b;
 	pCurrentSection->nPC += 1;
 	nPC += 1;
 	pPCSymbol->nValue += 1;
@@ -772,10 +758,8 @@
 	checkcodesection();
 	checksectionoverflow(1);
 	if (rpn_isReloc(expr)) {
-		if (nPass == 2) {
-			pCurrentSection->tData[nPC] = 0;
-			createpatch(PATCH_BYTE, expr);
-		}
+		pCurrentSection->tData[nPC] = 0;
+		createpatch(PATCH_BYTE, expr);
 		pCurrentSection->nPC += 1;
 		nPC += 1;
 		pPCSymbol->nValue += 1;
@@ -793,10 +777,8 @@
 	checkcodesection();
 	checksectionoverflow(2);
 	b &= 0xFFFF;
-	if (nPass == 2) {
-		pCurrentSection->tData[nPC] = b & 0xFF;
-		pCurrentSection->tData[nPC + 1] = b >> 8;
-	}
+	pCurrentSection->tData[nPC] = b & 0xFF;
+	pCurrentSection->tData[nPC + 1] = b >> 8;
 	pCurrentSection->nPC += 2;
 	nPC += 2;
 	pPCSymbol->nValue += 2;
@@ -808,17 +790,12 @@
  */
 void out_RelWord(struct Expression *expr)
 {
-	uint32_t b;
-
 	checkcodesection();
 	checksectionoverflow(2);
-	b = expr->nVal & 0xFFFF;
 	if (rpn_isReloc(expr)) {
-		if (nPass == 2) {
-			pCurrentSection->tData[nPC] = b & 0xFF;
-			pCurrentSection->tData[nPC + 1] = b >> 8;
-			createpatch(PATCH_WORD_L, expr);
-		}
+		pCurrentSection->tData[nPC] = 0;
+		pCurrentSection->tData[nPC + 1] = 0;
+		createpatch(PATCH_WORD_L, expr);
 		pCurrentSection->nPC += 2;
 		nPC += 2;
 		pPCSymbol->nValue += 2;
@@ -835,12 +812,10 @@
 {
 	checkcodesection();
 	checksectionoverflow(sizeof(int32_t));
-	if (nPass == 2) {
-		pCurrentSection->tData[nPC] = b & 0xFF;
-		pCurrentSection->tData[nPC + 1] = b >> 8;
-		pCurrentSection->tData[nPC + 2] = b >> 16;
-		pCurrentSection->tData[nPC + 3] = b >> 24;
-	}
+	pCurrentSection->tData[nPC] = b & 0xFF;
+	pCurrentSection->tData[nPC + 1] = b >> 8;
+	pCurrentSection->tData[nPC + 2] = b >> 16;
+	pCurrentSection->tData[nPC + 3] = b >> 24;
 	pCurrentSection->nPC += 4;
 	nPC += 4;
 	pPCSymbol->nValue += 4;
@@ -852,19 +827,14 @@
  */
 void out_RelLong(struct Expression *expr)
 {
-	int32_t b;
-
 	checkcodesection();
 	checksectionoverflow(4);
-	b = expr->nVal;
 	if (rpn_isReloc(expr)) {
-		if (nPass == 2) {
-			pCurrentSection->tData[nPC] = b & 0xFF;
-			pCurrentSection->tData[nPC + 1] = b >> 8;
-			pCurrentSection->tData[nPC + 2] = b >> 16;
-			pCurrentSection->tData[nPC + 3] = b >> 24;
-			createpatch(PATCH_LONG_L, expr);
-		}
+		pCurrentSection->tData[nPC] = 0;
+		pCurrentSection->tData[nPC + 1] = 0;
+		pCurrentSection->tData[nPC + 2] = 0;
+		pCurrentSection->tData[nPC + 3] = 0;
+		createpatch(PATCH_LONG_L, expr);
 		pCurrentSection->nPC += 4;
 		nPC += 4;
 		pPCSymbol->nValue += 4;
@@ -884,10 +854,8 @@
 	checksectionoverflow(1);
 
 	/* Always let the linker calculate the offset. */
-	if (nPass == 2) {
-		pCurrentSection->tData[nPC] = 0;
-		createpatch(PATCH_BYTE_JR, expr);
-	}
+	pCurrentSection->tData[nPC] = 0;
+	createpatch(PATCH_BYTE_JR, expr);
 	pCurrentSection->nPC += 1;
 	nPC += 1;
 	pPCSymbol->nValue += 1;
@@ -915,13 +883,12 @@
 	checkcodesection();
 	checksectionoverflow(fsize);
 
-	if (nPass == 2) {
-		int32_t dest = nPC;
-		int32_t todo = fsize;
+	int32_t dest = nPC;
+	int32_t todo = fsize;
 
-		while (todo--)
-			pCurrentSection->tData[dest++] = fgetc(f);
-	}
+	while (todo--)
+		pCurrentSection->tData[dest++] = fgetc(f);
+
 	pCurrentSection->nPC += fsize;
 	nPC += fsize;
 	pPCSymbol->nValue += fsize;
@@ -958,13 +925,12 @@
 	checkcodesection();
 	checksectionoverflow(length);
 
-	if (nPass == 2) {
-		int32_t dest = nPC;
-		int32_t todo = length;
+	int32_t dest = nPC;
+	int32_t todo = length;
 
-		while (todo--)
-			pCurrentSection->tData[dest++] = fgetc(f);
-	}
+	while (todo--)
+		pCurrentSection->tData[dest++] = fgetc(f);
+
 	pCurrentSection->nPC += length;
 	nPC += length;
 	pPCSymbol->nValue += length;
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -55,7 +55,6 @@
 
 	expr->nRPNLength = len;
 	expr->isReloc = src1->isReloc || src2->isReloc;
-	expr->isPCRel = src1->isPCRel || src2->isPCRel;
 }
 
 #define joinexpr() mergetwoexpressions(expr, src1, src2)
@@ -91,7 +90,6 @@
 	expr->nRPNLength = 0;
 	expr->nRPNOut = 0;
 	expr->isReloc = 0;
-	expr->isPCRel = 0;
 }
 
 /*
@@ -123,14 +121,6 @@
 }
 
 /*
- * Determine if the current expression can be pc-relative
- */
-uint32_t rpn_isPCRelative(const struct Expression *expr)
-{
-	return expr->isPCRel;
-}
-
-/*
  * Add symbols, constants and operators to expression
  */
 void rpn_Number(struct Expression *expr, uint32_t i)
@@ -147,15 +137,8 @@
 void rpn_Symbol(struct Expression *expr, char *tzSym)
 {
 	if (!sym_isConstant(tzSym)) {
-		const struct sSymbol *psym;
-
 		rpn_Init(expr);
-
-		psym = sym_FindSymbol(tzSym);
-
-		if (psym == NULL || psym->pSection == pCurrentSection
-		    || psym->pSection == NULL)
-			expr->isPCRel = 1;
+		sym_Ref(tzSym);
 		expr->isReloc = 1;
 		pushbyte(expr, RPN_SYM);
 		while (*tzSym)
@@ -189,13 +172,7 @@
 
 	if (!sym_isConstant(tzSym)) {
 		rpn_Init(expr);
-
-		/*
-		 * Check that the symbol exists by evaluating and discarding the
-		 * value.
-		 */
-		sym_GetValue(tzSym);
-
+		sym_Ref(tzSym);
 		expr->isReloc = 1;
 		pushbyte(expr, RPN_BANK_SYM);
 		while (*tzSym)
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -154,12 +154,15 @@
  * Creates the full name of a local symbol in a given scope, by prepending
  * the name with the parent symbol's name.
  */
-static size_t fullSymbolName(char *output, size_t outputSize, char *localName,
-			     const struct sSymbol *scope)
+static void fullSymbolName(char *output, size_t outputSize, char *localName,
+			   const struct sSymbol *scope)
 {
 	const struct sSymbol *parent = scope->pScope ? scope->pScope : scope;
+	int n = snprintf(output, outputSize, "%s%s", parent->tzName, localName);
 
-	return snprintf(output, outputSize, "%s%s", parent->tzName, localName);
+	if (n >= (int)outputSize)
+		fatalerror("Symbol name is too long: '%s%s'",
+			   parent->tzName, localName);
 }
 
 /*
@@ -207,7 +210,7 @@
 }
 
 /*
- * Find a symbol by name and scope
+ * Find a symbol by name, with automatically determined scope
  */
 struct sSymbol *sym_FindSymbol(char *tzName)
 {
@@ -256,15 +259,8 @@
  */
 uint32_t sym_isConstDefined(char *tzName)
 {
-	struct sSymbol *psym, *pscope;
+	struct sSymbol *psym = sym_FindSymbol(tzName);
 
-	if (*tzName == '.')
-		pscope = pScope;
-	else
-		pscope = NULL;
-
-	psym = findsymbol(tzName, pscope);
-
 	if (psym && (psym->nType & SYMF_DEFINED)) {
 		uint32_t mask = SYMF_EQU | SYMF_SET | SYMF_MACRO | SYMF_STRING;
 
@@ -280,19 +276,9 @@
 
 uint32_t sym_isDefined(char *tzName)
 {
-	struct sSymbol *psym, *pscope;
+	struct sSymbol *psym = sym_FindSymbol(tzName);
 
-	if (*tzName == '.')
-		pscope = pScope;
-	else
-		pscope = NULL;
-
-	psym = findsymbol(tzName, pscope);
-
-	if (psym && (psym->nType & SYMF_DEFINED))
-		return 1;
-	else
-		return 0;
+	return (psym && (psym->nType & SYMF_DEFINED));
 }
 
 /*
@@ -300,21 +286,9 @@
  */
 uint32_t sym_isConstant(char *s)
 {
-	struct sSymbol *psym, *pscope;
+	struct sSymbol *psym = sym_FindSymbol(s);
 
-	if (*s == '.')
-		pscope = pScope;
-	else
-		pscope = NULL;
-
-	psym = findsymbol(s, pscope);
-
-	if (psym != NULL) {
-		if (psym->nType & SYMF_CONST)
-			return 1;
-	}
-
-	return 0;
+	return (psym && (psym->nType & SYMF_CONST));
 }
 
 /*
@@ -327,7 +301,7 @@
 	if (pSym != NULL)
 		return pSym->pMacro;
 
-	yyerror("Stringsymbol '%s' not defined", tzSym);
+	yyerror("String symbol '%s' not defined", tzSym);
 
 	return NULL;
 }
@@ -337,15 +311,8 @@
  */
 uint32_t sym_GetConstantValue(char *s)
 {
-	struct sSymbol *psym, *pscope;
+	struct sSymbol *psym = sym_FindSymbol(s);
 
-	if (*s == '.')
-		pscope = pScope;
-	else
-		pscope = NULL;
-
-	psym = findsymbol(s, pscope);
-
 	if (psym != NULL) {
 		if (psym->nType & SYMF_CONST)
 			return getvaluefield(psym);
@@ -359,63 +326,12 @@
 }
 
 /*
- * Return a symbols value... "estimated" if not defined yet
- */
-uint32_t sym_GetValue(char *s)
-{
-	struct sSymbol *psym, *pscope;
-
-	if (*s == '.')
-		pscope = pScope;
-	else
-		pscope = NULL;
-
-	psym = findsymbol(s, pscope);
-
-	if (psym != NULL) {
-		if (psym->nType & SYMF_DEFINED) {
-			if (psym->nType & (SYMF_MACRO | SYMF_STRING))
-				yyerror("'%s' is a macro or string symbol", s);
-
-			return getvaluefield(psym);
-		}
-
-		if (nPass == 2) {
-			/*
-			 * Assume undefined symbols are imported from
-			 * somwehere else
-			 */
-			psym->nType |= SYMF_IMPORT;
-		}
-
-		/* 0x80 seems like a good default value... */
-		return 0x80;
-	}
-
-	if (nPass == 1) {
-		createsymbol(s);
-		return 0x80;
-	}
-
-	yyerror("'%s' not defined", s);
-
-	return 0;
-}
-
-/*
  * Return a defined symbols value... aborts if not defined yet
  */
 uint32_t sym_GetDefinedValue(char *s)
 {
-	struct sSymbol *psym, *pscope;
+	struct sSymbol *psym = sym_FindSymbol(s);
 
-	if (*s == '.')
-		pscope = pScope;
-	else
-		pscope = NULL;
-
-	psym = findsymbol(s, pscope);
-
 	if (psym != NULL) {
 		if ((psym->nType & SYMF_DEFINED)) {
 			if (psym->nType & (SYMF_MACRO | SYMF_STRING))
@@ -545,30 +461,43 @@
 }
 
 /*
- * Add an equated symbol
+ * Create a symbol that will be non-relocatable and ensure that it
+ * hasn't already been defined or referenced in a context that would
+ * require that it be relocatable
  */
-void sym_AddEqu(char *tzSym, int32_t value)
+static struct sSymbol *createNonrelocSymbol(char *tzSym)
 {
-	if ((nPass == 1) || ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
-		/* only add equated symbols in pass 1 */
-		struct sSymbol *nsym = findsymbol(tzSym, NULL);
+	struct sSymbol *nsym = findsymbol(tzSym, NULL);
 
-		if (nsym != NULL) {
-			if (nsym->nType & SYMF_DEFINED) {
-				yyerror("'%s' already defined in %s(%d)", tzSym,
-					nsym->tzFileName, nsym->nFileLine);
-			}
-		} else {
-			nsym = createsymbol(tzSym);
+	if (nsym != NULL) {
+		if (nsym->nType & SYMF_DEFINED) {
+			yyerror("'%s' already defined at %s(%u)",
+				tzSym, nsym->tzFileName, nsym->nFileLine);
+		} else if (nsym->nType & SYMF_REF) {
+			yyerror("'%s' already referenced at %s(%u)",
+				tzSym, nsym->tzFileName, nsym->nFileLine);
 		}
+	} else {
+		nsym = createsymbol(tzSym);
+	}
 
-		if (nsym) {
-			nsym->nValue = value;
-			nsym->nType |= SYMF_EQU | SYMF_DEFINED | SYMF_CONST;
-			nsym->pScope = NULL;
-			updateSymbolFilename(nsym);
-		}
+	return nsym;
+}
+
+/*
+ * Add an equated symbol
+ */
+void sym_AddEqu(char *tzSym, int32_t value)
+{
+	struct sSymbol *nsym = createNonrelocSymbol(tzSym);
+
+	if (nsym) {
+		nsym->nValue = value;
+		nsym->nType |= SYMF_EQU | SYMF_DEFINED | SYMF_CONST;
+		nsym->pScope = NULL;
+		updateSymbolFilename(nsym);
 	}
+
 }
 
 /*
@@ -585,17 +514,8 @@
  */
 void sym_AddString(char *tzSym, char *tzValue)
 {
-	struct sSymbol *nsym = findsymbol(tzSym, NULL);
+	struct sSymbol *nsym = createNonrelocSymbol(tzSym);
 
-	if (nsym != NULL) {
-		if (nsym->nType & SYMF_DEFINED) {
-			yyerror("'%s' already defined in %s(%d)",
-				tzSym, nsym->tzFileName, nsym->nFileLine);
-		}
-	} else {
-		nsym = createsymbol(tzSym);
-	}
-
 	if (nsym) {
 		nsym->pMacro = malloc(strlen(tzValue) + 1);
 
@@ -602,7 +522,7 @@
 		if (nsym->pMacro != NULL)
 			strcpy(nsym->pMacro, tzValue);
 		else
-			fatalerror("No memory for stringequate");
+			fatalerror("No memory for string equate");
 
 		nsym->nType |= SYMF_STRING | SYMF_DEFINED;
 		nsym->ulMacroSize = strlen(tzValue);
@@ -617,11 +537,7 @@
 {
 	const struct sSymbol *pSym = findsymbol(tzSym, NULL);
 
-	if (pSym != NULL) {
-		if (pSym->nType & SYMF_STRING)
-			return 1;
-	}
-	return 0;
+	return (pSym && (pSym->nType & SYMF_STRING));
 }
 
 /*
@@ -631,8 +547,20 @@
 {
 	struct sSymbol *nsym = findsymbol(tzSym, NULL);
 
-	if (nsym == NULL) {
-		/* Symbol hasn been found, create */
+	if (nsym != NULL) {
+		if (nsym->nType & SYMF_DEFINED) {
+			if (!(nsym->nType & SYMF_CONST))
+				yyerror("'%s' already defined as non-constant at %s(%u)",
+					tzSym,
+					nsym->tzFileName,
+					nsym->nFileLine);
+		} else if (nsym->nType & SYMF_REF) {
+			yyerror("'%s' already referenced at %s(%u)",
+				tzSym,
+				nsym->tzFileName,
+				nsym->nFileLine);
+		}
+	} else {
 		nsym = createsymbol(tzSym);
 	}
 
@@ -650,9 +578,6 @@
 void sym_AddLocalReloc(char *tzSym)
 {
 	if (pScope) {
-		if (strlen(tzSym) + strlen(pScope->tzName) > MAXSYMLEN)
-			fatalerror("Symbol too long");
-
 		char fullname[MAXSYMLEN + 1];
 
 		fullSymbolName(fullname, sizeof(fullname), tzSym, pScope);
@@ -669,59 +594,55 @@
 void sym_AddReloc(char *tzSym)
 {
 	struct sSymbol *scope = NULL;
+	struct sSymbol *nsym;
+	char *localPtr = strchr(tzSym, '.');
 
-	if ((nPass == 1)
-	    || ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
-		/* only add reloc symbols in pass 1 */
-		struct sSymbol *nsym;
-		char *localPtr = strchr(tzSym, '.');
+	if (localPtr != NULL) {
+		if (!pScope)
+			fatalerror("Local label in main scope");
 
-		if (localPtr != NULL) {
-			if (!pScope)
-				fatalerror("Local label in main scope");
+		struct sSymbol *parent = pScope->pScope ?
+					 pScope->pScope : pScope;
+		uint32_t parentLen = localPtr - tzSym;
 
-			struct sSymbol *parent = pScope->pScope ?
-						 pScope->pScope : pScope;
-			uint32_t 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 (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);
 		}
 
-		nsym = findsymbol(tzSym, scope);
+		scope = parent;
+	}
 
-		if (nsym != NULL) {
-			if (nsym->nType & SYMF_DEFINED) {
-				yyerror("'%s' already defined in %s(%d)", tzSym,
-					nsym->tzFileName, nsym->nFileLine);
-			}
-		} else {
-			nsym = createsymbol(tzSym);
+	nsym = findsymbol(tzSym, scope);
+
+	if (nsym != NULL) {
+		if (nsym->nType & SYMF_DEFINED) {
+			yyerror("'%s' already defined in %s(%d)", tzSym,
+				nsym->tzFileName, nsym->nFileLine);
 		}
+	} else {
+		nsym = createsymbol(tzSym);
+	}
 
-		if (nsym) {
-			nsym->nValue = nPC;
-			nsym->nType |= SYMF_RELOC | SYMF_DEFINED;
-			if (localPtr)
-				nsym->nType |= SYMF_LOCAL;
+	if (nsym) {
+		nsym->nValue = nPC;
+		nsym->nType |= SYMF_RELOC | SYMF_DEFINED;
+		if (localPtr)
+			nsym->nType |= SYMF_LOCAL;
 
-			if (exportall)
-				nsym->nType |= SYMF_EXPORT;
+		if (exportall)
+			nsym->nType |= SYMF_EXPORT;
 
-			nsym->pScope = scope;
-			nsym->pSection = pCurrentSection;
+		nsym->pScope = scope;
+		nsym->pSection = pCurrentSection;
 
-			updateSymbolFilename(nsym);
-		}
+		updateSymbolFilename(nsym);
 	}
+
 	pScope = findsymbol(tzSym, scope);
 }
 
@@ -734,10 +655,6 @@
  */
 int32_t sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2)
 {
-	/* Do nothing the first pass. */
-	if (nPass != 2)
-		return 1;
-
 	const struct sSymbol *nsym1 = sym_FindSymbol(tzSym1);
 	const struct sSymbol *nsym2 = sym_FindSymbol(tzSym2);
 
@@ -781,146 +698,66 @@
  */
 void sym_Export(char *tzSym)
 {
-	if (nPass == 1) {
-		/* only export symbols in pass 1 */
-		struct sSymbol *nsym = sym_FindSymbol(tzSym);
+	struct sSymbol *nsym = sym_FindSymbol(tzSym);
 
-		if (nsym == NULL)
-			nsym = createsymbol(tzSym);
+	if (nsym == NULL)
+		nsym = createsymbol(tzSym);
 
-		if (nsym)
-			nsym->nType |= SYMF_EXPORT;
-	} else {
-		const struct sSymbol *nsym = sym_FindSymbol(tzSym);
-
-		if (nsym != NULL) {
-			if (nsym->nType & SYMF_DEFINED)
-				return;
-		}
-		yyerror("'%s' not defined", tzSym);
-	}
+	if (nsym)
+		nsym->nType |= SYMF_EXPORT;
 }
 
 /*
- * Globalize a symbol (export if defined, import if not)
+ * Add a macro definition
  */
-void sym_Global(char *tzSym)
+void sym_AddMacro(char *tzSym)
 {
-	if (nPass == 2) {
-		/* only globalize symbols in pass 2 */
-		struct sSymbol *nsym = sym_FindSymbol(tzSym);
+	struct sSymbol *nsym = createNonrelocSymbol(tzSym);
 
-		if ((nsym == NULL) || ((nsym->nType & SYMF_DEFINED) == 0)) {
-			if (nsym == NULL)
-				nsym = createsymbol(tzSym);
-
-			if (nsym)
-				nsym->nType |= SYMF_IMPORT;
-		} else {
-			if (nsym)
-				nsym->nType |= SYMF_EXPORT;
-		}
+	if (nsym) {
+		nsym->nType |= SYMF_MACRO | SYMF_DEFINED;
+		nsym->pScope = NULL;
+		nsym->ulMacroSize = ulNewMacroSize;
+		nsym->pMacro = tzNewMacro;
+		updateSymbolFilename(nsym);
 	}
 }
 
 /*
- * Add a macro definition
+ * Flag that a symbol is referenced in an RPN expression
+ * and create it if it doesn't exist yet
  */
-void sym_AddMacro(char *tzSym)
+void sym_Ref(char *tzSym)
 {
-	if ((nPass == 1) || ((nPass == 2) && (sym_isDefined(tzSym) == 0))) {
-		/* only add macros in pass 1 */
-		struct sSymbol *nsym;
+	struct sSymbol *nsym = sym_FindSymbol(tzSym);
 
-		nsym = findsymbol(tzSym, NULL);
+	if (nsym == NULL) {
+		char fullname[MAXSYMLEN + 1];
+		int isLocal = 0;
 
-		if (nsym != NULL) {
-			if (nsym->nType & SYMF_DEFINED) {
-				yyerror("'%s' already defined in %s(%d)",
-					tzSym, nsym->tzFileName,
-					nsym->nFileLine);
-			}
-		} else {
-			nsym = createsymbol(tzSym);
+		if (*tzSym == '.') {
+			fullSymbolName(fullname, sizeof(fullname), tzSym,
+				       pScope);
+			tzSym = fullname;
+			isLocal = 1;
 		}
 
-		if (nsym) {
-			nsym->nValue = nPC;
-			nsym->nType |= SYMF_MACRO | SYMF_DEFINED;
-			nsym->pScope = NULL;
-			nsym->ulMacroSize = ulNewMacroSize;
-			nsym->pMacro = tzNewMacro;
-			updateSymbolFilename(nsym);
-		}
+		nsym = createsymbol(tzSym);
+
+		if (nsym && isLocal)
+			nsym->nType |= SYMF_LOCAL;
 	}
+
+	if (nsym)
+		nsym->nType |= SYMF_REF;
 }
 
 /*
- * Set whether to export all relocable symbols by default
+ * Set whether to export all relocatable symbols by default
  */
 void sym_SetExportAll(uint8_t set)
 {
 	exportall = set;
-}
-
-/*
- * Prepare for pass #1
- */
-void sym_PrepPass1(void)
-{
-	sym_Init();
-}
-
-/*
- * Prepare for pass #2
- */
-void sym_PrepPass2(void)
-{
-	int32_t i;
-
-	for (i = 0; i < HASHSIZE; i += 1) {
-		struct sSymbol **ppSym = &(tHashedSymbols[i]);
-
-		while (*ppSym) {
-			uint32_t mask = SYMF_SET | SYMF_STRING | SYMF_EQU;
-
-			if ((*ppSym)->nType & mask) {
-				struct sSymbol *pTemp;
-
-				pTemp = (*ppSym)->pNext;
-				free(*ppSym);
-				*ppSym = pTemp;
-			} else {
-				ppSym = &((*ppSym)->pNext);
-			}
-		}
-	}
-	pScope = NULL;
-	pPCSymbol->nValue = 0;
-
-	sym_AddString("__TIME__", SavedTIME);
-	sym_AddString("__DATE__", SavedDATE);
-	sym_AddString("__ISO_8601_LOCAL__", SavedTIMESTAMP_ISO8601_LOCAL);
-	sym_AddString("__ISO_8601_UTC__", SavedTIMESTAMP_ISO8601_UTC);
-	sym_AddString("__UTC_DAY__", SavedDAY);
-	sym_AddString("__UTC_MONTH__", SavedMONTH);
-	sym_AddString("__UTC_YEAR__", SavedYEAR);
-	sym_AddString("__UTC_HOUR__", SavedHOUR);
-	sym_AddString("__UTC_MINUTE__", SavedMINUTE);
-	sym_AddString("__UTC_SECOND__", SavedSECOND);
-	sym_AddEqu("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR);
-	sym_AddEqu("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR);
-	sym_AddEqu("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH);
-	sym_AddSet("_RS", 0);
-
-	sym_AddEqu("_NARG", 0);
-	p_NARGSymbol = findsymbol("_NARG", NULL);
-	p_NARGSymbol->Callback = Callback_NARG;
-	sym_AddEqu("__LINE__", 0);
-	p__LINE__Symbol = findsymbol("__LINE__", NULL);
-	p__LINE__Symbol->Callback = Callback__LINE__;
-
-	math_DefinePI();
 }
 
 /*
--- a/test/asm/label-redefinition.out
+++ b/test/asm/label-redefinition.out
@@ -1,3 +1,3 @@
 ERROR: label-redefinition.asm(7):
     'Sym' already defined in m(6)
-error: Assembly aborted in pass 1 (1 errors)!
+error: Assembly aborted (1 errors)!
--- a/test/asm/local-wrong-parent.out
+++ b/test/asm/local-wrong-parent.out
@@ -1,3 +1,3 @@
 ERROR: local-wrong-parent.asm(5):
     Not currently in the scope of 'WrongParent'
-error: Assembly aborted in pass 1 (1 errors)!
+error: Assembly aborted (1 errors)!
--- /dev/null
+++ b/test/asm/reference-undefined-sym.asm
@@ -1,0 +1,4 @@
+SECTION "sec", ROM0
+	db X
+
+X = 2
--- /dev/null
+++ b/test/asm/reference-undefined-sym.out
@@ -1,0 +1,3 @@
+ERROR: reference-undefined-sym.asm(4):
+    'X' already referenced at reference-undefined-sym.asm(2)
+error: Assembly aborted (1 errors)!
--- a/test/asm/undefined-dot.out
+++ b/test/asm/undefined-dot.out
@@ -1,3 +1,1 @@
-ERROR: undefined-dot.asm(3):
-    '.' not defined
-error: Assembly aborted in pass 2 (1 errors)!
+error: undefined-dot.asm(3) : '.' not defined