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
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
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.
.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
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 ***
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 ...
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.
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 ...
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
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".
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.
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
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
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.
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.
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.
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.
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?
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
@@:
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