News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Tip for more readable code using #LOCALDEF

Started by donkey, December 19, 2011, 08:50:46 PM

Previous topic - Next topic

donkey

There are many times when I come back to a snippet of code after not using it for a couple of years and scratch my head wondering how it works. I should know, I wrote it, but there are times when the register designations are a bit complex and hard to follow. Lately I've been trying to write a particularly complicated peice of code that I want to avoid using memory based storage for. Well, avoiding using memory means a lot of registers holding the data and keeping track of which register has what data in a particular procedure can get you pulling your hair out. Enter #LOCALDEF, using it I can assign an ALIAS to a register then use that alias in its place. There are a couple of advantages to this, changing the register the alias is describing changes it through the whole procedure automatically and most importantly its easy to read and understand what the procedure is doing, finally since we are using #LOCALDEF, the definitions are local to the procedure, in other words you can reuse them as much as you like in other procedures.

Here's an example of a simple procedure that counts spaces:

CountSpaces FRAME pString
mov EDI,[pString]
mov ESI,0
mov EAX,0

.GETNEXTCHAR
mov DL,[EDI+ESI]
inc ESI
cmp DL,0
je >.ENDOFSTRING
cmp DL,' '
jne .GETNEXTCHAR
inc EAX
jmp .GETNEXTCHAR

.ENDOFSTRING
ret
endf


Now granted that procedure is really easy to follow but I'm not trying to confuse anyone, just demonstrating how using an alias can make your code more readable. Here's the same code using aliases:

CountSpaces FRAME pString
#LOCALDEF @BASEPTR EDI
#LOCALDEF @CHARINDEX ESI
#LOCALDEF @SPACECOUNT EAX
#LOCALDEF @CURRENTCHAR DL

mov @BASEPTR,[pString]
mov @CHARINDEX,0
mov @SPACECOUNT,0

.GETNEXTCHAR
mov @CURRENTCHAR,[@BASEPTR+@CHARINDEX]
inc @CHARINDEX
cmp @CURRENTCHAR,0
je >.ENDOFSTRING
cmp @CURRENTCHAR,' '
jne .GETNEXTCHAR
inc @SPACECOUNT
jmp .GETNEXTCHAR

.ENDOFSTRING
ret
endf


Note that above I started aliases with a @, that is not necessary but it helps me to remember that the label actually directly resolves to a register.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

jj2007

Edgar,

In my experience it takes only a few months until I have not the faintest idea what rubbish I was programming a few months ago :wink

Here is the Masm equivalent - I usually add the name of the register to remember it is a register:

RunPipe proc
LOCAL hReadOut, hWriteOut
   PipeEditEsi equ <esi>
   mov PipeEditEsi, hPipeEdit
   invoke ShowWindow, PipeEditEsi, SW_RESTORE
   SetMyFocus PipeEditEsi

It's a good technique, although during development, typing 100 times @CURRENTCHAR is prohibitive. Ex-post Find & Replace is better :bg

dedndave

TEXTEQU has an advantage for textual aliasing in that the label is "re-usable" - it may be assigned new values later in the source

_OutBufSize   TEXTEQU <[EBP+32]> ;output buffer size in bytes
_OutBufBase   TEXTEQU <[EBP+28]> ;output buffer base address
_InpValSize   TEXTEQU <[EBP+24]> ;input value size in bytes
_InpValBase   TEXTEQU <[EBP+20]> ;input value base address

;                      [EBP+16]   PROC return address
;                      [EBP+12]   saved ESI contents
;                      [EBP+8]    saved EDI contents
;                      [EBP+4]    saved EBX contents
;                      [EBP]      saved EBP contents

_SignXorMask  TEXTEQU <[EBP-4]>  ;sign XOR mask
_OutLastDword TEXTEQU <[EBP-8]>  ;address of last dword in output buffer


i also use "=" equates for numeric values - for the same reason

StyleFlags = WS_CHILD or WS_VISIBLE or WS_CLIPCHILDREN

        INVOKE  CreateWindowEx,edx,offset szClientClass,edx,
                StyleFlags,ecx,ecx,ecx,ecx,eax,edx,ebx,esp
;
;
;
StyleFlags = WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS

        INVOKE  CreateWindowEx,edx,offset szClientClass,edx,
                StyleFlags,ecx,ecx,ecx,ecx,eax,edx,ebx,esp


not that i have created any huge projects, but i try to reduce symbol space where practical