[nasm:nasm-2.15.xx] preproc: add %*? and %*??
nasm-bot for H. Peter Anvin
hpa at zytor.com
Sat Jul 18 13:54:10 PDT 2020
Commit-ID: 6263a2a4c2883f86a0339701bc0a99eaf2a783e6
Gitweb: http://repo.or.cz/w/nasm.git?a=commitdiff;h=6263a2a4c2883f86a0339701bc0a99eaf2a783e6
Author: H. Peter Anvin <hpa at zytor.com>
AuthorDate: Sat, 18 Jul 2020 13:47:59 -0700
Committer: H. Peter Anvin <hpa at zytor.com>
CommitDate: Sat, 18 Jul 2020 13:47:59 -0700
preproc: add %*? and %*??
The %? and %?? tokens are ambiguous when used inside a multi-line
macro. Add tokens %*? and %*?? that only expand during single-macro
expansion.
Signed-off-by: H. Peter Anvin (Intel) <hpa at zytor.com>
---
asm/preproc.c | 161 ++++++++++++++++++++++++++++++++++++++++---------------
doc/changes.src | 12 +++++
doc/nasmdoc.src | 49 ++++++++++++++---
test/selfref.asm | 24 +++++++++
4 files changed, 196 insertions(+), 50 deletions(-)
diff --git a/asm/preproc.c b/asm/preproc.c
index fec9520c..b291437c 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -125,7 +125,8 @@ enum pp_token_type {
TOK_LOCAL_MACRO, TOK_ENVIRON, TOK_STRING,
TOK_NUMBER, TOK_FLOAT, TOK_OTHER,
TOK_INTERNAL_STRING, TOK_NAKED_STRING,
- TOK_PREPROC_Q, TOK_PREPROC_QQ,
+ TOK_PREPROC_Q, TOK_PREPROC_SQ, /* %?, %*? */
+ TOK_PREPROC_QQ, TOK_PREPROC_SQQ, /* %??, %*?? */
TOK_PASTE, /* %+ */
TOK_COND_COMMA, /* %, */
TOK_INDIRECT, /* %[...] */
@@ -1456,6 +1457,11 @@ static Token *tokenize(const char *line)
p++;
if (*p == '?')
p++;
+ } else if (*p == '*' && p[1] == '?') {
+ /* %*? and %*?? */
+ p += 2;
+ if (*p == '?')
+ p++;
} else if (*p == '!') {
/* Environment variable reference */
p++;
@@ -1516,6 +1522,16 @@ static Token *tokenize(const char *line)
type = TOK_PREPROC_ID;
break;
+ case '*':
+ type = TOK_OTHER;
+ if (line[2] == '?') {
+ if (toklen == 3)
+ type = TOK_PREPROC_SQ;
+ else if (toklen == 4 && line[3] == '?')
+ type = TOK_PREPROC_SQQ;
+ }
+ break;
+
case '!':
type = (toklen == 2) ? TOK_OTHER : TOK_ENVIRON;
break;
@@ -1584,7 +1600,8 @@ static Token *tokenize(const char *line)
/* type = -1; */
}
} else if (p[0] == '$' && p[1] == '$') {
- type = TOK_OTHER; /* TOKEN_BASE */
+ /* TOKEN_BASE - treat as TOK_ID for pasting purposes */
+ type = TOK_ID;
p += 2;
} else if (nasm_isnumstart(*p)) {
bool is_hex = false;
@@ -1650,7 +1667,8 @@ static Token *tokenize(const char *line)
p--; /* Point to first character beyond number */
if (p == line+1 && *line == '$') {
- type = TOK_OTHER; /* TOKEN_HERE */
+ /* TOKEN_HERE - treat as TOK_ID for pasting purposes */
+ type = TOK_ID;
} else {
if (has_e && !is_hex) {
/* 1e13 is floating-point, but 1e13h is not */
@@ -2375,9 +2393,8 @@ restart:
continue;
}
}
- if (defn) {
- *defn = (nparam == m->nparam || nparam == -1) ? m : NULL;
- }
+ if (defn)
+ *defn = m;
return true;
}
m = m->next;
@@ -3019,7 +3036,8 @@ static SMacro *define_smacro(const char *mname, bool casesense,
struct hash_table *smtbl;
Context *ctx;
bool defining_alias = false;
- unsigned int nparam = 0;
+ int nparam = 0;
+ bool defined;
if (tmpl) {
defining_alias = tmpl->alias;
@@ -3028,48 +3046,101 @@ static SMacro *define_smacro(const char *mname, bool casesense,
mark_smac_params(expansion, tmpl, 0);
}
- while (1) {
- ctx = get_ctx(mname, &mname);
-
- if (!smacro_defined(ctx, mname, nparam, &smac, casesense, true)) {
- /* Create a new macro */
- smtbl = ctx ? &ctx->localmac : &smacros;
- smhead = (SMacro **) hash_findi_add(smtbl, mname);
- nasm_new(smac);
- smac->next = *smhead;
- *smhead = smac;
- break;
- } else if (!smac) {
- nasm_warn(WARN_OTHER, "single-line macro `%s' defined both with and"
- " without parameters", mname);
+ ctx = get_ctx(mname, &mname);
+
+ defined = smacro_defined(ctx, mname, nparam, &smac, casesense, true);
+
+ if (defined) {
+ if (smac->alias) {
+ if (smac->in_progress) {
+ nasm_nonfatal("macro alias loop");
+ goto fail;
+ }
+
+ if (!defining_alias && !ppopt.noaliases) {
+ /* It is an alias macro; follow the alias link */
+ SMacro *s;
+
+ smac->in_progress = true;
+ s = define_smacro(tok_text(smac->expansion), casesense,
+ expansion, tmpl);
+ smac->in_progress = false;
+ return s;
+ }
+ }
+
+ if (casesense ^ smac->casesense) {
/*
- * Some instances of the old code considered this a failure,
- * some others didn't. What is the right thing to do here?
+ *!macro-def-case-single [on] single-line macro defined both case sensitive and insensitive
+ *! warns when a single-line macro is defined both case
+ *! sensitive and case insensitive.
+ *! The new macro
+ *! definition will override (shadow) the original one,
+ *! although the original macro is not deleted, and will
+ *! be re-exposed if the new macro is deleted with
+ *! \c{%undef}, or, if the original macro is the case
+ *! insensitive one, the macro call is done with a
+ *! different case.
*/
- goto fail;
- } else if (!smac->alias || ppopt.noaliases || defining_alias) {
+ nasm_warn(WARN_MACRO_DEF_CASE_SINGLE, "case %ssensitive definition of macro `%s' will shadow %ssensitive macro `%s'",
+ casesense ? "" : "in",
+ mname,
+ smac->casesense ? "" : "in",
+ smac->name);
+ defined = false;
+ } else if ((!!nparam) ^ (!!smac->nparam)) {
/*
- * We're redefining, so we have to take over an
- * existing SMacro structure. This means freeing
- * what was already in it, but not the structure itself.
+ * Most recent versions of NASM considered this an error,
+ * so promote this warning to error by default.
+ *
+ *!macro-def-param-single [err] single-line macro defined with and without parameters
+ *! warns if the same single-line macro is defined with and
+ *! without parameters.
+ *! The new macro
+ *! definition will override (shadow) the original one,
+ *! although the original macro is not deleted, and will
+ *! be re-exposed if the new macro is deleted with
+ *! \c{%undef}.
*/
- clear_smacro(smac);
- break;
- } else if (smac->in_progress) {
- nasm_nonfatal("macro alias loop");
- goto fail;
- } else {
- /* It is an alias macro; follow the alias link */
- SMacro *s;
-
- smac->in_progress = true;
- s = define_smacro(tok_text(smac->expansion), casesense,
- expansion, tmpl);
- smac->in_progress = false;
- return s;
+ nasm_warn(WARN_MACRO_DEF_PARAM_SINGLE,
+ "macro `%s' defined both with and without parameters",
+ mname);
+ defined = false;
+ } else if (smac->nparam < nparam) {
+ /*
+ *!macro-def-greedy-single [on] single-line macro
+ *! definition shadows greedy macro warns when a
+ *! single-line macro is defined which would match a
+ *! previously existing greedy definition. The new macro
+ *! definition will override (shadow) the original one,
+ *! although the original macro is not deleted, and will
+ *! be re-exposed if the new macro is deleted with
+ *! \c{%undef}, and will be invoked if called with a
+ *! parameter count that does not match the new definition.
+ */
+ nasm_warn(WARN_MACRO_DEF_GREEDY_SINGLE,
+ "defining macro `%s' shadows previous greedy definition",
+ mname);
+ defined = false;
}
}
+ if (defined) {
+ /*
+ * We're redefinining, so we have to take over an
+ * existing SMacro structure. This means freeing
+ * what was already in it, but not the structure itself.
+ */
+ clear_smacro(smac);
+ } else {
+ /* Create a new macro */
+ smtbl = ctx ? &ctx->localmac : &smacros;
+ smhead = (SMacro **) hash_findi_add(smtbl, mname);
+ nasm_new(smac);
+ smac->next = *smhead;
+ *smhead = smac;
+ }
+
smac->name = nasm_strdup(mname);
smac->casesense = casesense;
smac->expansion = expansion;
@@ -4685,8 +4756,8 @@ issue_error:
}
done:
- free_tlist(origline);
- return DIRECTIVE_FOUND;
+ free_tlist(origline);
+ return DIRECTIVE_FOUND;
}
/*
@@ -5523,11 +5594,13 @@ static SMacro *expand_one_smacro(Token ***tpp)
switch (type) {
case TOK_PREPROC_Q:
+ case TOK_PREPROC_SQ:
delete_Token(t);
t = dup_Token(tline, mstart);
break;
case TOK_PREPROC_QQ:
+ case TOK_PREPROC_SQQ:
{
size_t mlen = strlen(m->name);
size_t len;
diff --git a/doc/changes.src b/doc/changes.src
index d1182271..e0215f1d 100644
--- a/doc/changes.src
+++ b/doc/changes.src
@@ -7,6 +7,18 @@
The NASM 2 series supports x86-64, and is the production version of NASM
since 2007.
+\S{cl-2.15.04} Version 2.15.04
+
+\b More sensible handling of the case where one single-line macro
+definition will shadow another. A warning will be issued, but the
+additional definition will be allowed. For the existing error case
+where both a parameterless and parametered macro are created, that
+warning is promoted to an error by default.
+
+\b Add special preprocessor tokens \c{%*?} and \c{%*??} that expand
+like \c{%?} and \c{%??} in single-line macros only. See
+\k{selfref%*?}.
+
\S{cl-2.15.03} Version 2.15.03
\b Add instructions from the Intel Instruction Set Extensions and
diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src
index 51a6b766..a112589e 100644
--- a/doc/nasmdoc.src
+++ b/doc/nasmdoc.src
@@ -2403,7 +2403,9 @@ macros, but for case-insensitive macros, they can differ.
For example:
-\c %idefine Foo mov %?,%??
+\c %imacro Foo 0
+\c mov %?,%??
+\c %endmacro
\c
\c foo
\c FOO
@@ -2413,14 +2415,49 @@ will expand to:
\c mov foo,Foo
\c mov FOO,Foo
-The sequence:
+These tokens can be used for single-line macros \e{if defined outside
+any multi-line macros.} See below.
+
+\S{selfref%*?} The Single-Line Macro Name: \i\c{%*?} and \i\c{%*??}
+
+If the tokens \c{%?} and \c{%??} are used inside a multi-line macro,
+they are expanded before any directives are processed. As a result,
+
+\c %imacro Foo 0
+\c %idefine Bar _%?
+\c mov BAR,bAr
+\c %endmacro
+\c
+\c foo
+\c mov eax,bar
+
+will expand to:
+
+\c mov _foo,_foo
+\c mov eax,_foo
+
+which may or may not be what you expected. The tokens \c{%*?} and
+\c{%*??} behave like \c{%?} and \c{%??} but are only expanded inside
+single-line macros. Thus:
+
+\c %imacro Foo 0
+\c %idefine Bar _%*?
+\c mov BAR,bAr
+\c %endmacro
+\c
+\c foo
+\c mov eax,bar
+
+will expand to:
-\c %idefine keyword $%?
+\c mov _BAR,_bAr
+\c mov eax,_bar
-can be used to make a keyword "disappear", for example in case a new
-instruction has been used as a label in older code. For example:
+The \c{%*?} can be used to make a keyword "disappear", for example in
+case a new instruction has been used as a label in older code. For
+example:
-\c %idefine pause $%? ; Hide the PAUSE instruction
+\c %idefine pause $%*? ; Hide the PAUSE instruction
\S{undef} Undefining Single-Line Macros: \i\c{%undef}
diff --git a/test/selfref.asm b/test/selfref.asm
new file mode 100644
index 00000000..90ecef06
--- /dev/null
+++ b/test/selfref.asm
@@ -0,0 +1,24 @@
+ bits 32
+
+%idefine zoom $%?
+ mov ebx,Zoom
+%idefine boom $%?
+ mov ecx,Boom
+
+%imacro Foo1 0
+ %idefine Bar1 _%?
+ %idefine baz1 $%?
+ mov BAR1,baz1
+%endmacro
+
+ foo1
+ mov eax,bar1
+
+%imacro Foo2 0
+ %idefine Bar2 _%*?
+ %idefine baz2 $%*?
+ mov BAR2,baz2
+%endmacro
+
+ foo2
+ mov eax,bar2
More information about the Nasm-commits
mailing list