diff --git a/CHANGES b/CHANGES index cb6cfc60..2e71c4f3 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,7 @@ * %substr can now be used to get other than one-character substrings. * New type of character/string constants, using backquotes (`...`), which support C-style escape sequences. +* %defstr and %idefstr to stringize macro definitions before creation. 2.02 ---- diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src index 03ef92ef..fd8af522 100644 --- a/doc/nasmdoc.src +++ b/doc/nasmdoc.src @@ -1957,7 +1957,7 @@ You can \i{pre-define} single-line macros using the `-d' option on the NASM command line: see \k{opt-d}. -\S{xdefine} Enhancing %define: \I\c{%ixdefine}\i\c{%xdefine} +\S{xdefine} Enhancing \c{%define}: \I\c{%ixdefine}\i\c{%xdefine} To have a reference to an embedded single-line macro resolved at the time that it is embedded, as opposed to when the calling macro is @@ -2074,7 +2074,7 @@ instruction has been used as a label in older code. For example: \c %idefine pause $%? ; Hide the PAUSE instruction -\S{undef} Undefining macros: \i\c{%undef} +\S{undef} Undefining Macros: \i\c{%undef} Single-line macros can be removed with the \c{%undef} command. For example, the following sequence: @@ -2121,6 +2121,27 @@ a relocatable reference such as a code or data address, or anything involving a register). +\S{defstr} Defining Strings: \I\c{%idefstr}\i\c{%defstr} + +\c{%defstr}, and its case-insensitive counterpart \c{%idefstr}, define +or redefine a single-line macro without parameters but converts the +entire right-hand side, after macro expansion, to a quoted string +before definition. + +For example: + +\c %defstr test TEST + +is equivalent to + +\c %define test 'TEST' + +This can be used, for example, with the \c{%!} construct (see +\k{getenv}): + +\c %defstr PATH %!PATH ; The operating system PATH variable + + \H{strlen} \i{String Handling in Macros}: \i\c{%strlen} and \i\c{%substr} It's often useful to be able to handle strings in macros. NASM @@ -3637,18 +3658,9 @@ For example, suppose that you have an environment variable \c{FOO}, and you want the contents of \c{FOO} to be embedded in your program. You could do that as follows: -\c %define FOO %!FOO -\c %define quote ' -\c -\c tmpstr db quote FOO quote +\c %defstr FOO %!FOO -At the time of writing, this will generate an "unterminated string" -warning at the time of defining "quote", and it will add a space -before and after the string that is read in. I was unable to find -a simple workaround (although a workaround can be created using a -multi-line macro), so I believe that you will need to either learn how -to create more complex macros, or allow for the extra spaces if you -make use of this feature in that way. +See \k{defstr} for notes on the \c{%defstr} directive. \C{directive} \i{Assembler Directives} diff --git a/insns.pl b/insns.pl index 00ab500b..9a8d3ed8 100644 --- a/insns.pl +++ b/insns.pl @@ -184,6 +184,7 @@ if ( !defined($output) || $output eq 'd' ) { print D "};\n"; foreach $h (sort(keys(%dinstables))) { + next if ($h eq ''); # Skip pseudo-instructions print D "\nstatic const struct itemplate * const itable_${h}[] = {\n"; foreach $j (@{$dinstables{$h}}) { print D " instrux + $j,\n"; diff --git a/pptok.dat b/pptok.dat index a70a2a17..1396eef2 100644 --- a/pptok.dat +++ b/pptok.dat @@ -17,6 +17,7 @@ %assign %clear %define +%defstr %depend %elif* %else @@ -28,6 +29,7 @@ %exitrep %iassign %idefine +%idefstr %if* %imacro %include diff --git a/preproc.c b/preproc.c index 475cb7e3..5d0d87a0 100644 --- a/preproc.c +++ b/preproc.c @@ -1028,7 +1028,7 @@ static Token *delete_Token(Token * t) * If expand_locals is not zero, identifiers of the form "%$*xxx" * will be transformed into ..@ctxnum.xxx */ -static char *detoken(Token * tlist, int expand_locals) +static char *detoken(Token * tlist, bool expand_locals) { Token *t; int len; @@ -2647,6 +2647,49 @@ static int do_directive(Token * tline) free_tlist(origline); return DIRECTIVE_FOUND; + case PP_DEFSTR: + case PP_IDEFSTR: + casesense = (i == PP_DEFSTR); + + tline = tline->next; + skip_white_(tline); + tline = expand_id(tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) { + error(ERR_NONFATAL, "`%s' expects a macro identifier", + pp_directives[i]); + free_tlist(origline); + return DIRECTIVE_FOUND; + } + + ctx = get_ctx(tline->text, false); + + mname = tline->text; + last = tline; + tline = expand_smacro(tline->next); + last->next = NULL; + + while (tok_type_(tline, TOK_WHITESPACE)) + tline = delete_Token(tline); + + p = detoken(tline, false); + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + macro_start->text = nasm_quote(p, strlen(p)); + macro_start->type = TOK_STRING; + macro_start->mac = NULL; + nasm_free(p); + + /* + * We now have a macro name, an implicit parameter count of + * zero, and a string token to use as an expansion. Create + * and store an SMacro. + */ + define_smacro(ctx, mname, casesense, 0, macro_start); + free_tlist(origline); + return DIRECTIVE_FOUND; + case PP_PATHSEARCH: { FILE *fp; diff --git a/version b/version index 044cceb2..839dcbd5 100644 --- a/version +++ b/version @@ -1 +1 @@ -2.03rc5 +2.03rc6