mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-04-24 19:00:23 +08:00
preproc: implement the %cond() and %sel() functions; fix memory leak
Implement the %cond() and %sel() functions that expand to a specific one of the arguments. %cond(x,y,z) is basically a shorthand for %sel(2-!(x),y,z) used when x is a boolean condition. Fix a memory leak in %strcat and %strlen. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
parent
8de66e9a50
commit
d9b36e3c9c
126
asm/preproc.c
126
asm/preproc.c
@ -644,6 +644,7 @@ static Token *expand_smacro(Token * tline);
|
||||
static Token *expand_id(Token * tline);
|
||||
static Context *get_ctx(const char *name, const char **namep);
|
||||
static Token *make_tok_num(Token *next, int64_t val);
|
||||
static int64_t get_tok_num(const Token *t, bool *err);
|
||||
static Token *make_tok_qstr(Token *next, const char *str);
|
||||
static Token *make_tok_qstr_len(Token *next, const char *str, size_t len);
|
||||
static Token *make_tok_char(Token *next, char op);
|
||||
@ -3584,6 +3585,7 @@ static Token *pp_strcat(Token *tline, const char *dname)
|
||||
|
||||
size_t len;
|
||||
Token *t;
|
||||
Token *res = NULL;
|
||||
char *q, *qbuf;
|
||||
|
||||
len = 0;
|
||||
@ -3601,8 +3603,7 @@ static Token *pp_strcat(Token *tline, const char *dname)
|
||||
default:
|
||||
nasm_nonfatal("non-string passed to `%s': %s", dname,
|
||||
tok_text(t));
|
||||
free_tlist(tline);
|
||||
return NULL;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3613,9 +3614,11 @@ static Token *pp_strcat(Token *tline, const char *dname)
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
return make_tok_qstr_len(NULL, qbuf, len);
|
||||
res = make_tok_qstr_len(NULL, qbuf, len);
|
||||
nasm_free(qbuf);
|
||||
return t;
|
||||
err:
|
||||
free_tlist(tline);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3629,6 +3632,7 @@ static Token *pp_substr(Token *tline, const char *dname)
|
||||
size_t len;
|
||||
struct ppscan pps;
|
||||
Token *t;
|
||||
Token *res = NULL;
|
||||
expr *evalresult;
|
||||
struct tokenval tokval;
|
||||
|
||||
@ -3636,7 +3640,7 @@ static Token *pp_substr(Token *tline, const char *dname)
|
||||
|
||||
if (!tok_is(t, TOKEN_STR)) {
|
||||
nasm_nonfatal("`%s' requires a string as parameter", dname);
|
||||
return NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
pps.tptr = skip_white(t->next);
|
||||
@ -3644,17 +3648,17 @@ static Token *pp_substr(Token *tline, const char *dname)
|
||||
pps.tptr = skip_white(pps.tptr->next);
|
||||
if (!pps.tptr) {
|
||||
nasm_nonfatal("`%s' requires a starting index", dname);
|
||||
return NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
pps.ntokens = -1;
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
|
||||
if (!evalresult) {
|
||||
return NULL;
|
||||
goto err;
|
||||
} else if (!is_simple(evalresult)) {
|
||||
nasm_nonfatal("non-constant value given to `%s'", dname);
|
||||
return NULL;
|
||||
goto err;
|
||||
}
|
||||
start = evalresult->value - 1;
|
||||
|
||||
@ -3665,10 +3669,10 @@ static Token *pp_substr(Token *tline, const char *dname)
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
|
||||
if (!evalresult) {
|
||||
return NULL;
|
||||
goto err;
|
||||
} else if (!is_simple(evalresult)) {
|
||||
nasm_nonfatal("non-constant value given to `%s'", dname);
|
||||
return NULL;
|
||||
goto err;
|
||||
}
|
||||
count = evalresult->value;
|
||||
}
|
||||
@ -3687,7 +3691,10 @@ static Token *pp_substr(Token *tline, const char *dname)
|
||||
start = -1, count = 0; /* empty string */
|
||||
|
||||
txt = (start < 0) ? "" : tok_text(t) + start;
|
||||
return make_tok_qstr_len(NULL, txt, count);
|
||||
res = make_tok_qstr_len(NULL, txt, count);
|
||||
err:
|
||||
free_tlist(tline);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -4850,7 +4857,6 @@ issue_error:
|
||||
*/
|
||||
if (macro_start)
|
||||
define_smacro(mname, casesense, macro_start, NULL);
|
||||
free_tlist(tline);
|
||||
break;
|
||||
|
||||
case PP_SUBSTR:
|
||||
@ -4869,7 +4875,6 @@ issue_error:
|
||||
*/
|
||||
if (macro_start)
|
||||
define_smacro(mname, casesense, macro_start, NULL);
|
||||
free_tlist(tline);
|
||||
break;
|
||||
|
||||
case PP_ASSIGN:
|
||||
@ -6909,22 +6914,34 @@ stdmac_join(const SMacro *s, Token **params, int nparams)
|
||||
static Token *
|
||||
stdmac_strcat(const SMacro *s, Token **params, int nparams)
|
||||
{
|
||||
nasm_assert(nparams == 1);
|
||||
return pp_strcat(expand_smacro_noreset(params[0]), s->name);
|
||||
Token *tline;
|
||||
(void)nparams;
|
||||
|
||||
tline = params[0];
|
||||
params[0] = NULL; /* Don't free this later */
|
||||
return pp_strcat(expand_smacro_noreset(tline), s->name);
|
||||
}
|
||||
|
||||
/* %substr() function */
|
||||
static Token *
|
||||
stdmac_substr(const SMacro *s, Token **params, int nparams)
|
||||
{
|
||||
nasm_assert(nparams == 1);
|
||||
return pp_substr(expand_smacro_noreset(params[0]), s->name);
|
||||
Token *tline;
|
||||
(void)nparams;
|
||||
|
||||
tline = params[0];
|
||||
params[0] = NULL; /* Don't free this later */
|
||||
return pp_substr(expand_smacro_noreset(tline), s->name);
|
||||
}
|
||||
|
||||
/* Expand a the argument and enforce it being a single quoted string */
|
||||
static Token *expand_to_string(Token *tlist, const char *dname)
|
||||
static Token *expand_to_string(Token **tp, const char *dname)
|
||||
{
|
||||
Token *t = zap_white(expand_smacro_noreset(tlist));
|
||||
Token *tlist, *t;
|
||||
|
||||
tlist = *tp;
|
||||
*tp = NULL; /* Don't free this later */
|
||||
t = zap_white(expand_smacro_noreset(tlist));
|
||||
|
||||
if (!tok_is(t, TOKEN_STR)) {
|
||||
nasm_nonfatal("`%s' requires string as parameter", dname);
|
||||
@ -6948,7 +6965,7 @@ stdmac_strlen(const SMacro *s, Token **params, int nparams)
|
||||
|
||||
(void)nparams;
|
||||
|
||||
t = expand_to_string(params[0], s->name);
|
||||
t = expand_to_string(¶ms[0], s->name);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
@ -6964,13 +6981,38 @@ stdmac_tok(const SMacro *s, Token **params, int nparams)
|
||||
|
||||
(void)nparams;
|
||||
|
||||
t = expand_to_string(params[0], s->name);
|
||||
t = expand_to_string(¶ms[0], s->name);
|
||||
if (!t)
|
||||
return NULL;
|
||||
|
||||
return reverse_tokens(tokenize(unquote_token_cstr(t)));
|
||||
}
|
||||
|
||||
/* %cond() or %sel() */
|
||||
static Token *
|
||||
stdmac_cond_sel(const SMacro *s, Token **params, int nparams)
|
||||
{
|
||||
int64_t which;
|
||||
bool err;
|
||||
|
||||
/*
|
||||
* params[0] will have been generated by make_tok_num.
|
||||
*/
|
||||
which = get_tok_num(params[0], &err);
|
||||
if (err)
|
||||
return NULL; /* Nothing to expand */
|
||||
|
||||
if (s->expandpvt.u) {
|
||||
/* Booleanize (for %cond): true -> 1, false -> 2 (else) */
|
||||
which = which ? 1 : 2;
|
||||
}
|
||||
|
||||
if (which < 1 || which >= nparams)
|
||||
return NULL;
|
||||
|
||||
return new_Token(NULL, tok_smac_param(which), "", 0);
|
||||
}
|
||||
|
||||
/* Add magic standard macros */
|
||||
struct magic_macros {
|
||||
const char *name;
|
||||
@ -7027,9 +7069,26 @@ static void pp_add_magic_stdmac(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* %sel() function */
|
||||
tmpl.nparam = 2;
|
||||
tmpl.recursive = true;
|
||||
tmpl.expand = stdmac_cond_sel;
|
||||
nasm_newn(tmpl.params, 2);
|
||||
tmpl.params[0].flags = SPARM_EVAL;
|
||||
tmpl.params[1].flags = SPARM_VARADIC;
|
||||
define_smacro("%sel", false, NULL, &tmpl);
|
||||
|
||||
/* %cond() function, a variation on %sel */
|
||||
tmpl.expandpvt.u = 1; /* Booleanize */
|
||||
for (tmpl.nparam = 2; tmpl.nparam <= 3; tmpl.nparam++) {
|
||||
nasm_newn(tmpl.params, tmpl.nparam);
|
||||
tmpl.params[0].flags = SPARM_EVAL;
|
||||
define_smacro("%cond", false, NULL, &tmpl);
|
||||
}
|
||||
|
||||
/* %is...() macro functions */
|
||||
nasm_zero(tmpl);
|
||||
tmpl.nparam = 1;
|
||||
tmpl.varadic = true;
|
||||
tmpl.expand = stdmac_is;
|
||||
tmpl.recursive = true;
|
||||
name_buf[0] = '%';
|
||||
@ -7644,6 +7703,29 @@ static Token *make_tok_num(Token *next, int64_t val)
|
||||
return next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the inverse of make_tok_num(). This only needs to be able
|
||||
* to parse the output of make_tok_num().
|
||||
*/
|
||||
static int64_t get_tok_num(const Token *t, bool *err)
|
||||
{
|
||||
bool minus = false;
|
||||
int64_t v;
|
||||
|
||||
if (tok_is(t, '-')) {
|
||||
minus = true;
|
||||
t = t->next;
|
||||
}
|
||||
if (!tok_is(t, TOKEN_NUM)) {
|
||||
if (err)
|
||||
*err = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
v = readnum(tok_text(t), err);
|
||||
return minus ? -v : v;
|
||||
}
|
||||
|
||||
/* Create a quoted string token */
|
||||
static Token *make_tok_qstr_len(Token *next, const char *str, size_t len)
|
||||
{
|
||||
|
@ -2853,6 +2853,20 @@ arguments, and can be used in any context where single-line macro
|
||||
expansion would be performed. Preprocessor functions were introduced
|
||||
in NASM 2.16.
|
||||
|
||||
\S{f_cond} \i\c{%cond()} Function
|
||||
|
||||
The \c{%cond()} function evaluates its first argument as an
|
||||
expression, then expands to its second argument if true (nonzero), and
|
||||
the third, if present, if false (zero). This is in effect a specialized
|
||||
version of the \i\c{%sel()} function; \c{%cond(x,y,z)} is equivalent
|
||||
to \c{%sel(2-!(x),y,z)}.
|
||||
|
||||
\c %define a 1
|
||||
\c %xdefine astr %cond(a,"true","false") ; %define astr "true"
|
||||
|
||||
The argument not selected is never expanded.
|
||||
|
||||
|
||||
\S{f_eval} \i\c{%eval()} Function
|
||||
|
||||
The \c{%eval()} function evaluates its argument as a numeric
|
||||
@ -2894,6 +2908,18 @@ argument to the conditional using \c{\{\}}:
|
||||
\c %endif
|
||||
|
||||
|
||||
\S{f_sel} \i\c{%sel()} Function
|
||||
|
||||
The \c{%sel()} function evaluates its first argument as an
|
||||
expression, then expands to its second argument if 1, the third
|
||||
argument if 2, and so on. If the value is less than 1 or larger than
|
||||
the number of arguments minus one, then the \c{%sel()} function
|
||||
expands to nothing.
|
||||
|
||||
\c %define b 2
|
||||
\c %xdefine bstr %sel(b,"one","two","three") ; %define bstr "two"
|
||||
|
||||
|
||||
\S{f_str} \i\c\{%str()} Function
|
||||
|
||||
The \c{%str()} function converts its argument, including any commas,
|
||||
|
Loading…
x
Reference in New Issue
Block a user