flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > MASM-like structures and procedures

Author
Thread Post new topic Reply to topic
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8353
Location: Kraków, Poland
Tomasz Grysztar 11 Jun 2005, 20:31
To show the potential power of the new features added to fasm recently I have designed a small package of macros that allow definitions of structures and procedures in a way very similar to MASM's.

The structures sample:
Code:
POINT struct
  x dd ?
  y dd ?
POINT ends

RECT struct
  left   dd ?
  top    dd ?
  right  dd ?
  bottom dd ?
RECT ends

WINDOWPLACEMENT struct
  length           dd sizeof.WINDOWPLACEMENT
  flags            dd ?
  showCmd          dd ?
  ptMinPosition    POINT
  ptMaxPosition    POINT
  rcNormalPosition RECT 0,0,100,100
WINDOWPLACEMENT ends

wp1 WINDOWPLACEMENT sizeof.WINDOWPLACEMENT,0,0,<0,0>,<100,100>,<10,10,50,50>

wp2 WINDOWPLACEMENT ; use default values    

And some procedures:
Code:
Demo1 proc a:BYTE, b:DWORD

     local c:WORD,d:RECT

        movzx     eax,[a]
        mov       [d.left],eax
        ret

Demo1 endp

Demo2 proc

      local d:DWORD

        mov     eax,[d]
        ret

Demo2 endp    


And here are the macros:
Code:
macro struct name
 { fields@struct equ name
   struc db val \{ fields@struct equ fields@struct,.,db,val \}
   struc dw val \{ fields@struct equ fields@struct,.,dw,val \}
   struc du val \{ fields@struct equ fields@struct,.,du,val \}
   struc dp val \{ fields@struct equ fields@struct,.,dp,val \}
   struc df val \{ fields@struct equ fields@struct,.,df,val \}
   struc dd val \{ fields@struct equ fields@struct,.,dd,val \}
   struc dq val \{ fields@struct equ fields@struct,.,dq,val \}
   struc dt val \{ fields@struct equ fields@struct,.,dt,val \} }

macro define@struct name,[field,type,default]
 { common struc name field \{
    match any, fields@struct \\{ fields@struct equ fields@struct,.,name,<field> \\}
    match , fields@struct \\{ label .
   forward
     match any, field \\\{ .#field type field \\\}
     match , field \\\{ .#field type default \\\}
   common \\} \}
   virtual at 0
    name name
    sizeof.#name = $ - name
   end virtual }

macro ends
 { restruc db,dw,du,dp,df,dd,dq,dt
   match fields,fields@struct \{ fields@struct equ
                                 define@struct fields \} }

struc struct
 { struct .
   name@struct equ . }

struc ends
 { match =.,name@struct \{ ends \} }

fields@struct equ

macro proc [params]
 { common
    match name arg,params
    \{ if used name
       name:
       defargs@proc arg \}
    match =all@args, all@args
    \{ if used params
       params:
       all@args equ \}
    local ..current,..size
    all@vars equ
    ..current = 0
    if ..ret | ..size
     push ebp
     mov ebp,esp
     if ..size
      sub esp,..size
     end if
    end if
    macro local [var]
    \{
       virtual at ebp-..size+..current
       match varname:vartype,var
       \\{
           macro label . \\\{ deflocal@proc .,: \\\}
           struc db val \\\{ deflocal@proc .,db val \\\}
           struc dw val \\\{ deflocal@proc .,dw val \\\}
           struc dp val \\\{ deflocal@proc .,dp val \\\}
           struc df val \\\{ deflocal@proc .,df val \\\}
           struc dd val \\\{ deflocal@proc .,dd val \\\}
           struc dt val \\\{ deflocal@proc .,dt val \\\}
           struc dq val \\\{ deflocal@proc .,dq val \\\}
           varname vartype
           purge label
           restruc db,dw,dp,df,dd,dt,dq
       \\}
       ..current = $-(ebp-..size)
       end virtual \}
    macro ret
     \{ ..size = (((..current-1) shr 2)+1) shl 2
        if ..ret | defined ..size
          leave
        end if
        if ..ret
         retn ..ret
        else
         retn
        end if \} }

macro defargs@proc [arg]
 { common
   virtual at ebp+8
   if ~ arg eq
   forward
     local ..arg,current@arg
     match argname:type, arg
      \{ current@arg equ argname
         label ..arg type
         argname equ ..arg
         if ( type in <pword,qword> )
           dq ?
         else
           dd ?
         end if \}
     match =current@arg,current@arg
      \{ current@arg equ arg
         arg equ ..arg
         ..arg dd ? \}
   common
     all@args equ current@arg
   forward
     restore current@arg
   common
     end if
     ..ret = $ - (ebp+8)
    end virtual }

macro deflocal@proc name,def
 { match any, all@vars \{ all@vars equ all@vars,name \}
   match ,all@vars \{ all@vars equ name \}
   local ..var
   name equ ..var
   ..var def }

struc byte { common . db ? }
struc word { common . dw ? }
struc dword { common . dd ? }
struc pword { common . dp ? }
struc qword { common . dq ? }
struc tword { common . dt ? }
struc dqword { common label . dqword
                   dq ?,? }

macro endp
 { purge return
   purge enter
   match all,all@args \{ restore all \}
   restore all@args
   match all,all@vars \{ restore all \}
   end if }

struc proc [params]
 { common proc . params
   name@proc equ . }

struc endp
 { match =.,name@proc \{ endp \} }

BYTE fix byte
WORD fix word
DWORD fix dword
PWORD fix pword
QWORD fix qword
TWORD fix tword
DQWORD fix dqword    
Post 11 Jun 2005, 20:31
View user's profile Send private message Visit poster's website Reply with quote
decard



Joined: 11 Sep 2003
Posts: 1092
Location: Poland
decard 11 Jun 2005, 21:18
Wow, FASM preprocessor is so powerfull now :O
Could you explain how does it work, ie. why structure and proc name can be written before macro?
Post 11 Jun 2005, 21:18
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8353
Location: Kraków, Poland
Tomasz Grysztar 11 Jun 2005, 21:32
The struc directive is used for this purpose, as it allows now to use the symbol constisting of individual dot to get the name of structure instance, and if preprocessor detects that this symbol was used inside the structure, it doesn't automatically generate the main label for structure, leaving this to you, so you can customize the definition to whatever you want. The difference shown on example:
Code:
struc byte value { db value }

a byte ? ; a: db ?

struc byte value { . db value }

b byte ? ; b db ?    

In second case the label is applied directly do the "db", so the label is defined with the byte type. As you should easily notice, this allows also to use the name of structure instance for completely different purposes than just label definition. This fragment from the above defines just a wrapper for the "struct" and "ends" macros:
Code:
struc struct
 { struct .
   name@struct equ . }

struc ends
 { match =.,name@struct \{ ends \} }    

It still can be improved, as such "ends" wrapper silently ignores when is used with name that doesn't match the name of currently used structure - it can be corrected to show an error or warning in such case.

The notes from this thread should also help understanding some of those macros.
Post 11 Jun 2005, 21:32
View user's profile Send private message Visit poster's website 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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.