News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

2 arguments from a vararg at a time (macro's)

Started by gelatine1, October 13, 2015, 02:18:47 AM

Previous topic - Next topic

gelatine1

So I am trying to write a macro and I found this http://www.masmforum.com/board/index.php?PHPSESSID=786dd40408172108b65a5a36b09c88c0&topic=18885.0. In that post jj2007 uses the FOR item,<args> to get one of the arguments at a time. I would like to be able to get 2 arguments at a time. Is that possible or not? Sample code below:


procR4 MACRO count:DWORD,args:VARARG
mov eax,count
        test eax,1
and eax,1 ;is count even ?
;which of the 2 is the fastest ?
;or would bt be faster ?
jnz @invalidcount
FOR item, <args>

        ;I would like to use 2 of the arguments at a time here.
    ENDM

@invalidcount:
        ;the messagebox isnt important here
;invoke MessageBox,0,addr error6t,addr error6t,MB_OK
ENDM


Thanks in advance

qWord

As usual there are many ways to do that, below one possible solution. Also, from your code I've got the impression that you maybe mix up what is done at runtime and what while assembling(?) - the count of arguments can be determined while assembling:
procR4 MACRO args:VARARG
LOCAL count,cntr,item1

count = 0
FOR item,<args>
count = count + 1
ENDM
IF count AND 1 ;; OR count EQ 0
.err <invalid argument !count>
EXITM
ENDIF

cntr = 0
FOR item2, <args>
IF cntr EQ 0
item1 TEXTEQU <item2>
ELSE

; --- your code goes here ---
; item1 is text macro holding first item
; item2 is replaced with second item

% echo <item1,item2>

ENDIF
cntr = cntr XOR 1
    ENDM

ENDM
MREAL macros - when you need floating point arithmetic while assembling!

gelatine1

Quote from: qWord on October 13, 2015, 03:58:24 AM
As usual there are many ways to do that, below one possible solution. Also, from your code I've got the impression that you maybe mix up what is done at runtime and what while assembling(?) - the count of arguments can be determined while assembling:

Thanks for the reply and yes that is perfectly possible (this is actually the first time I am writing macros... so I don't really know what happens at rune time and what happens while assembling. So you mean that all of the following code happens while assembling? I thought the counting would (slightly) slowdown my program..
I was also wondering what the meaning of the TEXTEQU is? the arguments passed would usually be a DWORD.


FOR item,<args>
count = count + 1
ENDM
IF count AND 1 ;; OR count EQ 0
.err <invalid argument !count>
EXITM
ENDIF

rrr314159

Yes, all that code is executed while assembling; no, it doesn't slow down the running program at all.

item1 TEXTEQU <item2>

- This assigns the literal value of item2 (for instance, it might be "My_Variable_Name") to item1. It has nothing to do with the value of that variable at run-time (for instance, "123456" or "123.456"); it's only the literal text-string that gets assigned. Of course item2 is left unchanged.

- TEXTEQU is to be distinguished from "EQU" and "=", which do similar but different jobs. Thus

count = count + 1

- assigns the numeric value of the assembly-time "symbol" count, plus 1, to count. Has nothing to do with run-time; in fact, "count" doesn't even exist at run-time.

- "EQU" does both jobs, in certain circumstances ... can be substituted for "TEXTEQU" in above statement; can be substituted for "=" in some cases ... Probably only qWord knows all the details, you don't have to worry about it for now

I am NaN ;)

gelatine1

Thanks for explaining pi r³ (never realised the meaning of your name before  :bgrin:). One more thing I forgot to ask... I would like to create a macro similar to the invoke macro and therefore I would like to take the arguments from the last to the first instead of from the first to the last, how should it be done ?

rrr314159

One way to do it, from ... I forget who,

argrev MACRO arglist:vararg
    LOCAL txt, arg
    txt TEXTEQU <>
   FOR arg, <arglist>
        txt CATSTR <arg>, <,>, txt
    ENDM
    txt SUBSTR txt, 1, @SizeStr( %txt ) - 1
    EXITM txt
ENDM


For invoke macro check out my nvk macro
I am NaN ;)

qWord

rrr314159,
the macro does not take care for the case that arglist is blank. "IFNB txt" around SUBSTR should fix it.

gelatine1,
I would suggest you to use "=" for variable values, EQU for (assembly-time) constant numeric values (or expressions) and TEXTEQU for any text. Actual this kind of usage is documented in the programmers guide.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

Another way to do it (if I understood correctly what you want). Note the code doesn't do anything, it just echos the args during assembly.

@invalidcount is local to the macro, otherwise you could use the macro only once.

include \masm32\include\masm32rt.inc ; plain Masm32 for the fans of pure assembler

procR4 MACRO count, args:VARARG
Local ct, @invalidcount
  mov eax,count
  test eax,1
  and eax,1 ;is count even ?
  ;which of the 2 is the fastest ?
  ;or would bt be faster ?
  jnz @invalidcount
  ct=1
  FOR item, <args>
if ct and 1 ; odd?
echo First arg= [item]
else
echo Second arg=[item]
echo
endif
ct=ct+1
  ;I would like to use 2 of the arguments at a time here.
  ENDM
@invalidcount:
ENDM

.code
start:
procR4 ecx, arg1A, arg1B, arg2A, arg2B, arg3A, arg3B
; procR4 ecx, arg1A, arg1B, arg2A, arg2B, arg3A, arg3B
exit
end start


This is what you see in the build output window:
***********
ASCII build
***********

First arg= [arg1A]
Second arg=[arg1B]

First arg= [arg2A]
Second arg=[arg2B]

First arg= [arg3A]
Second arg=[arg3B]

First arg= [arg1A]
Second arg=[arg1B]

First arg= [arg2A]
Second arg=[arg2B]

First arg= [arg3A]
Second arg=[arg3B]

rrr314159

You're right qWord; you know that comes straight from Microsoft, many years ago. If you look at my nvk macro, it's fixed there; I'd forgotten that had to be done. Anyway here it is in a simple sample program,

include \masm32\include\masm32rt.inc

argrev MACRO arglist:vararg
    LOCAL txt, arg
    txt TEXTEQU <>
   FOR arg, <arglist>
        txt CATSTR <arg>, <,>, txt
    ENDM
    IFNB txt
        txt SUBSTR txt, 1, @SizeStr( %txt ) - 1
    ENDIF
    EXITM txt
ENDM

%echo argrev (one, two, three, four) ; these will come out reversed
%echo argrev()      ; no error with no arguments, due to "IFNB txt" line

.code
start:

; note there's no run-time code, it all happens at assembly time

ret
end start
I am NaN ;)

gelatine1

#9
Thank you very much for the replies ;). So I was also wondering when I try to use the code qWord wrote (with procR4 3,2 for example) then the assembler gives me the error "syntax error : integer" What does this mean and how do I solve it ?

EDIT:
I used the following code:

procR4 MACRO args:VARARG
LOCAL count,cntr,item1
args TEXTEQU arrgrev(args)

count = 0
FOR item,<args>
count = count + 1
ENDM
IF count AND 1 ;; OR count EQ 0
.err <invalid argument !count>
EXITM
ENDIF

cntr = 0
FOR item2, <args>
IF cntr EQ 0
item1 TEXTEQU <item2>
ELSE
% echo <item1,item2>

ENDIF
cntr = cntr XOR 1
    ENDM

ENDM


I have another question about a macro I am trying to write. I currently have this macro:


R4 MACRO a,b  ;pushes a/b in real4 format onto the stack
mov aa,a
mov bb,b
fild aa
fild bb
fdivp st(1),st
sub esp,4
fstp dword ptr [esp]
ENDM


This uses much code which gets executed at runtime so I was thinking If it would be possible to do something shorter like this:


R4T MACRO a,b ;should return a/b
                            ;could be called as push R4T(3,2)
    LOCAL cnt
    cnt = a/b
    EXITM %cnt
ENDM


But that seems to do an integer division (maybe I should change the % sign there before cnt?).
I was also thinking about this but when I call R4TT 3,2 for example I would get the error "immediate operand not allowed"


R4TT MACRO a,b  ;pushes a/b in real4 format onto the stack
LOCAL aa,bb
aa=a
bb=b

fild aa
fild bb
fdivp st(1),st
sub esp,4
fstp dword ptr [esp]
ENDM


So is there anyone who could suggest a good way to do it or is the R4 Macro one of the best possible macros to achieve this?

rrr314159

Quote from: gelatine1the assembler gives me the error "syntax error : integer" What does this mean and how do I solve it ?

- you're ignoring the part where qWord wrote

; --- your code goes here ---
; item1 is text macro holding first item
; item2 is replaced with second item


- As jj2007 pointed out,

QuoteNote the code doesn't do anything, it just echos the args during assembly.

- You must have called the macro in your code so it tried to execute the "command" 3,2 (echoed from the macro) - that's no good. Remove the echo statement, replace with code which does what you want with item1 and item2.

- And I think the error statement says "syntax error : 3" ... ?

- Re. the R4 macro, your attempted simplifications are ignoring the difference between compile-time and run-time code; the original R4 is correct (assuming aa and bb are declared DWORDS), you can't simplify it like that
I am NaN ;)

gelatine1

Quote from: rrr314159 on October 14, 2015, 05:49:54 AM
- And I think the error statement says "syntax error : 3" ... ?

Nope, it says "syntax error: Integer" quite literally :/ I believe the error lies somewhere in the argrev macro but I can't seem to figure out how.
My procR4 macro looks like this now:

procR4 MACRO prc:REQ,args:VARARG ;pushes all arguments on the stack in the form first/second
;in real 4 format. Don't forget to use argrev()! example:
;procR4 dummy,argrev(5,2) Will push 5/2 onto the stack and call dummy
LOCAL count,cntr,item1
;args TEXTEQU argrev(args)   ; I would like to be able to use this inside the macro
count = 0
FOR item,<args>
count = count + 1
ENDM

IF count AND 1 ;; OR count EQ 0
.err <invalid argument !count>
EXITM
ENDIF

cntr = 0
FOR item1, <args>
IF cntr EQ 0
item2 TEXTEQU <item1>
ELSE
R4 item1,item2
ENDIF
cntr = cntr XOR 1
    ENDM
call prc
ENDM


And I use the macro like this (for example) :


procR4 glTranslatef,argrev(0,1,0,1,-5,1)


But If I remove the comment before 'args TEXTEQU argrev(args)' and use my macro like this:

procR4 glTranslatef,0,1,0,1,-5,1


I get the 'syntax error: integer again'. I would like to do this because I don't want to keep writing argrev inside my code..

Thanks in advance

rrr314159

Quote from: gelatine1Nope, it says "syntax error: Integer" quite literally

- strange, I'm using JWasm, says "3" not "Integer"

Anyway here's one way to handle the question, I modified the older ProcR4, make the corresponding changes to the new one, in the four lines that contain "args2"

procR4 MACRO args:VARARG
LOCAL count,cntr,item1, args2
args2 equ argrev(args)

count = 0
% FOR item,<args2>
count = count + 1
ENDM
IF count AND 1 ;; OR count EQ 0
.err <invalid argument !count>
EXITM
ENDIF

cntr = 0
% FOR item2, <args2>
IF cntr EQ 0
item1 TEXTEQU <item2>
ELSE
% echo <item1,item2>

ENDIF
cntr = cntr XOR 1
    ENDM
I am NaN ;)

qWord

gelatine1,

in the macro body, any occurrence of parameter args is replaced wit the arguments of call, thus the line
args TEXTEQU argrev(args)
is converted to
3,2 TEXTEQU argrev(3,2)
I guess now its clear where there error comes from...
You should take look at the MASM programmers guide, Chapter 9: "Using Macros".

Quote from: gelatine1 on October 13, 2015, 08:17:28 PM
This uses much code which gets executed at runtime so I was thinking If it would be possible to do something shorter like this:


R4T MACRO a,b ;should return a/b
                            ;could be called as push R4T(3,2)
    LOCAL cnt
    cnt = a/b
    EXITM %cnt
ENDM


But that seems to do an integer division (maybe I should change the % sign there before cnt?).
MASM it self does not have the capacity to calculate with FP values while assembling, however, with a lot of MACRO power it is possible - if you have no qualms in using 3rd party macros, take look here.
Quote from: gelatine1 on October 13, 2015, 08:17:28 PMI was also thinking about this but when I call R4TT 3,2 for example I would get the error "immediate operand not allowed"
There are no FPU instructions to load immediate values into FPU-registers. Nearly all interaction with non-FPU code must be done through memory operands.
MREAL macros - when you need floating point arithmetic while assembling!