I needed some new preprocessor directives for some macros I wanted
to make. The two new directives are %string and %delete.
%string works similar to %xdefine, except that whatever's on the right
hand side is converted to a string.
%delete works like %undef, except that where %undef will delete the
single line macro it's given as an operand, %delete expands it as far as
it will expand and deletes what it expands to. Naturally, as an expanded
macro is no longer a macro identifier, I also had to make %undef and %
delete accept strings as input.
I added these macros to make it possible for macros to create and later
delete other macros. E.g.:
%macro create 2
%push silly
%string %$var %1
%define %1 %2
%endmacro
%macro destroy 0
%delete %$var
%pop
%endmacro
So "create x, 12" will "%define x 12" and then "destroy" will basically "%
undef x". This wasn't possible before, since %undef wouldn't ever
expand a macro, and even if it did, %$var would expand to x which
would expand to 12.
Anyway, my patch has bugs. At the very least it makes NASM segfault if
you try to %undef %$v1 when there isn't a %$v1. I can't figure out what
I did to make it do that. Everything else seems to work just fine, though,
so I don't know what I did. (I also just learned C two weeks ago.) I
wouldn't have even bothered trying to make a patch, except that there
seems to be a mile long list of feature requests here, and I wanted to
give mine a better chance of being added to NASM sometime in the near
future.
Anyway, a diff should be attached, and my email address is peajay at
funrestraints dot com if you need to email me.
Logged In: NO
Nice, it didn't upload my diff. Well, I'll stick it on my website, here's a link:
http://xerse.nfshost.com/secret/nasmdiff
Logged In: YES
user_id=804543
Take a look at SF RFE #829879. It suggests %# as a
means for preventing the expansion of a single-line
macro. The required changes are small.
Also note that you can already "stringify" tokens
as long as you can live with "unterminated string"
warnings (which should be made suppressible -- but
that's another issue).
%MACRO AddSingleQuotes 2+
%PUSH local
%XDEFINE %$single '
%XDEFINE %1 %$single%2%$single
%POP
%ENDMACRO
%MACRO AddDoubleQuotes 2+
%PUSH local
%XDEFINE %$double "
%XDEFINE %1 %$double%2%$double
%POP
%ENDMACRO
AddSingleQuotes TEMP1,%!TEMP
AddDoubleQuotes TEMP2,%!TEMP
db TEMP1
db TEMP2
Last but not least, a "cleaner" solution would add
both %TOK2STR and %STR2TOK, to perform conversion
between token(s) and strings. (That is, your %STRING
should be accompanied by its opposite directive.)
Logged In: NO
> Take a look at SF RFE #829879
While I guess that would work, I like my solution better for these reasons:
The %string directive is useful for other things as well, for example I also
wrote a macro to call procedures, like "proccall function, x, [y]" which wants to
see if the first character of each operand is '[' so that it knows if it's dealing
with an effective address or not, but in order to use %substr, the parameters
first have to be strings.
So since there would be a %string directive for other purposes, then simply
allowing strings as operands to %undef and %delete (as well as all of the
other directives) seems like a more logical way of passing unexpandable
macro identifiers to them. It doesn't require creation of a new token type, but
instead uses one which was otherwise invalid in those contexts. Not to
mention, it just makes sense that %undef 'mac' should delete the macro mac
instead of complain about an invalid operand. As an added bonus, 'mac' is a
lot easier to look at than %#mac.
%delete is still necessary in either case, for example, with the create and
destroy macros from above, "create x" would do "%define %$var %#%1" and,
if I understand things correctly, the %1 would expand despite the %# being in
front of it, so that "%#x" would be assigned to %$var. (If it doesn't, then %#
won't work as a replacement for my solution.) However, then in the destroy
macro, changing "%delete %$var" to "%undef %$var" won't expand %$var into
%#x. We could get around this by writing a delete macro, since the
expansion would occur in the macro call, however, having %delete seems a lot
nicer than making people have to make their own delete macro.
Anyway, the "%xdefine %$single '" thing is an interesting hack, but it seems
like relying on the fact that NASM will assign a value to %$string despite the
error, and I don't like depending on the results of errors.
The best hack-type solution I came up with was to do this:
%define save %1
%define %1 %1 + ebp + 8
%1 equ 0
Which makes whatever %1 was (say it was 'var') expand to "var + ebp + 8",
and then expansion stops there to prevent recursion, and the assembler treats
var as 0, so it's effectively ignored. Then to delete it you do this:
delete save
Where delete is a macro that does an %undef, so that "save" becomes "var +
ebp + 8" and %undef deletes "var", while complaining about extra garbage
after the macro identifier.
That almost worked, but hacked solutions have a way of falling apart under the
right conditions, and so did that solution. Say I had a macro like this:
%macro proccall 1-*
%rep %0 - 1
%rotate -1
push %1
%endrep
%rotate -1
call %1
add esp, 4 * %0 - 4
%endmacro
In that case, when I passed 'var' to it, it would expand to "var + ebp + 8" and
then later when the push instruction was generated, it would expand again, to
"var + ebp + 8 + ebp + 8".
Also, during the six hours of trying to make this work without NASM
modifications, I discovered that this:
%xdefine x y
%define y z
Makes macro x work exactly the same as it would if I had done this:
%define x y
%define y z
While I understand why it does that, it does seem contrary to the intended
purpose of %xdefine. It could be corrected with some sort of flag to mark the
contents of macro x as unexpandable when x is defined with %xdefine, and in
doing so it would also remove the need for %string and %#, since you could
do this instead:
%xdefine x y
%define y z
%delete x
And the "%delete x" would expand to "%delete y", but 'y' wouldn't expand to
'z' since the contents of 'x' are unexpandable, and so it would "%delete y" as
desired.
It seems easy enough to do, when you're expanding macros, simply don't
expand %xdefine'd macros until all of the other macros are expanded, then
expand them but don't look at the string again after that. However, I'm not sure
if such a modification to %xdefine's behavior would be desireable or not.
> would add both %TOK2STR and %STR2TOK
Should I assume then that it will be called %tok2str, and go ahead and update
my code to reflect that?
Logged In: YES
user_id=804543
> [%STRING is useful]
Absolutely.
> [directives that accept identifiers should accept strings]
As an additional twist, imagine that the preprocessor were
capable of expanding identifiers handed to directives. That
is, accept identifiers, preprocessor identifiers, numbers,
as well as tokens which result in token separation, token
concatenation, prohibition of smac expansion, or recursion.
(If you look through the various SF RFEs: %<, %>, %#, %^.)
In other words: the final identifier can be the result of
various operations.
Don't choke, but I've got such a beast. :-)
> [%DELETE]
I need to think about this one some more.
> [%TOK2STR and %STR2TOK]
I merely wanted to point out that these form a pair, and
which names I picked for them.