flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > MASM-like structures and procedures

Thread Post new topic Reply to topic
Tomasz Grysztar

Joined: 16 Jun 2003
Posts: 8346
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:
POINT struct
  x dd ?
  y dd ?
POINT ends

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

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

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

wp2 WINDOWPLACEMENT ; use default values    

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

     local c:WORD,d:RECT

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

Demo1 endp

Demo2 proc

      local d:DWORD

        mov     eax,[d]

Demo2 endp    

And here are the macros:
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 .
     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
       defargs@proc arg \}
    match =all@args, all@args
    \{ if used 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
        end if
        if ..ret
         retn ..ret
        end if \} }

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

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: 8346
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:
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:
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.