flat assembler
Message board for the users of flat assembler.

Index > Macroinstructions > Modular preprocessor for fasmg/fasm2

Author
Thread Post new topic Reply to topic
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8394
Location: Kraków, Poland
Tomasz Grysztar 05 May 2025, 09:08
Extensions like "inlinemacro" that come with fasm2 header set require a custom global preprocessor, which idiomatically looks like:
Code:
calminstruction ?! &line&    
and is able to transparently analyse all the lines of the source and possibly mutate them before passing to the assembly.

This also requires some additional handling around includes, because such preprocessing macros are non-recursive, so they are not active during the processing of included contents, as it all happens within a single call to interceptor macro, with the line being the "include" statement.

Because of this detail, while multiple preprocessors can be easily stacked on top of each other, it is harder to get them to cooperate nicely inside included files. To provide a possible solution, I designed a modular preprocessor, which could be a standardised base for interoperating packages need to add custom preprocessors for all the lines.

A prototype looks like this:
Code:
; Modular preprocessor.

if ~ defined Preprocessor?

        define Preprocessor?
        Preprocessor? = 'Modular'

        calminstruction Preprocessor? &line&
                match =include any, line
                jyes outside
                assemble line
                exit
            outside:
                take Preprocessor?.outside, line
        end calminstruction

        macro Preprocessor?.init? chain
                chain
                macro include? file*, head
                        include file, Preprocessor?.init head
                        purge ?, include?
                end macro
                calminstruction ?! &line&
                        call    Preprocessor?, line
                        take    line, Preprocessor?.outside
                        jyes    outside
                        exit
                     outside:
                        assemble line
                end calminstruction
        end macro

        define Preprocessor?.start? Preprocessor?.start?

        macro Preprocessor?.start?
        end macro

        macro Preprocessor?.start?
                purge Preprocessor?.start?
                Preprocessor?.init?
        end macro

end if    
To add a new preprocessor into the chain, it is enough to define it as:
Code:
calminstruction Preprocessor?! &line&    
But instead of passing the line directly to assembly, it should call the "Preprocessor?" macro with the text of the line as only argument, to pass the line down the chain.

The preprocessors do not start right away. To start processing all the subsequent lines, it is necessary to call the macro:
Code:
Preprocessor?.start    
There is also a symbolic link that allows to call it just as easily from CALM:
Code:
assemble Preprocessor?.start    
Repeated calls to this macro are allowed and have no additional effect.

For example, this is a simple implementation of FIX command (similar to fasm's directive):
Code:
define fix? fix?

calminstruction (name) fix? &value&
        arrange name, fix.name
        publish name, value
        assemble Preprocessor?.start
    done:
end calminstruction

calminstruction Preprocessor?! &line&
        local any
        match any =fix? any?, line
        jyes skip
        transform line, fix
    skip:
        call Preprocessor?, line
end calminstruction    
And the inline macro package can be adapted to use this engine, allowing multiple preprocessors to cooperate:
Code:
define inlinemacro? inlinemacro

calminstruction inlinemacro?! declaration&
        local   name
        match   name(arguments?), declaration
        jyes    define
        match   name= arguments?, declaration
        jyes    define
        match   name arguments?, declaration
    define:
        arrange tmp, =__inline__.name
        arrange name, =inlinemacro.name
        publish name, tmp
        arrange tmp, =struc (=return?) name arguments
        assemble tmp
end calminstruction

macro end?.inlinemacro?!
        end struc
end macro

calminstruction Preprocessor?! &text&
        local   head, tail, name, arguments, more, i
        init    i, 0
        match   =inlinemacro? more, text
        jyes    ready
        transform text, inlinemacro
        jno     ready
        match   =else? more, text
        jno     preprocess
        compute i, i+1
        arrange text, =__inline__.(=else =if 1) =__inline__.(=__return__.i==1) text =__inline__.(=end =if) =__inline__.(=if ~=definite =__return__.i)
    preprocess:
        match   head? =__inline__.name?(tail?, text
        jno     ready
        match   arguments?) tail?, tail
        jno     ready   ; syntax error
    collect:
        match   arguments?, arguments, ()
        jyes    inline
        match   more?) tail?, tail
        jno     ready   ; syntax error
        arrange arguments, arguments) more
        jump    collect
    inline:
        match   , name
        jyes    special
        local   tmp, return
        compute i, i+1
        arrange return, =__return__.i
        arrange tmp, return =inlinemacro.name arguments
        arrange text, head return tail
        take    text, tmp
        jump    preprocess
    special:
        arrange text, head tail
        take    text, arguments
        jump    preprocess
    ready:
        call    Preprocessor?, text
        take    , text
        take    text, text
        jyes    preprocess
end calminstruction

Preprocessor.start    
Post 05 May 2025, 09:08
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8394
Location: Kraków, Poland
Tomasz Grysztar 05 May 2025, 09:25
My fun little test with all the above packages combined:
Code:
mret? fix return =

inlinemacro cat(a,b)
            MRET       a bappend b
end inlinemacro

display cat(9, 'Test')    
Post 05 May 2025, 09:25
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-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.