ref: 27f38770d4860305ef90922743f399eedf52de63
parent: db1f77f90b9441671df6382c13a9c5ef54663967
author: Rangi <remy.oukaour+rangi42@gmail.com>
date: Tue Apr 20 15:50:46 EDT 2021
Parentheses in macro args prevent commas from starting new arguments This is similar to C's behavior, and convenient for passing function calls as single values, like `MUL(3.0, 4.0)` or `STRSUB("str", 2, 1)`. Fixes #704
--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -2056,6 +2056,7 @@
lexer_GetLineNo(), lexer_GetColNo());
/* This is essentially a modified `appendStringLiteral` */
+ unsigned int parenDepth = 0;
size_t i = 0;
int c;
@@ -2076,8 +2077,7 @@
discardComment();
c = peek();
/* fallthrough */
- case ',': /* End of macro arg */
- case '\r':
+ case '\r': /* End of line */
case '\n':
case EOF:
goto finish;
@@ -2092,12 +2092,29 @@
append_yylval_string(c); /* Append the slash */
break;
+ case ',': /* End of macro arg */
+ if (parenDepth == 0)
+ goto finish;
+ goto append;
+
+ case '(': /* Open parentheses inside macro args */
+ if (parenDepth < UINT_MAX)
+ parenDepth++;
+ goto append;
+
+ case ')': /* Close parentheses inside macro args */
+ if (parenDepth > 0)
+ parenDepth--;
+ goto append;
+
case '\\': /* Character escape */
shiftChar();
c = peek();
switch (c) {
- case ',': /* Escape `\,` only inside a macro arg */
+ case ',': /* Escapes only valid inside a macro arg */
+ case '(':
+ case ')':
case '\\': /* Escapes shared with string literals */
case '"':
case '{':
@@ -2137,6 +2154,7 @@
/* fallthrough */
default: /* Regular characters will just get copied */
+append:
append_yylval_string(c);
shiftChar();
break;
--- a/src/asm/rgbasm.5
+++ b/src/asm/rgbasm.5
@@ -1184,7 +1184,11 @@
.Pp
Macro arguments support all the escape sequences of strings, as well as
.Ql \[rs],
-to escape commas, since those otherwise separate arguments.
+to escape commas, as well as
+.Ql \[rs](
+and
+.Ql \[rs])
+to escape parentheses, since those otherwise separate and enclose arguments, respectively.
.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.
.Pp
@@ -1553,18 +1557,27 @@
Line continuations work as usual inside macros or lists of macro arguments.
However, some characters need to be escaped, as in the following example:
.Bd -literal -offset indent
-MACRO PrintMacro
+MACRO PrintMacro1
+ PRINTLN STRCAT(\[rs]1)
+ENDM
+ PrintMacro1 "Hello "\[rs], \[rs]
+ "world"
+MACRO PrintMacro2
PRINT \[rs]1
ENDM
-
- PrintMacro STRCAT("Hello "\[rs], \[rs]
- "world\[rs]n")
+ PrintMacro2 STRCAT("Hello ", \[rs]
+ "world\[rs]n")
.Ed
.Pp
-The comma needs to be escaped to avoid it being treated as separating the macro's arguments.
+The comma in
+.Ql PrintMacro1
+needs to be escaped to prevent it from starting another macro argument.
+The comma in
+.Ql PrintMacro2
+does not need escaping because it is inside parentheses, similar to macro arguments in C.
The backslash in
.Ql \[rs]n
-does not need to be escaped because string literals also work as usual inside macro arguments.
+also does not need escaping because string literals work as usual inside macro arguments.
.Pp
Since there are only nine digits, you can only access the first nine macro arguments like this.
To use the rest, you need to put the multi-digit argument number in angle brackets, like
--- /dev/null
+++ b/test/asm/macro-arg-parentheses.asm
@@ -1,0 +1,19 @@
+MACRO printargs
+ REPT _NARG
+ PRINTLN \1
+ SHIFT
+ ENDR
+ENDM
+
+ printargs mul(3.0, 4.0)
+
+MACRO printlit
+ REPT _NARG
+ PRINTLN "\1"
+ SHIFT
+ ENDR
+ENDM
+
+ printlit a(b,c\,d), ((e,f),g), ))h, i\,j,
+ printlit \(k, l), (m:\)n,o(p)q), (r,s)t
+ printlit "))u,v(", ("w,x","y,z"),
--- /dev/null
+++ b/test/asm/macro-arg-parentheses.out
@@ -1,0 +1,11 @@
+$C0000
+a(b,c,d)
+((e,f),g)
+))h
+i,j
+(k
+l)
+(m:)n,o(p)q)
+(r,s)t
+"))u,v("
+("w,x","y,z")
--- a/test/asm/raw-macro-args.asm
+++ b/test/asm/raw-macro-args.asm
@@ -22,7 +22,7 @@
printargs "literal \"\\\"", \ ; comment 2
"""multi-"line"
""string"" arg"""
- printargs MUL(2.0\, 3.0)
+ printargs MUL(2.0, 3.0)
printargs "unclosed
printlit NUM
@@ -32,7 +32,7 @@
printlit "literal \"\\\"", \ ; comment 4
"""multi-"line"
""string"" arg"""
- printlit MUL(2.0\, 3.0)
+ printlit MUL(2.0, 3.0)
printlit this\n is\, \{not\} a\\n syntax\" error
printlit "unclosed
printlit """EOF
\ No newline at end of file