A new macro preprocessor for Fortran: FMacro

Hi everyone,

I’d like to announce a new macro preprocessor for Fortran (written in Fortran). It’s called FMacro, and located at hsnyder/FMacro: A macro preprocessor for Fortran (github.com). It is quite basic, but it only takes about 5 minutes to learn, requires nothing more than a Fortran compiler, and it solves most or all of the generic programming needs that I regularly encounter when writing Fortran.

This software is brand new - I welcome any bug reports, and while I’m aiming to keep it minimal, I’m open to feature requests as well. Note that I just now changed the name from “FtnTemple” to “FMacro”, so I apologize for the confusion to the few people from this community who had already found and starred it on github.

Note that there are already several more advanced (though more complex) preprocessors for Fortran, so if FMacro doesn’t meet your needs or suit your taste, you might wish to have a look at fypp, CoCo or prep.

19 Likes

Excellent! Perhaps we can use your FMacro as a basis for a Fortran implementation of a subset of fypp.

2 Likes

Just going to try it, but if it handles constant suffixes it would be nice to show that in an example
(ie can I use 0_T and if so how to handle whether to use 0 or 0.0 or 0.0d0). Can handle some of that with kind parameters, but it can be tricky.

It doesn’t currently support suffixes for literals. Is there a strong need? If you’re using FMacro to generate implementations for multiple real kinds, couldn’t you just use a literal with the largest supported real kind, and let the compiler do the work of down-converting? And if you’re supporting integer and non-integer types, I figure most literals would be 0 or 1.

Regarding suffixes for literals – one approach might be to define them as parameters, e.g.

subroutine test(x, y)
    ! Suppose these arguments have type/kind expanded from type(T)
    real(16), intent(inout) :: x(:)
    integer(8), intent(in) :: y

    ! We can define suffixes for literals to match the kind of x and y.
    integer, parameter :: wp = kind(x), ip = kind(y)

    print*, exp(-2.0_wp), exp(-2_ip * 1.0)

end subroutine

I imagine this might be more efficient than just using the largest supported kind (?).

@hsnyder This looks cool. Does it support the use of multiple macro parameters? - for example we might want the above subroutine for work for all combinations of real/integer kinds. This situation arises in some stdlib routines, for example in the selection module (note the double loop over arraykind and intkind).

It does not support that yet, but it’s my intention to add such functionality.