shithub: rgbds

Download patch

ref: 7dd8ba37f11d38fa6a45737922e6af1dbcc9b468
parent: 6842c831fdedec5deff3f1dc7fcca1465a4a9bd7
author: ISSOtm <[email protected]>
date: Sat Feb 5 07:15:32 EST 2022

Allow changing recursion depth limit at runtime

--- a/include/asm/fstack.h
+++ b/include/asm/fstack.h
@@ -77,6 +77,7 @@
 void fstk_StopRept(void);
 bool fstk_Break(void);
 
+void fstk_NewRecursionDepth(size_t newDepth);
 void fstk_Init(char const *mainPath, size_t maxDepth);
 
 #endif /* RGBDS_ASM_FSTACK_H */
--- a/include/asm/lexer.h
+++ b/include/asm/lexer.h
@@ -83,6 +83,7 @@
 	size_t size;
 };
 
+void lexer_CheckRecursionDepth(void);
 char const *lexer_GetFileName(void);
 uint32_t lexer_GetLineNo(void);
 uint32_t lexer_GetColNo(void);
--- a/src/asm/fstack.c
+++ b/src/asm/fstack.c
@@ -284,8 +284,9 @@
  */
 static void newContext(struct FileStackNode *fileInfo)
 {
-	if (++contextDepth >= maxRecursionDepth)
-		fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth);
+	++contextDepth;
+	fstk_NewRecursionDepth(maxRecursionDepth); // Only checks if the max depth was exceeded
+
 	struct Context *context = malloc(sizeof(*context));
 
 	if (!context)
@@ -505,6 +506,13 @@
 
 	fstk_StopRept();
 	return true;
+}
+
+void fstk_NewRecursionDepth(size_t newDepth)
+{
+	if (contextDepth >= newDepth)
+		fatalerror("Recursion limit (%zu) exceeded\n", newDepth);
+	maxRecursionDepth = newDepth;
 }
 
 void fstk_Init(char const *mainPath, size_t maxDepth)
--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -668,15 +668,9 @@
 	if (!size)
 		return;
 
-	if (name) {
-		size_t depth = 0;
+	if (name)
+		lexer_CheckRecursionDepth();
 
-		for (struct Expansion *exp = lexerState->expansions; exp; exp = exp->parent) {
-			if (depth++ >= maxRecursionDepth)
-				fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth);
-		}
-	}
-
 	struct Expansion *exp = malloc(sizeof(*exp));
 
 	if (!exp)
@@ -690,6 +684,16 @@
 	exp->owned = owned;
 
 	lexerState->expansions = exp;
+}
+
+void lexer_CheckRecursionDepth(void)
+{
+	size_t depth = 0;
+
+	for (struct Expansion *exp = lexerState->expansions; exp; exp = exp->parent) {
+		if (depth++ >= maxRecursionDepth)
+			fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth);
+	}
 }
 
 static void freeExpansion(struct Expansion *expansion)
--- a/src/asm/opt.c
+++ b/src/asm/opt.c
@@ -1,3 +1,4 @@
+#include <ctype.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <stdint.h>
@@ -5,6 +6,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "asm/fstack.h"
 #include "asm/lexer.h"
 #include "asm/main.h"
 #include "asm/section.h"
@@ -17,6 +19,7 @@
 	bool haltnop;
 	bool optimizeLoads;
 	bool warningsAreErrors;
+	size_t maxRecursionDepth;
 	// Don't be confused: we use the size of the **global variable** `warningStates`!
 	enum WarningState warningStates[sizeof(warningStates)];
 	struct OptStackEntry *next;
@@ -39,6 +42,12 @@
 	fillByte = fill;
 }
 
+void opt_R(size_t newDepth)
+{
+	fstk_NewRecursionDepth(newDepth);
+	lexer_CheckRecursionDepth();
+}
+
 void opt_h(bool halt)
 {
 	haltnop = halt;
@@ -85,6 +94,29 @@
 			error("Invalid argument for option 'p'\n");
 		}
 		break;
+
+	case 'r': {
+		++s; // Skip 'r'
+		while (isblank(*s))
+			++s; // Skip leading whitespace
+
+		if (s[0] == '\0') {
+			error("Missing argument to option 'r'\n");
+			break;
+		}
+
+		char *endptr;
+		unsigned long newDepth = strtoul(s, &endptr, 10);
+
+		if (*endptr != '\0') {
+			error("Invalid argument to option 'r' (\"%s\")\n", s);
+		} else if (errno == ERANGE) {
+			error("Argument to 'r' is out of range (\"%s\")\n", s);
+		} else {
+			opt_R(newDepth);
+		}
+		break;
+	}
 
 	case 'h':
 		if (s[1] == '\0')
--- a/src/asm/rgbasm.5
+++ b/src/asm/rgbasm.5
@@ -1993,6 +1993,7 @@
 .Ss Changing options while assembling
 .Ic OPT
 can be used to change some of the options during assembling from within the source, instead of defining them on the command-line.
+.Pq See Xr rgbasm 1 .
 .Pp
 .Ic OPT
 takes a comma-separated list of options as its argument:
@@ -2008,8 +2009,10 @@
     LD [$FF88], A         ; optimized to use LDH by default
 .Ed
 .Pp
-The options that OPT can modify are currently:
-.Cm b , g , p , h , L ,
+The options that
+.Ic OPT
+can modify are currently:
+.Cm b , g , p , r , h , L ,
 and
 .Cm W .
 The Boolean flag options
--- /dev/null
+++ b/test/asm/opt-r.asm
@@ -1,0 +1,13 @@
+OPT r34 ; :3
+OPT r 360
+
+; Invalid
+OPT r ; Missing arg
+OPT r 2a ; Bad decimal
+
+; Check that it has an effect
+OPT r 1
+MACRO m
+	m
+ENDM
+	m
--- /dev/null
+++ b/test/asm/opt-r.err
@@ -1,0 +1,6 @@
+error: opt-r.asm(5):
+    Missing argument to option 'r'
+error: opt-r.asm(6):
+    Invalid argument to option 'r' ("2a")
+FATAL: opt-r.asm(13):
+    Recursion limit (1) exceeded