Preprocessor macro pattern matching

To find and replace a macro expansion, define a macro whose body is a call to BRONTO_REWRITE_MACRO(). There must be two arguments to the call. The first argument represents the macro invocation to match and should itself be a call to before() with an argument representing the macro to match. The other argument must be a call to after() with an argument whose tokens will be substituted into any matching calls or inline to replace the macro expansion with its correpsonding definition.

Basic Example
#define REPLACE_NULL_WITH_NULLPTR \
  BRONTO_REWRITE_MACRO(before(NULL), after(nullptr))

Replacements may also be defined as function-like macros whose arguments may be used in both the match and correpsonding replacement.

Function Example
#define REPLACE_MAX_WITH_STD(a, b) \
  BRONTO_REWRITE_MACRO(before(MAX(a, b), after(std::max(a, b))))

Variadic macro functions are also supported:

Variadic Example
#define REPLACE_MIN_WITH_STD(...) \
  BRONTO_REWRITE_MACRO(before(MIN(__VA_ARGS__), after(std::min(__VA_ARGS__)))

Macro arguments are the only time further replacement of the after() or inline argument is done. In all other cases, the tokens will be used to directly replace any matching macro expansion from the before() clause.

Additionally, rather than taking the replacement tokens from the rule itself, a rule may specify inline as the replacement which will use the original macro definition as the replacement for the expansion site:

inline Example
#define MY_MACRO(fmt, ...) printf(fmt, __VA_OPT__(,) __VA_ARGS__)
#define INLINE_PRINTF(...) \
  BRONTO_REWRITE_MACRO(before(MY_MACRO(__VA_ARGS__)), inline)

before

Requirements

The single argument passed to the before() function must be a single macro expansion to be replaced. It may be either a single token or a sequence of tokens corresponding to a function-like macro invocation. This macro need not have been defined yet and the rule will match any call to a macro with the same name and arguments.

Semantics

The argument to the before() function represent the tokens to match during macro expansion. With the exception of macro argument arising from the rule definition itself, tokens will be matched exactly. If the replacement rule is defined as a function-like macro with parameters, those parameters may be used as "capture groups" where they will match any number of source tokens which may be used in the replacement to preserve those tokens.

after

Requirements

The after() function requires only that the (possibly empty) sequence of tokens which will replace matching macro expansions occur between balanced parentheses.

Semantics

The tokens in the argument to after() will replace the entirety of the matching macro expansion. Each captured macro argument will be replaced by the tokens which comprise the corresponding argument at the original expansion location. __VA_ARGS__ and __VA_OPT__ are also supported. Neither token-pasting nor stringification are supported.

inline

Requirements

Rather than specifying the tokens with which to replace a matching macro expansion, the inline token may be used. When this is used as part of a replacement rule, the replacement tokens will be taken from the macro being expanded. The macro body generally follows the requirements of `after()', specifically:

  • Both function-like and single-token macros are supported, but must be user-defined.
  • Built-in macros like __file__, __LINE__, or __COUNTER__ are not supported.
  • Stringification and token pasting are not supported.

Semantics

The semantics of inline are equivalent to those of after(). The tokens from the macro definition will be used exactly, except that macro parameters within the expansion body will be replaced by the corresponding argument, including both __VA_ARGS__ and __VA_OPT__.

On this page