News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Multiple instructions on one line macro.

Started by hutch--, October 09, 2016, 12:06:37 PM

Previous topic - Next topic

hutch--

I am not sure its useful but it does work OK.

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

    include \masm32\include64\masm64rt.inc

    mi MACRO a1,a2,a3,a4,a5,a6,a7,a8,a9,a0
      a1
      a2
      a3
      a4
      a5
      a6
      a7
      a8
      a9
      a0
    ENDM

    close MACRO exitcode:=<0>
      mov rcx, exitcode
      call ExitProcess
    ENDM

    .code

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

entry_point proc

    mi <mov rax, 1>,<add rax, 2>,<sub rax, 3>,waitkey,close,ret

entry_point endp

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

    end

jj2007

Basic style:

include \Masm32\MasmBasic\Res\JBasic.inc      ; download

mijj MACRO args:VARARG
Local isL, isR, isFlag, argsLen
  isR=0
  isFlag=1
  While isFlag
      isL=isR+1
      isR INSTR isL, <args>, <:>
      ife isR
            isR=@SizeStr(<args>)+1
            isFlag=0
      endif
      @SubStr(<args>, isL, isR-isL)
  ENDM
ENDM
Init
  PrintLine Chr$("This code was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format")
  mijj mov rax, 100:add rax, 30:sub rax, 7: <Inkey Str$("rax=%i", rax)>
EndOfCode


Output:
This code was assembled with ml64 in 64-bit format
rax=123


Problem with both versions is the premature expansion of macros - therefore <brackets> around the macros.

Mikl__

#2
Hi, hutch--!
This is macro from the article "Как писать на MASM в строчку" (How to write on MASM in single line) of Svet(R)off​ 2001 from site ASSEMBLER.RU
Google translating article into English

hutch--

With a little more effort, this one works OK.
[[t]
; *************************************************************************
; -------------------------------------------------------------------------

    multiple_instruction MACRO args:VARARG
      LOCAL arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg0,cntr,flag

      cntr = 1                      ;; counter determined which buffer is being written to
      flag = 0                      ;; flag starts as clear

      arg1 equ <>
      arg2 equ <>
      arg3 equ <>
      arg4 equ <>
      arg5 equ <>
      arg6 equ <>
      arg7 equ <>
      arg8 equ <>
      arg9 equ <>
      arg0 equ <>

    ;; ---------------------------------
      FORC char,<args>
        IFIDN <char>,<:>            ;; test if char is the ":" delimiter
          IF flag eq 0
            cntr = cntr + 1         ;; only increment the counter if the flag is clear
          ENDIF
          flag = 1                  ;; set the flag so you only get 1 increment of cntr
          goto over
        ENDIF
        flag = 0                    ;; clear the flag when the next char is not a space

        IF cntr eq 1
          arg1 CATSTR arg1,<char>   ;;
        ELSEIF cntr eq 2
          arg2 CATSTR arg2,<char>   ;;
        ELSEIF cntr eq 3
          arg3 CATSTR arg3,<char>   ;;
        ELSEIF cntr eq 4
          arg4 CATSTR arg4,<char>   ;;
        ELSEIF cntr eq 5
          arg5 CATSTR arg5,<char>   ;;
        ELSEIF cntr eq 6
          arg6 CATSTR arg6,<char>   ;;
        ELSEIF cntr eq 7
          arg7 CATSTR arg7,<char>   ;;
        ELSEIF cntr eq 8
          arg8 CATSTR arg8,<char>   ;;
        ELSEIF cntr eq 9
          arg9 CATSTR arg9,<char>   ;;
        ELSEIF cntr eq 10
          arg0 CATSTR arg0,<char>   ;;
        ELSEIF cntr eq 11
          % echo *********************************************
          % echo ERROR : too many arguments, 10 argument limit
          % echo *********************************************
          .err <too many arguments>
          goto over
        ENDIF
      :over
      ENDM
    ;; ---------------------------------

      arg1
      arg2
      arg3
      arg4
      arg5
      arg6
      arg7
      arg8
      arg9
      arg0

    ENDM

; --------------------------------

    mi MACRO args:VARARG
      multiple_instruction args
    ENDM

; -------------------------------------------------------------------------
; *************************************************************************
[/tt]

Looks like this in use.

    mi \
    mov rax,1 : add rax,1 : sub rax,3 : xor rax,rax
    mi waitkey : fn ExitProcess,0 : ret

jj2007

#4
Quote from: Mikl__ on October 09, 2016, 01:09:59 PMGoogle translating article into English

QuoteAssembler - the greatest language, the king of languages, virtually devoid of shortcomings worthy of people's love and worship

Absolutely :t

  mi   mov rax, 100:add rax, 30:sub rax, 7: <Print Str$("version Hutch...\t rax=%i\n", rax)>
  mijj mov rax, 100:add rax, 30:sub rax, 7: <Print Str$("version JJ...   \t rax=%i\n", rax)>


Output:
version Hutch...         rax=1
version JJ...            rax=123

(expected: 123; assembled with ml64 in 64-bit format)

Can't see, though, why yours shouldn't work - it looks ok ::)

A look in the *.lst file:

FORC char,<mov rax,100:add rax,30:sub rax,7: Print offset s$buffer>

??0104 INSTR ??0100, <mov rax,100:add rax,30:sub rax,7: Print Str$("version JJ:    \t rax=%i\n", rax)>, <"> ;

So the FORC version gets expanded (offset...), the other one is still Str$(...).

Attached a new version, baptised mulComs, builds with ML/ML64, HJWasm and AsmC.

This works now:
  mi mov rax, 100:add rax, 30:sub rax, 7: <Print Str$("version Hutch...\t rax=%i\n", rax)>
  mulComs mov rax, 100:add rax, 30:sub rax, 7: <Print Str$("version JJ:     \t rax=%i\n", rax)>


P.S.: Try version Hutch: instead of version Hutch...

hutch--

I have tracked down at this end what is happening and I have seen it before, the "conout" macro that I test with is being filled out before the "mi" macro is being executed so it misses the result of previous instructions.

jj2007

Indeed:
Quote from: jj2007 on October 09, 2016, 12:50:41 PM
Problem with both versions is the premature expansion of macros - therefore <brackets> around the macros.

Question is why your mi doesn't work with my Print Str$(), despite the brackets, while mine does. My guess is that the FORC is the problem.

hutch--

This shows the problem.

Arg count = 4
mov r15,100
add r15,30
sub r15,7
add r15,r15

Arg count = 3
conout "Result = ",??0025,??0001
waitkey
fn __imp_ExitProcess,0


From being in the FORC loop, macros and other operators are being expanded before the parent macro is run.

jj2007

It seems so. My version avoids CATSTR, and therefore expansion:

mulComs MACRO args:VARARG
Local isL, isR, isFlag, argsLen, isQ
  isR=0
  isFlag=1
  While isFlag
isL=isR+1
isQ INSTR isL, <args>, <"> ; xxx : Print "Hello: a problem" : xxx
isR INSTR isL, <args>, <:>
if isQ and isQ lt isR
isQ INSTR isQ+1, <args>, <">
isR INSTR isQ, <args>, <:>
endif
ife isR
isR=@SizeStr(<args>)+1
isFlag=0
endif

@SubStr(<args>, isL, isR-isL)
  ENDM
ENDM


hutch--

I put this line at the front of the main macro before either the FORC loop and any instance of CATSTR and still got this.

      % echo Args = args

and get this output,

Args = conout "Result = ",??0025,??0001 : waitkey : fn __imp_ExitProcess,0

It does not appear to be a problem with macros that have static parameter or an API call but it prevents an embedded macro from getting results in the same calling macro before it.

hutch--

After wasting some hours, I cannot find a format of passing a macro inside another macro that does not expand the embedded macro unless it is contained in a string so I have put it aside at the moment. I can get this to work correctly as it isolates macro expansion by placing such a macro on its own line. This restricts the use to non accumulated arguments.

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

    include \masm32\include64\masm64rt.inc

    .code

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

entry_point proc

    mi mov rax, 100 : sub rax, 75 : shl rax, 2
    conout "Result = ",str$(rax),lf
    mi waitkey : invoke ExitProcess,0 : ret

entry_point endp

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

    end

May have a play with it later but have more important things to do.

Mikl__

file which is mentioned in the article of Svet(R)off "How to write on MASM in single line"
QuoteWishes to enjoy a new kind of source code and learn some style ideas can click here
Wow! It is 400-th message on the forum, it is necessary to celebrate it - I will go to pour himself some vodka from a samovar, feed the bear and play the balalaika

hutch--


jj2007

Quote from: Mikl__ on October 10, 2016, 01:47:44 PMfile which is mentioned in the article of Svet(R)off "How to write on MASM in single line"

Wow, he has a multiple instructions macro called "@", and puts the comments in front:
List_DX_Modes PROC
@<;Clear variables>,<mov modes_buffer,0>,<mov modes_number,0>
@<;Create list modes buffer>,<invoke GlobalAlloc,GPTR,MODES_BUFFER_SIZE>,<or eax,eax>,<jz bad>,<mov modes_buffer,eax>
@<;Create a DirectDraw object>,<invoke DirectDrawCreate,NULL,offset(lpDD),NULL>,<cmp eax,DD_OK>,<jne bad>


Reminds me of the old, old times when I had to keep a certain fat BASIC source below 16384 lines, for technical reasons :icon_mrgreen:

In the meantime, I added my version as mcs (=multiple commands) to the MB package, for use with (32-bit) MasmBasic and the dual 32-/64-bit JBasic variant; tested with all "our" assemblers here. More here.

hutch--

The problem is for the design I was after that I wanted to keep it simple, just have a " : " between each component and for static content it works fine, what beats embedded dependent content is the characteristic of the macro engine to expand nested macros before the parent macro is called which defeats sequential dependent components. The form I have got is usable and simple but dependent procedure calls or macros must be put on a separate line to get the previous data.

mi \
mov rax, 100 : add rax, 300 : shl rax, 1

This works fine and is simple notation, as soon as it gets cluttered with notation, it loses any advantage it has.