flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > New Language Macros

Author
Thread Post new topic Reply to topic
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 19 Mar 2013, 09:36
An updated version of my LANGUAGE.INC:
Code:
; $$$$$$$$$$$$$$$ 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+Cool+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:
Code:
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:
Code:
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
Post 19 Mar 2013, 09:36
View user's profile Send private message Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1670
Location: Toronto, Canada
AsmGuru62 19 Mar 2013, 13:01
I would have done StrCpy with MOVSB.
Post 19 Mar 2013, 13:01
View user's profile Send private message Send e-mail Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 23 Mar 2013, 02:44
Code excerpts:
Code:
; n+(((p-1)-(n+p-1))&(p-1))

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 

; create AA.BBB.CCCb/AA.BB.CC.DDb BIT structures

function triplet, a, b, c
let eax=[a], eax<<6,\
ecx=[b], ecx<<3, eax|ecx, eax|[c]
endf

function quadruplet, a, b, c, d
let eax=[a], eax<<6, ecx=[b], ecx<<4,\
edx=[c], edx<<2, eax|ecx, eax|edx, eax|[d]
endf

; scale by 256 (2^Cool then calculate deltas

let [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

; draw arbitrary line from x1/y1 to x2/y2...

function draw.line.a, x1, y1, x2, y2, c
locals i, x, y, px, py, dx, dy
let eax=[x2], eax-[x1], [dx]=eax,\
 ecx=[y2], ecx-[y1], [dy]=ecx,\
 eax>>1, [x]=eax, ecx>>1, [y]=ecx,\
 [px]=[x1], [py]=[y1]
vga.xy [px], [py]
let [eax]=[c], ecx=[dy]
.if [dx]>ecx
  .loop [i]=0 to [dx]
    let eax=[y], eax+[dy], [y]=eax
    .if eax>=[dx]
      let eax=[dx], [y]-eax, [py]++
    .end
    let [px]++
    draw.pixel [px], [py], [c]
  .endl
.else
  .loop [i]=0 to [dy]
    let eax=[x], eax+[dx], [x]=eax
    .if eax>=[dy]
      let eax=[dy], [x]-eax, [px]++
    .end
    let [py]++
    draw.pixel [px], [py], [c]
  .endl
.end
endf

; convert 32BPP image to alpha based on a
; grayscale source image...

; destiny|=((source&BLUE)<<24)

function convert.image.alpha, image, source
push esi edi
let esi=[source], esi=[?image.p+esi],\
 edi=[image], eax=edi, edi=[?image.p+edi],\
 ecx=[?image.w+eax], edx=[?image.h+eax], ecx*edx
.convert:
 let eax=[esi], eax&0FFh, eax<<24,\
 [edi]|eax, edi+4, esi+4, ecx--
jnz .convert
pop edi esi
endf  

; draw 32BPP scanline with alpha (AA.RR.GG.BBh)

; * 0     - 100% visible/opaque
; * 1-254 - transparent
; * 255   - 100% invisible (a&0FF000000h=0)

function draw.scanline.a, pixels, x, y, w
locals i
push esi edi
let eax=&[i], esi=&[x], edi=&[y], ecx=&[w]
clip.scanline eax, esi, edi, ecx
fail .e
vga.xy [esi], [edi]
let edi=eax,\
 esi=[pixels], esi+[i]
.loop [x]=0 to [w]      ; draw pixels
  let eax=[esi]         ; get pixel
  .if eax&0FF000000h    ; alpha?
    let ecx=eax
    shr ecx, 24
    .if ecx=0FFh        ; invisible
      jmp .next
    .end
    mix [edi], eax, ecx ; result in eax
  .end
  let [edi]=eax         ; *vga++=*p++
  .next:
  let esi+4, edi+4
.endl
.e: pop edi esi
endf 

; draw "bitmap"; 2D pixel array...

function draw.bitmap, pixels,\
 x, y, w, h, key, alpha
locals p, i, iw, b
try visible? \               ; visible?
 [x], [y], [w], [h]
let eax=[pixels], [p]=eax,\  ; p=pixels
 ecx=[w], ecx<<2, [iw]=ecx,\ ; image w in bytes
 ecx=[y], ecx+[h], [b]=ecx   ; bottom=y+h
.loop [i]=[y] to [b]         ; draw h # scanlines
  draw.scanline [p],\        ; from y to b
   [x], [i], [w],\
   [key], [alpha]
  let eax=[iw], [p]+eax      ; increment p by iw
.endl
endf

; rotate 'r'ight (90) or 'l'eft (270)

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

; create palette ARGB32 from image...

function create.palette, image, nc
locals i, n, c, pn, pixels, palette, size
let eax=[nc], eax*4, [size]=eax
try [palette]=allocate eax
memory.zero [palette], [size]
let eax=[image], [pixels]=[?image.p+eax],\
 ecx=[?image.w+eax], edx=[?image.h+eax],\
 ecx*edx, [n]=ecx, [pn]=0
.loop [i]=0 to [n]
  let eax=[pixels], [pixels]+4, [c]=[eax],\
   ecx=[pn], ecx++
  .if.unique.color [palette], [eax], ecx
    let eax=[palette], eax+[pn],\
    [eax]=[c], [pn]+4
  .end
.endl
let ecx=[pn], ecx/4, ecx++
endf [palette]

; reverse byte order ("endianness") of
; ARGB32/BGRA32 pixels/palette...

function reverse.pixels, p, n
locals i
.loop [i]=0 to [n]
  let eax=[p], ecx=[eax]
  bswap ecx
  let [eax]=ecx, [p]+4
.endl
endf

; convert array of pixels/colors/palette
; from.to A/RGB. p: 32=memory, 24=file

function convert.pixels.32.24, p, n
locals i
let eax=[p], edx=eax
.loop [i]=0 to [n]
  let ecx=[edx+1], ch=[edx+2],\
  [eax]=ecx, edx+4, eax+3
.endl
endf

function convert.pixels.24.32, p, n
locals i
let eax=[p], edx=eax, ecx=[n],\
 eax=&[eax+ecx*4-4], ecx*3, ecx-3, edx+ecx
.loop [i]=0 to [n]
  let ecx=[edx], ecx&0FFFFFFh, ecx<<8,\
  [eax]=ecx, edx-3, eax-4
.endl
endf

function compress.pixels, pixels, n
locals i, p, s, c, pc, rle, size
let [size]=[n], eax=[pixels],\
 [p]=eax, [s]=eax
.loop [i]=0 to [n]
  let eax=[s], ecx==>[eax], [c]=ecx
  .if [i]
    .if [pc]=ecx
      .if [eax+1] not cl
        jmp .next
      .end
      let [rle]=0
      .while [eax]=cl
        let [rle]++, eax++, [size]--,\
         edx=[rle], edx+[i]
        .if edx>=[n]
          jmp .stop
        .end
        .if [rle]>14 ; 4BIT (2-15)
          .stop:
          let cl=11111111b
        .end
      .endw ; set rle byte and advance...
      let [s]=eax, eax=[p], [p]++, [size]++,\
       ecx=[rle], cl|11100000b, [eax]=cl
      jmp .el
    .end
  .end
  .next:
  let eax=[p], ecx==>[c], [eax]=cl,\
   [p]++, [s]++
  .el: let [pc]=[c]
.endl
endf [size]

function uncompress.pixels, pixels, n
locals i, p, q, s, c, x, pc, rle, size
let eax=[n], [size]=eax
try [p]=allocate eax
let [q]=eax, [s]=[pixels]
.loop [i]=0 to [n]
  let eax=[s], ecx==>[eax], [c]=ecx
  .if ecx&11100000b
    let ecx&1111b, [rle]=ecx, ecx--,\
     [size]+ecx, eax=[p], ecx=[c],\
     [eax]=cl, edx=[pc]
    .loop [x]=0 to [rle]
      let [eax]=dl, eax++
    .endl
    let [p]=eax, [s]++
  .else
    let eax=[p], ecx=[c], [pc]=ecx,\
    [eax]=cl, [p]++, [s]++
  .end
.endl
memory.copy [pixels], [q], [size]
destroy [q]
endf [size]    
Guru: No time to explain. Suffice to say, I work on much bigger projects with 1,400+ routines (released 900+) and Z77 is evolving into Universal ASM for true portability. Studying ARM7 now.
Post 23 Mar 2013, 02:44
View user's profile Send private message Reply with quote
baldr



Joined: 19 Mar 2008
Posts: 1651
baldr 07 Apr 2013, 21:08
uart777,

db is a reserved word. Care to explain?
Post 07 Apr 2013, 21:08
View user's profile Send private message Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 10 Apr 2013, 08:31
baldr: Example excerpt. Locals can temporarily rename directives.

Guru: 5th time you've suggested that my macros are unoptimized. Prove it. Show me the numbers. All claims and no evidence.

Optimization rule #1: Concentrate on what needs to be optimized: graphics rendering, file processing, advanced searching, etc. Otherwise, there will be no noticeable difference in speed. If I were to optimize text.copy, XMM movaps 128BIT copy is way faster than movsb for large sizes/files and it would be a separate CPU-specific routine. Not a replacement for universal byte-copy or inline macro and there is no one-for-all solution.

You have no reason to use ASM. Little text-editors and tetris games can be made in JavaScript. No special knowledge is required as with compilers/languages, OS, embedded systems.
Post 10 Apr 2013, 08:31
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.