uart777
Joined: 17 Jan 2012
Posts: 369
|
Hi, everyone!
Years ago, I was toying with the "let a=b" example macro written by Tomasz. I thought it was an interesting concept and a good example of the match directive, but it wasn't seriously useful because there is no difference between "mov eax,1" and "let eax=1"... not if there's only 1 operation.
So, I modified "let" with a forward to process multiple arguments then added more instructions - <<>> (shl/shr), &| (and/or) r=&[] (lea) - and basic optimizations like r=0 (xor r, r), x+1 (inc x). Now, it's extremely useful. You can write low-level "expressions" (so to speak) in polish notation, left to right with no precedence. Example:
; a=b*c+d>>4. reduces 5 lines to 1
let eax=[b], eax*[c], eax+[d], eax>>4, [a]=eax
Here are example procedures that use "let" entirely:
; mix a, b, n - alpha combination. n=0-255
; note: this only processes one pixel, but is
; fast enough for small images such as text,
; controls and anti-aliasing edges
command mix, a, b, n
locals sr, sg, sb, dr, dg, db
let eax=[a], edx=[b]
.if [n]=NO ; if no alpha, return a
jmp .r
.end
.if [n]>254 ; if maximum, return b
let eax=edx
jmp .r
.end
let \ ; extract r/g/b components
ecx=eax, ecx>>16, ecx&0FFh, [sr]=ecx,\
ecx=eax, ecx>>8, ecx&0FFh, [sg]=ecx,\
ecx=eax, ecx&0FFh, [sb]=ecx,\
ecx=edx, ecx>>16, ecx&0FFh, [dr]=ecx,\
ecx=edx, ecx>>8, ecx&0FFh, [dg]=ecx,\
ecx=edx, ecx&0FFh, [db]=ecx
let \ ; calculate deltas: (((s-d)*a)>>+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
.r:
endc
command draw.tilemap, tm
locals p, i,\
x, y, mx, my, mw, mh, tw, th,\
locations, images
let eax=[tm],\
[mx]=[?map.x+eax], [my]=[?map.y+eax],\
[mw]=[?map.w+eax], [mh]=[?map.h+eax],\
[tw]=[?map.tile.w+eax], [th]=[?map.tile.h+eax],\
ecx=&[?map.locations.p+eax], [locations]=ecx,\
ecx=&[?map.images+eax], [images]=ecx
let [i]=0
.loop [y]=0 to [mh]
.loop [x]=0 to [mw]
array.index [locations], [i]
.if dword [eax] not -1
get [p]=array.index [images], [eax]
let eax=[x], eax*[tw], eax+[mx],\
ecx=[y], ecx*[th], ecx+[my]
.if eax>=[screen.w]
jmp .end.x
.end
.if ecx>=[screen.h]
jmp .end.y
.end
draw.image.at [p], eax, ecx
.end
.end.x:
inc [i]
.endl
.endl
.end.y:
endc
command text.copy, a, b
let eax=[a], edx=[b]
.while byte [edx] ; while *b
let cl=[edx],\ ; *a++=*b++
[eax]=cl,\
eax+1, edx+1
.endw
let byte [eax]=0
endc
Finally, here's the advanced "let" macro (not quite finished yet):
macro let [p] {
forward
define ?s 0
match =0 a==&b, ?s p \{ ; a=&[b], lea r, [b]
lea a, b
define ?s 1
\}
match =0 a==>b, ?s p \{ ; a=>[b], movsx r, byte [b]
movsx a, byte b
define ?s 1
\}
match =0 a==b, ?s p \{ ; a=b, mov or push/pop
if a eqtype [] & b eqtype [] ; m=m
push dword b
pop dword a
else
; if r=0, use xor r,r
if a in <eax,ecx,edx,ebx,esi,edi> & b eq 0
xor a, a
else
mov a, b
end if
end if
define ?s 1
\}
; (match a-b must be located before a+b
; because it causes ambiguity with [disp+imm]?)
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
\}
match =0 a*b, ?s p \{ imul a, b
define ?s 1 \}
; for idiv, only eax/n is allowed
; n must be r/m, not i. alters edx
; example: eax=n/123 may be written:
; let eax=n, ecx=123, eax/ecx
match =0 =eax/n, ?s p \{
cdq
idiv n
define ?s 1 \}
match =0 a<<b, ?s p \{ shl a, b
define ?s 1 \}
match =0 a>>b, ?s p \{ shr a, b
define ?s 1 \}
match =0 a&b, ?s p \{ and a, b
define ?s 1 \}
match =0 a|b, ?s p \{ or a, b
define ?s 1 \}
if ?s eq 0
ERROR: 'Invalid HL syntax: ' p
end if
}
|