shithub: rgbds

Download patch

ref: cab9cb06a3816964cf72da4017baa304729ab82d
parent: 62bea23c49cc74d8a894b88002da2290dbc60f82
author: Rangi <remy.oukaour+rangi42@gmail.com>
date: Fri Jan 8 11:28:51 EST 2021

Store IF depth relative to each fstack context

This disallows starting/ending an IF inside an
INCLUDEd file or a macro expansion

--- a/include/asm/asm.h
+++ b/include/asm/asm.h
@@ -25,7 +25,6 @@
 #define MAXINCPATHS	128
 
 extern uint32_t nTotalLines;
-extern uint32_t nIFDepth;
 extern struct Section *pCurrentSection;
 
 #endif /* RGBDS_ASM_ASM_H */
--- a/include/asm/fstack.h
+++ b/include/asm/fstack.h
@@ -53,6 +53,9 @@
 
 struct MacroArgs;
 
+uint32_t fstk_GetIFDepth(void);
+void fstk_IncIFDepth(void);
+void fstk_DecIFDepth(void);
 void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo);
 void fstk_DumpCurrent(void);
 struct FileStackNode *fstk_GetFileStack(void);
--- a/src/asm/fstack.c
+++ b/src/asm/fstack.c
@@ -31,6 +31,7 @@
 	struct Context *parent;
 	struct FileStackNode *fileInfo;
 	struct LexerState *lexerState;
+	uint32_t nIFDepth;
 	uint32_t uniqueID;
 	struct MacroArgs *macroArgs; /* Macro args are *saved* here */
 	uint32_t nbReptIters;
@@ -47,8 +48,23 @@
 static unsigned int nbIncPaths = 0;
 static char const *includePaths[MAXINCPATHS];
 
-char const *dumpNodeAndParents(struct FileStackNode const *node)
+uint32_t fstk_GetIFDepth(void)
 {
+	return contextStack->nIFDepth;
+}
+
+void fstk_IncIFDepth(void)
+{
+	contextStack->nIFDepth++;
+}
+
+void fstk_DecIFDepth(void)
+{
+	contextStack->nIFDepth--;
+}
+
+static const char *dumpNodeAndParents(struct FileStackNode const *node)
+{
 	char const *name;
 
 	if (node->type == NODE_REPT) {
@@ -200,6 +216,10 @@
 
 bool yywrap(void)
 {
+	if (contextStack->nIFDepth != 0)
+		fatalerror("Ended block with %" PRIu32 " unterminated IF construct%s\n",
+			   contextStack->nIFDepth, contextStack->nIFDepth == 1 ? "" : "s");
+
 	if (contextStack->fileInfo->type == NODE_REPT) { /* The context is a REPT block, which may loop */
 		struct FileStackReptNode *fileInfo = (struct FileStackReptNode *)contextStack->fileInfo;
 
@@ -283,6 +303,7 @@
 	fileInfo->referenced = false;
 	fileInfo->lineNo = lexer_GetLineNo();
 	context->fileInfo = fileInfo;
+	context->nIFDepth = 0;
 	context->forName = NULL;
 	/*
 	 * Link new entry to its parent so it's reachable later
@@ -429,7 +450,7 @@
 
 	contextStack->lexerState = lexer_OpenFileView(body, size, reptLineNo);
 	if (!contextStack->lexerState)
-		fatalerror("Failed to set up lexer for rept block\n");
+		fatalerror("Failed to set up lexer for REPT block\n");
 	lexer_SetStateAtEOL(contextStack->lexerState);
 	contextStack->uniqueID = macro_UseNewUniqueID();
 	return true;
@@ -521,6 +542,7 @@
 
 	context->parent = NULL;
 	context->lexerState = state;
+	context->nIFDepth = 0;
 	context->uniqueID = 0;
 	macro_SetUniqueID(0);
 	context->nbReptIters = 0;
--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -1966,7 +1966,7 @@
 {
 	dbgPrint("Skipping IF block (toEndc = %s)\n", toEndc ? "true" : "false");
 	lexer_SetMode(LEXER_NORMAL);
-	int startingDepth = nIFDepth;
+	int startingDepth = fstk_GetIFDepth();
 	int token;
 	bool atLineStart = lexerState->atLineStart;
 
@@ -1990,7 +1990,7 @@
 				token = readIdentifier(c);
 				switch (token) {
 				case T_POP_IF:
-					nIFDepth++;
+					fstk_IncIFDepth();
 					break;
 
 				case T_POP_ELIF:
@@ -1999,10 +1999,10 @@
 						break;
 					/* fallthrough */
 				case T_POP_ENDC:
-					if (nIFDepth == startingDepth)
+					if (fstk_GetIFDepth() == startingDepth)
 						goto finish;
 					if (token == T_POP_ENDC)
-						nIFDepth--;
+						fstk_DecIFDepth();
 				}
 			}
 			atLineStart = false;
@@ -2087,11 +2087,11 @@
 					break;
 
 				case T_POP_IF:
-					nIFDepth++;
+					fstk_IncIFDepth();
 					break;
 
 				case T_POP_ENDC:
-					nIFDepth--;
+					fstk_DecIFDepth();
 				}
 			}
 			atLineStart = false;
--- a/src/asm/main.c
+++ b/src/asm/main.c
@@ -46,7 +46,7 @@
 char **cldefines;
 
 clock_t nStartClock, nEndClock;
-uint32_t nTotalLines, nIFDepth;
+uint32_t nTotalLines;
 
 #if defined(YYDEBUG) && YYDEBUG
 extern int yydebug;
@@ -488,7 +488,6 @@
 	nStartClock = clock();
 
 	nTotalLines = 0;
-	nIFDepth = 0;
 	sym_Init(now);
 	sym_SetExportAll(exportall);
 
@@ -501,10 +500,6 @@
 		errx(1, "Assembly aborted (%u errors)!", nbErrors);
 	if (dependfile)
 		fclose(dependfile);
-
-	if (nIFDepth != 0)
-		errx(1, "Unterminated IF construct (%" PRIu32 " levels)!",
-		     nIFDepth);
 
 	sect_CheckUnionClosed();
 
--- a/src/asm/parser.y
+++ b/src/asm/parser.y
@@ -563,7 +563,7 @@
 ;
 
 if		: T_POP_IF const T_NEWLINE {
-			nIFDepth++;
+			fstk_IncIFDepth();
 			executeElseBlock = !$2;
 			if (executeElseBlock)
 				lexer_SetMode(LEXER_SKIP_TO_ELIF);
@@ -571,7 +571,7 @@
 ;
 
 elif		: T_POP_ELIF const T_NEWLINE {
-			if (nIFDepth <= 0)
+			if (fstk_GetIFDepth() == 0)
 				fatalerror("Found ELIF outside an IF construct\n");
 
 			if (!executeElseBlock) {
@@ -585,7 +585,7 @@
 ;
 
 else		: T_POP_ELSE T_NEWLINE {
-			if (nIFDepth <= 0)
+			if (fstk_GetIFDepth() == 0)
 				fatalerror("Found ELSE outside an IF construct\n");
 
 			if (!executeElseBlock)
@@ -594,10 +594,10 @@
 ;
 
 endc		: T_POP_ENDC T_NEWLINE {
-			if (nIFDepth <= 0)
+			if (fstk_GetIFDepth() == 0)
 				fatalerror("Found ENDC outside an IF construct\n");
 
-			nIFDepth--;
+			fstk_DecIFDepth();
 			executeElseBlock = false;
 		}
 ;
--- a/test/asm/break.asm
+++ b/test/asm/break.asm
@@ -20,3 +20,4 @@
     break
   no endc
 endr
+println "done"
--- a/test/asm/break.err
+++ b/test/asm/break.err
@@ -2,4 +2,5 @@
     done 5
 warning: break.asm(17): [-Wuser]
     OK
-error: Unterminated IF construct (1 levels)!
+FATAL: break.asm(18) -> break.asm::REPT~1(23):
+    Ended block with 1 unterminated IF construct
--- /dev/null
+++ b/test/asm/unterminated-if-include.inc
@@ -1,0 +1,3 @@
+if 1
+  println "inside include"
+; no endc
--- /dev/null
+++ b/test/asm/unterminated-if.asm
@@ -1,0 +1,15 @@
+if 1
+  if 0
+    println "A"
+  elif 1
+    println "B"
+  else
+    println "C"
+  endc
+else
+  println "D"
+endc
+
+INCLUDE "unterminated-if-include.inc"
+
+println "done"
--- /dev/null
+++ b/test/asm/unterminated-if.err
@@ -1,0 +1,2 @@
+FATAL: unterminated-if.asm(13) -> unterminated-if-include.inc(4):
+    Ended block with 1 unterminated IF construct
--- /dev/null
+++ b/test/asm/unterminated-if.out
@@ -1,0 +1,2 @@
+B
+inside include