diff --git a/include/asm/asm.h b/include/asm/asm.h index 47d7d256..8a563a18 100644 --- 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 */ diff --git a/include/asm/fstack.h b/include/asm/fstack.h index c05e73e6..ace82372 100644 --- a/include/asm/fstack.h +++ b/include/asm/fstack.h @@ -53,6 +53,9 @@ extern size_t nMaxRecursionDepth; 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); diff --git a/src/asm/fstack.c b/src/asm/fstack.c index b3aabc2d..444e53a8 100644 --- a/src/asm/fstack.c +++ b/src/asm/fstack.c @@ -31,6 +31,7 @@ struct Context { 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,7 +48,22 @@ size_t nMaxRecursionDepth; 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; @@ -200,6 +216,10 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size) 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 @@ static void newContext(struct FileStackNode *fileInfo) 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 @@ static bool newReptContext(int32_t reptLineNo, char *body, size_t size) 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 @@ void fstk_Init(char const *mainPath, size_t maxRecursionDepth) context->parent = NULL; context->lexerState = state; + context->nIFDepth = 0; context->uniqueID = 0; macro_SetUniqueID(0); context->nbReptIters = 0; diff --git a/src/asm/lexer.c b/src/asm/lexer.c index a131c08f..d5e28b8b 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -1966,7 +1966,7 @@ static int skipIfBlock(bool toEndc) { 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 @@ static int skipIfBlock(bool toEndc) token = readIdentifier(c); switch (token) { case T_POP_IF: - nIFDepth++; + fstk_IncIFDepth(); break; case T_POP_ELIF: @@ -1999,10 +1999,10 @@ static int skipIfBlock(bool toEndc) 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 @@ static int yylex_SKIP_TO_ENDR(void) break; case T_POP_IF: - nIFDepth++; + fstk_IncIFDepth(); break; case T_POP_ENDC: - nIFDepth--; + fstk_DecIFDepth(); } } atLineStart = false; diff --git a/src/asm/main.c b/src/asm/main.c index 0626c0da..530f293b 100644 --- a/src/asm/main.c +++ b/src/asm/main.c @@ -46,7 +46,7 @@ const size_t cldefine_entrysize = 2 * sizeof(void *); char **cldefines; clock_t nStartClock, nEndClock; -uint32_t nTotalLines, nIFDepth; +uint32_t nTotalLines; #if defined(YYDEBUG) && YYDEBUG extern int yydebug; @@ -488,7 +488,6 @@ int main(int argc, char *argv[]) nStartClock = clock(); nTotalLines = 0; - nIFDepth = 0; sym_Init(now); sym_SetExportAll(exportall); @@ -502,10 +501,6 @@ int main(int argc, char *argv[]) if (dependfile) fclose(dependfile); - if (nIFDepth != 0) - errx(1, "Unterminated IF construct (%" PRIu32 " levels)!", - nIFDepth); - sect_CheckUnionClosed(); double timespent; diff --git a/src/asm/parser.y b/src/asm/parser.y index f25cdb6b..36cb8504 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -563,7 +563,7 @@ conditional : if ; if : T_POP_IF const T_NEWLINE { - nIFDepth++; + fstk_IncIFDepth(); executeElseBlock = !$2; if (executeElseBlock) lexer_SetMode(LEXER_SKIP_TO_ELIF); @@ -571,7 +571,7 @@ if : T_POP_IF 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"); if (!executeElseBlock) { @@ -585,7 +585,7 @@ elif : T_POP_ELIF const T_NEWLINE { ; 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 @@ else : T_POP_ELSE T_NEWLINE { ; 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; } ; diff --git a/test/asm/break.asm b/test/asm/break.asm index 5cf295d8..7182e9b3 100644 --- a/test/asm/break.asm +++ b/test/asm/break.asm @@ -20,3 +20,4 @@ rept 1 break no endc endr +println "done" diff --git a/test/asm/break.err b/test/asm/break.err index c4e97d4e..11acbf2c 100644 --- a/test/asm/break.err +++ b/test/asm/break.err @@ -2,4 +2,5 @@ warning: break.asm(9): [-Wuser] 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 diff --git a/test/asm/unterminated-if-include.inc b/test/asm/unterminated-if-include.inc new file mode 100644 index 00000000..4ccdf2c6 --- /dev/null +++ b/test/asm/unterminated-if-include.inc @@ -0,0 +1,3 @@ +if 1 + println "inside include" +; no endc diff --git a/test/asm/unterminated-if.asm b/test/asm/unterminated-if.asm new file mode 100644 index 00000000..ad105392 --- /dev/null +++ b/test/asm/unterminated-if.asm @@ -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" diff --git a/test/asm/unterminated-if.err b/test/asm/unterminated-if.err new file mode 100644 index 00000000..f45e268d --- /dev/null +++ b/test/asm/unterminated-if.err @@ -0,0 +1,2 @@ +FATAL: unterminated-if.asm(13) -> unterminated-if-include.inc(4): + Ended block with 1 unterminated IF construct diff --git a/test/asm/unterminated-if.out b/test/asm/unterminated-if.out new file mode 100644 index 00000000..35709401 --- /dev/null +++ b/test/asm/unterminated-if.out @@ -0,0 +1,2 @@ +B +inside include