flat assembler
Message board for the users of flat assembler.

 Index > Macroinstructions > New .if/.else/.loop Approach
Author
uart777

Joined: 17 Jan 2012
Posts: 369
uart777
Hi. Just wanted to share my unique variations of .if/.else
and loops. I thought programmers might be interested in
seeing a different approach.

FASM's version of .if is much more advanced, but this one
is simpler and results in faster assembly processing.

Have fun!

Code:
```
; \$\$\$\$\$\$\$\$\$\$\$\$\$\$\$ Z77 ASM LIBRARY \$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$
; *************** SUNGOD SOFTWARE ****************
; ??????????????????? IF.INC ?????????????????????

!NOT equ 0

; jump if condition to l (or !NOT if 1)

macro JIF l, [c] {
common
local s
define s 0
macro J O,A,C,B, [X] \{
match =0 X, s c \\{
O A, B ; opcode o1, o2
if !NOT eq 0
j\#C l
else
jN\#C l
end if
define s 1
\\}
\}
J cmp,a,LE,b, a<==b    ; a<=b
J cmp,a,GE,b, a>==b    ; a>=b
J cmp,a,L,b, a<b       ; a<b
J cmp,a,G,b, a>b       ; a>b
J cmp,a,E,b, a==b      ; a=b
J cmp,a,NE,b, a =not b ; a not b (unequal)
J test,a,NE,b, a&b     ; a&b
J or,a,NE,b, a|b       ; a|b
J cmp,a,E,0, =not a    ; not a (=0)
J cmp,a,NE,0, a        ; a (not 0)
if s eq 0
ERROR: 'Invalid expression'
end if
purge J
}

; jump if NOT condition to l

macro JIFN l, [c] {
common
!NOT equ 1
JIF l, c
!NOT equ 0 ; restore default
}

; HL IF/ELSE

macro .if.begin {
local ..start, ..else, ..end
?IF equ
?START equ ..start
?ELSE equ ..else
?END equ ..end
?START:
}

macro .if [c] {
common
.if.begin
JIFN ?ELSE, c ; if false, jmp to end
}

macro .if.n [c] {
common
.if.begin
JIF ?ELSE, c
}

macro .else {
jmp ?END
?ELSE:
restore ?IF
?IF equ ,
}

macro .else.if [c] {
common
jmp ?END
?ELSE:
restore ?ELSE
local ..else
?ELSE equ ..else
JIFN ?ELSE, c
}

macro .end {
if ?IF eq
?ELSE:
end if
?END:
restore ?IF, ?START, ?ELSE, ?END
}

jNE equ jne
jNNE equ je
jNG equ jng
jNL equ jnl

; \$\$\$\$\$\$\$\$\$\$\$\$\$\$\$ Z77 ASM LIBRARY \$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$
; *************** SUNGOD SOFTWARE ****************
; ?????????????????? LOOP.INC ????????????????????

; .loop i=x to n
; .endl

; .while a<b
; .endw

; .until a=b
; .endu

; .continue
; .break

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

macro .loop [c] {
local ..start, ..end
?START equ ..start
?END equ ..end
define ?s 0
match i==x =to n, c \{
define ?s 1
?INDEX equ i
push x ; let i=x
pop i
?START:
mov ecx, i
cmp ecx, n
jge ?END
\}
if ?s eq 0
ERROR: 'Incorrect loop syntax'
end if
}

macro .endl {
inc ?INDEX    ; i++
jmp ?START    ; continue
?END:
restore ?START, ?END, ?INDEX
}

macro .while [c] {
common
.if c
}

macro .endw {
jmp ?START
.end
}

macro .until [c] {
common
.if.n c
}

.endu fix .endw

macro .continue { jmp ?START }
macro .break { jmp ?END }    ```

Last edited by uart777 on 18 Jan 2012, 16:39; edited 1 time in total
17 Jan 2012, 23:38
Picnic

Joined: 05 May 2007
Posts: 1300
Picnic
Hi uart777,

Can you give a usage example of .loop macro because i'm having an illegal instruction error.
18 Jan 2012, 12:35
uart777

Joined: 17 Jan 2012
Posts: 369
uart777
Oh, sorry. Edited. Replaced let i=x with push x, pop i. It was written this way to support all memory operands as in: .loop [a]=[b] to [c]

; an example with my code...

include 'z.inc'

integer i=0
text t(32), f='Value: %n/%hh/%bb'

code
.loop [i]=0 to 3
print t, f, [i], [i], [i]
MessageBoxA 0, t, t, 0 ; no invoke needed with my code
.endl ; < remember, .endl for .loop
exit
18 Jan 2012, 16:22
Picnic

Joined: 05 May 2007
Posts: 1300
Picnic
Well it's nice.
I did a small modification tο adjust the loop counter properly.

Code:
```macro .loop [c] {
local ..start, ..end
define ?s 0
match i==x =to n, c \{
define ?s 1
push x ; let i=x
pop i
..start:
?START equ ..start
?END equ ..end
?INDEX equ i
?LIMIT equ n
\}
if ?s eq 0
ERROR: 'Incorrect loop syntax'
end if
}

macro .endl {
mov ecx, ?INDEX
cmp ecx, ?LIMIT
je ?END
inc ?INDEX    ; i++
jmp ?START    ; continue
?END:
restore ?START, ?END, ?INDEX, ?LIMIT
}
```
19 Jan 2012, 00:05
uart777

Joined: 17 Jan 2012
Posts: 369
uart777
Thanks. Nothing is wrong with the index/counter. I have tested .if/.else/.loop extensively, even used them to create useful programs like art/image editors and mini dis/assemblers.

However, I just noticed that .break and .continue do NOT WORK properly. They jmp to the beginning or end of ANY recent HL block including if.

To correct this, each HL block must have a distinctive begin and end (?BEGIN.IF, ?BEGIN.LOOP, etc) or there must be separate versions of break/continue (.breakl, .breakw). Otherwise, something like this will not work:

.loop [i]=0 to [variables.n]
array.index variables, [i]
let eax=&[?variable.name+eax]
.if.text.equal [token], eax
.break ; error: jmps to .if start, not .loop
jmp @f ; < use this instead
.end
.endl
@@:
24 Jan 2012, 03:24
Picnic

Joined: 05 May 2007
Posts: 1300
Picnic
uart777 wrote:
Thanks. Nothing is wrong with the index/counter. I have tested .if/.else/.loop extensively, even used them to create useful programs like art/image editors and mini dis/assemblers.

Oh, forgive my carelessness uart777. It was late at night.
24 Jan 2012, 07:13
Overflowz

Joined: 03 Sep 2010
Posts: 1046
Overflowz
Hi uart777, I'm not fimilar with macro and can you post that macro, where we can use API calls without invoke ? Thank you.
24 Jan 2012, 11:19
uart777

Joined: 17 Jan 2012
Posts: 369
uart777
Hi, Overflowz. I have custom "library; import" macros that construct
the PE import table manually (db x) and define the name itself as a
macro which calls it from the ITA. Thus, no "invoke"-like prefix and
automatic error checking on number of parameters. To understand
this, check out my command/"proc/edure" file:

Code:
```; \$\$\$\$\$\$\$\$\$\$\$\$\$\$ Z77 ASM LIBRARY \$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$\$
; ************** SUNGOD SOFTWARE *****************
; ???????????????? COMMAND.INC ???????????????????

; push parameters forwards or backwards

macro pushf [p] { ; push parameters forward
common if ~ p eq
forward pushd p
common end if
}

macro pushr [p] { ; push parameters backwards
common            ; to access forwards
if ~p eq
reverse pushd p
common
end if
}

; call a/ddress direct or p/ointer indirect

macro calla a, [p] {
common pushr p
call a
}

macro callp c, [p] { common calla [c], p }

; call direct with "variable arguments" (...)
; then push invisible # parameters last
; (TEXT>print t, f, ... uses this convention)

macro callv c, [p] {
common ?n=1
reverse pushd p
?n=?n+1
common push ?n
call c
}

; call cdecl direct (or indirect if [c])

macro cdecl c, [p] {
common ?n=0
reverse pushd p
?n=?n+1
common
call c
}

; call DirectX "interface"

macro callx c, x, [p] {
common
pushr p            ; push parameters
mov eax, [c]
push eax           ; push class address
mov eax, [eax]
call dword [eax+x] ; call c+m
}

macro callfp f { ; call function pointer
cmp dword [f], 0 ; if defined
jz @f
calla dword [f]
@@:
}

;;;;;;;;;;;;;;;;;;;; COMMAND ;;;;;;;;;;;;;;;;;;;;

; create "function/proc/edure"

macro command name, [p] {
common

; only insert this inside of the executable
; if it was used somewhere

if used !#name
!#name: ; real command !name

; macro to call with no callp/"invoke" prefix.
; example: f a, b, c

macro name p \{
pushr p
call !#name
\}

!#name.\$type='c'
?begin equ !#name
?parameters equ p
..n.parameters=0
..n.locals=0
..locals.size=0

; create parameter names and offsets

if ~ p eq          ; if parameters
virtual at ebp+8
forward
local ..p
..p dd ?         ; (ebp++i*4
p equ ..p
..n.parameters=..n.parameters+1
common
end virtual
push ebp         ; create stack frame
mov ebp, esp
end if
; ...
}

; HL return statement. use this instead of
; ret/n in HL commands. no ret/urn before endc.
; it inserts one automatically

macro return v {
common
if ~ v eq ; value?
mov eax, v
end if
if ..n.parameters<>0   ; if parameters
leave
ret ..n.parameters*4 ; ret n
else if ..n.locals<>0  ; if locals
leave
ret
else
ret
end if
}

; end command

macro endc {
return
.\$=\$-?begin ; total size
if ..n.parameters<>0 ; if parameters
match p, ?parameters \{ restore p, ?begin \}
end if
if ..n.locals<>0 ; if locals
match l, local.names \{ restore l \}
end if
; ...
end if ; end "if used name" at very beginning
}

; locals ... - create local 32BIT variables.
; example: locals x, y, n, c

macro locals [p] {
common local.names equ p
forward ..n.locals=..n.locals+1
common ..locals.size=..n.locals*4
virtual at ebp-..locals.size
forward
local ..l
..l dd ?
p equ ..l
common
end virtual
if ..n.parameters=0
push ebp ; create stack frame
mov ebp, esp
end if
sub esp, ..locals.size ; "allocate" locals
}

; localz ... - same but initialize locals;
; for local pointers that re/allocate
; memory or structures that should have
; 0/default values

macro localz [p] {
common
locals p
push edi
mov edi, esp
xor eax, eax
mov ecx, (..locals.size shr 2)
rep stosd
pop edi
}
```

Example usage:

Code:
```; draw "bitmap"; 2D pixel array

command draw.bitmap, pixels, x, y, w, h, key, alpha
locals p, i, iw
visible [x], [y], [w], [h]  ; invisible? return
fail .r
let eax=[pixels], [p]=eax,\ ; p=pixels
ecx=[w], ecx<<2, [iw]=ecx   ; image w in bytes
.loop [i]=0 to [h]
let eax=[y], eax+[i]
draw.scanline [p], [x], eax, [w],\
[key], [alpha]
let eax=[iw], [p]+eax
.endl
.r:
endc
```

Now, to call this, just write its name and parameters (no
"invoke"-like prefix):

draw.bitmap [p], [x], [y], [w], [h], [key], [alpha]

- SUNGOD SOFTWARE
25 Jan 2012, 04:58
 Display posts from previous: All Posts1 Day7 Days2 Weeks1 Month3 Months6 Months1 Year Oldest FirstNewest First

 Jump to: Select a forum Official----------------AssemblyPeripheria General----------------MainTutorials and ExamplesDOSWindowsLinuxUnixMenuetOS Specific----------------MacroinstructionsOS ConstructionIDE DevelopmentProjects and IdeasNon-x86 architecturesHigh Level LanguagesProgramming Language DesignCompiler Internals Other----------------FeedbackHeapTest Area

Forum Rules:
 You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot vote in polls in this forumYou cannot attach files in this forumYou can download files in this forum