News:

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

Main Menu

If condition Then action one-liner

Started by jj2007, October 06, 2013, 04:20:08 AM

Previous topic - Next topic

qWord

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

hutch--

JJ,

No pain, no gain. Humour aside, the ugly notation for MASM code does exactly what I want a single line macro to do and it is tidy in code output terms.


IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                      Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include\masm32rt.inc

    slen PROTO pstr:DWORD

    iph MACRO arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8
      .if arg1
        arg2
        arg3
        arg4
        arg5
        arg6
        arg7
        arg8
      .endif
    ENDM

    nsf MACRO                       ;; no stack frame
      OPTION PROLOGUE:NONE
      OPTION EPILOGUE:NONE
    ENDM

    sfo MACRO                       ;; stack frame on
      OPTION PROLOGUE:PrologueDef
      OPTION EPILOGUE:EpilogueDef
    ENDM

    mi MACRO arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arga,argb,argc,argd,arge,argf, \
       argg,argh,argi,argj,argk,argl,argm,argn,argo,argp,argq,argr,args,argt,argu,argv,argw
      arg1
      arg2
      arg3
      arg4
      arg5
      arg6
      arg7
      arg8
      arg9
      arga
      argb
      argc
      argd
      arge
      argf
      argg
      argh
      argi
      argj
      argk
      argl
      argm
      argn
      argo
      argp
      argq
      argr
      args
      argt
      argu
      argv
      argw
    ENDM

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

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

main proc

    mov eax, 1
    iph eax !!= 1,<mov eax, 3>

    mov eax, 1
    iph eax == 1,<xor eax, eax>,<add eax, 10>

    mov eax, 2
    mi <.if eax !!= 1>,<xor eax, eax>,<add eax, 1>,<add eax, 1>,<add eax, 1>,<.endif>

    ret

main endp

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

    mi <nsf>,<slen proc pstr:DWORD>,<mov eax,[esp+4]>,<sub eax,1>,<lbl:>,<add eax,1>,\
       <cmp DWORD PTR [eax],0>,<jne lbl>,<sub eax,[esp+4]>,<retn>,<slen endp>,<sfo>

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

end start


the /EP listing output shows the result.


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

main proc

    mov eax, 1
      .if eax != 1
        mov eax, 3
      .endif

    mov eax, 1
      .if eax == 1
        xor eax, eax
        add eax, 10
      .endif

    mov eax, 2
      .if eax != 1
      xor eax, eax
      add eax, 1
      add eax, 1
      add eax, 1
      .endif

    ret

main endp

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

      OPTION PROLOGUE:NONE
      OPTION EPILOGUE:NONE
      slen proc pstr:DWORD
      mov eax,[esp+4]
      sub eax,1
      lbl:
      add eax,1
      cmp DWORD PTR [eax],0
      jne lbl
      sub eax,[esp+4]
      retn
      slen endp
      OPTION PROLOGUE:PrologueDef
      OPTION EPILOGUE:EpilogueDef

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

dedndave

i remember MS BASIC - lol
you guys are working awfully hard to make ASM not like ASM
am i in the wrong forum ?   :redface:

hutch--

Now I have a question for anyone old enough to know the answer, I from time to time find a problem that MASM will execute components of a macro out of order based on how it reads the macro line of text. Long ago i saw a technique to force MASM to read the data in order but I equally long ago forgot what it was.

Anyone have any idea about how this is done ?

jj2007

Quote from: dedndave on October 07, 2013, 12:33:25 PM
you guys are working awfully hard to make ASM not like ASM
am i in the wrong forum ?   :redface:
You are in the right forum, Dave. Despite my heavy use of macros, my biggest source (RichMasm) is still >80% "pure" assembler. But without macros there would be a lot of really boring and repetitive stuff... it's a question of productivity.
Can you imagine a long WndProc with endless .if ... .elseif series instead of Switch ... Case? Or worse, jxx instead of HLL syntax? No thanks 8)

Quote from: hutch-- on October 07, 2013, 01:32:02 PMMASM will execute components of a macro out of order based on how it reads the macro line of text.

Not sure what you mean: Execution before the line as in .elseif rv(instr()))==0? Or expansion with the % operator?

hutch--

I have attached a test file stripped down to show the characteristic. It is not the macro that I need to fix, I already have a number of ways of doing this, its just that I have forgotten how to force the order of the macros so the left one is executed first.

IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                      Build this template with "CONSOLE ASSEMBLE AND LINK"
                      To see the /EP output run "makeit.bat"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

      .486                                      ; create 32 bit code
      .model flat, stdcall                      ; 32 bit memory model
      option casemap :none                      ; case sensitive

    ifc MACRO arg1,arg2,arg3:VARARG
        echo cif here
      .if arg1
      arg2
    ENDM

    then MACRO arg1:VARARG
        echo then here
        arg1
      ;; .endif
      EXITM <>
    ENDM

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    ret

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

main proc

  ; ----------------------------------------
  ; with the following macro call the "then"
  ; macro is written BEFORE the "ifc" macro
  ; ----------------------------------------
    ifc eax == 1, then(add eax, 2)

    .endif      ; <<<< this is added because the code is written before the .IF in the 1st macro

    ret

main endp

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

end start

jj2007

> ifc eax == 1, then(add eax, 2)

Hutch,
you mean something like
  mov eax, chr$(("pTest=")
  print eax, str$(eax)  ; please print eax first, then str$(eax)
??
Not possible afaik :(

qWord

Quote from: hutch-- on October 07, 2013, 05:32:51 PMhow to force the order of the macros so the left one is executed first
prefixing the macro name by an exclamation mark prevent expansion:

    ifc MACRO arg1,args:VARARG
      echo arg1,args
      .if arg1
       args
      .endif
    ENDM
    then MACRO args:VARARG
      echo args
       args
      EXITM <>
    ENDM
    ifc eax == 1,!then(add eax, 2)
MREAL macros - when you need floating point arithmetic while assembling!

dedndave


hutch--

Thanks, that is what I was after.

This seems to work OK, with the equate for "then" the macro parser started to squark on the comma inside the "then" result so I went back to angle brackets and removed the EXITM <>.


    ifc MACRO arg1,arg2:VARARG
      .if arg1
      arg2
    ENDM

    then equ <!thn>

    thn MACRO arg1:VARARG
      arg1
      .endif
    ENDM

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

    ifc eax == 1, then <add eax, 2>


I think to get what JJ was after you would need to parse the entire line but at least this comes close for a simple pair of macros.

qWord

procedural macros are generally not expanded in such "call-situations"  thus the exclamation mark and the EQU could be omitted.
MREAL macros - when you need floating point arithmetic while assembling!

hutch--

Yep, works fine.

This line produces the following code expansion.

ifc eax == 1, then <add eax, 2>


/EP list file.

      .if eax == 1
      add eax,2
      .endif


PS: I like the "when" semantic, reads nicely and makes sense.

jj2007

Quote from: qWord on October 08, 2013, 01:29:10 AM
procedural macros are generally not expanded in such "call-situations"  thus the exclamation mark and the EQU could be omitted.

I stumbled over a very odd behaviour when using the exclamation mark:

include \masm32\include\masm32rt.inc
If_ MACRO arg:VARARG        ; If_ not eax Then inc ecx : add ecx, ...
LOCAL is, args
  is INSTR <arg>, <Then>
  ife is
        .err @CatStr(<*** no Then in line >, %@Line, < ***>)
  else
        args CATSTR @SubStr(<arg>, is+5), <: >
        ifidni @SubStr(<arg>, 1, 3), <not>
                .if !@SubStr(<arg>, 5, is-5)
                        If_2 args
                .endif
        else
                .if @SubStr(<arg>, 1, is-1)
                        If_2 args
                .endif
        endif
  endif
ENDM

If_2 MACRO args
LOCAL args, cc, is
  cc INSTR args, <:>
  is=1
  WHILE cc gt is
        tmp$ SUBSTR args, is, cc-is
        % echo tmp$
        tmp$
        is=cc+1
        cc INSTR is, args, <:>
  ENDM
ENDM

fakestr$ MACRO arg
  pushad
  print "## "
  popad
  exitm chr$("x")
ENDM

.code
start:
        m2m eax, 103
        If_ eax Then dec eax: dec eax: dec eax: print str$(eax), " - should be 100", 13, 10

        m2m eax, 103
        If_ eax Then dec eax: dec eax: dec eax: print !fakestr$(eax), " - should be one '#' and one 'x'", 13, 10

        inkey "ok?"

        exit

end start


The first If_ eax Then dec eax... delivers 103 instead of 100 because of macro expansion happening before even the test of the condition; which clearly demonstrates that one must be very careful with using functional macros after the Then.

The second one shows the odd behaviour. As the text says, you should see one '#' and one 'x' - and that is what you see indeed when you take away the exclamation mark...

Source attached (pure Masm32).

P.S.: Apart from this, the If_ ... Then macro works like a charm, it will be included in the next MasmBasic update. To be consistent with For_ ... Next, I moved the underscore behind the If. For multiple instruction, the colon is now being used, as in most Basic dialects. Thanks for all the helpful remarks :icon14:

qWord

the problem is that the text macro "args" contains the macro call to fakestr$(): whenever this text macro is used as argument for the string functions, MASM expand it as far as possible. That is the reason why the fake macro is called so often. The problem could be solved by directly passing the input of If_ to the submacros:
If_ MACRO arg:VARARG        ; If_ not eax Then inc ecx : add ecx, ...
LOCAL is, args
  is INSTR <arg>, <Then>
  ife is
        .err @CatStr(<*** no Then in line >, %@Line, < ***>)
  else
        args CATSTR @SubStr(<arg>, is+5), <: >
        ifidni @SubStr(<arg>, 1, 3), <not>
                .if !@SubStr(<arg>, 5, is-5)
                        If_2 %is+5,<&arg: >
                .endif
        else
                .if @SubStr(<arg>, 1, is-1)
                        If_2 %is+5,<&arg: >
                .endif
        endif
  endif
ENDM

If_2 MACRO pos,args
LOCAL cc, is
echo pos,args
  cc INSTR pos,<&args>, <:>
  is=pos
  WHILE cc gt is
        tmp$ SUBSTR <&args>, is, cc-is
        tmp$
        is=cc+1
        cc INSTR is, <&args>, <:>
  ENDM
ENDM


BTW: If_2: the local variable args has the same name as the macro parameter
MREAL macros - when you need floating point arithmetic while assembling!

hutch--

JJ,

I think this one does the job.


IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                      Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include\masm32rt.inc

    eql textequ <==>        ;; equal
    neq textequ <!!=>       ;; not equal
    ltn textequ <!<>        ;; less than
    gtt textequ <!>>        ;; greater than
    gte textequ <!>=>       ;; greater or equal
    lte textequ <!<=>       ;; less than or equal

    lnif MACRO arg:VARARG
      LOCAL larg
      LOCAL rarg
      LOCAL cpoz

      cpoz INSTR 1, <arg>, <then>

      IF cpoz eq 0
        .ERR
        echo -------------------------------------
        echo "then" expected with "lnif" statement
        echo -------------------------------------
        EXITM
      ENDIF

      larg SUBSTR <arg>, 1, cpoz-2
      rarg SUBSTR <arg>, cpoz+4

      .if larg
        rarg
      .endif

    ENDM


    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

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

main proc

    lnif eax eql 1 then add eax, 1
    lnif eax neq 1 then add eax, 1
    lnif eax ltn 1 then add eax, 1
    lnif eax gtt 1 then add eax, 1
    lnif eax gte 1 then add eax, 1
    lnif eax lte 1 then add eax, 1

    ret

main endp

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

end start