The MASM Forum

General => The Campus => Topic started by: Rav on June 28, 2022, 05:44:10 AM

Title: What am I doing wrong in the creation and use of this macro?
Post by: Rav on June 28, 2022, 05:44:10 AM
I'm using Visual Studio version 17.2.5 (the latest as of this moment).  I'm trying to create a simple macro to delete a leading blank, if any, off of one of the arguments to the macro, and I'm having trouble getting it to even assemble (let alone work).  I'm pretty new to writing macros.  Here's the relevant fragment of my test program:

; ==================================================
.model flat, stdcall

.DATA
.CODE

MyProc   proc   near


mTest MACRO mystr

char SUBSTR <mystr>,1,1   ; Get first char.
IFIDN char,< >         ; If first char is blank ...
%mystr% SUBSTR <mystr>,2   ; ... delete leading blank.
ENDIF

xor eax,eax ; (Any instruction before - irrelevant what)
mystr      ; This line in the assembled code should be   cmp eax,123   with NO leading blank.
xor eax,eax ; (Any instruction after - irrelevant what)
      
ENDM


mTest < cmp eax,123> ; Argument has a leading blank.
ret

MyProc endp
end MyProc

; ==================================================

When I attempt to assemble it, I get "syntax error: SUBSTR".  Here's what the macro expanded to when I invoked it:

% cmp eax,123% SUBSTR < cmp eax,123>,2

Which is obviously wrong.  What am I doing wrong?  And is there a better way to do what I'm trying to do?  Thanks  / Rav
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: jj2007 on June 28, 2022, 06:18:31 AM
A few Rules for the Forum (https://www.jj2007.eu/Masm32_Tips_Tricks_and_Traps.htm)
Quote* Post your complete code. Some believe that older members are eager to construct the missing headers around your snippets, but this belief is FALSE
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: Rav on June 28, 2022, 06:27:22 AM
Quote from: jj2007 on June 28, 2022, 06:18:31 AM
A few Rules for the Forum (https://www.jj2007.eu/Masm32_Tips_Tricks_and_Traps.htm)
Quote* Post your complete code. Some believe that older members are eager to construct the missing headers around your snippets, but this belief is FALSE

Hi, jj2007.  This is the complete code.  It attempts to do just what I mentioned, which is delete the (possibly) leading blank from a macro argument.  That's all I need it to do.  Aside from the single line that errors out, the rest assembles fine.  Thanks.
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: HSE on June 28, 2022, 06:54:13 AM
.386
.model flat, stdcall
.CODE

mTest MACRO mystr

  xor eax,eax ; (Any instruction before - irrelevant what)
  char SUBSTR <mystr>,1,1   ; Get first char.
  IFIDN char,< >         ; If first char is blank ...
     mystr2 SUBSTR <mystr>,2   ; ... delete leading blank.
     mystr2      ; This line in the assembled code should be   cmp eax,123   with NO leading blank.
  ELSE
     mystr
  ENDIF
  xor eax,eax ; (Any instruction after - irrelevant what)
ENDM

MyProc   proc
   mTest < cmp eax,123> ; Argument has a leading blank.
   ret
MyProc endp
end MyProc
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: jj2007 on June 28, 2022, 07:12:47 AM
Quote from: Rav on June 28, 2022, 06:27:22 AMHi, jj2007.  This is the complete code.

Oh, really? Why does the assembler spit out so many error messages then?

*** Assemble using mlv614  ***
Assembling: tmp_file.asm
tmp_file.asm(2) : error A2085: instruction or register not accepted in current CPU mode
tmp_file.asm(4) : error A2013: .MODEL must precede this directive
tmp_file.asm(5) : error A2013: .MODEL must precede this directive
tmp_file.asm(7) : error A2034: must be in segment block : MyProc
tmp_file.asm(24) : error A2085: instruction or register not accepted in current CPU mode
mTest(4): Macro Called From
  tmp_file.asm(24): Main Line Code
tmp_file.asm(24) : error A2034: must be in segment block
mTest(7): Macro Called From
  tmp_file.asm(24): Main Line Code
tmp_file.asm(24) : error A2085: instruction or register not accepted in current CPU mode
mTest(8): Macro Called From
  tmp_file.asm(24): Main Line Code
tmp_file.asm(24) : error A2034: must be in segment block
mTest(9): Macro Called From
  tmp_file.asm(24): Main Line Code
tmp_file.asm(25) : error A2034: must be in segment block
tmp_file.asm(27) : fatal error A1010: unmatched block nesting : MyProc
*** Assembly error ***
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: NoCforMe on June 28, 2022, 07:24:55 AM
See, this is why I don't even bother with MASM macros unless my back is up against the wall. Learning the rules of using them makes my head hurt (even more than learning all the other rules of assembly-language programming). All that expansion and transformation crap ...
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: HSE on June 28, 2022, 07:34:33 AM
Quote from: NoCforMe on June 28, 2022, 07:24:55 AM
See, this is why I don't even bother with MASM macros unless my back is up against the wall. Learning the rules of using them makes my head hurt (even more than learning all the other rules of assembly-language programming). All that expansion and transformation crap ...

CPU was missing. It's a beginner common error.
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: NoCforMe on June 28, 2022, 07:56:46 AM
Quote from: HSE on June 28, 2022, 07:34:33 AM
Quote from: NoCforMe on June 28, 2022, 07:24:55 AM
See, this is why I don't even bother with MASM macros unless my back is up against the wall. Learning the rules of using them makes my head hurt (even more than learning all the other rules of assembly-language programming). All that expansion and transformation crap ...

CPU was missing. It's a beginner common error.

You're referring to the CPU in my head, right? Well, gotta admit it's a bit obsolete, possibly partially damaged, prone to unexplained behavior, etc.
I'm not a beginner, but would almost be if I had to delve into the dark world of MASM macos ...
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: HSE on June 28, 2022, 08:09:03 AM
Quote from: NoCforMe on June 28, 2022, 07:56:46 AM
You're referring to the CPU in my head, right?

:biggrin:  :biggrin: :biggrin:  In the head... of the file:.386
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: Rav on June 28, 2022, 08:28:56 AM
Quote from: jj2007 on June 28, 2022, 07:12:47 AM
Quote from: Rav on June 28, 2022, 06:27:22 AMHi, jj2007.  This is the complete code.

Oh, really? Why does the assembler spit out so many error messages then?

*** Assemble using mlv614  ***
Assembling: tmp_file.asm
tmp_file.asm(2) : error A2085: instruction or register not accepted in current CPU mode
tmp_file.asm(4) : error A2013: .MODEL must precede this directive
tmp_file.asm(5) : error A2013: .MODEL must precede this directive
tmp_file.asm(7) : error A2034: must be in segment block : MyProc
tmp_file.asm(24) : error A2085: instruction or register not accepted in current CPU mode
mTest(4): Macro Called From
  tmp_file.asm(24): Main Line Code
tmp_file.asm(24) : error A2034: must be in segment block
mTest(7): Macro Called From
  tmp_file.asm(24): Main Line Code
tmp_file.asm(24) : error A2085: instruction or register not accepted in current CPU mode
mTest(8): Macro Called From
  tmp_file.asm(24): Main Line Code
tmp_file.asm(24) : error A2034: must be in segment block
mTest(9): Macro Called From
  tmp_file.asm(24): Main Line Code
tmp_file.asm(25) : error A2034: must be in segment block
tmp_file.asm(27) : fatal error A1010: unmatched block nesting : MyProc
*** Assembly error ***


I don't know why it does that for you, jj2007.  I get none of those errors here.  Only the "syntax error: SUBSTR".
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: Rav on June 28, 2022, 08:39:04 AM
Quote from: HSE on June 28, 2022, 06:54:13 AM
.386
.model flat, stdcall
.CODE

mTest MACRO mystr

  xor eax,eax ; (Any instruction before - irrelevant what)
  char SUBSTR <mystr>,1,1   ; Get first char.
  IFIDN char,< >         ; If first char is blank ...
     mystr2 SUBSTR <mystr>,2   ; ... delete leading blank.
     mystr2      ; This line in the assembled code should be   cmp eax,123   with NO leading blank.
  ELSE
     mystr
  ENDIF
  xor eax,eax ; (Any instruction after - irrelevant what)
ENDM

MyProc   proc
   mTest < cmp eax,123> ; Argument has a leading blank.
   ret
MyProc endp
end MyProc


Thank you, HSE.  While what you provided works (which is a great step in the right direction), the output isn't exactly what I had wanted.  When I use ML.EXE to assemble your routine (ML /Fl /c test.asm), the test.lst output file contains the following:

00000000         MyProc   proc
               mTest < cmp eax,123> ; Argument has a leading blank.
00000000  33 C0        1     xor eax,eax ; (Any instruction before - irrelevant what)
00000002  83 F8 7B        1       mystr2      ; This line in the assembled code should be   cmp eax,123   with NO leading blank.
00000005  33 C0        1     xor eax,eax ; (Any instruction after - irrelevant what)
00000007  C3            ret
00000008         MyProc endp

So while the object code contains the correct instructions (83 F8 7B, which is cmp eax,123), the LISTING contains " mystr2" (notice the leading blank, by the way), not "cmp eax,123" as desired (and with no leading blank).  I want the listing to contain the source of the assembled code, not the name of the variable that contains it.  I hope that makes sense.  If this isn't possible I'll make do without it -- not the end of the world.
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: HSE on June 28, 2022, 09:31:03 AM
Try to force expansion, ej.: IFIDN char,< >         ; If first char is blank ...
     mystr2 SUBSTR <mystr>,2   ; ... delete leading blank.
     %mystr2      ; This line in the assembled code should be   cmp eax,123   with NO leading blank.
  ELSE
     mystr
  ENDIF
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: Rav on June 28, 2022, 10:06:04 AM
Quote from: HSE on June 28, 2022, 09:31:03 AM
Try to force expansion, ej.: IFIDN char,< >         ; If first char is blank ...
     mystr2 SUBSTR <mystr>,2   ; ... delete leading blank.
     %mystr2      ; This line in the assembled code should be   cmp eax,123   with NO leading blank.
  ELSE
     mystr
  ENDIF


Thanks, but all that did was add the % character onto the front of the line, so now the line in the listing file is this:

%mystr2 ; This line in the assembled code should be   cmp eax,123   with NO leading blank.

No need to spend any more time on this.  I was just hoping it could be done.  It's not a show-stopper.  Thanks again.  / Rav
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: jj2007 on June 28, 2022, 10:08:36 AM
Quote from: Rav on June 28, 2022, 08:28:56 AMI don't know why it does that for you, jj2007.  I get none of those errors here.  Only the "syntax error: SUBSTR".

You didn't post the complete code. You posted untested code that could never have assembled without errors on your machine, that's why I refuse to even look at such code.

Here is what works for you:

mTest MACRO mystr
  Local char, mystr2
  char SUBSTR <mystr>,1,1   ; Get first char.
  IFIDN char,< >         ; If first char is blank ...
mystr2 SUBSTR <mystr>,2   ; ... delete leading blank.
  ELSE
mystr2 equ <mystr>
  ENDIF

  xor eax,eax ; (Any instruction before - irrelevant what)
  mystr2      ; This line in the assembled code should be   cmp eax,123   with NO leading blank.
  xor eax,eax ; (Any instruction after - irrelevant what)
ENDM


You cannot change a macro argument.
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: Rav on June 28, 2022, 10:37:56 AM
Quote from: jj2007 on June 28, 2022, 10:08:36 AM
Quote from: Rav on June 28, 2022, 08:28:56 AMI don't know why it does that for you, jj2007.  I get none of those errors here.  Only the "syntax error: SUBSTR".

You didn't post the complete code. You posted untested code that could never have assembled without errors on your machine, that's why I refuse to even look at such code.

Here is what works for you:

mTest MACRO mystr
  Local char, mystr2
  char SUBSTR <mystr>,1,1   ; Get first char.
  IFIDN char,< >         ; If first char is blank ...
mystr2 SUBSTR <mystr>,2   ; ... delete leading blank.
  ELSE
mystr2 equ <mystr>
  ENDIF

  xor eax,eax ; (Any instruction before - irrelevant what)
  mystr2      ; This line in the assembled code should be   cmp eax,123   with NO leading blank.
  xor eax,eax ; (Any instruction after - irrelevant what)
ENDM


You cannot change a macro argument.

Once again:  I DID post complete code.  I DID test the code I posted.  There IS NO OTHER CODE.  The only error I got during assembly of the code that I posted was "syntax error: SUBSTR".  There were NO OTHER ERRORs.  And getting that ONE error was WHY I made my original post.  Why you got a bunch of errors that I did NOT get is unknown to me.  I did not get those errors.
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: jj2007 on June 28, 2022, 11:10:02 AM
Quote from: Rav on June 28, 2022, 10:37:56 AMOnce again:  I DID post complete code.  I DID test the code I posted.  There IS NO OTHER CODE.  The only error I got during assembly of the code that I posted was "syntax error: SUBSTR".  There were NO OTHER ERRORs.  And getting that ONE error was WHY I made my original post.  Why you got a bunch of errors that I did NOT get is unknown to me.  I did not get those errors.

OK, mystery solved - my apologies: you did not get those errors because you are using a very recent version of ML.exe which, apparently, does no longer need the usual .686p at the start of the file. That makes your code incompatible with the setups of most but not all members here. The Masm32 SDK comes with ML version 6.14; all MASM versions up to version 9.0 need the .*86, same for the Watcom gang.

My advice: add a .686p on top of all your sources. Visual Crap may not need it, but you can spare yourself such negative experiences.

And keep in mind that you cannot change a macro argument, as explained earlier. It will choke.

Technically speaking, you can change a proc argument, though:

MyTest proc zStringPtr:DWORD
  mov zStringPtr, 123


However, you should never do that, it's considered bad and risky coding.
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: Rav on June 28, 2022, 11:24:35 AM
Quote from: jj2007 on June 28, 2022, 11:10:02 AM
Quote from: Rav on June 28, 2022, 10:37:56 AMOnce again:  I DID post complete code.  I DID test the code I posted.  There IS NO OTHER CODE.  The only error I got during assembly of the code that I posted was "syntax error: SUBSTR".  There were NO OTHER ERRORs.  And getting that ONE error was WHY I made my original post.  Why you got a bunch of errors that I did NOT get is unknown to me.  I did not get those errors.

OK, mystery solved - my apologies: you did not get those errors because you are using a very recent version of ML.exe which, apparently, does no longer need the usual .686p at the start of the file. That makes your code incompatible with the setups of most but not all members here. The Masm32 SDK comes with ML version 6.14; all MASM versions up to version 9.0 need the .*86, same for the Watcom gang.

My advice: add a .686p on top of all your sources. Visual Crap may not need it, but you can spare yourself such negative experiences.

And keep in mind that you cannot change a macro argument, as explained earlier. It will choke.

Technically speaking, you can change a proc argument, though:

MyTest proc zStringPtr:DWORD
  mov zStringPtr, 123


However, you should never do that, it's considered bad and risky coding.

Thanks for saying that -- I appreciate it.  And thanks for the additional info.
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: NoCforMe on June 28, 2022, 11:34:50 AM
Quote from: jj2007 on June 28, 2022, 11:10:02 AM
Technically speaking, you can change a proc argument, though:

MyTest proc zStringPtr:DWORD
  mov zStringPtr, 123


However, you should never do that, it's considered bad and risky coding.

Just to address this small issue, was reading about this the other day and the writer said that procedure arguments are basically the same as local variables; they're all on the stack, it's just that arguments get set by the caller. So no harm, no foul if you change an argument--just so long as you're sure you're never going to need it again, 'cause you can't get it back once you've overwritten it. Amiright?
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: hutch-- on June 28, 2022, 01:11:35 PM
Rav,

Macros have their uses if you are used to writing them but stripping leading blanks or tabs from text is best done with a tiny loop where you start at the beginning of the string and scan through the start of the string until the next character is neither a space (ascii 32) or a tab (ascii 9). Code of this type is both tiny and fast.

    mov ecx, pstr                       ; load the string
    sub ecx, 1                          ; set up for loop

  @@:
    add ecx, 1
    cmp BYTE PTR [ecx], 32              ; test for space
    jne @F
    cmp BYTE PTR [ecx], 9               ; test for tab
    jne @B

  @@:
Title: Re: What am I doing wrong in the creation and use of this macro?
Post by: hutch-- on June 28, 2022, 01:27:47 PM
Here is the complete example.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    sptrim PROTO sptr:DWORD,buffr:DWORD


    .data
      MyString db "        12345678",0      ; the string
      pstr dd MyString                      ; its pointer
      buffer db "                         " ; buffer
      pbuf dd buffer                        ; its pointer

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL pout :DWORD

    print pstr,13,10

    invoke sptrim,pstr,pbuf
    mov pout, eax

    print pout, 13, 10

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

sptrim proc sptr:DWORD,buffr:DWORD

    mov ecx, sptr                       ; load the string
    sub ecx, 1                          ; set up for loop

  @@:
    add ecx, 1
    cmp BYTE PTR [ecx], 32              ; test for space
    jne @F
    cmp BYTE PTR [ecx], 9               ; test for tab
    jne @B

  @@:
    mov edx, buffr
    sub ecx, 1
    sub edx, 1

  @@:
    add ecx, 1
    add edx, 1
    mov al, BYTE PTR [ecx]
    mov BYTE PTR [edx], al
    test al, al
    jnz @B

    mov eax, buffr

    ret 8

sptrim endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start