mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Store IF depth relative to each fstack context
This disallows starting/ending an IF inside an INCLUDEd file or a macro expansion
This commit is contained in:
@@ -25,7 +25,6 @@
|
|||||||
#define MAXINCPATHS 128
|
#define MAXINCPATHS 128
|
||||||
|
|
||||||
extern uint32_t nTotalLines;
|
extern uint32_t nTotalLines;
|
||||||
extern uint32_t nIFDepth;
|
|
||||||
extern struct Section *pCurrentSection;
|
extern struct Section *pCurrentSection;
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_ASM_H */
|
#endif /* RGBDS_ASM_ASM_H */
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ extern size_t nMaxRecursionDepth;
|
|||||||
|
|
||||||
struct MacroArgs;
|
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_Dump(struct FileStackNode const *node, uint32_t lineNo);
|
||||||
void fstk_DumpCurrent(void);
|
void fstk_DumpCurrent(void);
|
||||||
struct FileStackNode *fstk_GetFileStack(void);
|
struct FileStackNode *fstk_GetFileStack(void);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ struct Context {
|
|||||||
struct Context *parent;
|
struct Context *parent;
|
||||||
struct FileStackNode *fileInfo;
|
struct FileStackNode *fileInfo;
|
||||||
struct LexerState *lexerState;
|
struct LexerState *lexerState;
|
||||||
|
uint32_t nIFDepth;
|
||||||
uint32_t uniqueID;
|
uint32_t uniqueID;
|
||||||
struct MacroArgs *macroArgs; /* Macro args are *saved* here */
|
struct MacroArgs *macroArgs; /* Macro args are *saved* here */
|
||||||
uint32_t nbReptIters;
|
uint32_t nbReptIters;
|
||||||
@@ -47,7 +48,22 @@ size_t nMaxRecursionDepth;
|
|||||||
static unsigned int nbIncPaths = 0;
|
static unsigned int nbIncPaths = 0;
|
||||||
static char const *includePaths[MAXINCPATHS];
|
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;
|
char const *name;
|
||||||
|
|
||||||
@@ -200,6 +216,10 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
|
|||||||
|
|
||||||
bool yywrap(void)
|
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 */
|
if (contextStack->fileInfo->type == NODE_REPT) { /* The context is a REPT block, which may loop */
|
||||||
struct FileStackReptNode *fileInfo = (struct FileStackReptNode *)contextStack->fileInfo;
|
struct FileStackReptNode *fileInfo = (struct FileStackReptNode *)contextStack->fileInfo;
|
||||||
|
|
||||||
@@ -283,6 +303,7 @@ static void newContext(struct FileStackNode *fileInfo)
|
|||||||
fileInfo->referenced = false;
|
fileInfo->referenced = false;
|
||||||
fileInfo->lineNo = lexer_GetLineNo();
|
fileInfo->lineNo = lexer_GetLineNo();
|
||||||
context->fileInfo = fileInfo;
|
context->fileInfo = fileInfo;
|
||||||
|
context->nIFDepth = 0;
|
||||||
context->forName = NULL;
|
context->forName = NULL;
|
||||||
/*
|
/*
|
||||||
* Link new entry to its parent so it's reachable later
|
* Link new entry to its parent so it's reachable later
|
||||||
@@ -429,7 +450,7 @@ static bool newReptContext(int32_t reptLineNo, char *body, size_t size)
|
|||||||
|
|
||||||
contextStack->lexerState = lexer_OpenFileView(body, size, reptLineNo);
|
contextStack->lexerState = lexer_OpenFileView(body, size, reptLineNo);
|
||||||
if (!contextStack->lexerState)
|
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);
|
lexer_SetStateAtEOL(contextStack->lexerState);
|
||||||
contextStack->uniqueID = macro_UseNewUniqueID();
|
contextStack->uniqueID = macro_UseNewUniqueID();
|
||||||
return true;
|
return true;
|
||||||
@@ -521,6 +542,7 @@ void fstk_Init(char const *mainPath, size_t maxRecursionDepth)
|
|||||||
|
|
||||||
context->parent = NULL;
|
context->parent = NULL;
|
||||||
context->lexerState = state;
|
context->lexerState = state;
|
||||||
|
context->nIFDepth = 0;
|
||||||
context->uniqueID = 0;
|
context->uniqueID = 0;
|
||||||
macro_SetUniqueID(0);
|
macro_SetUniqueID(0);
|
||||||
context->nbReptIters = 0;
|
context->nbReptIters = 0;
|
||||||
|
|||||||
@@ -1966,7 +1966,7 @@ static int skipIfBlock(bool toEndc)
|
|||||||
{
|
{
|
||||||
dbgPrint("Skipping IF block (toEndc = %s)\n", toEndc ? "true" : "false");
|
dbgPrint("Skipping IF block (toEndc = %s)\n", toEndc ? "true" : "false");
|
||||||
lexer_SetMode(LEXER_NORMAL);
|
lexer_SetMode(LEXER_NORMAL);
|
||||||
int startingDepth = nIFDepth;
|
int startingDepth = fstk_GetIFDepth();
|
||||||
int token;
|
int token;
|
||||||
bool atLineStart = lexerState->atLineStart;
|
bool atLineStart = lexerState->atLineStart;
|
||||||
|
|
||||||
@@ -1990,7 +1990,7 @@ static int skipIfBlock(bool toEndc)
|
|||||||
token = readIdentifier(c);
|
token = readIdentifier(c);
|
||||||
switch (token) {
|
switch (token) {
|
||||||
case T_POP_IF:
|
case T_POP_IF:
|
||||||
nIFDepth++;
|
fstk_IncIFDepth();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_POP_ELIF:
|
case T_POP_ELIF:
|
||||||
@@ -1999,10 +1999,10 @@ static int skipIfBlock(bool toEndc)
|
|||||||
break;
|
break;
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case T_POP_ENDC:
|
case T_POP_ENDC:
|
||||||
if (nIFDepth == startingDepth)
|
if (fstk_GetIFDepth() == startingDepth)
|
||||||
goto finish;
|
goto finish;
|
||||||
if (token == T_POP_ENDC)
|
if (token == T_POP_ENDC)
|
||||||
nIFDepth--;
|
fstk_DecIFDepth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atLineStart = false;
|
atLineStart = false;
|
||||||
@@ -2087,11 +2087,11 @@ static int yylex_SKIP_TO_ENDR(void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_POP_IF:
|
case T_POP_IF:
|
||||||
nIFDepth++;
|
fstk_IncIFDepth();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_POP_ENDC:
|
case T_POP_ENDC:
|
||||||
nIFDepth--;
|
fstk_DecIFDepth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atLineStart = false;
|
atLineStart = false;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const size_t cldefine_entrysize = 2 * sizeof(void *);
|
|||||||
char **cldefines;
|
char **cldefines;
|
||||||
|
|
||||||
clock_t nStartClock, nEndClock;
|
clock_t nStartClock, nEndClock;
|
||||||
uint32_t nTotalLines, nIFDepth;
|
uint32_t nTotalLines;
|
||||||
|
|
||||||
#if defined(YYDEBUG) && YYDEBUG
|
#if defined(YYDEBUG) && YYDEBUG
|
||||||
extern int yydebug;
|
extern int yydebug;
|
||||||
@@ -488,7 +488,6 @@ int main(int argc, char *argv[])
|
|||||||
nStartClock = clock();
|
nStartClock = clock();
|
||||||
|
|
||||||
nTotalLines = 0;
|
nTotalLines = 0;
|
||||||
nIFDepth = 0;
|
|
||||||
sym_Init(now);
|
sym_Init(now);
|
||||||
sym_SetExportAll(exportall);
|
sym_SetExportAll(exportall);
|
||||||
|
|
||||||
@@ -502,10 +501,6 @@ int main(int argc, char *argv[])
|
|||||||
if (dependfile)
|
if (dependfile)
|
||||||
fclose(dependfile);
|
fclose(dependfile);
|
||||||
|
|
||||||
if (nIFDepth != 0)
|
|
||||||
errx(1, "Unterminated IF construct (%" PRIu32 " levels)!",
|
|
||||||
nIFDepth);
|
|
||||||
|
|
||||||
sect_CheckUnionClosed();
|
sect_CheckUnionClosed();
|
||||||
|
|
||||||
double timespent;
|
double timespent;
|
||||||
|
|||||||
@@ -563,7 +563,7 @@ conditional : if
|
|||||||
;
|
;
|
||||||
|
|
||||||
if : T_POP_IF const T_NEWLINE {
|
if : T_POP_IF const T_NEWLINE {
|
||||||
nIFDepth++;
|
fstk_IncIFDepth();
|
||||||
executeElseBlock = !$2;
|
executeElseBlock = !$2;
|
||||||
if (executeElseBlock)
|
if (executeElseBlock)
|
||||||
lexer_SetMode(LEXER_SKIP_TO_ELIF);
|
lexer_SetMode(LEXER_SKIP_TO_ELIF);
|
||||||
@@ -571,7 +571,7 @@ if : T_POP_IF const T_NEWLINE {
|
|||||||
;
|
;
|
||||||
|
|
||||||
elif : T_POP_ELIF const T_NEWLINE {
|
elif : T_POP_ELIF const T_NEWLINE {
|
||||||
if (nIFDepth <= 0)
|
if (fstk_GetIFDepth() == 0)
|
||||||
fatalerror("Found ELIF outside an IF construct\n");
|
fatalerror("Found ELIF outside an IF construct\n");
|
||||||
|
|
||||||
if (!executeElseBlock) {
|
if (!executeElseBlock) {
|
||||||
@@ -585,7 +585,7 @@ elif : T_POP_ELIF const T_NEWLINE {
|
|||||||
;
|
;
|
||||||
|
|
||||||
else : T_POP_ELSE T_NEWLINE {
|
else : T_POP_ELSE T_NEWLINE {
|
||||||
if (nIFDepth <= 0)
|
if (fstk_GetIFDepth() == 0)
|
||||||
fatalerror("Found ELSE outside an IF construct\n");
|
fatalerror("Found ELSE outside an IF construct\n");
|
||||||
|
|
||||||
if (!executeElseBlock)
|
if (!executeElseBlock)
|
||||||
@@ -594,10 +594,10 @@ else : T_POP_ELSE T_NEWLINE {
|
|||||||
;
|
;
|
||||||
|
|
||||||
endc : T_POP_ENDC T_NEWLINE {
|
endc : T_POP_ENDC T_NEWLINE {
|
||||||
if (nIFDepth <= 0)
|
if (fstk_GetIFDepth() == 0)
|
||||||
fatalerror("Found ENDC outside an IF construct\n");
|
fatalerror("Found ENDC outside an IF construct\n");
|
||||||
|
|
||||||
nIFDepth--;
|
fstk_DecIFDepth();
|
||||||
executeElseBlock = false;
|
executeElseBlock = false;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -20,3 +20,4 @@ rept 1
|
|||||||
break
|
break
|
||||||
no endc
|
no endc
|
||||||
endr
|
endr
|
||||||
|
println "done"
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ warning: break.asm(9): [-Wuser]
|
|||||||
done 5
|
done 5
|
||||||
warning: break.asm(17): [-Wuser]
|
warning: break.asm(17): [-Wuser]
|
||||||
OK
|
OK
|
||||||
error: Unterminated IF construct (1 levels)!
|
FATAL: break.asm(18) -> break.asm::REPT~1(23):
|
||||||
|
Ended block with 1 unterminated IF construct
|
||||||
|
|||||||
3
test/asm/unterminated-if-include.inc
Normal file
3
test/asm/unterminated-if-include.inc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
if 1
|
||||||
|
println "inside include"
|
||||||
|
; no endc
|
||||||
15
test/asm/unterminated-if.asm
Normal file
15
test/asm/unterminated-if.asm
Normal file
@@ -0,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"
|
||||||
2
test/asm/unterminated-if.err
Normal file
2
test/asm/unterminated-if.err
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
FATAL: unterminated-if.asm(13) -> unterminated-if-include.inc(4):
|
||||||
|
Ended block with 1 unterminated IF construct
|
||||||
2
test/asm/unterminated-if.out
Normal file
2
test/asm/unterminated-if.out
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
B
|
||||||
|
inside include
|
||||||
Reference in New Issue
Block a user