Skip to content

Commit 4150848

Browse files
author
H. Peter Anvin
committed
preproc: implement %substr() and %tok() preprocessor functions
Implement preprocessor functions equivalent to the %substr and %deftok directive. Signed-off-by: H. Peter Anvin <[email protected]>
1 parent 913901e commit 4150848

File tree

1 file changed

+107
-69
lines changed

1 file changed

+107
-69
lines changed

asm/preproc.c

Lines changed: 107 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -3586,6 +3586,8 @@ static Token *pp_strcat(Token *tline, const char *dname)
35863586
break;
35873587
case TOKEN_STR:
35883588
unquote_token(t);
3589+
/* fall through */
3590+
case TOKEN_INTERNAL_STR:
35893591
len += t->len;
35903592
break;
35913593
default:
@@ -3608,6 +3610,78 @@ static Token *pp_strcat(Token *tline, const char *dname)
36083610
return t;
36093611
}
36103612

3613+
/*
3614+
* Implement substring extraction as used by the %substr directive
3615+
* and function.
3616+
*/
3617+
static Token *pp_substr(Token *tline, const char *dname)
3618+
{
3619+
int64_t start, count;
3620+
const char *txt;
3621+
size_t len;
3622+
struct ppscan pps;
3623+
Token *t;
3624+
expr *evalresult;
3625+
struct tokenval tokval;
3626+
3627+
t = skip_white(tline);
3628+
3629+
if (!tok_is(t, TOKEN_STR)) {
3630+
nasm_nonfatal("`%s' requires a string as parameter", dname);
3631+
return NULL;
3632+
}
3633+
3634+
pps.tptr = skip_white(t->next);
3635+
if (tok_is(pps.tptr, TOKEN_COMMA))
3636+
pps.tptr = skip_white(pps.tptr->next);
3637+
if (!pps.tptr) {
3638+
nasm_nonfatal("`%s' requires a starting index", dname);
3639+
return NULL;
3640+
}
3641+
3642+
pps.ntokens = -1;
3643+
tokval.t_type = TOKEN_INVALID;
3644+
evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
3645+
if (!evalresult) {
3646+
return NULL;
3647+
} else if (!is_simple(evalresult)) {
3648+
nasm_nonfatal("non-constant value given to `%s'", dname);
3649+
return NULL;
3650+
}
3651+
start = evalresult->value - 1;
3652+
3653+
pps.tptr = skip_white(pps.tptr);
3654+
if (!pps.tptr) {
3655+
count = 1; /* Backwards compatibility: one character */
3656+
} else {
3657+
tokval.t_type = TOKEN_INVALID;
3658+
evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
3659+
if (!evalresult) {
3660+
return NULL;
3661+
} else if (!is_simple(evalresult)) {
3662+
nasm_nonfatal("non-constant value given to `%s'", dname);
3663+
return NULL;
3664+
}
3665+
count = evalresult->value;
3666+
}
3667+
3668+
unquote_token(t);
3669+
len = t->len;
3670+
3671+
/* make start and count being in range */
3672+
if (start < 0)
3673+
start = 0;
3674+
if (count < 0)
3675+
count = len + count + 1 - start;
3676+
if (start + count > (int64_t)len)
3677+
count = len - start;
3678+
if (!len || count < 0 || start >=(int64_t)len)
3679+
start = -1, count = 0; /* empty string */
3680+
3681+
txt = (start < 0) ? "" : tok_text(t) + start;
3682+
return make_tok_qstr_len(NULL, txt, count);
3683+
}
3684+
36113685
/**
36123686
* find and process preprocessor directive in passed line
36133687
* Find out if a line contains a preprocessor directive, and deal
@@ -4666,9 +4740,7 @@ static int do_directive(Token *tline, Token **output)
46664740
}
46674741

46684742
/*
4669-
* Convert the string to a token stream. Note that smacros
4670-
* are stored with the token stream reversed, so we have to
4671-
* reverse the output of tokenize().
4743+
* Convert the string to a token stream.
46724744
*/
46734745
macro_start = tokenize(unquote_token_cstr(t));
46744746

@@ -4763,89 +4835,29 @@ static int do_directive(Token *tline, Token **output)
47634835
* zero, and a string token to use as an expansion. Create
47644836
* and store an SMacro.
47654837
*/
4766-
define_smacro(mname, casesense, macro_start, NULL);
4838+
if (macro_start)
4839+
define_smacro(mname, casesense, macro_start, NULL);
47674840
free_tlist(tline);
47684841
break;
47694842

47704843
case PP_SUBSTR:
4771-
{
4772-
int64_t start, count;
4773-
const char *txt;
4774-
size_t len;
4775-
47764844
if (!(mname = get_id(&tline, dname)))
47774845
goto done;
47784846

47794847
last = tline;
47804848
tline = expand_smacro(tline->next);
47814849
last->next = NULL;
47824850

4783-
t = skip_white(tline);
4784-
4785-
/* t should now point to the string */
4786-
if (!tok_is(t, TOKEN_STR)) {
4787-
nasm_nonfatal("`%s' requires string as second parameter", dname);
4788-
free_tlist(tline);
4789-
goto done;
4790-
}
4791-
4792-
pps.tptr = t->next;
4793-
pps.ntokens = -1;
4794-
tokval.t_type = TOKEN_INVALID;
4795-
evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
4796-
if (!evalresult) {
4797-
free_tlist(tline);
4798-
goto done;
4799-
} else if (!is_simple(evalresult)) {
4800-
nasm_nonfatal("non-constant value given to `%s'", dname);
4801-
free_tlist(tline);
4802-
goto done;
4803-
}
4804-
start = evalresult->value - 1;
4805-
4806-
pps.tptr = skip_white(pps.tptr);
4807-
if (!pps.tptr) {
4808-
count = 1; /* Backwards compatibility: one character */
4809-
} else {
4810-
tokval.t_type = TOKEN_INVALID;
4811-
evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
4812-
if (!evalresult) {
4813-
free_tlist(tline);
4814-
goto done;
4815-
} else if (!is_simple(evalresult)) {
4816-
nasm_nonfatal("non-constant value given to `%s'", dname);
4817-
free_tlist(tline);
4818-
goto done;
4819-
}
4820-
count = evalresult->value;
4821-
}
4822-
4823-
unquote_token(t);
4824-
len = t->len;
4825-
4826-
/* make start and count being in range */
4827-
if (start < 0)
4828-
start = 0;
4829-
if (count < 0)
4830-
count = len + count + 1 - start;
4831-
if (start + count > (int64_t)len)
4832-
count = len - start;
4833-
if (!len || count < 0 || start >=(int64_t)len)
4834-
start = -1, count = 0; /* empty string */
4835-
4836-
txt = (start < 0) ? "" : tok_text(t) + start;
4837-
len = count;
4838-
macro_start = make_tok_qstr_len(NULL, txt, len);
4839-
4851+
macro_start = pp_substr(tline, dname);
48404852
/*
48414853
* We now have a macro name, an implicit parameter count of
4842-
* zero, and a numeric token to use as an expansion. Create
4854+
* zero, and a string token to use as an expansion. Create
48434855
* and store an SMacro.
48444856
*/
4845-
define_smacro(mname, casesense, macro_start, NULL);
4857+
if (macro_start)
4858+
define_smacro(mname, casesense, macro_start, NULL);
48464859
free_tlist(tline);
48474860
break;
4848-
}
48494861

48504862
case PP_ASSIGN:
48514863
if (!(mname = get_id(&tline, dname)))
@@ -6887,6 +6899,30 @@ stdmac_strcat(const SMacro *s, Token **params, int nparams)
68876899
return pp_strcat(expand_smacro_noreset(params[0]), s->name);
68886900
}
68896901

6902+
/* %substr() function */
6903+
static Token *
6904+
stdmac_substr(const SMacro *s, Token **params, int nparams)
6905+
{
6906+
nasm_assert(nparams == 1);
6907+
return pp_substr(expand_smacro_noreset(params[0]), s->name);
6908+
}
6909+
6910+
/* %tok() function */
6911+
static Token *
6912+
stdmac_tok(const SMacro *s, Token **params, int nparams)
6913+
{
6914+
Token *t = expand_smacro_noreset(params[0]);
6915+
6916+
(void)nparams;
6917+
6918+
if (!tok_is(t, TOKEN_STR)) {
6919+
nasm_nonfatal("`%s' requires string as parameter", s->name);
6920+
return NULL;
6921+
}
6922+
6923+
return reverse_tokens(tokenize(unquote_token_cstr(t)));
6924+
}
6925+
68906926
/* Add magic standard macros */
68916927
struct magic_macros {
68926928
const char *name;
@@ -6905,6 +6941,8 @@ static void pp_add_magic_stdmac(void)
69056941
{ "%eval", false, 1, SPARM_EVAL|SPARM_VARADIC, stdmac_join },
69066942
{ "%str", false, 1, SPARM_GREEDY|SPARM_STR, stdmac_join },
69076943
{ "%strcat", false, 1, SPARM_GREEDY, stdmac_strcat },
6944+
{ "%substr", false, 1, SPARM_GREEDY, stdmac_substr },
6945+
{ "%tok", false, 1, 0, stdmac_tok },
69086946
{ NULL, false, 0, 0, NULL }
69096947
};
69106948
const struct magic_macros *m;

0 commit comments

Comments
 (0)