Author Topic: [SOLVED] Conditional Assembly-preprocessor  (Read 8668 times)

Offline shaynox

  • Full Member
  • **
  • Posts: 118
  • Country: gr
[SOLVED] Conditional Assembly-preprocessor
« on: March 05, 2015, 07:14:51 PM »
Hello,

I would like to compare a macro parameter to a CPU register (%if (%1 = xmm0)), but it didn't work when I try put in first macro parameter, a RAM variable, whereas I put a register it's work.

Work:
Code: [Select]
if rax, '==', 1
ret
endif

Don't work:
Code: [Select]
if [var_quit_program], '==', i32(1)
ret
endif

Nasm give me this error for the wrong one:

Quote
expression syntax error

Any idea ?

Here's my complete macro:

Code: [Select]
;===============================================================================.
; if elseif else endif                                                         |
; Purpose : 1st use : if  Operand 1, cmp, Operand 2                            |
;                         {...}                                                |
;                     elseif Operand 1, cmp, Operand 2                         |
;                         {...}                                                |
;                     else                                                     |
;                         {...}                                                |
;                     endif                                                    |
;                                                                              |
;           2nd use : if     Operand 1, cmp, Operand 2, label                  |
;                     elseif Operand 1, cmp, Operand 2, label                  |
;                     else   label                                             |
;                     endif                                                    |
;===============================================================================.
; %0 = number of parameters received
; %1 = Operand 1
; %2 = == ; != ; > ; >= ; < ; <=
; %3 = Operand 2
; %4 = label
%macro if 3-*

%push if ; push while macro calling tracing

; %if   (%1 = xmm0 || %1 = xmm1 || %1 = xmm2 || %1 = xmm3 || %1 = xmm4 || %1 = xmm5 || %1 = xmm6 || %1 = xmm7 || %1 = xmm8 || %1 = xmm9 || %1 = xmm10 || %1 = xmm11 || %1 = xmm12 || %1 = xmm13 || %1 = xmm14 || %1 = xmm15)
; vcomiss %1, %3
; %elif (%1 = ymm0 || %1 = ymm1 || %1 = ymm2 || %1 = ymm3 || %1 = ymm4 || %1 = ymm5 || %1 = ymm6 || %1 = ymm7 || %1 = ymm8 || %1 = ymm9 || %1 = ymm10 || %1 = ymm11 || %1 = ymm12 || %1 = ymm13 || %1 = ymm14 || %1 = ymm15)
; vcomiss %1, %3
; %elif (%1 = zmm0 || %1 = zmm1 || %1 = zmm2 || %1 = zmm3 || %1 = zmm4 || %1 = zmm5 || %1 = zmm6 || %1 = zmm7 || %1 = zmm8 || %1 = zmm9 || %1 = zmm10 || %1 = zmm11 || %1 = zmm12 || %1 = zmm13 || %1 = zmm14 || %1 = zmm15)
; vcomiss %1, %3
; %else
cmp %1, %3
; %endif

%if (%0 = 3)

%if (%2 = '==')
jne %$no_if
%endif

%if (%2 = '!=')
je %$no_if
%endif

%if (%2 = '<') ; for unsigned value
jae %$no_if
%endif

%if (%2 = ' <') ; for signed value
jge %$no_if
%endif

%if (%2 = '>') ; for unsigned value
jbe %$no_if
%endif

%if (%2 = ' >') ; for signed value
jle %$no_if
%endif
%if (%2 = '<=') ; for unsigned value
ja %$no_if
%endif

%if (%2 = ' <=') ; for signed value
jg %$no_if
%endif

%if (%2 = '>=') ; for unsigned value
jb %$no_if
%endif

%if (%2 = ' >=') ; for signed value
jl %$no_if
%endif

%elif (%0 = 4)

%if (%2 = '==')
je %4
%endif

%if (%2 = '!=')
jne %4
%endif

%if (%2 = '<') ; for unsigned value
jb %4
%endif

%if (%2 = ' <') ; for signed value
jl %4
%endif

%if (%2 = '>') ; for unsigned value
ja %4
%endif

%if (%2 = ' >') ; for signed value
jg %4
%endif
%if (%2 = '<=') ; for unsigned value
jbe %4
%endif

%if (%2 = ' <=') ; for signed value
jle %4
%endif

%if (%2 = '>=') ; for unsigned value
jae %4
%endif

%if (%2 = ' >=') ; for signed value
jge %4
%endif

jmp %$no_if

%else
%error "Incorrect parameter number"
%endif

%endmacro

%macro elseif 3-4

jmp %$end

%ifctx  if
%$no_if:
%repl elseif ; replace name of macro calling tracing by elseif

cmp %1, %3

%if (%0 = 3)

%if (%2 = '==')
jne %$no_elseif
%endif

%if (%2 = '!=')
je %$no_elseif
%endif

%if (%2 = '<') ; for unsigned value
jae %$no_elseif
%endif

%if (%2 = ' <') ; for signed value
jge %$no_elseif
%endif

%if (%2 = '>') ; for unsigned value
jbe %$no_elseif
%endif

%if (%2 = ' >') ; for signed value
jle %$no_elseif
%endif

%if (%2 = '<=') ; for unsigned value
ja %$no_elseif
%endif

%if (%2 = ' <=') ; for signed value
jg %$no_elseif
%endif

%if (%2 = '>=') ; for unsigned value
jb %$no_elseif
%endif

%if (%2 = ' >=') ; for signed value
jl %$no_elseif
%endif

%endif

%if(%0 = 4)

%if (%2 = '==')
je %4
%endif

%if (%2 = '!=')
jne %4
%endif

%if (%2 = '<') ; for unsigned value
jb %4
%endif

%if (%2 = ' <') ; for signed value
jl %4
%endif

%if (%2 = '>') ; for unsigned value
ja %4
%endif

%if (%2 = ' >') ; for signed value
jg %4
%endif

%if (%2 = '<=') ; for unsigned value
jbe %4
%endif

%if (%2 = ' <=') ; for signed value
jle %4
%endif

%if (%2 = '>=') ; for unsigned value
jae %4
%endif

%if (%2 = ' >=') ; for signed value
jge %4
%endif

jmp %$no_elseif
%endif
%else
%error "expected else before else if"
%endif

%endmacro

%macro else 0-1

%if (%0 = 0)
jmp %$end

%ifctx  if
%$no_if:
%elifctx  elseif
%$no_elseif:
%else
%error "expected if before else"
%endif
%endif

%if (%0 = 1)
%ifctx  if
%$no_if:
jmp %1
%elifctx  elseif
%$no_elseif:
jmp %1
%else
%error "expected if before else"
%endif
%endif

%repl else

%endmacro

%macro endif 0

%$end:

%ifctx if
%$no_if:
%pop
%elifctx  elseif
%$no_elseif:
%pop
%elifctx  else
%pop
%else
%error "expected if before endif"
%endif

%endmacro
;===============================================================================.
; /if elseif else endif                                                         |
;===============================================================================.



PS: Also I try to give the possibility to code multiple elseif, but I didn't arrived to do it :/
« Last Edit: March 12, 2015, 12:12:27 AM by shaynox »

Offline Rob Neff

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 429
  • Country: us
Re: Conditional Assembly-preprocessor
« Reply #1 on: March 06, 2015, 01:57:32 AM »
PS: Also I try to give the possibility to code multiple elseif, but I didn't arrived to do it :/

You can learn by looking at how we did it in NASM-X by examining the macro definitions for IF, ELSE, ELSIF, and ENDIF contained in the file /nasmx/inc/nasmx.inc
They're not as complicated as some of the other macros such as INVOKE.


Offline shaynox

  • Full Member
  • **
  • Posts: 118
  • Country: gr
Re: Conditional Assembly-preprocessor
« Reply #2 on: March 06, 2015, 11:42:31 AM »
I have read and didn't find my happiness.

Code: [Select]
;//////////////////////////////////////////////////////////////////////////////
;//
;// The following macros provide a convenient way
;// to simulate high level constructs.  They allow
;// nesting of statements of arbitrary depth.
;// Note that the address labels generated are dot-
;// prepended to not break NASMX locals!

%imacro IF 3.nolist
%push __NX_CTX_IF__
; we must obtain any outer context label sequence
; to enable the break macro to succeed.
%ifndef __NX_OPER_LABEL_SEQ__
%xdefine __NX_OPER_LABEL_SEQ__ 0
%endif
%assign %$__nx_oper_label_seq %[__NX_OPER_LABEL_SEQ__]
; sequence label numbers for the IF macro must be
; separate from looping sequence label numbers.
%ifndef __NX_OPER_IF_LABEL_SEQ__
%xdefine __NX_OPER_IF_LABEL_SEQ__ 0
%endif
%assign %$__nx_oper_if_label_seq %[__NX_OPER_IF_LABEL_SEQ__] + 1
%undef __NX_OPER_IF_LABEL_SEQ__
%xdefine __NX_OPER_IF_LABEL_SEQ__ %[%$__nx_oper_if_label_seq]

%assign %$__nx_oper_else 0
%assign %$__nx_oper_if_label_next 1
cmp %1, %3
RJMP %2, .__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]
%endmacro


%imacro ELSIF 3.nolist
%ifctx __NX_CTX_IF__
%if %$__nx_oper_else > 0
%error "ELSIF cannot follow ELSE block."
%endif
jmp .__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]
.__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]:
%assign %$__nx_oper_if_label_next 1+%$__nx_oper_if_label_next
cmp %1, %3
RJMP %2, .__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]
%else
%error "ELSIF directive must be within an IF block."
%endif
%endmacro


%imacro ELSE 0.nolist
%ifctx __NX_CTX_IF__
%if %$__nx_oper_else > 0
%error "There can only be one ELSE per IF block."
%else
%assign %$__nx_oper_else 1
jmp .__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]
.__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]:
%assign %$__nx_oper_if_label_next 1+%$__nx_oper_if_label_next
%endif
%else
%error "ELSE directive must be within an IF block."
%endif
%endmacro


%imacro ENDIF 0.nolist
%ifctx __NX_CTX_IF__
; must have a forward label in case elsif/else macros used.
.__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]_%[%$__nx_oper_if_label_next]:
.__NX_OPER_IF_LABEL_%[%$__nx_oper_if_label_seq]:
%pop
%else
%error "ENDIF directive must be within an IF block."
%endif
%endmacro
« Last Edit: March 06, 2015, 12:54:16 PM by shaynox »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Conditional Assembly-preprocessor
« Reply #3 on: March 06, 2015, 10:57:54 PM »
When looking at IF, ELSE, ELSIF, and ENDIF, don't overlook the RJMP macro which is where the "real" work is going on. IF, ELSE, ELSIF, and ENDIF are mostly for providing nesting, context control, and a friendly syntax around the RJMP macro.

Code: (nasmx.inc: 3754) [Select]
%imacro RJMP 2.nolist
; This macro preforms the opposite conditional jump
; than what the value suggests, it's used internally
; by other macros
%ifidni %1, ==
jne %2
%elifidni %1, >
jle %2
%elifidni %1, <
jge %2
%elifidni %1, >=
jl %2
%elifidni %1, <=
jg %2
%elifidni %1, !=
je %2
%elifidni %1, !>
jg %2
%elifidni %1, !<
jl %2
%elifidni %1, CARRY
jnc %2
%elifidni %1, BELOW
jnb %2
%elifidni %1, ABOVE
jna %2
%elifidni %1, PARITY
jnp %2
%elifidni %1, SIGNED
jns %2
%elifidni %1, OVERFLOW
jno %2
%elifidni %1, !CARRY
jc %2
%elifidni %1, !BELOW
jb %2
%elifidni %1, !ABOVE
ja %2
%elifidni %1, !PARITY
jp %2
%elifidni %1, !SIGNED
js %2
%elifidni %1, !OVERFLOW
jo %2
%endif
%endmacro

I know it seems odd that we JNE on an "==" in %1, but the internal use of this macro is to generate a branch instruction over the code associated with the truth condition, so we need the opposite of the truth condition.

About Bryant Keller
bkeller@about.me

Offline shaynox

  • Full Member
  • **
  • Posts: 118
  • Country: gr
Re: Conditional Assembly-preprocessor
« Reply #4 on: March 06, 2015, 11:59:52 PM »
Thanks, it's work with %ifidni.

Do you know how to make an OR logic in %ifidni ?


PS: I see the %ifidni don't recognize when there is a space between 1st operand and comma: %ifidni  %1 , xmm0.
« Last Edit: March 07, 2015, 03:21:49 AM by shaynox »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Re: Conditional Assembly-preprocessor
« Reply #5 on: March 11, 2015, 11:39:48 PM »
Do you know how to make an OR logic in %ifidni ?

No, there is no OR logic for %ifidni, you just have to use a bunch of %ifidni/%elifidni statements like what was done above.

PS: I see the %ifidni don't recognize when there is a space between 1st operand and comma: %ifidni  %1 , xmm0.

%ifid compares the first identifier against the second, if you put a space before the comma, it assumes that space is part of the first identifier. It always seemed weird to me too, but I'm sure there are people out there who have made use of this feature.

About Bryant Keller
bkeller@about.me

Offline shaynox

  • Full Member
  • **
  • Posts: 118
  • Country: gr
Re: [SOLVED] Conditional Assembly-preprocessor
« Reply #6 on: March 14, 2015, 03:48:56 AM »
ok thanks.