[nasm:nasm-2.16.xx] preproc, %map(): require second colon, update documentation

nasm-bot for H. Peter Anvin hpa at zytor.com
Mon Oct 16 13:44:05 PDT 2023


Commit-ID:  9f83c383e42d65c03c463b55d2ab4faba2bfdeff
Gitweb:     http://repo.or.cz/w/nasm.git?a=commitdiff;h=9f83c383e42d65c03c463b55d2ab4faba2bfdeff
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Mon, 16 Oct 2023 13:42:16 -0700
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Mon, 16 Oct 2023 13:42:16 -0700

preproc, %map(): require second colon, update documentation

Require the second colon before the grouped parameter count; otherwise
the syntax is ambiguous since an expression can start with (.

Update/complete the documentation and the examples.

Signed-off-by: H. Peter Anvin <hpa at zytor.com>


---
 asm/preproc.c   | 58 ++++++++++++++++++++++++++++-----------------------------
 doc/nasmdoc.src | 58 +++++++++++++++++++++++++++++++++++++++++++++++----------
 test/map.asm    | 14 +++++++++++---
 3 files changed, 88 insertions(+), 42 deletions(-)

diff --git a/asm/preproc.c b/asm/preproc.c
index e8070ea2..cf495bcd 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -7455,41 +7455,41 @@ stdmac_map(const SMacro *s, Token **params, int nparam)
 
     fixargs = NULL;
     fixparams = 0;
+    mparams = 1;
     t = skip_white(t->next);
     if (tok_is(t, ':')) {
         fixargs = t->next;
         fixparams = count_smacro_args(fixargs, &t);
-        if (fixparams)
-            t = skip_white(t->next);
-    }
-    mparams = 1;
-    if (tok_is(t, ':')) {
-        struct ppscan pps;
-        struct tokenval tokval;
-        expr *evalresult;
-        Token *ep;
+        t = skip_white(t->next);
 
-        pps.tptr = ep = zap_white(expand_smacro_noreset(t->next));
-        t->next = NULL;
-        pps.ntokens = -1;
-        tokval.t_type = TOKEN_INVALID;
-        evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
-        free_tlist(ep);
+        if (tok_is(t, ':')) {
+            struct ppscan pps;
+            struct tokenval tokval;
+            expr *evalresult;
+            Token *ep;
+
+            pps.tptr = ep = zap_white(expand_smacro_noreset(t->next));
+            t->next = NULL;
+            pps.ntokens = -1;
+            tokval.t_type = TOKEN_INVALID;
+            evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
+            free_tlist(ep);
 
-        if (!evalresult || tokval.t_type) {
-            nasm_nonfatal("invalid expression in parameter count for `%s' in function %s",
-                          mname, s->name);
-            return NULL;
-        } else if (!is_simple(evalresult)) {
-            nasm_nonfatal("non-constant expression in parameter count for `%s' in function %s",
-                          mname, s->name);
-            return NULL;
-        }
-        mparams = reloc_value(evalresult);
-        if (mparams < 1) {
-            nasm_nonfatal("invalid parameter count for `%s' in function %s",
-                          mname, s->name);
-            return NULL;
+            if (!evalresult || tokval.t_type) {
+                nasm_nonfatal("invalid expression in parameter count for `%s' in function %s",
+                              mname, s->name);
+                return NULL;
+            } else if (!is_simple(evalresult)) {
+                nasm_nonfatal("non-constant expression in parameter count for `%s' in function %s",
+                              mname, s->name);
+                return NULL;
+            }
+            mparams = reloc_value(evalresult);
+            if (mparams < 1) {
+                nasm_nonfatal("invalid parameter count for `%s' in function %s",
+                              mname, s->name);
+                return NULL;
+            }
         }
     }
 
diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src
index 42bee347..3aabd6c8 100644
--- a/doc/nasmdoc.src
+++ b/doc/nasmdoc.src
@@ -2901,7 +2901,7 @@ the macro. Note that just as for single-line macros, \c{%count()}
 treats an empty argument list as a single empty argument.
 
 \c %xdefine empty %count()        ; %define empty 1
-\c %xdefine one   %count(1) 	  ; %define one 1
+\c %xdefine one   %count(1)	  ; %define one 1
 \c %xdefine two   %count(5,q)	  ; %define two 2
 \c %define  list  a,b,46
 \c %xdefine lc1   %count(list)	  ; %define lc 1 (just one argument)
@@ -2959,22 +2959,60 @@ argument to the conditional using \c{\{\}}:
 \S{f_map} \i\c{%map()} Function
 
 The \c{%map()} function takes as its first parameter the name of a
-single-line macro, optionally followed by a colon and an integer
-expression (default 1), specifying the number of parameter to the
-macro, \e{n}.
+single-line macro, followed by up to two optional colon-separated
+subparameters:
 
-The following parameters are then passed as parameters to the given
-macro for expansion, in groups of \e{n}, and the results turned into a
-comma-separated list.
+\b The first subparameter, if present, should be a list of macro
+parameters enclosed in parentheses. Note that \c{()} represents a
+one-argument list containing an empty parameter; omit the parentheses
+to specify no parameters.
+
+\b The second subparameter, if present, represent the number of
+group size for additional parameters to the macro (default 1).
+
+Further parameters, if any, are then passed as additional parameters to the
+given macro for expansion, in sets given by the specified group size,
+and the results turned into a comma-separated list. If no additional
+parameters are given, \c{%map()} expands to nothing.
 
 For example:
 
-\c %define alpha(&x,y) y dup (x)
-\c       db %map(alpha:2,foo,bar,baz,quux)
+\c %define alpha(&x)     x
+\c %define alpha(&x,y)	 y dup (x)
+\c %define alpha(s,&x,y) y dup (x,s)
+\c ; 0 fixed + 1 grouped parameters per call, calls alpha(&x)
+\c       db %map(alpha,foo,bar,baz,quux)
+\c ; 0 fixed + 2 grouped parameters per call, calls alpha(&x,y)
+\c	 db %map(alpha::2,foo,bar,baz,quux)
+\c ; 1 fixed + 2 grouped parameters per call, calls alpha(s,&x,y)
+\c       db %map(alpha:("!"):2,foo,bar,baz,quux)
+
+... expands to:
+
+\c       db 'foo','bar','baz','quux'
+\c       db bar dup ('foo'),quux dup ('baz')
+\c       db bar dup ('foo',"!"),quux dup ('baz',"!")
+
+As a more complex example, a macro that joins quoted strings together
+with a user-specified delimiter string:
+
+\c %define join(sep)        ''      ; handle the case of zero strings
+\c %define _join(sep,str)   sep,str ; helper macro
+\c %define join(sep,s1,sn+) %strcat(s1, %map(_join:(sep) %, sn))
+\c
+\c       db join(':')
+\c       db join(':','a')
+\c       db join(':','a','b')
+\c       db join(':','a','b','c')
+\c       db join(':','a','b','c','d')
 
 ... expands to:
 
-\c       db bar dup ("foo"),quux dup ("baz")
+\c       db ''
+\c       db 'a'
+\c       db 'a:b'
+\c       db 'a:b:c'
+\c       db 'a:b:c:d'
 
 
 \S{f_num} \i\c{%num()} Function
diff --git a/test/map.asm b/test/map.asm
index 48f4739d..2538b7d5 100644
--- a/test/map.asm
+++ b/test/map.asm
@@ -1,7 +1,15 @@
 %define foo(x) (x+1)
 %define bar(=x,y) (x*y)
 %define baz(x+) %(x)
-
 	dw %map(foo,1,2,3,4)
-	dw %map(bar:2,1+2,3+4,5+6,7+8)
-	dw %map(baz:2,1+2,3+4,5+6,7+8)
+	dw %map(bar::2,1+2,3+4,5+6,7+8)
+	dw %map(baz::2,1+2,3+4,5+6,7+8)
+
+bar	equ 8
+quux	equ 4
+%define alpha(&x)	x
+%define alpha(&x,y)	y dup (x)
+%define alpha(s,&x,y)	y dup (x,s)
+	db %map(alpha,foo,bar,baz,quux)
+	db %map(alpha::2,foo,bar,baz,quux)
+	db %map(alpha:("!"):2,foo,bar,baz,quux)


More information about the Nasm-commits mailing list