Macro management and expansion core of the fpx Fortran preprocessor
This module implements a complete, standards-inspired macro system supporting:
- Object-like and function-like macros
- Variadic macros (
... and __VA_ARGS__)
- Parameter stringification (
#param) and token pasting (##)
- Built-in predefined macros:
__FILE__, __FILENAME__, __LINE__, __DATE__, __TIME__, __TIMESTAMP__
- Recursive expansion with circular dependency detection via digraph analysis
- Dynamic macro table of
macro objects with efficient addition, lookup, removal
- Full support for nested macro calls and proper argument handling
The design allows safe, repeated expansion while preventing infinite recursion. All operations are container-agnostic using allocatable dynamic arrays.
- Define and use simple macros:
type(macro), allocatable :: macros(:)
call add(macros, macro('PI', '3.1415926535'))
call add(macros, macro('MSG(x)', 'print *, ″Hello ″, x'))
print *, expand_all('area = PI * r**2', macros, 'circle.F90', 10, .false.)
- Variadic macro with stringification and pasting:
call add(macros, macro('DEBUG_PRINT(...)', 'print *, ″DEBUG[″, __FILE__, ″:″, __LINE__, ″]: ″, __VA_ARGS__'))
print *, expand_all('DEBUG_PRINT(″value =″, x)', macros, ″test.f90″, 42, .false.)
- Token pasting with ##:
call add(macros, macro('MAKE_VAR(name,num)', 'var_name_##num'))
print *, expand_all('real :: MAKE_VAR(temp,42)', macros, 'file.F90', 5, .false.)
|
| type | macro |
| | Derived type representing a single preprocessor macro Extends string with macro-specific fields: replacement value, parameters, variadic flag, and cyclic self-reference detection. More...
|
| |
| interface | add |
| | Add one or more macros to a dynamic table. More...
|
| |
| interface | clear |
| | Remove all macros from a table. More...
|
| |
| interface | get |
| | Retrieve a macro by index. More...
|
| |
| interface | insert |
| | Insert more macro to a dynamic table. More...
|
| |
| interface | remove |
| | Remove a macro at given index. More...
|
| |
| interface | sizeof |
| | Return current number of stored macros. More...
|
| |
◆ buffer_size
| integer, parameter buffer_size = 256 |
|
private |
Default buffer size.
Definition at line 65 of file macro.f90.
◆ expand_all()
| character(:) function, allocatable, public expand_all |
( |
character(*), intent(in) | line, |
|
|
type(macro), dimension(:), intent(in) | macros, |
|
|
character(*), intent(in) | filepath, |
|
|
integer, intent(in) | iline, |
|
|
logical, intent(out) | stitch, |
|
|
logical, intent(in) | has_extra ) |
Fully expand a line including predefined macros (FILE, LINE, etc.) First performs normal macro expansion via expand_macros(), then substitutes standard predefined tokens with current file/line/date information.
- Parameters
-
| [in] | line | Input source line |
| [in] | macros | Current macro table |
| [in] | filepath | Current source file path |
| [in] | iline | Current line number |
| [out] | stitch | Set to .true.true. if result ends with '&' (Fortran continuation) |
| [in] | has_extra | Has extra macros (non-standard) like FILENAME and TIMESTAMP |
- Returns
- Expanded line with all macros and predefined tokens replaced
Remarks
Definition at line 194 of file macro.f90.
◆ expand_macros()
| character(:) function, allocatable, public expand_macros |
( |
character(*), intent(in) | line, |
|
|
type(macro), dimension(:), intent(in) | macros, |
|
|
logical, intent(out) | stitch ) |
Core recursive macro expander (handles function-like, variadic, #, ##)
Performs actual macro replacement with full support for:
- Function-like macros with argument collection
- Stringification (
#param)
- Token pasting (
##)
- Variadic macros and
__VA_ARGS__, __VA_OPT__
- Recursion with cycle detection via digraph
- Proper handling of nested parentheses and quoted strings
- Parameters
-
| [in] | line | Input line |
| [in] | macros | Current macro table |
| [out] | stitch | .true. if final line ends with '&' |
- Returns
- Line with user-defined macros expanded (predefined tokens untouched)
Remarks
Definition at line 308 of file macro.f90.
◆ is_circular()
| logical function is_circular |
( |
type(macro), dimension(:), intent(in) | macros, |
|
|
integer, intent(in) | idx ) |
|
private |
Detect whether expanding macro at index idx would cause a cycle Builds a dependency graph from macro replacement texts and checks for circular paths. Used during expansion to avoid infinite recursion.
Remarks
Definition at line 614 of file macro.f90.
◆ is_defined()
| logical function, public is_defined |
( |
character(*), intent(in) | name, |
|
|
type(macro), dimension(:), intent(in) | macros, |
|
|
integer, intent(inout), optional | idx ) |
Check if a macro with given name exists in table.
- Parameters
-
| [in] | name | Macro name to test |
| [in] | macros | Current macro table |
| [in,out] | idx | Optional: returns index (1-based) if found |
- Returns
- .true. if macro is defined
Remarks
Definition at line 676 of file macro.f90.
◆ tostring()
| character(:) function, allocatable tostring |
( |
class(*), intent(in) | any | ) |
|
|
private |
Generic conversion of polymorphic value to string Used internally during macro argument stringification and debugging. Supports integers, reals, logicals, characters, and complex.
Remarks
Definition at line 699 of file macro.f90.