uart777
Joined: 17 Jan 2012
Posts: 369
|
An updated version of my LANGUAGE.INC: ; $$$$$$$$$$$$$$$ Z77 ASM LIBRARY $$$$$$$$$$$$$$$$
; *************** SUNGOD SOFTWARE ****************
; ???????????????? LANGUAGE.INC ??????????????????
; $$$$$$$$$$ EVOLUTION OF HL ASM SYNTAX $$$$$$$$$$
; display error if no match
macro verify.syntax name {
if ?s eq 0
'Invalid syntax: ' name
end if
}
; verify size of block/text/array
macro verify.size n {
if n eq
'Size must be specified'
else if ~ n eqtype 0
'Size must be numeric'
else if n eq 0
'Size cannot be zero'
end if
}
macro ?list.attach list, item {
match any, list \{ list equ list, item \}
match , list \{ list equ item \}
}
;;;;;;;;;;;;;;;;; VARIABLE.INC ;;;;;;;;;;;;;;;;;;;
; define variable of type
macro !DV type, name, value {
local l
l=$
name type value ; example: msg db 'Hello'
name#.$=$-l ; size
}
; define b/w/d/q/t variable
macro !D1 name, value { !DV db, name, value }
macro !D2 name, value { !DV dw, name, value }
macro !D4 name, value { !DV dd, name, value }
macro !D8 name, value { !DV dq, name, value }
macro !DF name, value { !DV dt, name, value }
; define address size variables: 16/32/64BIT
macro VOID [a] {
common
if USE=32
!D !D4, a
else
!D !D8, a
end if
}
macro align n {
if n eq
align 8
else
align n
end if
}
; define byte array. BLOCK b(size)
macro BLOCK [p] {
forward
define ?s 0
match =0 name(size), ?s p \{
verify.size size
!DV db, name, size dup(0)
define ?s 1
\}
verify.syntax BLOCK
}
; define literal 'text' array
macro TEXTA name, [t] {
?nta=0
common
label name dword
forward local l
dd l
?nta=?nta+1
forward l db t, 0
name#.$=?nta
}
; create HL 'text' variable/s. TEXT t='X'.
; note: (n) is the size
macro TEXT [p] {
forward
local l
define ?s 0
; TEXT t(n)='abc'
match =0 name(size)==text, ?s p \{
l=$
verify.size size
!DV db, name, <text,0>
times (size-($-l)) db 0
define ?s 1
\}
; TEXT t(n)
match =0 name(size), ?s p \{
verify.size size
!DV db, name, size dup(0)
name\#.$=size
define ?s 1
\}
; TEXT t='abc'
match =0 name==text, ?s p \{
!DV db, name, <text,0> ; name db 't', 0
define ?s 1
\}
; TEXT t
match =0 name, ?s p \{
'Size must be specified:' name
define ?s 1
\}
verify.syntax TEXT
}
;;;;;;;;;;;;;; DEFINE HL VARIABLE ;;;;;;;;;;;;;;;;
; define X. syntax: type then any a/a=b
; sequence/s separated with ,s. example:
; NUMBER x, y, w=320, h=240
; variables=0 if there is no initial value
macro !D type, [p] {
common
if p eq
'Name expected'
end if
forward
define ?s 0
match =0 a==b, ?s p \{ ; a=b
type a, b
define ?s 1
\}
match =0 a=,, ?s p \{ ; a, (next)
type a, 0
define ?s 1
\}
match =0 a, ?s p \{ ; a (end)
type a, 0
define ?s 1
\}
verify.syntax variable
}
; HL variable names
macro BYTE [a] { !D !D1, a }
macro WBYTE [a] { !D !D2, a }
macro NUMBER [a] { !D !D4, a }
macro NUMERO [a] { !D !D8, a }
macro REAL [a] { !D !D4, a }
macro REAL8 [a] { !D !D8, a }
macro REAL10 [a] { !D !DF, a }
NUMBER.P fix VOID
TEXT.P fix VOID
IMAGE.P fix VOID
FONT.P fix VOID
WORD fix WBYTE
DWORD fix NUMBER
BOOLEAN fix NUMBER
HANDLE fix VOID
; alternative names...
void fix VOID
char fix BYTE
integer fix NUMBER
string fix TEXT
Void fix VOID
Byte fix BYTE
Integer fix NUMBER
Color fix NUMBER
Text fix TEXT
Array fix ARRAY
Index fix .index
Structure fix STRUCTURE
EndS fix ENDS
Function fix function
EndF fix endf
Return fix return
Escape fix escape
Let fix let
Get fix get
Try fix try
Fail fix fail
Fault fix fault
If fix .if
End fix .end
While fix .while
EndW fix .endw
Loop fix .loop
EndL fix .endl
;;;;;;;;;;;;;; NUMERIC CONSTANTS ;;;;;;;;;;;;;;;;;
; create a list of incremental values starting
; at 0. example:
; numeric A, B=7, D ; here, A=0, D=8
macro numeric [id] {
common
local n
n=0 ; n=0
forward
define ?v 0 ; initial value?
match a==b, id \{
a=b
n=b ; set n
define ?v 1 ; yes, specified
\}
if ?v=0 ; else=n (previous+1)
id=n
end if
n=n+1 ; n++
}
numeric YES=1, NO=0, TRUE=1, FALSE=0,\
NULL=0, DEFAULT=0, NONE=-1, INVALID=-1,\
INFINITE=-1, NOTHING=-1
; note: -1 means "not zero and not maximum"
; (FFFF/FF/FFh) for indices, sizes, handles
; (index or pointer), etc, where >=0 is
; valid/finite/something...
; .if [n]=INFINITE ; if -1
; .if [handle]=INVALID ; if -1
; .if [n] not INVALID ; if not -1
; .if [win]>NOTHING ; if >=0
; "enumeration" with variable
macro numerate v, [id] {
common NUMBER v
numeric id
}
; create successive powers of 2 starting
; at BIT0, from right to left
macro powers [id] {
common local n
n=0
forward id=1 shl n
n=n+1
}
; create readable bit structure from
; left to right. example: 0000ABCDb.
; powerz A, B, C, D ; A=8, B=4, C=2, D=1
macro powerz [id] {
common local n
n=1
forward n=n+1
common n=n-2
forward id=1 shl n
n=n-1
}
;;;;;;;;;;;;;;;; LITERAL 'TEXT' ;;;;;;;;;;;;;;;;
; create array of literal 'text' + addresses
; example: TEXTA colors, 'Black', 'White'
; access: let ecx=[index], eax=[colors+ecx*4]
macro TEXTA name, [t] {
?nta=0
common
label name dword
forward local l
dd l
?nta=?nta+1
forward l db t, 0
name#.$=?nta
}
; same but align each to size
macro TEXTAA name, size, [t] {
common
?nta=0
label name dword
forward
local l
dd l
?nta=?nta+1
forward
l db t, 0
times (size-($-l)) db 0 ; align
common
name#.$=?nta
}
; HL TEXT array syntax...
; TEXTS t[]='abc', 'xyz', '123'
; TEXTS t[](4)='ann', 'kim', 'sue'
macro TEXTS [p] {
common
define ?s 0
match name[](size)==t, p \{
TEXTAA name, size, t
define ?s 1
\}
match =0 name[]==t, ?s p \{
TEXTA name, t
define ?s 1
\}
verify.syntax TEXTS
}
; same as TEXTA but with ids. example:
; MESSAGES error.messages,\
; E_NONE='None',\
; E_MEMORY='Insufficient Memory',\
; E_LOAD='Error Loading File',\
; E_VGA='Unsupported Resolution',\
; E_ETC='Etc'
macro MESSAGES name, [p] {
common ?n=0
label name dword
forward
local l
dd l
forward
match a==b, p \{
l db b, 0
a=?n
?n=?n+1
\}
common
name#.$=?n
}
macro MESSAGEZ name, i, prefix, [p] {
common
NUMBER i
?n=0
label name dword
forward
local l
dd l
forward
match a==b, p \{
l db b, 0
prefix\#_\#a=?n
?n=?n+1
\}
common
name#.$=?n
numeric prefix#_#LAST=?n
}
; create 'text' in code. r/egister='t/ext'
; WARNING: all commands that accept a literal
; 'text' parameter (.t suffix) will alter eax.
; only intended for testing and utilities
macro make.txt r, t {
if t eqtype ""
local ..t, ..e
jmp ..e
..t db t, 0
..e:
mov r, ..t
else
mov r, t
end if
}
; define TEXT in code
macro TXT [p] {
common
local ..e
jmp ..e
TEXT p
..e:
}
;;;;;;;;;;;;;;;;;;;;; LET ;;;;;;;;;;;;;;;;;;;;;;;;
; perform HL assignment/s, operation/s and
; low-level "expressions". example:
; let esi=[source], ecx>>8, eax=&[esi+ecx*4]
; ecx=[p], ecx-1, edx=[n], edx+ecx, eax=ecx,\
; eax-edx, eax&ecx, ecx=eax, edx=[n], eax+edx,\
; [r]<<8, [g]<<8, [b]<<8, ecx=[n],\
; eax=[r2], eax<<8, eax-[r], eax/ecx, [nr]=eax,\
; eax=[g2], eax<<8, eax-[g], eax/ecx, [ng]=eax,\
; eax=[b2], eax<<8, eax-[b], eax/ecx, [nb]=eax
; signed is the default for numbers that can
; be negative (ex, coordinates). some symbols
; are for unsigned operations (>>> is shr)
; WARNING: +/- [b+/-i] sequence will not be
; interpreted correctly. both ++/--/+-/-+ cannot
; used. replace let eax+[?image.x+edx] (has 2 ++)
; with: let ecx=[?image.x+edx], eax+ecx
macro let [p] {
forward
define ?s 0
; a=&[b], lea r, [b]
match =0 a==&b, ?s p \{
lea a, b
define ?s 1
\}
; a==>[b], movzx r, byte [b]
match =0 a====>b, ?s p \{
movzx a, byte b
define ?s 1
\}
; a=>[b], movsx r, byte [b]
match =0 a==>b, ?s p \{
movsx a, byte b
define ?s 1
\}
; a=b, mov or push/pop or xor
match =0 a==b, ?s p \{
if a eqtype [] & b eqtype [] ; m=m
push dword b
pop dword a
else
if b eq 0 & \
a in <eax,ecx,edx,ebx,esi,edi>
xor a, a
else
mov a, b
end if
end if
define ?s 1
\}
; binary and/or
match =0 a&b, ?s p \{ and a, b
define ?s 1 \}
match =0 a|b, ?s p \{ or a, b
define ?s 1 \}
; shifts. note: >>> must be matched
; before >>
match =0 a>>>b, ?s p \{ shr a, b
define ?s 1 \}
match =0 a<<b, ?s p \{ sal a, b
define ?s 1 \}
match =0 a>>b, ?s p \{ sar a, b
define ?s 1 \}
; increment/decrement
match =0 a--, ?s p \{
dec a
define ?s 1
\}
match =0 a++, ?s p \{
inc a
define ?s 1
\}
; add/subtract
match =0 a-b, ?s p \{
if b eq 1
dec a
else
sub a, b
end if
define ?s 1
\}
match =0 a+b, ?s p \{
if b eq 1
inc a
else
add a, b
end if
define ?s 1
\}
; multiply. 2/4/8 will be optimized
; and replaced with shift left 1/2/3
match =0 a*b, ?s p \{
if b eq 2
sal a, 1
else if b eq 4
sal a, 2
else if b eq 8
sal a, 3
else
imul a, b
end if
define ?s 1
\}
; divide. a: must be eax or m/2/4/8.
; b: must be m, ecx or 2/4/8. example:
; eax=n/123 may be written as:
; let eax=[n], ecx=123, eax/ecx
; ... instead of 4 separate lines
match =0 a/b, ?s p \{
if b eq 2
sar a, 1
else if b eq 4
sar a, 2
else if b eq 8
sar a, 3
else
if a eq eax
cdq
idiv b
else
'Unsupported'
end if
end if
define ?s 1
\}
; jmp/jz/jnz. only support the most
; common ones for fast assembly speed...
match =0 =jmp l, ?s p \{
jmp l
define ?s 1
\}
match =0 =jz l, ?s p \{
jz l
define ?s 1
\}
match =0 =jnz l, ?s p \{
jnz l
define ?s 1
\}
; neg/not unary prefixes
match =0 =neg a, ?s p \{
neg a
define ?s 1
\}
match =0 =not a, ?s p \{
not a
define ?s 1
\}
verify.syntax .let
}
; set/end hl block
macro set.hl.block c { HL.BLOCK=c }
macro end.hl.block c {
if HL.BLOCK=c
HL.BLOCK=0
else
'end/x unexpected'
end if
}
numeric IF.BLOCK, ELSE.BLOCK,\
LOOP.BLOCK
;;;;;;;;;;;;;;; FASM'S STRUCT.INC ;;;;;;;;;;;;;;;;
; an edited version of \MACRO\STRUCT.INC designed
; for Z77 HL variables
; NOTE: VARIABLE.INC>BLOCK can define/reserve
; any byte array so it replaces rb/rw/etc
macro struct name {
virtual at 0
fields@struct equ name
match child parent, name \{
fields@struct equ child,fields@\#parent \}
sub@struct equ
macro define.field.member type \{
struc type [val] \\{ \\common
define field@struct .,type,<val>
fields@struct equ fields@struct,field@struct \\}
\}
macro define.field.macro type \{
macro type [val] \\{ \\common \\local anonymous
define field@struct anonymous,type,<val>
fields@struct equ fields@struct,field@struct \\}
\}
define.field.member db
define.field.member dw
define.field.member dd
define.field.macro db
define.field.macro dw
define.field.macro dd
macro struct \{
fields@struct equ fields@struct,,substruct,<
sub@struct equ substruct
\}
}
macro ends {
match , sub@struct \{
restruc db,dw,dd
purge db,dw,dd
purge struct
match name tail,fields@struct, \\{
if $
'Error: Invalid member'
end if
\\}
match name=,fields,fields@struct \\{
fields@struct equ
make@struct name,fields
define fields@\\#name fields \\}
end virtual \}
match any, sub@struct \{
fields@struct equ fields@struct> \}
restore sub@struct
}
macro make@struct name,[field,type,def] {
common
local define
define equ name
forward
local sub
match , field \{
make@substruct type,name,sub def
define equ define,.,sub, \}
match any, field \{
define equ define,.#field,type,<def> \}
common
match fields, define \{ define@struct fields \}
}
macro define@struct name,[field,type,def] {
common
local list
list equ
forward
if ~ field eq .
name#field type def
sizeof.#name#field=$-name#field
else
label name#.#type
rb sizeof.#type
end if
local value
match any, list \{ list equ list, \}
list equ list <value>
common
sizeof.#name = $
restruc name
match values, list \{
struc name value \\{ \\local \\..base
match any, fields@struct \\\{
fields@struct equ fields@struct,.,name,<values> \\\}
match , fields@struct \\\{ label \\..base
forward
match , value \\\\{ field type def \\\\}
match any, value \\\\{ field type value
if ~ field eq .
rb sizeof.#name#field - ($-field)
end if \\\\}
common label . at \\..base \\\}
\\}
macro name value \\{
match any, fields@struct \\\{ \\\local anonymous
fields@struct equ fields@struct,anonymous,name,<values> \\\}
match , fields@struct \\\{
forward
match , value \\\\{ type def \\\\}
match any, value \\\\{ \\\\local ..field
..field = $
type value
if ~ field eq .
rb sizeof.#name#field - ($-..field)
end if \\\\}
common \\\} \\} \}
}
macro enable@substruct {
macro make@substruct substruct,\
parent,name,[field,type,def] \{
\common
\local define
define equ parent,name
\forward
\local sub
match , field \\{ match any, type \\\{ enable@substruct
make@substruct type,parent,sub def
purge make@substruct
define equ define,.,sub, \\\} \\}
match any, field \\{ define equ define,.\#field,type,<def> \\}
\common
match fields, define \\{ define@\#substruct fields \\} \}
}
enable@substruct
macro define@substruct parent,name,[field,type,def] {
common
virtual at parent#.#name
forward
if ~ field eq .
parent#field type def
sizeof.#parent#field = $ - parent#field
else
label parent#.#type
rb sizeof.#type
end if
common
sizeof.#name = $ - parent#.#name
end virtual
struc name value \{
label .\#name
forward
match , value \\{ field type def \\}
match any, value \\{ field type value
if ~ field eq .
rb sizeof.#parent#field - ($-field)
end if \\}
common \}
macro name value \{
\local ..anonymous
..anonymous name \}
}
; $$$$$$$$$$$$$$ Z77 ASM LIBRARY $$$$$$$$$$$$$$$$$
; ************** SUNGOD SOFTWARE *****************
; ??????????????? STRUCTURE.INC ??????????????????
macro STRUCTURE type {
?TYPE equ type
struct _#type
macro type [names] \{ ; IMAGE a, b, c
forward
names _\#type
common
\}
type#.$=sizeof._#type
}
macro TYPE [p] {
common
match name==members, p \{
STRUCTURE name
members
ends
\}
}
macro INHERIT [s] { forward s#.X }
macro ASSUME [p] {
match name==type, p \{
virtual at 0
type name
end virtual
\}
}
macro ENDS name {
ends
if ~p eq
ASSUME name=?TYPE
end if
}
structure fix STRUCTURE ; optional
ends fix ENDS
; $$$$$$$$$$$$$$ Z77 ASM LIBRARY $$$$$$$$$$$$$$$$$
; ************** SUNGOD SOFTWARE *****************
; ??????????????? FUNCTION.INC ???????????????????
macro pushr [p] { ; push parameters backwards
common ; to access forwards
if ~p eq
reverse
if p eq
'Invalid # of parameter/s'
end if
pushd p
common
end if
}
; call a/ddress direct or p/ointer indirect
macro call a, [p] {
common pushr p
call a
}
macro callp c, [p] { common call [c], p }
; call "variadic" procedure with "variable
; arguments" (...). push invisible # arguments
; last, call, then adjust esp after
macro callv c, [p] {
common ?n=0
reverse pushd p
?n=?n+1
common push ?n
call c
add esp, (?n+1)*4
}
; call "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 method offset
}
; call function pointer if non-zero
macro callfp f {
cmp dword [f], 0
jz @f
call dword [f]
@@:
}
; call function if defined
macro ?call name, [p] {
common
if defined name
call name, p
end if
}
; call function then get return. example:
; get [n]=text.n [t]
; get [c]=rgb 128, 0, 64
macro get [p] {
common
define ?s 0
match v==f, p \{
f
mov v, eax
define ?s 1
\}
match =0 v==f ps, ?s p \{
f ps
mov v, eax
\}
}
; set label for try
define ?try.l .!
macro fault l { define ?try.l l }
; call function then jmp to return
; if it returns 0. example:
; try open filename
; try [p]=allocate 4*KB
macro try [p] {
common
define ?s 0
match a==b, p \{
b
mov a, eax
define ?s 1
\}
if ?s eq 0
common p
end if
fail ?try.l ; endf
}
;;;;;;;;;;;;;; FUNCTION/PROCEDURE ;;;;;;;;;;;;;;;
macro DEBUG { ?DEBUG?: }
macro if.debug { if defined ?DEBUG? }
; create "function/proc/edure"...
macro function name, [p] {
common
; if debug, insert function name to view as
; a "string" in PE Explorer
if.debug
@@: db `name, 0
end if
; only insert this inside of the executable
; if it was accessed somewhere
if used !#name
!#name: ; real function !name
; macro to call with no 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=\ ; i++
..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 functions. no ret/urn before endf.
; it inserts one automatically
macro return v {
if ~v eq ; value?
mov eax, v
end if
if ..n.parameters<>0 ; if parameters
mov esp, ebp
pop ebp
ret ..n.parameters*4 ; ret n
else if ..n.locals<>0 ; if locals
mov esp, ebp
pop ebp
ret
else
ret
end if
}
; exit function; an effecient "return"
; that jmps to endf without repeating
; epilogue sequence (use this if there
; are locals/parameters and registers
; to preserve)
macro escape v {
if ~v eq
mov eax, v
end if
jmp .!
}
; end function
macro endf v {
if ~v eq
mov eax, v
end if
.!:
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 \}
fault .! ; reset try label
end if
; end "if used name" at very beginning
; of function
end if
}
; 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 ; create stack frame?
push ebp
mov ebp, esp
end if
sub esp, ..locals.size ; allocate locals
}
;;;;;;;;;;;;;;;;;; TESTING... ;;;;;;;;;;;;;;;;;;;;
; create locals of specified sizes or 32BIT.
; example:
; locale x, y, username(32), filename(256),\
; image(IMAGE.$), my.font(FONT.$), etc
macro locale [p] {
common
..locals.size=0
forward ; get names and sizes
define ?s 0
match name(size), p \{ ; size specified
?list.attach local.names, name
verify.size size
..locals.size=..locals.size+size
define ?s 1
\}
match =0 name, ?s p \{ ; default 32BIT
?list.attach local.names, name
..locals.size=..locals.size+4
define ?s 1
\}
..n.locals=..n.locals+1
common
virtual at ebp-..locals.size ; get offsets
forward
local ..l
define ?s 0
match name(size), p \{
..l dd (size/4) dup(?)
name equ ..l
define ?s 1
\}
match =0 name, ?s p \{ ; default 32BIT
..l dd ?
name equ ..l
define ?s 1
\}
common
end virtual
if ..n.parameters=0 ; create stack frame?
push ebp
mov ebp, esp
end if
sub esp, ..locals.size ; allocate locals
}
; create locals of size
macro localss size, [p] {
common local.names equ p
if ..n.parameters=0 \
& ..n.locals=0
push ebp
mov ebp, esp
end if
forward ..n.locals=..n.locals+1
common ..locals.size=..n.locals*size
virtual at ebp-..locals.size
forward
local ..l
..l: db size dup(0)
p equ ..l
common
end virtual
sub esp, ..locals.size
}
macro localt [p] { common localss 1*KB, p }
macro localst [p] { common localss 256, p }
; load structure members to locals of the
; same name. example:
; get.s eax, ?box, box, x, y, w, h -
; loads box.x/y/w/h to local x/y/w/h using eax
; as a base register and it produces 4 lines
; (# parameters in [v])
; 2-DO: replace this with an improved
; "assume" keyword that automatically adds
; a base register for the duration of function
; or until it's re-assigned
macro get.s r, vs, s, [v] {
common let r=[s]
forward let [v]=[vs#.#v+r]
}
; $$$$$$$$$$$$$$$ Z77 ASM LIBRARY $$$$$$$$$$$$$$$$
; *************** SUNGOD SOFTWARE ****************
; ??????????????????? IF.INC ?????????????????????
true equ eax
false equ not eax
result equ eax
?NOT equ 0
?use.r 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 \\{
if ?use.r eq 0
O A, B ; opcode o1, o2
else
mov ?use.r, A
O ?use.r, B
end if
if ?NOT eq 0
j\#C l
else
jN\#C l
end if
define ?s 1
\\}
\}
; standard expressions...
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 (a<>b)
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
'Invalid expression'
end if
purge J
?use.r equ 0
}
; 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
}
; call function with parameters then
; .if non/zero
macro !if f, [p] {
common f p
.if eax
}
macro !if.n f, [p] {
common f p
.if not eax
}
jNE equ jne
jNNE equ je
jNG equ jng
jNL equ jnl
macro jif r, c, l {
test r, r
j#c l
}
macro fail l {
if l eq
jif eax, z, .!
else
jif eax, z, l
end if
}
macro failn l {
if l eq
cmp eax, -1
je .!
else
cmp eax, -1
je l
end if
}
macro success l { jif eax, nz, l }
failnz fix success
; fail? or escape? on condition
; example: escape? eax=-1
macro fail? [c] {
common
if c eq
test eax, eax
jz .!
else
.if c
jmp .!
.end
end if
}
macro escape? [c] { common .jif .!, c }
; $$$$$$$$$$$$$$$ Z77 ASM LIBRARY $$$$$$$$$$$$$$$$
; *************** SUNGOD SOFTWARE ****************
; ?????????????????? LOOP.INC ????????????????????
; .while a<b
; .endw
; .until a=b
; .endu
; .loop i=x to n
; .endl
; .for i=n, i>0, i-- ; assign, compare, operate
; .endf
; WARNING: .loop/.for alters ECX on entry/exit to
; support cmp memory operands. .while/.until do
; not alter any registers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
macro .while [c] {
common
local ..next, ..out
?NEXT equ ..next
?OUT equ ..out
.if c
; ...
}
macro .endw {
?NEXT:
jmp ?START
.end
?OUT:
restore ?NEXT, ?OUT
}
macro .until [c] {
common
?NOT equ 1
.while c
?NOT equ 0
}
.endu fix .endw
; for [i]=0, [i]<[n], [i]++ ; algorithm:
; .for let a, .while b, let c
macro .for [p] {
common
local ..nextf
?NEXT equ ..nextf
?FOR equ
define ?s 0
match a=,b=,c, p \{
?use.r equ ecx
let a
.while b ; {
?FOR equ c
define ?s 1
\}
verify.syntax .for
}
macro .endf {
let ?FOR
.endw ; }
}
; .loop [i]=0 to [n]
macro .loop [c] {
common
local ..start, ..end
?START equ ..start
?END equ ..end
define ?s 0
match =0 i==x =to n, ?s c \{
define ?s 1
?INDEX equ i
push x
pop i
?START:
mov ecx, i
cmp ecx, n
jge ?END
\}
verify.syntax .loop
}
macro .endl {
inc ?INDEX ; i++
jmp ?START ; continue
?END:
restore ?START, ?END, ?INDEX
}
Example: function align.n, n, p
let ecx=[p], ecx-1, edx=[n], edx+ecx, eax=ecx,\
eax-edx, eax&ecx, ecx=eax, edx=[n], eax+edx
endf
let \ ; calculate deltas: (((s-d)*a)/256)+d
eax=[sr], eax-[dr], eax*[n], eax>>8, eax+[dr],\
ecx=[sg], ecx-[dg], ecx*[n], ecx>>8, ecx+[dg],\
edx=[sb], edx-[db], edx*[n], edx>>8, edx+[db]
let \ ; construct RGB
eax<<16, ecx<<8, eax|ecx, eax|edx
function rotate.image, image, way
locals x, y, w, h, p, s, col, row
let eax=[image], [s]=[?image.p+eax],\
[w]=[?image.w+eax], [h]=[?image.h+eax]
try [p]=scratch [h], [w] ; w/h reversed
.if [way]='r' ; right, 90
let eax=[h], eax--, [col]=eax
.loop [y]=0 to [h]
.loop [x]=0 to [w]
let eax=[x], eax*[h], eax+[col], eax<<2,\
eax+[p], edx=[y], edx*[w], edx+[x], edx<<2,\
edx+[s], [eax]=[edx]
.endl
let [col]--
.endl
.else.if [way]='l' ; left, 270
let [col]=0
.loop [y]=0 to [h]
let eax=[w], eax--, [row]=eax
.loop [x]=0 to [w]
let eax=[row], eax*[h], eax+[col], eax<<2,\
eax+[p], edx=[y], edx*[w], edx+[x], edx<<2,\
edx+[s], [eax]=[edx], [row]--
.endl
let [col]++
.endl
.end
end.scratch [image]
let eax=[image],\ ; adjust location
edx=[?image.x+eax], ecx=[w], ecx>>1, edx+ecx,\
ecx=[h], ecx>>1, edx-ecx, [?image.x+eax]=edx,\
edx=[?image.y+eax], ecx=[h], ecx>>1, edx+ecx,\
ecx=[w], ecx>>1, edx-ecx, [?image.y+eax]=edx
endf Optional "Uppercase" naming convention: Structure Image
Void p
Integer x, y, w, h, bpp=32
Color key, alpha
EndS ?image
Function String.Length, t
Let eax=[t]
While byte [eax]
Let eax++
EndW
Let eax-[t]
EndF Z77 ("Future Assembler" syntax) is the first "language" written in FASM by one who has been studying compiler/assembler creation/internals since the late 90s. It is, by far, the most useful, tested and proven to be highly effective with a library and examples.
You are lucky to have this for reference. I had to learn the hard way, all by myself with no help and have spent years trying to perfect this language. Hope this helps beginners learn how to write macros.
Last edited by uart777 on 23 Mar 2013, 02:49; edited 2 times in total
|