Author Topic: Multiple instructions on one line macro.  (Read 11441 times)

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Multiple instructions on one line macro.
« Reply #15 on: October 10, 2016, 08:55:06 PM »
Here is a simple test that shows that it works OK calling a procedure which can process inline content. It seems that its only a problem with inline macros that are embedded in a parent macro.

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

    include \masm32\include64\masm64rt.inc

    .code

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

entry_point proc

    LOCAL var   :QWORD

    mi \
    mov rax, 100 : add rax, 100 : shl rax, 1 : mov var, rax : fn showit,var
    conout str$(var)," inline macro",lf

    waitkey

    invoke ExitProcess,0

    ret

entry_point endp

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

showit proc var:QWORD

    conout str$(var)," showit proc",lf

    ret

showit endp

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

    end
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Multiple instructions on one line macro.
« Reply #16 on: October 10, 2016, 08:57:34 PM »
It seems that its only a problem with inline macros that are embedded in a parent macro.

More precisely, function() macros, i.e. those that return something, get expanded in the moment when they are being passed as an argument, like e.g. Hex$() below. But even those can be kept on one line, provided they are <passed as strings>:
Code: [Select]
include \masm32\MasmBasic\MasmBasic.inc
      Init
      Dim PtrSSE() As DWORD
      For_ ct=0 To 99      ; 100 aligned pointers
            mcs Alloc16 Rand(10000) : mov PtrSSE(ct), eax : <Print Hex$(al), " ">
      Next
EndOfCode

Question is if users read the manual:

      - mcs allows to put several commands on one line, separated by a colon as in Basic
      - if macros depend on previous commands, like e.g. Str$(...), <put them in brackets>

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Multiple instructions on one line macro.
« Reply #17 on: October 10, 2016, 10:23:43 PM »
Problem is it does not work.

    LOCAL var   :QWORD

    mi \
    mov rax, 100 : add rax, 100 : shl rax, 1 : mov var, rax : fn showit,var
    conout str$(var)," inline macro",lf

    xor rax, rax
    mi \
    mov rax, 100 : <conout str$(rax)," this fails",lf,lf>

    waitkey

    invoke ExitProcess,0

    ret

Output is as follows.

400 showit proc
400 inline macro
0 this fails


It also fails on every variation of angle brackets.

Here is a further variation that still fails, it appears that ML64 always expands embedded macros before their parent macro.

    mtst MACRO arg:VARARG
    % echo arg
    ENDM
.............
    mtst mov rax, 100 : <conout str$(rax)>
    mtst <mov rax, 100 : conout str$(rax)>
    mtst mov rax, 100 : conout <str$(rax)>

All fail due to prior expansion.

hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Multiple instructions on one line macro.
« Reply #18 on: October 10, 2016, 11:42:47 PM »
I've made some ugly and complicated tests with your mi macro, and it seems the FORC is really the problem. Mine works fine with <conout str$(rax)>, apparently because <args> gets expanded only step by step, i.e. in @SubStr ::)

Code: [Select]
mcs MACRO args:VARARG   ; part of the MasmBasic package
Local isL, isR, isQ
  isR=0
  While 1
isL=isR+1
isQ INSTR isL, <args>, <"> ; xx : Print "Hello: a problem" : xx
isR INSTR isL, <args>, <:>
if isQ and isQ lt isR
isQ INSTR isQ+1, <args>, <">
isR INSTR isQ, <args>, <:>
endif
if isR
@SubStr(<args>, isL, isR-isL)
else
@SubStr(<args>, isL)
EXITM
endif
  ENDM
ENDM

Of course, you are welcome to use my code in your include files. Over time, I have taken so many ideas from your includes that it is a pleasure to give something back :icon14:
« Last Edit: October 11, 2016, 12:51:57 AM by jj2007 »

qWord

  • Member
  • *****
  • Posts: 1475
  • The base type of a type is the type itself
    • SmplMath macros
Re: Multiple instructions on one line macro.
« Reply #19 on: October 11, 2016, 04:03:36 AM »
An option is to delay the expansion by using wrappers for the function like macros. The result of an function like macro is no further expanded.

Code: [Select]
include \masm32\include\masm32rt.inc


mi TEXTEQU <__delay()>

__delay_expansion = 0

__delay macro
__delay_expansion = 1
EXITM <_mi>
endm

_mi macro args:VARARG

_mi_cmd TEXTEQU <args>
_mi_size SIZESTR <args>
_mi_pos = 1
_mi_colon_pos INSTR <args>,<:>
WHILE _mi_colon_pos NE 0
_mi_cmd SUBSTR <args>,_mi_pos, _mi_colon_pos - _mi_pos

__delay_expansion = 0
% &_mi_cmd
__delay_expansion = 1

_mi_pos = _mi_colon_pos + 1
_mi_colon_pos INSTR _mi_pos,<args>,<:>
ENDM
IF _mi_pos LE _mi_size
_mi_cmd SUBSTR <args>,_mi_pos
__delay_expansion = 0
% &_mi_cmd
__delay_expansion = 1
ENDIF

__delay_expansion = 0
endm

myStr$ macro arg
IFE __delay_expansion
EXITM str$(arg)
ELSE
EXITM <str$(arg)>
ENDIF
endm

myCmd$ macro arg
IFE __delay_expansion
EXITM cmd$(arg)
ELSE
EXITM <cmd$(arg)>
ENDIF
endm


.code
main proc

mi mov eax,123 : fn MessageBox,0,myStr$(eax),0,0 : mov eax, myCmd$(0)

exit
main endp
end main

pro: no further syntax elements needed to control expansion
con: all function likes macros must be changed
MREAL macros - when you need floating point arithmetic while assembling!

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Multiple instructions on one line macro.
« Reply #20 on: October 11, 2016, 08:46:36 AM »
Thanks guys, you both have some interesting ideas, the problem for what my target was is notational simplicity, it was originally targeted at purely mnemonics where you could bundle a sequence of uninteresting mnemonics onto one line to reduce clutter something like this.

NOSTACKFRAME
.szLen proc
  mi mov rax, rcx : sub rax, 1
  lbl:
  mi add rax, 1 : movzx r10, BYTE PTR [rax] : test r10, r10 : jnz lbl
  lbl1:
  mi sub rax, rcx : ret
.szLen endp
STACKFRAME


Here is a variation.

  mi NOSTACKFRAME : .szLen proc : mov rax, rcx : sub rax, 1
  lbl:
  mi add rax, 1 : movzx r10, BYTE PTR [rax] : test r10, r10 : jnz lbl
  lbl1:
  mi sub rax, rcx : ret : .szLen endp : STACKFRAME



It will also handle function/API calls and simple non dependent macro statements but will not handle result dependent embedded macros.

Calling a procedure directly works fine but the general approach is clunky and fails in terms of simplicity.

xor rax, rax
mi mov rax, 100 : fn .str$,rax : conout rax," this works as a proc",lf

hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 10583
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Multiple instructions on one line macro.
« Reply #21 on: October 11, 2016, 11:18:03 AM »
I slightly tweaked the original macro to take different delimiters then made a set of wrappers with multiple variations.

    .mi MACRO args:VARARG           ;; multiple instructions
      .multiple_instruction :,args
    ENDM

    .ma MACRO args:VARARG           ;; multiple arguments
      .multiple_instruction #,args
    ENDM

    .mn MACRO args:VARARG           ;; alternate multiple arguments
      .multiple_instruction ~,args
    ENDM

    .m MACRO args:VARARG            ;; alternate multiple arguments
      .multiple_instruction ^,args
    ENDM


Using any of the alternatives allows you to use labels so you can produce nightmares like this.

; NOSTACKFRAME
 ;
 ; szLen proc
 ;
 ;   ; rcx = address of string
 ;
 ;     mov rax, rcx
 ;     sub rax, 1
 ;   lbl:
 ;   REPEAT 3
 ;     add rax, 1
 ;     movzx r10, BYTE PTR [rax]
 ;     test r10, r10
 ;     jz lbl1
 ;   ENDM
 ;
 ;     add rax, 1
 ;     movzx r10, BYTE PTR [rax]
 ;     test r10, r10
 ;     jnz lbl
 ;
 ;   lbl1:
 ;     sub rax, rcx
 ;
 ;     ret
 ;
 ; szLen endp
 ;
 ; STACKFRAME

  .ma NOSTACKFRAME # .szLen proc # mov rax,rcx # sub rax,1 # lbl:
  REPEAT 3
  .ma add rax,1 # movzx r10, BYTE PTR [rax] # test r10,r10 # jz lbl1
  ENDM
  .ma add rax,1 # movzx r10, BYTE PTR [rax] # test r10,r10
  .ma jnz lbl # lbl1: # sub rax,rcx # ret # .szLen endp # STACKFRAME

hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: Multiple instructions on one line macro.
« Reply #22 on: October 11, 2016, 05:12:14 PM »
Using any of the alternatives allows you to use labels so you can produce nightmares like this.

Different, but on par with slickhuh.asm :badgrin: