Allow changing recursion depth limit at runtime

This commit is contained in:
ISSOtm
2022-02-05 12:15:32 +01:00
committed by Eldred Habert
parent 6842c831fd
commit 7dd8ba37f1
9 changed files with 80 additions and 12 deletions

View File

@@ -77,6 +77,7 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
void fstk_StopRept(void); void fstk_StopRept(void);
bool fstk_Break(void); bool fstk_Break(void);
void fstk_NewRecursionDepth(size_t newDepth);
void fstk_Init(char const *mainPath, size_t maxDepth); void fstk_Init(char const *mainPath, size_t maxDepth);
#endif /* RGBDS_ASM_FSTACK_H */ #endif /* RGBDS_ASM_FSTACK_H */

View File

@@ -83,6 +83,7 @@ struct CaptureBody {
size_t size; size_t size;
}; };
void lexer_CheckRecursionDepth(void);
char const *lexer_GetFileName(void); char const *lexer_GetFileName(void);
uint32_t lexer_GetLineNo(void); uint32_t lexer_GetLineNo(void);
uint32_t lexer_GetColNo(void); uint32_t lexer_GetColNo(void);

View File

@@ -284,8 +284,9 @@ bool yywrap(void)
*/ */
static void newContext(struct FileStackNode *fileInfo) static void newContext(struct FileStackNode *fileInfo)
{ {
if (++contextDepth >= maxRecursionDepth) ++contextDepth;
fatalerror("Recursion limit (%zu) exceeded\n", maxRecursionDepth); fstk_NewRecursionDepth(maxRecursionDepth); // Only checks if the max depth was exceeded
struct Context *context = malloc(sizeof(*context)); struct Context *context = malloc(sizeof(*context));
if (!context) if (!context)
@@ -507,6 +508,13 @@ bool fstk_Break(void)
return true; 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) void fstk_Init(char const *mainPath, size_t maxDepth)
{ {
struct LexerState *state = lexer_OpenFile(mainPath); struct LexerState *state = lexer_OpenFile(mainPath);

View File

@@ -668,14 +668,8 @@ static void beginExpansion(char const *str, bool owned, char const *name)
if (!size) if (!size)
return; return;
if (name) { if (name)
size_t depth = 0; 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)); struct Expansion *exp = malloc(sizeof(*exp));
@@ -692,6 +686,16 @@ static void beginExpansion(char const *str, bool owned, char const *name)
lexerState->expansions = exp; 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) static void freeExpansion(struct Expansion *expansion)
{ {
free(expansion->name); free(expansion->name);

View File

@@ -1,3 +1,4 @@
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@@ -5,6 +6,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "asm/fstack.h"
#include "asm/lexer.h" #include "asm/lexer.h"
#include "asm/main.h" #include "asm/main.h"
#include "asm/section.h" #include "asm/section.h"
@@ -17,6 +19,7 @@ struct OptStackEntry {
bool haltnop; bool haltnop;
bool optimizeLoads; bool optimizeLoads;
bool warningsAreErrors; bool warningsAreErrors;
size_t maxRecursionDepth;
// Don't be confused: we use the size of the **global variable** `warningStates`! // Don't be confused: we use the size of the **global variable** `warningStates`!
enum WarningState warningStates[sizeof(warningStates)]; enum WarningState warningStates[sizeof(warningStates)];
struct OptStackEntry *next; struct OptStackEntry *next;
@@ -39,6 +42,12 @@ void opt_P(uint8_t fill)
fillByte = fill; fillByte = fill;
} }
void opt_R(size_t newDepth)
{
fstk_NewRecursionDepth(newDepth);
lexer_CheckRecursionDepth();
}
void opt_h(bool halt) void opt_h(bool halt)
{ {
haltnop = halt; haltnop = halt;
@@ -86,6 +95,29 @@ void opt_Parse(char *s)
} }
break; 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': case 'h':
if (s[1] == '\0') if (s[1] == '\0')
opt_h(false); opt_h(false);

View File

@@ -1993,6 +1993,7 @@ block, all of them but the first one are ignored.
.Ss Changing options while assembling .Ss Changing options while assembling
.Ic OPT .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. 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 .Pp
.Ic OPT .Ic OPT
takes a comma-separated list of options as its argument: takes a comma-separated list of options as its argument:
@@ -2008,8 +2009,10 @@ POPO
LD [$FF88], A ; optimized to use LDH by default LD [$FF88], A ; optimized to use LDH by default
.Ed .Ed
.Pp .Pp
The options that OPT can modify are currently: The options that
.Cm b , g , p , h , L , .Ic OPT
can modify are currently:
.Cm b , g , p , r , h , L ,
and and
.Cm W . .Cm W .
The Boolean flag options The Boolean flag options

13
test/asm/opt-r.asm Normal file
View File

@@ -0,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

6
test/asm/opt-r.err Normal file
View File

@@ -0,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

0
test/asm/opt-r.out Normal file
View File