I have noticed that many macros are used as operands eg:
push GetLoWord(in_lParam)
push in_wParam
push in_hWnd
call addr_handler
In this case the macro is defined thus:
GetLoWord macro data32
mov eax, data32
and eax, 0000ffffh
exitm <eax>
endm
I am reliably assured that the first snippet will expand thus:
mov eax, data32
and eax, 0000ffffh
push eax
push in_wParam
push in_hWnd
call addr_handler
From this I deduce that when used as an operand (rather than an instruction which is the 'normal' form of macro use) a macro's body is expanded BEFORE the instruction mnemonic for which it is the 'operand' and the argument for exitm is placed where the macro is placed in the text. Am I correct in this? Is this always the case? I failed to find this fact in Chapter 9 of the MASM programmer's guide (v6.1). Does anybody know of where I might find the documentation on Macro expansion?
Thank you in anticipation,
Michael
It is implementation dependent but basically yes that is what actually happens.
I can not guess what was in the mind of MASM creators but i can tell you what I do in Solar Assembler in this case.
The encoding of push <macro_name> is postponed because a macro is detected and an recursive parser takes over and parses/encodes the macro body. When that parser returns the push encoding will continue and be finished up.
However at this time a "lot" of code was already generated by the macro body that could also contain another macro ... ;).
This makes sense because the assembler doesnt know which opcode to use until it knows the types of each parameter, so it cannot have emitted an opcode until the macro is expanded and the types are known.
Remember that there isnt a 1:1 correspendence with Intel syntax and opcodes. 'mov' definately maps to more than 1 opcode, as do most instructions.
Quote from: BogdanOntanu on November 02, 2007, 09:19:44 PM
The encoding of push <macro_name> is postponed because a macro is detected and an recursive parser takes over and parses/encodes the macro body. When that parser returns the push encoding will continue and be finished up.
However at this time a "lot" of code was already generated by the macro body that could also contain another macro ... ;).
Just for fun: This is a valid Basic code, with Rep$ being a "replace macro". The principle is the same: Tell the parser to look for the innermost element, expand it, look for the second-innermost element, etc...
My$=@Rep$("|",CrLf$,@Rep$("#EN",ElName$(1),@Rep$("#NE",STR$(nr_c&),@Rep$("#NI",STR$(ColVal&-EvCt&),t$))))+"."
Quote from: jj2007 on November 03, 2007, 09:07:55 AM
My$=@Rep$("|",CrLf$,@Rep$("#EN",ElName$(1),@Rep$("#NE",STR$(nr_c&),@Rep$("#NI",STR$(ColVal&-EvCt&),t$))))+"."
All I can say to that is... YUCK! :lol
Quote from: BogdanOntanu on November 02, 2007, 09:19:44 PM
The encoding of push <macro_name> is postponed because a macro is detected and an recursive parser takes over and parses/encodes the macro body. When that parser returns the push encoding will continue and be finished up.
Thanks for that comprehensive answer. It also answers how the FNMacros work. It is none intuitive, however, and could easily fool the neophyte who might not realise that the order of his instructions would be changed. I can see it as a very powerful featrure. It is a shame that somebody has not documented it.
Thanks again to all those responding.
Michael