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

preproc: add a %selbits() function

Although one can implement this "manually" in terms of %sel(), this
function is *really* useful for making multi-mode tests and allows for
better error checking.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin
2025-10-07 09:17:59 -07:00
parent e4044cfc48
commit f1b6d3188c
3 changed files with 73 additions and 23 deletions

View File

@@ -7738,9 +7738,9 @@ stdmac_tok(const SMacro *s, Token **params, int nparams)
return reverse_tokens(tokenize(unquote_token_cstr(params[0])));
}
/* %cond() or %sel() */
/* %sel() */
static Token *
stdmac_cond_sel(const SMacro *s, Token **params, int nparams)
stdmac_sel(const SMacro *s, Token **params, int nparams)
{
int64_t which;
@@ -7749,29 +7749,57 @@ stdmac_cond_sel(const SMacro *s, Token **params, int nparams)
*/
which = get_tok_num(params[0], NULL);
if (s->expandpvt.u) {
/* Booleanize (for %cond): true -> 1, false -> 2 (else) */
which = which ? 1 : 2;
if (which >= nparams) {
/* false, and no else clause */
return NULL;
}
} else {
if (unlikely(which < 1)) {
nasm_warn(WARN_PP_SEL_RANGE,
"%s(%"PRId64") is not a valid selector", s->name, which);
return NULL;
} else if (unlikely(which >= nparams)) {
nasm_warn(WARN_PP_SEL_RANGE,
"%s(%"PRId64") exceeds the number of arguments",
s->name, which);
return NULL;
}
if (unlikely(which < 1)) {
nasm_warn(WARN_PP_SEL_RANGE,
"%s(%"PRId64") is not a valid selector", s->name, which);
return NULL;
} else if (unlikely(which >= nparams)) {
nasm_warn(WARN_PP_SEL_RANGE,
"%s(%"PRId64") exceeds the number of arguments",
s->name, which);
return NULL;
}
return new_Token(NULL, tok_smac_param(which), "", 0);
}
/* %cond() */
static Token *
stdmac_cond(const SMacro *s, Token **params, int nparams)
{
int64_t which;
(void)s;
(void)params;
/*
* params[0] will have been generated by make_tok_num.
*/
which = get_tok_num(params[0], NULL);
/* Booleanize: true -> 1, false -> 2 (else) */
which = which ? 1 : 2;
if (which >= nparams) {
/* false, and no else clause */
return NULL;
}
return new_Token(NULL, tok_smac_param(which), "", 0);
}
/* %selbits() */
static Token *
stdmac_selbits(const SMacro *s, Token **params, int nparams)
{
int which = ilog2_32(globl.bits)-4;
(void)s;
(void)params;
if (nparams <= which)
which = nparams - 1;
return new_Token(NULL, tok_smac_param(which), "", 0);
}
/* %count() function */
static Token *
stdmac_count(const SMacro *s, Token **params, int nparams)
@@ -8173,6 +8201,7 @@ static void pp_add_magic_simple(void)
{ "%null", false, 1, SPARM_GREEDY, stdmac_null },
{ "%pathsearch", false, 1, SPARM_PLAIN, stdmac_pathsearch },
{ "%realpath", false, 1, SPARM_PLAIN, stdmac_realpath },
{ "%selbits", false, 1, SPARM_PLAIN|SPARM_VARADIC, stdmac_selbits },
{ "%str", false, 1, SPARM_GREEDY|SPARM_STR, stdmac_join },
{ "%strcat", false, 1, SPARM_STR|SPARM_CONDQUOTE|SPARM_VARADIC, stdmac_strcat },
{ "%strlen", false, 1, SPARM_STR|SPARM_CONDQUOTE, stdmac_strlen },
@@ -8268,15 +8297,16 @@ static void pp_add_magic_miscfunc(void)
/* %sel() function */
nasm_zero(tmpl);
tmpl.nparam = 2;
tmpl.expand = stdmac_cond_sel;
tmpl.expand = stdmac_sel;
nasm_newn(tmpl.params, tmpl.nparam);
tmpl.params[0].flags = SPARM_EVAL;
tmpl.params[1].flags = SPARM_VARADIC;
define_magic("%sel", false, &tmpl);
/* %cond() function, a variation on %sel */
/* %cond() function */
nasm_zero(tmpl);
tmpl.nparam = 3;
tmpl.expandpvt.u = 1; /* Booleanize */
tmpl.expand = stdmac_cond;
nasm_newn(tmpl.params, tmpl.nparam);
tmpl.params[0].flags = SPARM_EVAL;
tmpl.params[1].flags = 0;

View File

@@ -31,6 +31,8 @@ It is the production version of NASM since 2025.
now be specified for the same group; the resulting group includes
all sections specified in all \c{GROUP} directives for the group.
\b A new \c{%selbits()} preprocessor function. See \k{f_selbits}.
\S{cl-3.00} Version 3.00

View File

@@ -1011,6 +1011,24 @@ expands to nothing.
The arguments not selected are never expanded.
\S{f_selbits} \i\c{%selbits()} Function
The \c{%selbits()} function returns its first, second, or third
argument depending on if the current mode is 16, 32 or 64 bits. If
less than three arguments are given, the last argument is considered
repeated. Like \c{%cond()}, this is a specialized version of the
\c{%sel()} function.
For example:
\c BITS 64
\c
\c %define breg %selbits(bx,ebx,rbx)
\c %define vreg %selbits(ax,eax)
\c
\c mov vreg,[breg] ; mov eax,[rbx]
\S{f_str} \i\c\{%str()} Function
The \c{%str()} function converts its argument, including any commas,