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