shithub: rgbds

Download patch

ref: c755fa3469af9c4179b36f7b06ef54a95b8eafeb
parent: e78a1d5bfd2840fa94c6a4c75a4e3aabeb904b70
author: Rangi <remy.oukaour+rangi42@gmail.com>
date: Fri Apr 16 17:15:01 EDT 2021

`readIdentifier` does not process characters that get truncated

Previously a '.' could be past the truncation limit but still
cause the identifier to be marked as local, violating an
assertion in `sym_AddLocalLabel`.

Fixes #832

--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -1210,6 +1210,11 @@
 	return (c <= 'Z' && c >= 'A') || (c <= 'z' && c >= 'a') || c == '.' || c == '_';
 }
 
+static bool continuesIdentifier(int c)
+{
+	return startsIdentifier(c) || (c <= '9' && c >= '0') || c == '#' || c == '@';
+}
+
 static int readIdentifier(char firstChar)
 {
 	dbgPrint("Reading identifier or keyword\n");
@@ -1217,30 +1222,24 @@
 	yylval.tzSym[0] = firstChar;
 	uint16_t nodeID = keywordDict[0].children[dictIndex(firstChar)];
 	int tokenType = firstChar == '.' ? T_LOCAL_ID : T_ID;
-	size_t i;
+	size_t i = 1;
 
-	for (i = 1; ; i++) {
-		int c = peek();
-
-		/* If that char isn't in the symbol charset, end */
-		if ((c > '9' || c < '0')
-		 && (c > 'Z' || c < 'A')
-		 && (c > 'z' || c < 'a')
-		 && c != '#' && c != '.' && c != '@' && c != '_')
-			break;
+	/* Continue reading while the char is in the symbol charset */
+	for (int c = peek(); continuesIdentifier(c); i++, c = peek()) {
 		shiftChar();
 
-		/* Write the char to the identifier's name */
-		if (i < sizeof(yylval.tzSym) - 1)
+		if (i < sizeof(yylval.tzSym) - 1) {
+			/* Write the char to the identifier's name */
 			yylval.tzSym[i] = c;
 
-		/* If the char was a dot, mark the identifier as local */
-		if (c == '.')
-			tokenType = T_LOCAL_ID;
+			/* If the char was a dot, mark the identifier as local */
+			if (c == '.')
+				tokenType = T_LOCAL_ID;
 
-		/* Attempt to traverse the tree to check for a keyword */
-		if (nodeID) /* Do nothing if matching already failed */
-			nodeID = keywordDict[nodeID].children[dictIndex(c)];
+			/* Attempt to traverse the tree to check for a keyword */
+			if (nodeID) /* Do nothing if matching already failed */
+				nodeID = keywordDict[nodeID].children[dictIndex(c)];
+		}
 	}
 
 	if (i > sizeof(yylval.tzSym) - 1) {
--- /dev/null
+++ b/test/asm/local-truncated.asm
@@ -1,0 +1,11 @@
+SECTION "Test", ROM0
+
+MACRO a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
+	println "truncated :("
+ENDM
+
+a012:
+	a012.local
+
+a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012:
+	a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012.local
--- /dev/null
+++ b/test/asm/local-truncated.err
@@ -1,0 +1,7 @@
+warning: local-truncated.asm(10): [-Wlong-string]
+    Symbol name too long, got truncated
+ERROR: local-truncated.asm(10):
+    'a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' already defined at local-truncated.asm(3)
+warning: local-truncated.asm(11): [-Wlong-string]
+    Symbol name too long, got truncated
+error: Assembly aborted (1 error)!
--- /dev/null
+++ b/test/asm/local-truncated.out
@@ -1,0 +1,1 @@
+truncated :(