mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Prohibit nested macros
After discussion (starting there: https://github.com/gbdev/rgbds/pull/594#issuecomment-706437458 ), it was decided that plain nested macros should not be allowed. Since #590 is fixed, EQUS can be used as a workaround; multiline strings (#589) will make that easier on the user when implemented. Fixes #588, supersedes and closes #594. Additionally, closes #388.
This commit is contained in:
@@ -2045,7 +2045,6 @@ finish:
|
|||||||
void lexer_CaptureMacroBody(char **capture, size_t *size)
|
void lexer_CaptureMacroBody(char **capture, size_t *size)
|
||||||
{
|
{
|
||||||
char *captureStart = startCapture();
|
char *captureStart = startCapture();
|
||||||
unsigned int level = 0;
|
|
||||||
int c = peek(0);
|
int c = peek(0);
|
||||||
|
|
||||||
/* If the file is `mmap`ed, we need not to unmap it to keep access to the macro */
|
/* If the file is `mmap`ed, we need not to unmap it to keep access to the macro */
|
||||||
@@ -2082,41 +2081,19 @@ void lexer_CaptureMacroBody(char **capture, size_t *size)
|
|||||||
} while (isWhitespace(c));
|
} while (isWhitespace(c));
|
||||||
/* Now, try to match either `REPT` or `ENDR` as a **whole** identifier */
|
/* Now, try to match either `REPT` or `ENDR` as a **whole** identifier */
|
||||||
if (startsIdentifier(c)) {
|
if (startsIdentifier(c)) {
|
||||||
switch (readIdentifier(c)) {
|
if (readIdentifier(c) == T_POP_ENDM) {
|
||||||
case T_ID:
|
/* Read (but don't capture) until EOL or EOF */
|
||||||
/* We have an initial label, look for a single colon */
|
lexerState->capturing = false;
|
||||||
do {
|
do {
|
||||||
c = nextChar();
|
c = peek(0);
|
||||||
} while (isWhitespace(c));
|
if (c == EOF || c == '\r' || c == '\n')
|
||||||
if (c != ':') /* If not a colon, give up */
|
break;
|
||||||
break;
|
shiftChars(1);
|
||||||
/* And finally, a `MACRO` token */
|
} while (c != EOF && c != '\r' && c != '\n');
|
||||||
do {
|
/* Handle Windows CRLF */
|
||||||
c = nextChar();
|
if (c == '\r' && peek(1) == '\n')
|
||||||
} while (isWhitespace(c));
|
shiftChars(1);
|
||||||
if (!startsIdentifier(c))
|
goto finish;
|
||||||
break;
|
|
||||||
if (readIdentifier(c) != T_POP_MACRO)
|
|
||||||
break;
|
|
||||||
level++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_POP_ENDM:
|
|
||||||
if (!level) {
|
|
||||||
/* Read (but don't capture) until EOL or EOF */
|
|
||||||
lexerState->capturing = false;
|
|
||||||
do {
|
|
||||||
c = peek(0);
|
|
||||||
if (c == EOF || c == '\r' || c == '\n')
|
|
||||||
break;
|
|
||||||
shiftChars(1);
|
|
||||||
} while (c != EOF && c != '\r' && c != '\n');
|
|
||||||
/* Handle Windows CRLF */
|
|
||||||
if (c == '\r' && peek(1) == '\n')
|
|
||||||
shiftChars(1);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
level--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lexerState->lineNo++;
|
lexerState->lineNo++;
|
||||||
|
|||||||
@@ -923,6 +923,26 @@ Note that a single colon
|
|||||||
.Ql \&:
|
.Ql \&:
|
||||||
following the macro's name is required.
|
following the macro's name is required.
|
||||||
Macros can't be exported or imported.
|
Macros can't be exported or imported.
|
||||||
|
.Pp
|
||||||
|
Plainly nesting macro definitions is not allowed, but this can be worked around using
|
||||||
|
.Ic EQUS .
|
||||||
|
This won't work:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
outer: MACRO
|
||||||
|
inner: MACRO
|
||||||
|
PRINTT "Hello!\[rs]n"
|
||||||
|
ENDM
|
||||||
|
ENDM
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
But this will:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
outer: MACRO
|
||||||
|
definition equs "inner: MACRO\[rs]nPRINTT \[rs]"Hello!\[rs]\[rs]n\[rs]"\[rs]nENDM"
|
||||||
|
definition
|
||||||
|
PURGE definition
|
||||||
|
ENDM
|
||||||
|
.Ed
|
||||||
.El
|
.El
|
||||||
.Ss Exporting and importing symbols
|
.Ss Exporting and importing symbols
|
||||||
Importing and exporting of symbols is a feature that is very useful when your project spans many source files and, for example, you need to jump to a routine defined in another file.
|
Importing and exporting of symbols is a feature that is very useful when your project spans many source files and, for example, you need to jump to a routine defined in another file.
|
||||||
|
|||||||
27
test/asm/nested-macrodef.asm
Normal file
27
test/asm/nested-macrodef.asm
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
outer_ok: MACRO
|
||||||
|
definition equs "inner_ok: MACRO\nPRINTT \"Hello!\\n\"\nENDM"
|
||||||
|
definition
|
||||||
|
PURGE definition
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
outer_ok
|
||||||
|
inner_ok
|
||||||
|
|
||||||
|
|
||||||
|
outer_arg: MACRO
|
||||||
|
definition equs "inner_arg: MACRO\nPRINTT \"outer: \1\\ninner: \\1\\n\"\nENDM"
|
||||||
|
definition
|
||||||
|
PURGE definition
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
outer_arg outside
|
||||||
|
inner_arg inside
|
||||||
|
|
||||||
|
|
||||||
|
outer: MACRO
|
||||||
|
WARN "Nested macros shouldn't work, whose argument would be \\1?"
|
||||||
|
inner: MACRO
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
outer
|
||||||
|
inner
|
||||||
5
test/asm/nested-macrodef.err
Normal file
5
test/asm/nested-macrodef.err
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
warning: nested-macrodef.asm(26) -> nested-macrodef.asm::outer(22): [-Wuser]
|
||||||
|
Nested macros shouldn't work, whose argument would be \1?
|
||||||
|
ERROR: nested-macrodef.asm(26) -> nested-macrodef.asm::outer(25):
|
||||||
|
Unterminated macro definition
|
||||||
|
error: Assembly aborted (1 errors)!
|
||||||
3
test/asm/nested-macrodef.out
Normal file
3
test/asm/nested-macrodef.out
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Hello!
|
||||||
|
outer: outside
|
||||||
|
inner: inside
|
||||||
Reference in New Issue
Block a user