Skip to content

Commit 516fbba

Browse files
author
H. Peter Anvin
committed
preproc: add conditional-string smacro parameters; simplify functions
Add the option of having strings only conditionally quoted (&&) -- do not quote an already quoted string again -- as opposed to always quoting a string. This makes a lot of the string functions way simpler to implement, and removes the need to share ad hoc parsing code with directives. Signed-off-by: H. Peter Anvin <[email protected]>
1 parent 30ff4f9 commit 516fbba

File tree

2 files changed

+110
-87
lines changed

2 files changed

+110
-87
lines changed

asm/preproc.c

Lines changed: 90 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -206,13 +206,14 @@ typedef Token *(*ExpandSMacro)(const SMacro *s, Token **params, int nparams);
206206
* if SPARM_GREEDY is set.
207207
*/
208208
enum sparmflags {
209-
SPARM_PLAIN = 0,
210-
SPARM_EVAL = 1, /* Evaluate as a numeric expression (=) */
211-
SPARM_STR = 2, /* Convert to quoted string ($) */
212-
SPARM_NOSTRIP = 4, /* Don't strip braces (!) */
213-
SPARM_GREEDY = 8, /* Greedy final parameter (+) */
214-
SPARM_VARADIC = 16, /* Any number of separate arguments */
215-
SPARM_OPTIONAL = 32 /* Optional argument */
209+
SPARM_PLAIN = 0,
210+
SPARM_EVAL = 1, /* Evaluate as a numeric expression (=) */
211+
SPARM_STR = 2, /* Convert to quoted string ($) */
212+
SPARM_NOSTRIP = 4, /* Don't strip braces (!) */
213+
SPARM_GREEDY = 8, /* Greedy final parameter (+) */
214+
SPARM_VARADIC = 16, /* Any number of separate arguments */
215+
SPARM_OPTIONAL = 32, /* Optional argument */
216+
SPARM_CONDQUOTE = 64 /* With SPARM_STR, don't re-quote a string */
216217
};
217218

218219
struct smac_param {
@@ -2875,11 +2876,11 @@ list_smacro_def(enum preproc_token op, const Context *ctx, const SMacro *m)
28752876
if (m->nparam) {
28762877
/*
28772878
* Space for ( and either , or ) around each
2878-
* parameter, plus up to 4 flags.
2879+
* parameter, plus up to 5 flags.
28792880
*/
28802881
int i;
28812882

2882-
size += 1 + 4 * m->nparam;
2883+
size += 1 + 5 * m->nparam;
28832884
for (i = 0; i < m->nparam; i++)
28842885
size += m->params[i].name.len;
28852886
}
@@ -2910,8 +2911,11 @@ list_smacro_def(enum preproc_token op, const Context *ctx, const SMacro *m)
29102911

29112912
if (flags & SPARM_NOSTRIP)
29122913
*--p = '!';
2913-
if (flags & SPARM_STR)
2914+
if (flags & SPARM_STR) {
29142915
*--p = '&';
2916+
if (flags & SPARM_CONDQUOTE)
2917+
*--p = '&';
2918+
}
29152919
if (flags & SPARM_EVAL)
29162920
*--p = '=';
29172921
*--p = ',';
@@ -3019,6 +3023,9 @@ static int parse_smacro_template(Token ***tpp, SMacro *tmpl)
30193023
case '&':
30203024
flags |= SPARM_STR;
30213025
break;
3026+
case TOKEN_DBL_AND:
3027+
flags |= SPARM_STR|SPARM_CONDQUOTE;
3028+
break;
30223029
case '!':
30233030
flags |= SPARM_NOSTRIP;
30243031
break;
@@ -3691,15 +3698,16 @@ static Token *pp_strcat(Token *tline, const char *dname)
36913698
return res;
36923699
}
36933700

3701+
36943702
/*
36953703
* Implement substring extraction as used by the %substr directive
36963704
* and function.
36973705
*/
3706+
static Token *pp_substr_common(Token *t, int64_t start, int64_t count);
3707+
36983708
static Token *pp_substr(Token *tline, const char *dname)
36993709
{
37003710
int64_t start, count;
3701-
const char *txt;
3702-
size_t len;
37033711
struct ppscan pps;
37043712
Token *t;
37053713
Token *res = NULL;
@@ -3730,7 +3738,7 @@ static Token *pp_substr(Token *tline, const char *dname)
37303738
nasm_nonfatal("non-constant value given to `%s'", dname);
37313739
goto err;
37323740
}
3733-
start = evalresult->value - 1;
3741+
start = evalresult->value;
37343742

37353743
pps.tptr = skip_white(pps.tptr);
37363744
if (!pps.tptr) {
@@ -3747,10 +3755,24 @@ static Token *pp_substr(Token *tline, const char *dname)
37473755
count = evalresult->value;
37483756
}
37493757

3758+
res = pp_substr_common(t, start, count);
3759+
3760+
err:
3761+
free_tlist(tline);
3762+
return res;
3763+
}
3764+
3765+
static Token *pp_substr_common(Token *t, int64_t start, int64_t count)
3766+
{
3767+
size_t len;
3768+
const char *txt;
3769+
37503770
unquote_token(t);
37513771
len = t->len;
37523772

37533773
/* make start and count being in range */
3774+
start -= 1; /* First character is 1 */
3775+
37543776
if (start < 0)
37553777
start = 0;
37563778
if (count < 0)
@@ -3761,10 +3783,7 @@ static Token *pp_substr(Token *tline, const char *dname)
37613783
start = -1, count = 0; /* empty string */
37623784

37633785
txt = (start < 0) ? "" : tok_text(t) + start;
3764-
res = make_tok_qstr_len(NULL, txt, count);
3765-
err:
3766-
free_tlist(tline);
3767-
return res;
3786+
return make_tok_qstr_len(NULL, txt, count);
37683787
}
37693788

37703789
/**
@@ -5893,14 +5912,19 @@ static SMacro *expand_one_smacro(Token ***tpp)
58935912

58945913
if (flags & SPARM_STR) {
58955914
/* Convert expansion to a quoted string */
5896-
char *arg;
58975915
Token *qs;
58985916

58995917
qs = expand_smacro_noreset(params[i]);
5900-
arg = detoken(qs, false);
5901-
free_tlist(qs);
5902-
params[i] = make_tok_qstr(NULL, arg);
5903-
nasm_free(arg);
5918+
if ((flags & SPARM_CONDQUOTE) &&
5919+
tok_is(qs, TOKEN_STR) && !qs->next) {
5920+
/* A single quoted string token */
5921+
params[i] = qs;
5922+
} else {
5923+
char *arg = detoken(qs, false);
5924+
free_tlist(qs);
5925+
params[i] = make_tok_qstr(NULL, arg);
5926+
nasm_free(arg);
5927+
}
59045928
}
59055929
}
59065930
}
@@ -7051,78 +7075,61 @@ stdmac_join(const SMacro *s, Token **params, int nparams)
70517075
static Token *
70527076
stdmac_strcat(const SMacro *s, Token **params, int nparams)
70537077
{
7054-
Token *tline;
7055-
(void)nparams;
7078+
int i;
7079+
size_t len = 0;
7080+
char *str, *p;
70567081

7057-
tline = params[0];
7058-
params[0] = NULL; /* Don't free this later */
7059-
return pp_strcat(expand_smacro_noreset(tline), s->name);
7082+
(void)s;
7083+
7084+
for (i = 0; i < nparams; i++) {
7085+
unquote_token(params[i]);
7086+
len += params[i]->len;
7087+
}
7088+
7089+
nasm_newn(str, len+1);
7090+
p = str;
7091+
7092+
for (i = 0; i < nparams; i++) {
7093+
p = mempcpy(p, tok_text(params[i]), params[i]->len);
7094+
}
7095+
7096+
return make_tok_qstr_len(NULL, str, len);
70607097
}
70617098

70627099
/* %substr() function */
70637100
static Token *
70647101
stdmac_substr(const SMacro *s, Token **params, int nparams)
70657102
{
7066-
Token *tline;
7067-
(void)nparams;
7068-
7069-
tline = params[0];
7070-
params[0] = NULL; /* Don't free this later */
7071-
return pp_substr(expand_smacro_noreset(tline), s->name);
7072-
}
7073-
7074-
/* Expand a the argument and enforce it being a single quoted string */
7075-
static Token *expand_to_string(Token **tp, const char *dname)
7076-
{
7077-
Token *tlist, *t;
7078-
7079-
tlist = *tp;
7080-
*tp = NULL; /* Don't free this later */
7081-
t = zap_white(expand_smacro_noreset(tlist));
7103+
int64_t start, count;
70827104

7083-
if (!tok_is(t, TOKEN_STR)) {
7084-
nasm_nonfatal("`%s' requires string as parameter", dname);
7085-
return NULL;
7086-
}
7105+
(void)nparams;
7106+
(void)s;
70877107

7088-
t->next = zap_white(t->next);
7089-
if (t->next) {
7090-
nasm_nonfatal("`%s' requires exactly one string as parameter", dname);
7091-
return NULL;
7092-
}
7108+
start = get_tok_num(params[1], NULL);
7109+
count = get_tok_num(params[2], NULL);
70937110

7094-
return t;
7111+
return pp_substr_common(params[0], start, count);
70957112
}
70967113

70977114
/* %strlen() function */
70987115
static Token *
70997116
stdmac_strlen(const SMacro *s, Token **params, int nparams)
71007117
{
7101-
Token *t;
7102-
71037118
(void)nparams;
7119+
(void)s;
71047120

7105-
t = expand_to_string(&params[0], s->name);
7106-
if (!t)
7107-
return NULL;
7108-
7109-
unquote_token(t);
7110-
return make_tok_num(NULL, t->len);
7121+
unquote_token(params[0]);
7122+
return make_tok_num(NULL, params[0]->len);
71117123
}
71127124

71137125
/* %tok() function */
71147126
static Token *
71157127
stdmac_tok(const SMacro *s, Token **params, int nparams)
71167128
{
7117-
Token *t;
7118-
71197129
(void)nparams;
7130+
(void)s;
71207131

7121-
t = expand_to_string(&params[0], s->name);
7122-
if (!t)
7123-
return NULL;
7124-
7125-
return reverse_tokens(tokenize(unquote_token_cstr(t)));
7132+
return reverse_tokens(tokenize(unquote_token_cstr(params[0])));
71267133
}
71277134

71287135
/* %cond() or %sel() */
@@ -7272,12 +7279,6 @@ struct magic_macros {
72727279
ExpandSMacro func;
72737280
};
72747281

7275-
struct num_macros {
7276-
const char name[6];
7277-
uint8_t base;
7278-
char prefix;
7279-
};
7280-
72817282
static void pp_add_magic_stdmac(void)
72827283
{
72837284
static const struct magic_macros magic_macros[] = {
@@ -7289,10 +7290,9 @@ static void pp_add_magic_stdmac(void)
72897290
{ "%count", false, 1, SPARM_VARADIC, stdmac_count },
72907291
{ "%eval", false, 1, SPARM_EVAL|SPARM_VARADIC, stdmac_join },
72917292
{ "%str", false, 1, SPARM_GREEDY|SPARM_STR, stdmac_join },
7292-
{ "%strcat", false, 1, SPARM_GREEDY, stdmac_strcat },
7293-
{ "%strlen", false, 1, 0, stdmac_strlen },
7294-
{ "%substr", false, 1, SPARM_GREEDY, stdmac_substr },
7295-
{ "%tok", false, 1, 0, stdmac_tok },
7293+
{ "%strcat", false, 1, SPARM_STR|SPARM_CONDQUOTE|SPARM_VARADIC, stdmac_strcat },
7294+
{ "%strlen", false, 1, SPARM_STR|SPARM_CONDQUOTE, stdmac_strlen },
7295+
{ "%tok", false, 1, SPARM_STR|SPARM_CONDQUOTE, stdmac_tok },
72967296
{ NULL, false, 0, 0, NULL }
72977297
};
72987298
const struct magic_macros *m;
@@ -7361,6 +7361,18 @@ static void pp_add_magic_stdmac(void)
73617361
tmpl.params[2].def = make_tok_num(NULL, 10);
73627362
define_smacro("%num", false, NULL, &tmpl);
73637363

7364+
/* %substr() function */
7365+
nasm_zero(tmpl);
7366+
tmpl.nparam = 3;
7367+
tmpl.expand = stdmac_substr;
7368+
tmpl.recursive = true;
7369+
nasm_newn(tmpl.params, tmpl.nparam);
7370+
tmpl.params[0].flags = SPARM_STR|SPARM_CONDQUOTE;
7371+
tmpl.params[1].flags = SPARM_EVAL;
7372+
tmpl.params[2].flags = SPARM_EVAL|SPARM_OPTIONAL;
7373+
tmpl.params[2].def = make_tok_num(NULL, -1);
7374+
define_smacro("%substr", false, NULL, &tmpl);
7375+
73647376
/* %is...() macro functions */
73657377
nasm_zero(tmpl);
73667378
tmpl.nparam = 1;

doc/nasmdoc.src

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,17 +2424,22 @@ A single pair of parentheses is a subcase of a single, unused argument:
24242424

24252425
This is similar to the behavior of the C preprocessor.
24262426

2427-
\b If declared with an \c{=}, NASM will evaluate the argument as an
2428-
expression after expansion.
2427+
\b If declared with an \c{=}, NASM will expand the argument and then
2428+
evaluate it as a numeric expression.
24292429

2430-
\b If an argument declared with an \c{&}, a macro parameter will be
2431-
turned into a quoted string after expansion.
2430+
\b If declared with an \c{&}, NASM will expand the argument and then
2431+
turn into a quoted string; if the argument already \e{is} a quoted
2432+
string, it will be quoted again.
2433+
2434+
\b If declared with \c{&&}, NASM will expand the argument and then
2435+
turn it into a quoted string, but if the argument already is a quoted
2436+
string, it will \e{not} be re-quoted.
24322437

24332438
\b If declared with a \c{+}, it is a greedy or variadic parameter; it
2434-
includes any subsequent commas and parameters.
2439+
will include any subsequent commas and parameters.
24352440

24362441
\b If declared with an \c{!}, NASM will not strip whitespace and
2437-
braces (useful in conjunction with \c{&}).
2442+
braces (potentially useful in conjunction with \c{&} or \c{&&}.)
24382443

24392444
For example:
24402445

@@ -2849,7 +2854,9 @@ means "until N-1 characters before the end of string", i.e. \c{-1}
28492854
means until end of string, \c{-2} until one character before, etc.
28502855

28512856
The corresponding preprocessor function is \c{%substr()}, see
2852-
\k{f_substr}.
2857+
\k{f_substr}, however please note that the default value for the
2858+
length parameter, if omitted, is \c{-1} rather than \c{1} for
2859+
\c{%substr()}.
28532860

28542861

28552862
\H{ppfunc} \i{Preprocessor Functions}
@@ -3016,13 +3023,17 @@ in the same way the \i\c{%strlen} directive would, see \k{strlen}.
30163023

30173024
The \c{%substr()} function extracts a substring of a quoted string, in
30183025
the same way the \i\c{%substr} directive would, see \k{substr}. Note
3019-
that unlike the \c{%substr} directive, a comma is required after the
3020-
string argument.
3026+
that unlike the \c{%substr} directive, commas are required between all
3027+
parameters, is required after the string argument, and that the
3028+
default for the length argument, if omitted, is \c{-1} (i.e. the
3029+
remainder of the string) rather than \c{1}.
30213030

30223031
\c ; The following lines are all equivalent
30233032
\c %define mychar 'yzw'
30243033
\c %substr mychar 'xyzw' 2,-1
3034+
\c %xdefine mychar %substr('xyzw',2,3)
30253035
\c %xdefine mychar %substr('xyzw',2,-1)
3036+
\c %xdefine mychar %substr('xyzw',2)
30263037

30273038

30283039
\S{f_tok} \i\c{%tok()} function

0 commit comments

Comments
 (0)