shithub: rgbds

Download patch

ref: e7eac583daf97ff6eb69b7d6b36cb227fcee6876
parent: 51d5ff056766b327c939edf7f4b5323b69cba5d3
parent: cd107855e7b705b6677afa0777a19c55849743e5
author: Eldred Habert <[email protected]>
date: Sun Jan 26 09:30:47 EST 2020

Merge pull request #477 from ISSOtm/sym_overhaul

Overhaul the symbol system

--- a/include/asm/output.h
+++ b/include/asm/output.h
@@ -40,7 +40,6 @@
 void out_RelByte(struct Expression *expr);
 void out_RelWord(struct Expression *expr);
 void out_PCRelByte(struct Expression *expr);
-void out_CheckErrors(void);
 void out_WriteObject(void);
 void out_Skip(int32_t skip);
 void out_BinaryFile(char *s);
--- a/include/asm/symbol.h
+++ b/include/asm/symbol.h
@@ -9,7 +9,9 @@
 #ifndef RGBDS_SYMBOL_H
 #define RGBDS_SYMBOL_H
 
+#include <stdbool.h>
 #include <stdint.h>
+#include <string.h>
 
 #include "types.h"
 
@@ -16,13 +18,24 @@
 #define HASHSIZE	(1 << 16)
 #define MAXSYMLEN	256
 
+enum SymbolType {
+	SYM_LABEL,
+	SYM_EQU,
+	SYM_SET,
+	SYM_MACRO,
+	SYM_EQUS,
+	SYM_REF // Forward reference to a label
+};
+
 struct sSymbol {
 	char tzName[MAXSYMLEN + 1];
-	int32_t nValue;
-	uint32_t nType;
+	enum SymbolType type;
+	bool isConstant; /* Whether the symbol's value is currently known */
+	bool isExported; /* Whether the symbol is to be exported */
 	struct sSymbol *pScope;
 	struct sSymbol *pNext;
 	struct Section *pSection;
+	int32_t nValue;
 	uint32_t ulMacroSize;
 	char *pMacro;
 	int32_t (*Callback)(struct sSymbol *self);
@@ -30,26 +43,49 @@
 	uint32_t nFileLine; /* Line where the symbol was defined. */
 };
 
-/* Symbol will be relocated during linking, it's absolute value is unknown */
+static inline bool sym_IsDefined(struct sSymbol const *sym)
+{
+	return sym->type != SYM_REF;
+}
+static inline bool sym_IsConstant(struct sSymbol const *sym)
+{
+	return sym->isConstant;
+}
+static inline bool sym_IsNumeric(struct sSymbol const *sym)
+{
+	return sym->type == SYM_LABEL || sym->type == SYM_EQU
+	    || sym->type == SYM_SET;
+}
+static inline bool sym_IsLocal(struct sSymbol const *sym)
+{
+	return (sym->type == SYM_LABEL || sym->type == SYM_REF)
+		&& strchr(sym->tzName, '.');
+}
+static inline bool sym_IsExported(struct sSymbol const *sym)
+{
+	return sym->isExported;
+}
+/* Symbol will be relocated during linking, it's absolute value is unknown
 #define SYMF_RELOC	0x001
-/* Symbol is defined using EQU, will not be changed during linking */
+Symbol is defined using EQU, will not be changed during linking
 #define SYMF_EQU	0x002
-/* Symbol is (re)defined using SET, will not be changed during linking */
+Symbol is (re)defined using SET, will not be changed during linking
 #define SYMF_SET	0x004
-/* Symbol should be exported */
+Symbol should be exported
 #define SYMF_EXPORT	0x008
-/* Symbol referenced in RPN expression */
+Symbol referenced in RPN expression
 #define SYMF_REF	0x010
-/* Symbol is a local symbol */
+Symbol is a local symbol
 #define SYMF_LOCAL	0x020
-/* Symbol has been defined, not only referenced */
+Symbol has been defined, not only referenced
 #define SYMF_DEFINED	0x040
-/* Symbol is a macro */
+Symbol is a macro
 #define SYMF_MACRO	0x080
-/* Symbol is a stringsymbol */
+Symbol is a stringsymbol
 #define SYMF_STRING	0x100
-/* Symbol has a constant value, will not be changed during linking */
+Symbol has a constant value, will not be changed during linking
 #define SYMF_CONST	0x200
+*/
 
 uint32_t sym_CalcHash(const char *s);
 void sym_SetExportAll(uint8_t set);
@@ -67,22 +103,18 @@
 void sym_AddSet(char *tzSym, int32_t value);
 void sym_Init(void);
 uint32_t sym_GetConstantValue(char *s);
-uint32_t sym_isConstant(char *s);
 struct sSymbol *sym_FindSymbol(char *tzName);
 char *sym_FindMacroArg(int32_t i);
-char *sym_GetStringValue(char *tzSym);
+char *sym_GetStringValue(struct sSymbol const *sym);
 void sym_UseCurrentMacroArgs(void);
 void sym_SetMacroArgID(uint32_t nMacroCount);
-uint32_t sym_isString(char *tzSym);
 void sym_AddMacro(char *tzSym, int32_t nDefLineNo);
 void sym_Ref(char *tzSym);
 void sym_ShiftCurrentMacroArgs(void);
 void sym_AddString(char *tzSym, char *tzValue);
 uint32_t sym_GetDefinedValue(char *s);
-uint32_t sym_isDefined(char *tzName);
 void sym_Purge(char *tzName);
-uint32_t sym_isConstDefined(char *tzName);
-int32_t sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2);
+bool sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2);
 
 /* Functions to save and restore the current symbol scope. */
 struct sSymbol *sym_GetCurrentSymbolScope(void);
--- a/include/link/symbol.h
+++ b/include/link/symbol.h
@@ -19,7 +19,7 @@
 struct Symbol {
 	/* Info contained in the object files */
 	char *name;
-	enum SymbolType type;
+	enum ExportLevel type;
 	char const *objFileName;
 	char *fileName;
 	int32_t lineNo;
--- a/include/linkdefs.h
+++ b/include/linkdefs.h
@@ -59,7 +59,7 @@
 	SECTTYPE_INVALID
 };
 
-enum SymbolType {
+enum ExportLevel {
 	SYMTYPE_LOCAL,
 	SYMTYPE_IMPORT,
 	SYMTYPE_EXPORT
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -78,13 +78,14 @@
 	out_NewAbsSection(name, secttype, org, bank);
 }
 
-size_t symvaluetostring(char *dest, size_t maxLength, char *sym,
+size_t symvaluetostring(char *dest, size_t maxLength, char *symName,
 			const char *mode)
 {
 	size_t length;
+	struct sSymbol *sym = sym_FindSymbol(symName);
 
-	if (sym_isString(sym)) {
-		char *src = sym_GetStringValue(sym);
+	if (sym && sym->type == SYM_EQUS) {
+		char const *src = sym_GetStringValue(sym);
 		size_t i;
 
 		if (mode)
@@ -100,7 +101,7 @@
 		length = i;
 
 	} else {
-		uint32_t value = sym_GetConstantValue(sym);
+		uint32_t value = sym_GetConstantValue(symName);
 		int32_t fullLength;
 
 		/* Special cheat for binary */
@@ -1307,7 +1308,11 @@
 				oDontExpandStrings = true;
 			} '(' T_ID ')'
 		{
-			rpn_Number(&$$, sym_isConstDefined($4));
+			struct sSymbol const *sym = sym_FindSymbol($4);
+			if (sym && !(sym_IsDefined(sym) && sym->type != SYM_LABEL))
+				yyerror("Label \"%s\" is not a valid argument to DEF",
+					$4);
+			rpn_Number(&$$, !!sym);
 			oDontExpandStrings = false;
 		}
 		| T_OP_ROUND '(' const ')'
@@ -1447,7 +1452,11 @@
 				oDontExpandStrings = true;
 			} '(' T_ID ')'
 		{
-			constexpr_Number(&$$, sym_isConstDefined($4));
+			struct sSymbol const *sym = sym_FindSymbol($4);
+			if (sym && !(sym_IsDefined(sym) && sym->type != SYM_LABEL))
+				yyerror("Label \"%s\" is not a valid argument to DEF",
+					$4);
+			constexpr_Number(&$$, !!sym);
 			oDontExpandStrings = false;
 		}
 		| T_OP_STRCMP '(' string comma string ')'
--- a/src/asm/constexpr.c
+++ b/src/asm/constexpr.c
@@ -24,15 +24,13 @@
 
 void constexpr_Symbol(struct ConstExpression *expr, char *tzSym)
 {
-	if (!sym_isConstant(tzSym)) {
-		struct sSymbol *pSym = sym_FindSymbol(tzSym);
+	struct sSymbol *sym = sym_FindSymbol(tzSym);
 
-		if (pSym != NULL) {
-			expr->u.pSym = pSym;
-			expr->isSym = 1;
-		} else {
-			fatalerror("'%s' not defined", tzSym);
-		}
+	if (!sym) {
+		fatalerror("'%s' not defined", tzSym);
+	} else if (!sym_IsConstant(sym)) {
+		expr->u.pSym = sym;
+		expr->isSym = 1;
 	} else {
 		constexpr_Number(expr, sym_GetConstantValue(tzSym));
 	}
@@ -41,23 +39,21 @@
 void constexpr_BankSymbol(struct ConstExpression *expr, char *tzSym)
 {
 	constexpr_Number(expr, 0);
+	struct sSymbol *sym = sym_FindSymbol(tzSym);
 
-	if (sym_FindSymbol(tzSym) == pPCSymbol) {
+	if (!sym) {
+		yyerror("BANK argument doesn't exist");
+	} else if (sym == pPCSymbol) {
 		if (pCurrentSection->nBank == -1)
-			yyerror("%s's bank is not known yet", tzSym);
+			yyerror("Current bank is not known yet");
 		else
 			constexpr_Number(expr, pCurrentSection->nBank);
-	} else if (sym_isConstant(tzSym)) {
-		yyerror("BANK argument must be a relocatable identifier");
+	} else if (sym->type != SYM_LABEL) {
+		yyerror("BANK argument must be a label");
+	} else if (sym->pSection->nBank == -1) {
+		yyerror("BANK argument's bank is not known yet'");
 	} else {
-		struct sSymbol *pSymbol = sym_FindSymbol(tzSym);
-
-		if (!pSymbol)
-			yyerror("BANK argument doesn't exist");
-		else if (!pSymbol->pSection || pSymbol->pSection->nBank == -1)
-			yyerror("BANK argument must be a relocatable identifier");
-		else
-			constexpr_Number(expr, pSymbol->pSection->nBank);
+		constexpr_Number(expr, sym->pSection->nBank);
 	}
 }
 
--- a/src/asm/globlex.c
+++ b/src/asm/globlex.c
@@ -277,20 +277,24 @@
 		yyunputstr(rest);
 
 	/* If the symbol is an EQUS, expand it */
-	if (!oDontExpandStrings && sym_isString(dest)) {
-		char *s;
+	if (!oDontExpandStrings) {
+		struct sSymbol const *sym = sym_FindSymbol(dest);
 
-		lex_BeginStringExpansion(dest);
+		if (sym && sym->type == SYM_EQUS) {
+			char *s;
 
-		/* Feed the symbol's contents into the buffer */
-		yyunputstr(s = sym_GetStringValue(dest));
+			lex_BeginStringExpansion(dest);
 
-		/* Lines inserted this way shall not increase nLineNo */
-		while (*s) {
-			if (*s++ == '\n')
-				nLineNo--;
+			/* Feed the symbol's contents into the buffer */
+			yyunputstr(s = sym_GetStringValue(sym));
+
+			/* Lines inserted this way shall not increase nLineNo */
+			while (*s) {
+				if (*s++ == '\n')
+					nLineNo--;
+			}
+			return 0;
 		}
-		return 0;
 	}
 
 	strcpy(yylval.tzSym, dest);
--- a/src/asm/main.c
+++ b/src/asm/main.c
@@ -471,7 +471,6 @@
 			       (int)(60 / timespent * nTotalLines));
 	}
 
-	out_CheckErrors();
 	/* If no path specified, don't write file */
 	if (tzObjectname != NULL)
 		out_WriteObject();
--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -45,7 +45,7 @@
 
 struct PatchSymbol {
 	uint32_t ID;
-	struct sSymbol *pSymbol;
+	struct sSymbol const *pSymbol;
 	struct PatchSymbol *pNext;
 	struct PatchSymbol *pBucketNext; /* next symbol in hash table bucket */
 };
@@ -186,7 +186,7 @@
 /*
  * Write a NULL-terminated string to a file
  */
-static void fputstring(char *s, FILE *f)
+static void fputstring(char const *s, FILE *f)
 {
 	while (*s)
 		fputc(*s++, f);
@@ -259,15 +259,15 @@
 /*
  * Write a symbol to a file
  */
-static void writesymbol(struct sSymbol *pSym, FILE *f)
+static void writesymbol(struct sSymbol const *pSym, FILE *f)
 {
 	uint32_t type;
 	uint32_t offset;
 	int32_t sectid;
 
-	if (!(pSym->nType & SYMF_DEFINED))
+	if (!sym_IsDefined(pSym))
 		type = SYMTYPE_IMPORT;
-	else if (pSym->nType & SYMF_EXPORT)
+	else if (pSym->isExported)
 		type = SYMTYPE_EXPORT;
 	else
 		type = SYMTYPE_LOCAL;
@@ -283,7 +283,7 @@
 		break;
 	case SYMTYPE_EXPORT:
 		offset = pSym->nValue;
-		if (pSym->nType & SYMF_CONST)
+		if (pSym->type != SYM_LABEL)
 			sectid = -1;
 		else
 			sectid = getsectid(pSym->pSection);
@@ -307,7 +307,7 @@
  */
 static uint32_t nextID;
 
-static uint32_t addsymbol(struct sSymbol *pSym)
+static uint32_t addsymbol(struct sSymbol const *pSym)
 {
 	struct PatchSymbol *pPSym, **ppPSym;
 	uint32_t hash;
@@ -350,7 +350,7 @@
 
 		pSym = tHashedSymbols[i];
 		while (pSym) {
-			if (pSym->nType & SYMF_EXPORT)
+			if (pSym->isExported)
 				addsymbol(pSym);
 			pSym = pSym->pNext;
 		}
@@ -409,11 +409,16 @@
 			rpnexpr[rpnptr++] = rpn_PopByte(expr);
 			break;
 		case RPN_SYM:
+		{
 			symptr = 0;
 			while ((tzSym[symptr++] = rpn_PopByte(expr)) != 0)
 				;
 
-			if (sym_isConstant(tzSym)) {
+			struct sSymbol const *sym = sym_FindSymbol(tzSym);
+
+			if (!sym) {
+				break; // TODO: wtf?
+			} else if (sym_IsConstant(sym)) {
 				uint32_t value;
 
 				value = sym_GetConstantValue(tzSym);
@@ -423,11 +428,6 @@
 				rpnexpr[rpnptr++] = value >> 16;
 				rpnexpr[rpnptr++] = value >> 24;
 			} else {
-				struct sSymbol *sym = sym_FindSymbol(tzSym);
-
-				if (sym == NULL)
-					break;
-
 				symptr = addsymbol(sym);
 				rpnexpr[rpnptr++] = RPN_SYM;
 				rpnexpr[rpnptr++] = symptr & 0xFF;
@@ -436,6 +436,7 @@
 				rpnexpr[rpnptr++] = symptr >> 24;
 			}
 			break;
+		}
 		case RPN_BANK_SYM:
 		{
 			struct sSymbol *sym;
@@ -527,34 +528,6 @@
 }
 
 /*
- * Check for errors that could happen while writing an object file
- * This is important as out_WriteObject is skipped entirely when `-o` is omitted
- * Therefore, errors such as memory allocations still should be handled in
- * out_WriteObject and not here
- */
-void out_CheckErrors(void)
-{
-	/* Local symbols cannot be imported from elsewhere */
-	struct PatchSymbol *pSym = pPatchSymbols;
-
-	while (pSym) {
-		struct sSymbol *pSymbol = pSym->pSymbol;
-
-		if (!(pSymbol->nType & SYMF_DEFINED)
-		   && pSymbol->nType & SYMF_LOCAL) {
-			char *name = pSymbol->tzName;
-			char *localPtr = strchr(name, '.');
-
-			if (localPtr)
-				name = localPtr;
-			errx(1, "%s(%u) : '%s' not defined",
-			     pSymbol->tzFileName, pSymbol->nFileLine, name);
-		}
-		pSym = pSym->pNext;
-	}
-}
-
-/*
  * Write an objectfile
  */
 void out_WriteObject(void)
@@ -690,6 +663,7 @@
 
 	pPCSymbol->nValue = nPC;
 	pPCSymbol->pSection = pCurrentSection;
+	pPCSymbol->isConstant = pSect && pSect->nOrg != -1;
 }
 
 /*
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -143,7 +143,9 @@
 
 void rpn_Symbol(struct Expression *expr, char *tzSym)
 {
-	if (!sym_isConstant(tzSym)) {
+	struct sSymbol *sym = sym_FindSymbol(tzSym);
+
+	if (!sym || !sym_IsConstant(sym)) {
 		rpn_Init(expr);
 		sym_Ref(tzSym);
 		expr->isReloc = 1;
@@ -176,13 +178,15 @@
 
 void rpn_BankSymbol(struct Expression *expr, char *tzSym)
 {
+	struct sSymbol const *sym = sym_FindSymbol(tzSym);
+
 	/* The @ symbol is treated differently. */
-	if (sym_FindSymbol(tzSym) == pPCSymbol) {
+	if (sym == pPCSymbol) {
 		rpn_BankSelf(expr);
 		return;
 	}
 
-	if (sym_isConstant(tzSym)) {
+	if (sym && sym_IsConstant(sym)) {
 		yyerror("BANK argument must be a relocatable identifier");
 	} else {
 		rpn_Init(expr);
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -88,6 +88,9 @@
 	if (sym->Callback)
 		return sym->Callback(sym);
 
+	if (sym->type == SYM_LABEL)
+		return sym->nValue + sym->pSection->nOrg;
+
 	return sym->nValue;
 }
 
@@ -136,12 +139,13 @@
 	if (snprintf((*ppsym)->tzName, MAXSYMLEN + 1, "%s", s) > MAXSYMLEN)
 		warning(WARNING_LONG_STR, "Symbol name is too long: '%s'", s);
 
-	(*ppsym)->nValue = 0;
-	(*ppsym)->nType = 0;
+	(*ppsym)->isConstant = false;
+	(*ppsym)->isExported = false;
 	(*ppsym)->pScope = NULL;
 	(*ppsym)->pNext = NULL;
-	(*ppsym)->pMacro = NULL;
 	(*ppsym)->pSection = NULL;
+	(*ppsym)->nValue = 0;
+	(*ppsym)->pMacro = NULL;
 	(*ppsym)->Callback = NULL;
 	updateSymbolFilename(*ppsym);
 	return *ppsym;
@@ -252,58 +256,15 @@
 }
 
 /*
- * Determine if a symbol has been defined
- */
-uint32_t sym_isConstDefined(char *tzName)
-{
-	struct sSymbol *psym = sym_FindSymbol(tzName);
-
-	if (psym && (psym->nType & SYMF_DEFINED)) {
-		uint32_t mask = SYMF_EQU | SYMF_SET | SYMF_MACRO | SYMF_STRING;
-
-		if (psym->nType & mask)
-			return 1;
-
-		fatalerror("'%s' is not allowed as argument to the DEF function",
-			   tzName);
-	}
-
-	return 0;
-}
-
-uint32_t sym_isDefined(char *tzName)
-{
-	struct sSymbol *psym = sym_FindSymbol(tzName);
-
-	return (psym && (psym->nType & SYMF_DEFINED));
-}
-
-/*
- * Determine if the symbol is a constant
- */
-uint32_t sym_isConstant(char *s)
-{
-	struct sSymbol *psym = sym_FindSymbol(s);
-
-	/* The @ symbol is handled differently */
-	if (psym == pPCSymbol)
-		return pCurrentSection->nOrg != -1;
-
-	return (psym && (psym->nType & SYMF_CONST));
-}
-
-/*
  * Get a string equate's value
  */
-char *sym_GetStringValue(char *tzSym)
+char *sym_GetStringValue(struct sSymbol const *sym)
 {
-	const struct sSymbol *pSym = sym_FindSymbol(tzSym);
+	if (sym != NULL)
+		return sym->pMacro;
 
-	if (pSym != NULL)
-		return pSym->pMacro;
+	yyerror("String symbol '%s' not defined", sym->tzName);
 
-	yyerror("String symbol '%s' not defined", tzSym);
-
 	return NULL;
 }
 
@@ -318,10 +279,10 @@
 		if (pCurrentSection->nOrg == -1)
 			yyerror("Expected constant PC but section is not fixed");
 		else
-			return pPCSymbol->nValue;
+			return getvaluefield(psym);
 
 	} else if (psym != NULL) {
-		if (psym->nType & SYMF_CONST)
+		if (sym_IsConstant(psym))
 			return getvaluefield(psym);
 
 		fatalerror("Expression must have a constant value");
@@ -340,8 +301,8 @@
 	struct sSymbol *psym = sym_FindSymbol(s);
 
 	if (psym != NULL) {
-		if ((psym->nType & SYMF_DEFINED)) {
-			if (psym->nType & (SYMF_MACRO | SYMF_STRING))
+		if (sym_IsDefined(psym)) {
+			if (!sym_IsNumeric(psym))
 				yyerror("'%s' is a macro or string symbol", s);
 
 			return getvaluefield(psym);
@@ -472,10 +433,10 @@
 	struct sSymbol *nsym = findsymbol(tzSym, NULL);
 
 	if (nsym != NULL) {
-		if (nsym->nType & SYMF_DEFINED) {
+		if (sym_IsDefined(nsym)) {
 			yyerror("'%s' already defined at %s(%u)",
 				tzSym, nsym->tzFileName, nsym->nFileLine);
-		} else if (nsym->nType & SYMF_REF) {
+		} else {
 			yyerror("'%s' referenced as label at %s(%u)",
 				tzSym, nsym->tzFileName, nsym->nFileLine);
 		}
@@ -493,12 +454,11 @@
 {
 	struct sSymbol *nsym = createNonrelocSymbol(tzSym);
 
-	if (nsym) {
-		nsym->nValue = value;
-		nsym->nType |= SYMF_EQU | SYMF_DEFINED | SYMF_CONST;
-		nsym->pScope = NULL;
-		updateSymbolFilename(nsym);
-	}
+	nsym->nValue = value;
+	nsym->type = SYM_EQU;
+	nsym->isConstant = true;
+	nsym->pScope = NULL;
+	updateSymbolFilename(nsym);
 }
 
 /*
@@ -517,31 +477,19 @@
 {
 	struct sSymbol *nsym = createNonrelocSymbol(tzSym);
 
-	if (nsym) {
-		nsym->pMacro = malloc(strlen(tzValue) + 1);
+	nsym->pMacro = malloc(strlen(tzValue) + 1);
 
-		if (nsym->pMacro != NULL)
-			strcpy(nsym->pMacro, tzValue);
-		else
-			fatalerror("No memory for string equate");
+	if (nsym->pMacro != NULL)
+		strcpy(nsym->pMacro, tzValue);
+	else
+		fatalerror("No memory for string equate");
 
-		nsym->nType |= SYMF_STRING | SYMF_DEFINED;
-		nsym->ulMacroSize = strlen(tzValue);
-		nsym->pScope = NULL;
-	}
+	nsym->type = SYM_EQUS;
+	nsym->ulMacroSize = strlen(tzValue);
+	nsym->pScope = NULL;
 }
 
 /*
- * check if symbol is a string equated symbol
- */
-uint32_t sym_isString(char *tzSym)
-{
-	const struct sSymbol *pSym = findsymbol(tzSym, NULL);
-
-	return (pSym && (pSym->nType & SYMF_STRING));
-}
-
-/*
  * Alter a SET symbols value
  */
 void sym_AddSet(char *tzSym, int32_t value)
@@ -549,18 +497,18 @@
 	struct sSymbol *nsym = findsymbol(tzSym, NULL);
 
 	if (nsym != NULL) {
-		if (nsym->nType & SYMF_DEFINED) {
-			if (!(nsym->nType & SYMF_CONST))
+		if (sym_IsDefined(nsym)) {
+			if (nsym->type == SYM_LABEL)
 				yyerror("'%s' already defined as non-constant at %s(%u)",
 					tzSym,
 					nsym->tzFileName,
 					nsym->nFileLine);
-			else if (!(nsym->nType & SYMF_SET))
+			else if (nsym->type != SYM_SET)
 				yyerror("'%s' already defined as constant at %s(%u)",
 					tzSym,
 					nsym->tzFileName,
 					nsym->nFileLine);
-		} else if (nsym->nType & SYMF_REF) {
+		} else if (nsym->type == SYM_REF) {
 			yyerror("'%s' already referenced at %s(%u)",
 				tzSym,
 				nsym->tzFileName,
@@ -570,12 +518,11 @@
 		nsym = createsymbol(tzSym);
 	}
 
-	if (nsym) {
-		nsym->nValue = value;
-		nsym->nType |= SYMF_SET | SYMF_DEFINED | SYMF_CONST;
-		nsym->pScope = NULL;
-		updateSymbolFilename(nsym);
-	}
+	nsym->nValue = value;
+	nsym->type = SYM_SET;
+	nsym->isConstant = true;
+	nsym->pScope = NULL;
+	updateSymbolFilename(nsym);
 }
 
 /*
@@ -626,7 +573,7 @@
 	nsym = findsymbol(tzSym, scope);
 
 	if (nsym != NULL) {
-		if (nsym->nType & SYMF_DEFINED) {
+		if (sym_IsDefined(nsym)) {
 			yyerror("'%s' already defined in %s(%d)", tzSym,
 				nsym->tzFileName, nsym->nFileLine);
 		}
@@ -634,24 +581,21 @@
 		nsym = createsymbol(tzSym);
 	}
 
-	if (nsym) {
-		nsym->nValue = nPC;
-		nsym->nType |= SYMF_RELOC | SYMF_DEFINED;
-		if (localPtr)
-			nsym->nType |= SYMF_LOCAL;
+	nsym->nValue = nPC;
+	nsym->type = SYM_LABEL;
+	nsym->isConstant = pCurrentSection && pCurrentSection->nOrg != -1;
 
-		if (exportall)
-			nsym->nType |= SYMF_EXPORT;
+	if (exportall)
+		nsym->isExported = true;
 
-		nsym->pScope = scope;
-		nsym->pSection = pCurrentSection;
-		/* Labels need to be assigned a section, except PC */
-		if (!pCurrentSection && strcmp(tzSym, "@"))
-			yyerror("Label \"%s\" created outside of a SECTION",
-				tzSym);
+	nsym->pScope = scope;
+	nsym->pSection = pCurrentSection;
+	/* Labels need to be assigned a section, except PC */
+	if (!pCurrentSection && strcmp(tzSym, "@"))
+		yyerror("Label \"%s\" created outside of a SECTION",
+			tzSym);
 
-		updateSymbolFilename(nsym);
-	}
+	updateSymbolFilename(nsym);
 
 	pScope = findsymbol(tzSym, scope);
 }
@@ -663,7 +607,7 @@
  *
  * It returns 1 if the difference is defined, 0 if not.
  */
-int32_t sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2)
+bool sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2)
 {
 	const struct sSymbol *nsym1 = sym_FindSymbol(tzSym1);
 	const struct sSymbol *nsym2 = sym_FindSymbol(tzSym2);
@@ -675,25 +619,25 @@
 	if (nsym2 == NULL)
 		fatalerror("Symbol \"%s\" isn't defined.", tzSym2);
 
-	int32_t s1reloc = (nsym1->nType & SYMF_RELOC) != 0;
-	int32_t s2reloc = (nsym2->nType & SYMF_RELOC) != 0;
+	int32_t s1const = sym_IsConstant(nsym1);
+	int32_t s2const = sym_IsConstant(nsym2);
 
 	/* Both are non-relocatable */
-	if (!s1reloc && !s2reloc)
-		return 1;
+	if (s1const && s2const)
+		return true;
 
 	/* One of them is relocatable, the other one is not. */
-	if (s1reloc ^ s2reloc)
-		return 0;
+	if (s1const ^ s2const)
+		return false;
 
 	/*
 	 * Both of them are relocatable. Make sure they are defined (internal
 	 * coherency with sym_AddReloc and sym_AddLocalReloc).
 	 */
-	if (!(nsym1->nType & SYMF_DEFINED))
+	if (!sym_IsDefined(nsym1))
 		fatalerror("Relocatable symbol \"%s\" isn't defined.", tzSym1);
 
-	if (!(nsym2->nType & SYMF_DEFINED))
+	if (!sym_IsDefined(nsym2))
 		fatalerror("Relocatable symbol \"%s\" isn't defined.", tzSym2);
 
 	/*
@@ -708,13 +652,10 @@
  */
 void sym_Export(char *tzSym)
 {
+	sym_Ref(tzSym);
 	struct sSymbol *nsym = sym_FindSymbol(tzSym);
 
-	if (nsym == NULL)
-		nsym = createsymbol(tzSym);
-
-	if (nsym)
-		nsym->nType |= SYMF_EXPORT;
+	nsym->isExported = true;
 }
 
 /*
@@ -724,18 +665,16 @@
 {
 	struct sSymbol *nsym = createNonrelocSymbol(tzSym);
 
-	if (nsym) {
-		nsym->nType |= SYMF_MACRO | SYMF_DEFINED;
-		nsym->pScope = NULL;
-		nsym->ulMacroSize = ulNewMacroSize;
-		nsym->pMacro = tzNewMacro;
-		updateSymbolFilename(nsym);
-		/*
-		 * The symbol is created at the line after the `endm`,
-		 * override this with the actual definition line
-		 */
-		nsym->nFileLine = nDefLineNo;
-	}
+	nsym->type = SYM_MACRO;
+	nsym->pScope = NULL;
+	nsym->ulMacroSize = ulNewMacroSize;
+	nsym->pMacro = tzNewMacro;
+	updateSymbolFilename(nsym);
+	/*
+	 * The symbol is created at the line after the `endm`,
+	 * override this with the actual definition line
+	 */
+	nsym->nFileLine = nDefLineNo;
 }
 
 /*
@@ -748,7 +687,6 @@
 
 	if (nsym == NULL) {
 		char fullname[MAXSYMLEN + 1];
-		int isLocal = 0;
 
 		if (*tzSym == '.') {
 			if (!pScope)
@@ -757,17 +695,11 @@
 			fullSymbolName(fullname, sizeof(fullname), tzSym,
 				       pScope);
 			tzSym = fullname;
-			isLocal = 1;
 		}
 
 		nsym = createsymbol(tzSym);
-
-		if (nsym && isLocal)
-			nsym->nType |= SYMF_LOCAL;
+		nsym->type = SYM_REF;
 	}
-
-	if (nsym)
-		nsym->nType |= SYMF_REF;
 }
 
 /*
--- a/test/asm/label-diff.asm
+++ b/test/asm/label-diff.asm
@@ -27,7 +27,7 @@
 
 ; TODO: uncomment all that can be, there is seriously room for improvement here
 	; Diffing two constants should work
-; But it doesn't yet	print_diff Constant, Constant2
+	print_diff Constant, Constant2
 	; Diffing two labels in the same SECTION as well
 	print_diff Known2, Known
 	; Diffing a constant and a "floating" label cannot work
@@ -40,7 +40,7 @@
 	; Now let's fiddle with PC
 SECTION "fixed PC", ROM0[420]
 	; Diffing a constant and PC should work
-; But it doesn't yet	print_diff Constant, @
+	print_diff Constant, @
 	; Diffing a floating label and PC cannot work
 ; ...And that causes a fatal error	print_diff Known, @
 	; Diffinf a ref and PC cannot work
@@ -49,7 +49,7 @@
 	print_diff @, @
 	; Diffing PC and a label from here should work
 LocalFixed:
-; But it doesn't yet	print_diff LocalFixed, @
+	print_diff LocalFixed, @
 
 SECTION "Floating PC", ROM0
 	; Diffing a constant and PC cannot work
--- a/test/asm/label-diff.out
+++ b/test/asm/label-diff.out
@@ -1,5 +1,11 @@
+$FFFFFFE5
+$1B
 $4
 $FFFFFFFC
+$FFFFFE86
+$17A
+$0
+$0
 $0
 $0
 $0
--- a/test/asm/pc-bank.err
+++ b/test/asm/pc-bank.err
@@ -1,5 +1,5 @@
 ERROR: pc-bank.asm(2):
     Source address $2a00 not in $FF00 to $FFFF
 ERROR: pc-bank.asm(11):
-    @'s bank is not known yet
+    Current bank is not known yet
 error: Assembly aborted (2 errors)!
--- a/test/asm/pc-def.err
+++ b/test/asm/pc-def.err
@@ -1,2 +1,3 @@
 ERROR: pc-def.asm(1):
-    '@' is not allowed as argument to the DEF function
+    Label "@" is not a valid argument to DEF
+error: Assembly aborted (1 errors)!
--- a/test/asm/pc-def.out
+++ b/test/asm/pc-def.out
@@ -1,0 +1,1 @@
+defined
--- a/test/asm/undefined-dot.err
+++ b/test/asm/undefined-dot.err
@@ -1,1 +1,0 @@
-error: undefined-dot.asm(3) : '.' not defined