[nasm:master] preproc: implement %substr() and %tok() preprocessor functions
nasm-bot for H. Peter Anvin
hpa at zytor.com
Fri Nov 11 19:04:05 PST 2022
Commit-ID: 4150848a7de810b126777d5df627272527da5c05
Gitweb: http://repo.or.cz/w/nasm.git?a=commitdiff;h=4150848a7de810b126777d5df627272527da5c05
Author: H. Peter Anvin <hpa at zytor.com>
AuthorDate: Fri, 11 Nov 2022 19:02:41 -0800
Committer: H. Peter Anvin <hpa at zytor.com>
CommitDate: Fri, 11 Nov 2022 19:02:41 -0800
preproc: implement %substr() and %tok() preprocessor functions
Implement preprocessor functions equivalent to the %substr and %deftok
directive.
Signed-off-by: H. Peter Anvin <hpa at zytor.com>
---
asm/preproc.c | 176 +++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 107 insertions(+), 69 deletions(-)
diff --git a/asm/preproc.c b/asm/preproc.c
index f0c7103c..865c0982 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -3586,6 +3586,8 @@ static Token *pp_strcat(Token *tline, const char *dname)
break;
case TOKEN_STR:
unquote_token(t);
+ /* fall through */
+ case TOKEN_INTERNAL_STR:
len += t->len;
break;
default:
@@ -3608,6 +3610,78 @@ static Token *pp_strcat(Token *tline, const char *dname)
return t;
}
+/*
+ * Implement substring extraction as used by the %substr directive
+ * and function.
+ */
+static Token *pp_substr(Token *tline, const char *dname)
+{
+ int64_t start, count;
+ const char *txt;
+ size_t len;
+ struct ppscan pps;
+ Token *t;
+ expr *evalresult;
+ struct tokenval tokval;
+
+ t = skip_white(tline);
+
+ if (!tok_is(t, TOKEN_STR)) {
+ nasm_nonfatal("`%s' requires a string as parameter", dname);
+ return NULL;
+ }
+
+ pps.tptr = skip_white(t->next);
+ if (tok_is(pps.tptr, TOKEN_COMMA))
+ pps.tptr = skip_white(pps.tptr->next);
+ if (!pps.tptr) {
+ nasm_nonfatal("`%s' requires a starting index", dname);
+ return NULL;
+ }
+
+ pps.ntokens = -1;
+ tokval.t_type = TOKEN_INVALID;
+ evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
+ if (!evalresult) {
+ return NULL;
+ } else if (!is_simple(evalresult)) {
+ nasm_nonfatal("non-constant value given to `%s'", dname);
+ return NULL;
+ }
+ start = evalresult->value - 1;
+
+ pps.tptr = skip_white(pps.tptr);
+ if (!pps.tptr) {
+ count = 1; /* Backwards compatibility: one character */
+ } else {
+ tokval.t_type = TOKEN_INVALID;
+ evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
+ if (!evalresult) {
+ return NULL;
+ } else if (!is_simple(evalresult)) {
+ nasm_nonfatal("non-constant value given to `%s'", dname);
+ return NULL;
+ }
+ count = evalresult->value;
+ }
+
+ unquote_token(t);
+ len = t->len;
+
+ /* make start and count being in range */
+ if (start < 0)
+ start = 0;
+ if (count < 0)
+ count = len + count + 1 - start;
+ if (start + count > (int64_t)len)
+ count = len - start;
+ if (!len || count < 0 || start >=(int64_t)len)
+ start = -1, count = 0; /* empty string */
+
+ txt = (start < 0) ? "" : tok_text(t) + start;
+ return make_tok_qstr_len(NULL, txt, count);
+}
+
/**
* find and process preprocessor directive in passed line
* Find out if a line contains a preprocessor directive, and deal
@@ -4666,9 +4740,7 @@ issue_error:
}
/*
- * Convert the string to a token stream. Note that smacros
- * are stored with the token stream reversed, so we have to
- * reverse the output of tokenize().
+ * Convert the string to a token stream.
*/
macro_start = tokenize(unquote_token_cstr(t));
@@ -4763,16 +4835,12 @@ issue_error:
* zero, and a string token to use as an expansion. Create
* and store an SMacro.
*/
- define_smacro(mname, casesense, macro_start, NULL);
+ if (macro_start)
+ define_smacro(mname, casesense, macro_start, NULL);
free_tlist(tline);
break;
case PP_SUBSTR:
- {
- int64_t start, count;
- const char *txt;
- size_t len;
-
if (!(mname = get_id(&tline, dname)))
goto done;
@@ -4780,72 +4848,16 @@ issue_error:
tline = expand_smacro(tline->next);
last->next = NULL;
- t = skip_white(tline);
-
- /* t should now point to the string */
- if (!tok_is(t, TOKEN_STR)) {
- nasm_nonfatal("`%s' requires string as second parameter", dname);
- free_tlist(tline);
- goto done;
- }
-
- pps.tptr = t->next;
- pps.ntokens = -1;
- tokval.t_type = TOKEN_INVALID;
- evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
- if (!evalresult) {
- free_tlist(tline);
- goto done;
- } else if (!is_simple(evalresult)) {
- nasm_nonfatal("non-constant value given to `%s'", dname);
- free_tlist(tline);
- goto done;
- }
- start = evalresult->value - 1;
-
- pps.tptr = skip_white(pps.tptr);
- if (!pps.tptr) {
- count = 1; /* Backwards compatibility: one character */
- } else {
- tokval.t_type = TOKEN_INVALID;
- evalresult = evaluate(ppscan, &pps, &tokval, NULL, true, NULL);
- if (!evalresult) {
- free_tlist(tline);
- goto done;
- } else if (!is_simple(evalresult)) {
- nasm_nonfatal("non-constant value given to `%s'", dname);
- free_tlist(tline);
- goto done;
- }
- count = evalresult->value;
- }
-
- unquote_token(t);
- len = t->len;
-
- /* make start and count being in range */
- if (start < 0)
- start = 0;
- if (count < 0)
- count = len + count + 1 - start;
- if (start + count > (int64_t)len)
- count = len - start;
- if (!len || count < 0 || start >=(int64_t)len)
- start = -1, count = 0; /* empty string */
-
- txt = (start < 0) ? "" : tok_text(t) + start;
- len = count;
- macro_start = make_tok_qstr_len(NULL, txt, len);
-
+ macro_start = pp_substr(tline, dname);
/*
* We now have a macro name, an implicit parameter count of
- * zero, and a numeric token to use as an expansion. Create
+ * zero, and a string token to use as an expansion. Create
* and store an SMacro.
*/
- define_smacro(mname, casesense, macro_start, NULL);
+ if (macro_start)
+ define_smacro(mname, casesense, macro_start, NULL);
free_tlist(tline);
break;
- }
case PP_ASSIGN:
if (!(mname = get_id(&tline, dname)))
@@ -6887,6 +6899,30 @@ stdmac_strcat(const SMacro *s, Token **params, int nparams)
return pp_strcat(expand_smacro_noreset(params[0]), 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);
+}
+
+/* %tok() function */
+static Token *
+stdmac_tok(const SMacro *s, Token **params, int nparams)
+{
+ Token *t = expand_smacro_noreset(params[0]);
+
+ (void)nparams;
+
+ if (!tok_is(t, TOKEN_STR)) {
+ nasm_nonfatal("`%s' requires string as parameter", s->name);
+ return NULL;
+ }
+
+ return reverse_tokens(tokenize(unquote_token_cstr(t)));
+}
+
/* Add magic standard macros */
struct magic_macros {
const char *name;
@@ -6905,6 +6941,8 @@ static void pp_add_magic_stdmac(void)
{ "%eval", false, 1, SPARM_EVAL|SPARM_VARADIC, stdmac_join },
{ "%str", false, 1, SPARM_GREEDY|SPARM_STR, stdmac_join },
{ "%strcat", false, 1, SPARM_GREEDY, stdmac_strcat },
+ { "%substr", false, 1, SPARM_GREEDY, stdmac_substr },
+ { "%tok", false, 1, 0, stdmac_tok },
{ NULL, false, 0, 0, NULL }
};
const struct magic_macros *m;
More information about the Nasm-commits
mailing list