NASM - The Netwide Assembler

NASM Forum => Using NASM => Topic started by: Zdenek Sojka on February 27, 2009, 02:01:29 AM

Title: problems with 'certain' macro parameters
Post by: Zdenek Sojka on February 27, 2009, 02:01:29 AM
Recently I finally decided to upgrade from nasm-0.96.39 to nasm-2.05.01, and my code doesn't compile anymore:

%macro once 1
%ifdef def%1
 %error defined
%endif
;%define def%1 ; something like this is in the actual code,
;%define xxx%1 (%2) ; but it is not needed to show the changed behaviour
%endmacro

once 1
once 8F

once 3E ;error
once 8E ;error

once 3EA ;error

When the parameter is of form "(numbers)E(anything)", nasm-2 fails with error:
tst.asm:10: error: (once:1) `%ifdef' expects macro identifiers

Is there a way to fix that inside the macro 'once'?
Changing that at every place where that macro is used means changing several thousands of places where it is used, and also places where those defined 'one-line macros' def%1/xxx%1 are used.
Title: Re: problems with 'certain' macro parameters
Post by: Frank Kotler on February 27, 2009, 07:32:58 AM
Oh, my! That's an interesting one. After looking at the changed code, and thinking about it a bit, I have come to the conclusion that it's a bug in Nasm. In Nasm-0.98.39 (I assume -0.96.39 was a typo), though, not in recent Nasm. I don't think Nasm should have been letting you use "(numbers)(anything not a number)" in the first place - with or without an 'E'.

That may not be the correct viewpoint however. Strictly speaking, "(numbers)E(anything)" is not a correct formulation of what's broken. If 'h' (either case) follows the 'E' (either case), Nasm decides that's okay. "once 3ehx" works. So perhaps you're "supposed" to be able to start macro parameters with a numeral... even if it isn't a valid number of any kind. You're not "supposed" to be able to do it with a "regular identifier".

So, I dunno, maybe Nasm is just being too quick to decide that anything with an 'e' in it is "is_float = true;"  Somewhere in here... (preproc.c 876)

} else if (isnumstart(*p)) {
       bool is_hex = false;
       bool is_float = false;
       bool has_e = false;
       char c, *r;

/*
             * A numeric token.
             */

if (*p == '$') {
      p++;
      is_hex = true;
       }

for (;;) {
      c = *p++;

if (!is_hex && (c == 'e' || c == 'E')) {
          has_e = true;
          if (*p == '+' || *p == '-') {
         /* e can only be followed by +/- if it is either a
            prefixed hex number or a floating-point number */
         p++;
         is_float = true;
          }
      } else if (c == 'H' || c == 'h' || c == 'X' || c == 'x') {
          is_hex = true;
      } else if (c == 'P' || c == 'p') {
          is_float = true;
          if (*p == '+' || *p == '-')
         p++;
      } else if (isnumchar(c) || c == '_')
          ; /* just advance */
      else if (c == '.') {
          /* we need to deal with consequences of the legacy
             parser, like "1.nolist" being two tokens
             (TOK_NUMBER, TOK_ID) here; at least give it
             a shot for now.  In the future, we probably need
             a flex-based scanner with proper pattern matching
             to do it as well as it can be done.  Nothing in
             the world is going to help the person who wants
             0x123.p16 interpreted as two tokens, though. */
          r = p;
          while (*r == '_')
         r++;

if (nasm_isdigit(*r) || (is_hex && nasm_isxdigit(*r)) ||
         (!is_hex && (*r == 'e' || *r == 'E')) ||
         (*r == 'p' || *r == 'P')) {
         p = r;
         is_float = true;
          } else
         break;   /* Terminate the token */
      } else
          break;
       }
       p--;   /* Point to first character beyond number */

if (has_e && !is_hex) {
      /* 1e13 is floating-point, but 1e13h is not */
      is_float = true;
       }

type = is_float ? TOK_FLOAT : TOK_NUMBER;
        } else if (nasm_isspace(*p)) {
-------------------------

I'm not sure of the "intent" of your macro parameters....

once foo

... definitely not a number - an identifier.

once 1

... a number

once 8F

...??? but Nasm eats it...

once 3Ez

... nasm thinks it's a float??? and barfs

once 3ehx

... 'cause the 'h' is in there, "is_hex = true;" and Nasm eats it again.

At this point, I'm so confused I don't know what we "want" Nasm to do... nor what you "want" to do with these "neither fish nor fowl" parameters...

Best,
Frank
Title: Re: problems with 'certain' macro parameters
Post by: Zdenek Sojka on February 27, 2009, 12:53:03 PM
Thank you for your quick reply and a nice explanation, Frank!

I think I thought macro parameters are passed as strings and any evaluation is done after replacing %1 tokens in the macro.

Anyway, fixing my code won't be that hard with a proper regexp (or simple Find&Replace "once " -> "once Z").

Have a nice day,
Zdenek
Title: Re: problems with 'certain' macro parameters
Post by: Frank Kotler on February 27, 2009, 06:52:46 PM
Well, I copied your original post and my reply to the development team. Here's their take:

----------------------------
This looks like an error in token pasting.  Basically, right now it's
rejecting anything that looks like a floating-point number, even though
it's alphanumeric.

The real issue, of course, is that we're using token type as a proxy for
something else, which is "it's alphanumeric".

It's unambigously a bug and should be fixed.  It shouldn't even be all
that hard to fix.

-hpa
------------------------

Soooo... If you're willing to wait, it'll probably be fixed in a near-future version. If you can work around it, that will allow you/others to use "intermediate" (buggy) versions of Nasm... which *do* get distributed. If you can come up with a script ("shouldn't be hard"... but I don't speak regex) to prepend an underscore to anything that starts with a number... or some such... that might be your best bet. If that'll work for ya. If you're "stuck with" those names, I guess you're "stuck with" certain versions of Nasm, too. Bummer.

I didn't mention it, but I couldn't figure out any way to fix it in the macro (I'm not a sophisticated macro user). I may play with it some more, but if Nasm won't accept it, I don't see much we can do. I think you're right that parameters are passed as strings, and Nasm's getting confused evaluating "token type"...

Thanks for the feedback, Zdenek. We *do* test changes in code, but apparently not with (number)E(anything). Our users and their projects are our best "test suites", so keep the feedback coming!

Latest versions can always be found at http://www.nasm.us (http://www.nasm.us) in the "snapshots" section. That's where the "fix" will appear, when it comes along...

Best,
Frank