Skip to content

Commit d9b36e3

Browse files
author
H. Peter Anvin
committed
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 <[email protected]>
1 parent 8de66e9 commit d9b36e3

File tree

2 files changed

+130
-22
lines changed

2 files changed

+130
-22
lines changed

asm/preproc.c

Lines changed: 104 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ static Token *expand_smacro(Token * tline);
644644
static Token *expand_id(Token * tline);
645645
static Context *get_ctx(const char *name, const char **namep);
646646
static Token *make_tok_num(Token *next, int64_t val);
647+
static int64_t get_tok_num(const Token *t, bool *err);
647648
static Token *make_tok_qstr(Token *next, const char *str);
648649
static Token *make_tok_qstr_len(Token *next, const char *str, size_t len);
649650
static Token *make_tok_char(Token *next, char op);
@@ -3584,6 +3585,7 @@ static Token *pp_strcat(Token *tline, const char *dname)
35843585

35853586
size_t len;
35863587
Token *t;
3588+
Token *res = NULL;
35873589
char *q, *qbuf;
35883590

35893591
len = 0;
@@ -3601,8 +3603,7 @@ static Token *pp_strcat(Token *tline, const char *dname)
36013603
default:
36023604
nasm_nonfatal("non-string passed to `%s': %s", dname,
36033605
tok_text(t));
3604-
free_tlist(tline);
3605-
return NULL;
3606+
goto err;
36063607
}
36073608
}
36083609

@@ -3613,9 +3614,11 @@ static Token *pp_strcat(Token *tline, const char *dname)
36133614
}
36143615
*q = '\0';
36153616

3616-
return make_tok_qstr_len(NULL, qbuf, len);
3617+
res = make_tok_qstr_len(NULL, qbuf, len);
36173618
nasm_free(qbuf);
3618-
return t;
3619+
err:
3620+
free_tlist(tline);
3621+
return res;
36193622
}
36203623

36213624
/*
@@ -3629,32 +3632,33 @@ static Token *pp_substr(Token *tline, const char *dname)
36293632
size_t len;
36303633
struct ppscan pps;
36313634
Token *t;
3635+
Token *res = NULL;
36323636
expr *evalresult;
36333637
struct tokenval tokval;
36343638

36353639
t = skip_white(tline);
36363640

36373641
if (!tok_is(t, TOKEN_STR)) {
36383642
nasm_nonfatal("`%s' requires a string as parameter", dname);
3639-
return NULL;
3643+
goto err;
36403644
}
36413645

36423646
pps.tptr = skip_white(t->next);
36433647
if (tok_is(pps.tptr, TOKEN_COMMA))
36443648
pps.tptr = skip_white(pps.tptr->next);
36453649
if (!pps.tptr) {
36463650
nasm_nonfatal("`%s' requires a starting index", dname);
3647-
return NULL;
3651+
goto err;
36483652
}
36493653

36503654
pps.ntokens = -1;
36513655
tokval.t_type = TOKEN_INVALID;
36523656
evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
36533657
if (!evalresult) {
3654-
return NULL;
3658+
goto err;
36553659
} else if (!is_simple(evalresult)) {
36563660
nasm_nonfatal("non-constant value given to `%s'", dname);
3657-
return NULL;
3661+
goto err;
36583662
}
36593663
start = evalresult->value - 1;
36603664

@@ -3665,10 +3669,10 @@ static Token *pp_substr(Token *tline, const char *dname)
36653669
tokval.t_type = TOKEN_INVALID;
36663670
evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
36673671
if (!evalresult) {
3668-
return NULL;
3672+
goto err;
36693673
} else if (!is_simple(evalresult)) {
36703674
nasm_nonfatal("non-constant value given to `%s'", dname);
3671-
return NULL;
3675+
goto err;
36723676
}
36733677
count = evalresult->value;
36743678
}
@@ -3687,7 +3691,10 @@ static Token *pp_substr(Token *tline, const char *dname)
36873691
start = -1, count = 0; /* empty string */
36883692

36893693
txt = (start < 0) ? "" : tok_text(t) + start;
3690-
return make_tok_qstr_len(NULL, txt, count);
3694+
res = make_tok_qstr_len(NULL, txt, count);
3695+
err:
3696+
free_tlist(tline);
3697+
return res;
36913698
}
36923699

36933700
/**
@@ -4850,7 +4857,6 @@ static int do_directive(Token *tline, Token **output)
48504857
*/
48514858
if (macro_start)
48524859
define_smacro(mname, casesense, macro_start, NULL);
4853-
free_tlist(tline);
48544860
break;
48554861

48564862
case PP_SUBSTR:
@@ -4869,7 +4875,6 @@ static int do_directive(Token *tline, Token **output)
48694875
*/
48704876
if (macro_start)
48714877
define_smacro(mname, casesense, macro_start, NULL);
4872-
free_tlist(tline);
48734878
break;
48744879

48754880
case PP_ASSIGN:
@@ -6909,22 +6914,34 @@ stdmac_join(const SMacro *s, Token **params, int nparams)
69096914
static Token *
69106915
stdmac_strcat(const SMacro *s, Token **params, int nparams)
69116916
{
6912-
nasm_assert(nparams == 1);
6913-
return pp_strcat(expand_smacro_noreset(params[0]), s->name);
6917+
Token *tline;
6918+
(void)nparams;
6919+
6920+
tline = params[0];
6921+
params[0] = NULL; /* Don't free this later */
6922+
return pp_strcat(expand_smacro_noreset(tline), s->name);
69146923
}
69156924

69166925
/* %substr() function */
69176926
static Token *
69186927
stdmac_substr(const SMacro *s, Token **params, int nparams)
69196928
{
6920-
nasm_assert(nparams == 1);
6921-
return pp_substr(expand_smacro_noreset(params[0]), s->name);
6929+
Token *tline;
6930+
(void)nparams;
6931+
6932+
tline = params[0];
6933+
params[0] = NULL; /* Don't free this later */
6934+
return pp_substr(expand_smacro_noreset(tline), s->name);
69226935
}
69236936

69246937
/* Expand a the argument and enforce it being a single quoted string */
6925-
static Token *expand_to_string(Token *tlist, const char *dname)
6938+
static Token *expand_to_string(Token **tp, const char *dname)
69266939
{
6927-
Token *t = zap_white(expand_smacro_noreset(tlist));
6940+
Token *tlist, *t;
6941+
6942+
tlist = *tp;
6943+
*tp = NULL; /* Don't free this later */
6944+
t = zap_white(expand_smacro_noreset(tlist));
69286945

69296946
if (!tok_is(t, TOKEN_STR)) {
69306947
nasm_nonfatal("`%s' requires string as parameter", dname);
@@ -6948,7 +6965,7 @@ stdmac_strlen(const SMacro *s, Token **params, int nparams)
69486965

69496966
(void)nparams;
69506967

6951-
t = expand_to_string(params[0], s->name);
6968+
t = expand_to_string(&params[0], s->name);
69526969
if (!t)
69536970
return NULL;
69546971

@@ -6964,13 +6981,38 @@ stdmac_tok(const SMacro *s, Token **params, int nparams)
69646981

69656982
(void)nparams;
69666983

6967-
t = expand_to_string(params[0], s->name);
6984+
t = expand_to_string(&params[0], s->name);
69686985
if (!t)
69696986
return NULL;
69706987

69716988
return reverse_tokens(tokenize(unquote_token_cstr(t)));
69726989
}
69736990

6991+
/* %cond() or %sel() */
6992+
static Token *
6993+
stdmac_cond_sel(const SMacro *s, Token **params, int nparams)
6994+
{
6995+
int64_t which;
6996+
bool err;
6997+
6998+
/*
6999+
* params[0] will have been generated by make_tok_num.
7000+
*/
7001+
which = get_tok_num(params[0], &err);
7002+
if (err)
7003+
return NULL; /* Nothing to expand */
7004+
7005+
if (s->expandpvt.u) {
7006+
/* Booleanize (for %cond): true -> 1, false -> 2 (else) */
7007+
which = which ? 1 : 2;
7008+
}
7009+
7010+
if (which < 1 || which >= nparams)
7011+
return NULL;
7012+
7013+
return new_Token(NULL, tok_smac_param(which), "", 0);
7014+
}
7015+
69747016
/* Add magic standard macros */
69757017
struct magic_macros {
69767018
const char *name;
@@ -7027,9 +7069,26 @@ static void pp_add_magic_stdmac(void)
70277069
}
70287070
}
70297071

7072+
/* %sel() function */
7073+
tmpl.nparam = 2;
7074+
tmpl.recursive = true;
7075+
tmpl.expand = stdmac_cond_sel;
7076+
nasm_newn(tmpl.params, 2);
7077+
tmpl.params[0].flags = SPARM_EVAL;
7078+
tmpl.params[1].flags = SPARM_VARADIC;
7079+
define_smacro("%sel", false, NULL, &tmpl);
7080+
7081+
/* %cond() function, a variation on %sel */
7082+
tmpl.expandpvt.u = 1; /* Booleanize */
7083+
for (tmpl.nparam = 2; tmpl.nparam <= 3; tmpl.nparam++) {
7084+
nasm_newn(tmpl.params, tmpl.nparam);
7085+
tmpl.params[0].flags = SPARM_EVAL;
7086+
define_smacro("%cond", false, NULL, &tmpl);
7087+
}
7088+
70307089
/* %is...() macro functions */
7090+
nasm_zero(tmpl);
70317091
tmpl.nparam = 1;
7032-
tmpl.varadic = true;
70337092
tmpl.expand = stdmac_is;
70347093
tmpl.recursive = true;
70357094
name_buf[0] = '%';
@@ -7644,6 +7703,29 @@ static Token *make_tok_num(Token *next, int64_t val)
76447703
return next;
76457704
}
76467705

7706+
/*
7707+
* Do the inverse of make_tok_num(). This only needs to be able
7708+
* to parse the output of make_tok_num().
7709+
*/
7710+
static int64_t get_tok_num(const Token *t, bool *err)
7711+
{
7712+
bool minus = false;
7713+
int64_t v;
7714+
7715+
if (tok_is(t, '-')) {
7716+
minus = true;
7717+
t = t->next;
7718+
}
7719+
if (!tok_is(t, TOKEN_NUM)) {
7720+
if (err)
7721+
*err = true;
7722+
return 0;
7723+
}
7724+
7725+
v = readnum(tok_text(t), err);
7726+
return minus ? -v : v;
7727+
}
7728+
76477729
/* Create a quoted string token */
76487730
static Token *make_tok_qstr_len(Token *next, const char *str, size_t len)
76497731
{

doc/nasmdoc.src

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2853,6 +2853,20 @@ arguments, and can be used in any context where single-line macro
28532853
expansion would be performed. Preprocessor functions were introduced
28542854
in NASM 2.16.
28552855

2856+
\S{f_cond} \i\c{%cond()} Function
2857+
2858+
The \c{%cond()} function evaluates its first argument as an
2859+
expression, then expands to its second argument if true (nonzero), and
2860+
the third, if present, if false (zero). This is in effect a specialized
2861+
version of the \i\c{%sel()} function; \c{%cond(x,y,z)} is equivalent
2862+
to \c{%sel(2-!(x),y,z)}.
2863+
2864+
\c %define a 1
2865+
\c %xdefine astr %cond(a,"true","false") ; %define astr "true"
2866+
2867+
The argument not selected is never expanded.
2868+
2869+
28562870
\S{f_eval} \i\c{%eval()} Function
28572871

28582872
The \c{%eval()} function evaluates its argument as a numeric
@@ -2894,6 +2908,18 @@ argument to the conditional using \c{\{\}}:
28942908
\c %endif
28952909

28962910

2911+
\S{f_sel} \i\c{%sel()} Function
2912+
2913+
The \c{%sel()} function evaluates its first argument as an
2914+
expression, then expands to its second argument if 1, the third
2915+
argument if 2, and so on. If the value is less than 1 or larger than
2916+
the number of arguments minus one, then the \c{%sel()} function
2917+
expands to nothing.
2918+
2919+
\c %define b 2
2920+
\c %xdefine bstr %sel(b,"one","two","three") ; %define bstr "two"
2921+
2922+
28972923
\S{f_str} \i\c\{%str()} Function
28982924

28992925
The \c{%str()} function converts its argument, including any commas,

0 commit comments

Comments
 (0)