Loading...
Searching...
No Matches
Macro

Definition

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__)
  • C++20/C23-style __VA_OPT__ handling for optional variadic content
  • Parameter stringification (#param) and token pasting (##)
  • Built-in predefined macros: __FILE__, __FILENAME__, __LINE__, __DATE__, __TIME__, __TIMESTAMP__, __FUNC__
  • 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.

Expansion Model
Macros are expanded recursively. Circular dependencies are detected through dependency graph analysis. Macro lookup is currently linear in the number of defined macros.
Expansion Pipeline
Macro processing occurs in two stages:
  • expand_macros performs recursive expansion of user-defined macros, including function-like macros, variadic substitutions, token pasting, stringification, and cycle detection.
  • expand_all subsequently substitutes predefined macros such as __FILE__, __LINE__, __DATE__, and related extensions.

This separation allows internal preprocessing routines to reuse the core expansion engine while selectively enabling predefined tokens.

Examples

  1. 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(context('area = PI * r**2', 10, './circle.F90', 'circle'), macros, stitch, .false., .false., .true.)
    !> prints: area = 3.1415926535 * r**2
  2. Variadic macro with stringification and pasting:
    call add(macros, macro('DEBUG_PRINT(...)', 'print *, ″DEBUG[″, __FILE__, ″:″, __LINE__, ″]: ″, __VA_ARGS__'))
    print *, expand_all(context('DEBUG_PRINT(″value =″, x)', 42, 'test.F90', 'text'), macros, stitch, .false., .false., .true.)
    !> prints: print *, 'DEBUG[', 'test.F90', ':', 42, ']: ', 'value =', x
  3. Token pasting with ##:
    call add(macros, macro('MAKE_VAR(name,num)', 'var_name_##num'))
    print *, expand_all(context('real :: MAKE_VAR(temp,42)', 5, 'file.F90', 'file'), macros, stitch, .false., .false.)
    !> prints: real :: var_name_42

Data Types

interface  macro
 Representation of a preprocessor macro. More...
interface  add
 Append macros to a macro table. More...
interface  clear
 Remove all macro definitions from a table. More...
interface  get
 Retrieve a macro by index. More...
interface  insert
 Insert a macro at a specified position. More...
interface  remove
 Remove a macro definition from a table. More...
interface  size_of
 Return the number of stored macro definitions. More...
interface  preprocess_line
 Abstract interface for line preprocessing callbacks. More...

Methods

◆ expand_all()

character(:) function, allocatable, public expand_all ( type(context), intent(in) ctx,
type(macro), dimension(:), intent(inout), allocatable macros,
logical, intent(out) stitch,
logical, intent(in) has_extra,
logical, intent(in) implicit_conti,
logical, intent(in) dollar_insert )

Expand a source line including predefined macros.

This routine represents the complete user-visible expansion phase.

Expansion proceeds in two steps:

  1. User-defined macros are expanded recursively through expand_macros.
  2. Built-in predefined macros are substituted using the current preprocessing context.

Supported predefined macros include:

  • __FILE__
  • __LINE__
  • __DATE__
  • __TIME__
  • __FUNC__
  • __FILENAME__ (extension)
  • __TIMESTAMP__ (extension)
Parameters
[in]ctx
Context
[in,out]macros
Current macro table
[out]stitch
Set to .true.true. if result ends with '&' (Fortran continuation)
[in]has_extra
Has extra macros (non-standard) like FILENAME and TIMESTAMP
[in]implicit_contiIf .true., implicit continuation is permitted
[in]dollar_insertIf .true., the syntax ${} is supported for macro insertion
Returns
Expanded line with all macros and predefined tokens replaced

Definition at line 325 of file macro.f90.

◆ expand_macros()

character(:) function, allocatable, public expand_macros ( character(*), intent(in) line,
type(macro), dimension(:), intent(inout), allocatable macros,
logical, intent(out) stitch,
logical, intent(in) implicit_conti,
logical, intent(in) dollar_insert,
type(context), intent(in) ctx )

Recursively expand user-defined macros.

Implements the core expansion engine used throughout fpx.

Supported features include:

  • object-like macros,
  • function-like macros,
  • variadic macros,
  • __VA_ARGS__,
  • __VA_OPT__,
  • parameter stringification,
  • token pasting,
  • nested expansion,
  • optional ${...} substitutions,
  • circular dependency detection.

Recursive expansion terminates automatically when cyclic dependencies are detected.

Parameters
[in]line
Line to be expanded
[in,out]macrosCurrent macro table
[out]stitch.true. if final line ends with '&'
[in]implicit_contiIf .true., implicit continuation is permitted
[in]dollar_insertIf .true., ${} macro substitution is supported
[in]ctx
Context
Returns
Line with user-defined macros expanded (predefined tokens untouched)

Definition at line 452 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 )

Determine whether a macro is currently defined.

Performs a linear search through the macro table and optionally returns the corresponding index.

Parameters
[in]name
Macro identifier.
[in]macros
Macro table.
[out]idx
Position of the matching entry, if present.
Returns
.true. if the macro exists.

Definition at line 824 of file macro.f90.