Fortran Preprocessor (fpx) - core parsing and preprocessing module.
This module implements a full-featured, modern Fortran preprocessor supporting:
- C-style line continuations with \ and \\
- Fortran-style & continuations
- #define, #undef, object-like and function-like macros with variadic support
- #include with proper path resolution and recursion guard
- Conditional compilation: #if, #ifdef, #ifndef, #elif, #else, #endif
- Non-standard #for directive
- C-style /* ... */ comments (nestable aware)
- Macro expansion with argument substitution and stringification (#) / token-pasting (##)
- Interactive REPL mode when reading from stdin
- Multiple entry points for file-to-file, unit-to-unit, etc.
- Support ${x} for substituting macro name
The preprocessor is designed to be standards-conforming where possible while adding useful extensions (variadic macros, better diagnostics, include path handling).
- Processing Pipeline
- Source files are processed in several stages:
- Input acquisition from files, units, or stdin
- C-style continuation handling (\, \\)
- Fortran continuation handling (&)
- C-style block comment removal
- Directive recognition and execution
- Conditional compilation evaluation
- Macro expansion
- Emission to the output stream
Include files recursively invoke the same processing pipeline.
- Parser State
- The parser maintains module-level state describing:
- current source file,
- line continuation status,
- comment state,
- deferred reprocessing buffers,
- interactive mode output state.
This state is reset at the beginning of each top-level preprocessing run.
The parser coordinates several specialized subsystems:
- fpx Extensions
- In addition to standard preprocessing facilities, fpx provides:
- #for / #endfor
- ${NAME} macro insertion
- implicit continuation support
- interactive REPL mode
- enhanced diagnostics
Examples
- Preprocess a file to stdout:
call preprocess('input.F90')
- Preprocess a file and write to another file:
call preprocess('src/main.F90', 'preprocessed/main.F90')
- Use in a build system with unit numbers:
integer :: iu, ou
open(newunit=iu, file='input.F90')
open(newunit=ou, file='output.F90')
call preprocess(iu, ou)
close(iu); close(ou)
- Interactive mode (stdin to stdout):
$ ./fpx
[in] #define PI 3.1415926535
[out]
[in] real :: x = pi*2
[out] real :: x = 3.1415926535*2
[in] (empty line or 'quit' to exit)