0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-07-24 10:25:42 -04:00

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@zytor.com>
This commit is contained in:
H. Peter Anvin 2023-10-16 13:42:16 -07:00
parent cb96db9b70
commit 9f83c383e4
3 changed files with 88 additions and 42 deletions

View File

@ -7455,41 +7455,41 @@ stdmac_map(const SMacro *s, Token **params, int nparam)
fixargs = NULL; fixargs = NULL;
fixparams = 0; fixparams = 0;
mparams = 1;
t = skip_white(t->next); t = skip_white(t->next);
if (tok_is(t, ':')) { if (tok_is(t, ':')) {
fixargs = t->next; fixargs = t->next;
fixparams = count_smacro_args(fixargs, &t); fixparams = count_smacro_args(fixargs, &t);
if (fixparams) t = skip_white(t->next);
t = skip_white(t->next);
}
mparams = 1;
if (tok_is(t, ':')) {
struct ppscan pps;
struct tokenval tokval;
expr *evalresult;
Token *ep;
pps.tptr = ep = zap_white(expand_smacro_noreset(t->next)); if (tok_is(t, ':')) {
t->next = NULL; struct ppscan pps;
pps.ntokens = -1; struct tokenval tokval;
tokval.t_type = TOKEN_INVALID; expr *evalresult;
evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL); Token *ep;
free_tlist(ep);
if (!evalresult || tokval.t_type) { pps.tptr = ep = zap_white(expand_smacro_noreset(t->next));
nasm_nonfatal("invalid expression in parameter count for `%s' in function %s", t->next = NULL;
mname, s->name); pps.ntokens = -1;
return NULL; tokval.t_type = TOKEN_INVALID;
} else if (!is_simple(evalresult)) { evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
nasm_nonfatal("non-constant expression in parameter count for `%s' in function %s", free_tlist(ep);
mname, s->name);
return NULL; if (!evalresult || tokval.t_type) {
} nasm_nonfatal("invalid expression in parameter count for `%s' in function %s",
mparams = reloc_value(evalresult); mname, s->name);
if (mparams < 1) { return NULL;
nasm_nonfatal("invalid parameter count for `%s' in function %s", } else if (!is_simple(evalresult)) {
mname, s->name); nasm_nonfatal("non-constant expression in parameter count for `%s' in function %s",
return NULL; 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;
}
} }
} }

View File

@ -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. treats an empty argument list as a single empty argument.
\c %xdefine empty %count() ; %define empty 1 \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 %xdefine two %count(5,q) ; %define two 2
\c %define list a,b,46 \c %define list a,b,46
\c %xdefine lc1 %count(list) ; %define lc 1 (just one argument) \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 \S{f_map} \i\c{%map()} Function
The \c{%map()} function takes as its first parameter the name of a The \c{%map()} function takes as its first parameter the name of a
single-line macro, optionally followed by a colon and an integer single-line macro, followed by up to two optional colon-separated
expression (default 1), specifying the number of parameter to the subparameters:
macro, \e{n}.
The following parameters are then passed as parameters to the given \b The first subparameter, if present, should be a list of macro
macro for expansion, in groups of \e{n}, and the results turned into a parameters enclosed in parentheses. Note that \c{()} represents a
comma-separated list. 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: For example:
\c %define alpha(&x,y) y dup (x) \c %define alpha(&x) x
\c db %map(alpha:2,foo,bar,baz,quux) \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: ... expands to:
\c db bar dup ("foo"),quux dup ("baz") \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 ''
\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 \S{f_num} \i\c{%num()} Function

View File

@ -1,7 +1,15 @@
%define foo(x) (x+1) %define foo(x) (x+1)
%define bar(=x,y) (x*y) %define bar(=x,y) (x*y)
%define baz(x+) %(x) %define baz(x+) %(x)
dw %map(foo,1,2,3,4) dw %map(foo,1,2,3,4)
dw %map(bar: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) 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)