Home > Mobile >  Extract all declared function names from header into boost.preprocessor
Extract all declared function names from header into boost.preprocessor

Time:07-19

I have a C header file containing various declarations of functions, enums, structs, etc, and I hope to extract all declared function names into a boost.preprocessor data structure for iteration, using only the C preprocessor.

All function declarations have two fixed distinct macros around the return type, something like,

// my_header.h
FOO int * BAR f(long, double);
FOO void BAR g();

My goal is to somehow transform it into one of the above linked boost.preprocessor types, such as (f, g) or (f)(g). I believe it is possible by cleverly defining FOO and BAR, but have not succeeded after trying to play around with boost.preprocessor and P99.

I believe this task can only be done with the preprocessor as,

  1. As a hard requirement, I need to stringify the function names as string literals later when iterating the list, so runtime string manipulation or existing C static reflection frameworks with template magic are out AFAIK.
  2. While it can be done with the help of other tools, they are either fragile (awk or grep as ad-hoc parsers) or overly complex for the task (LLVM/GCC plugin for something robust). It is also a motivation to avoid external dependencies other than those strictly necessary i.e. a conforming C compiler.

CodePudding user response:

I don't think this is going to work, due to limitations on where parentheses and commas need to occur.

What you can do, though, is the opposite. You could make a Boost.PP sequence that contains the signatures in some structured form and use it to generate the declarations as you showed them. In the end, you have the representation you want as well as the compiler's view of the declarations.

CodePudding user response:

After some closer look at the internals of preprocessor tricks, I believe this is theoretically impossible. This answer is kind of a more detailed expansion on top of @sehe's nice answer.

The fundamental working principle of arbitrary preprocessor lists like those in boost.preprocessor is indirect recursion. As such, it requires a way to consume one argument and pass the remaining on. The only two ways for CPP are commas (which can separate arguments) and enclosing parentheses (which can invoke macros).

In the case of f(int, long), f is neither followed by a comma nor surrounded by a pair of parenthese, so there is no way for it to be separated from the following list by the preprocessor without knowing the name in advance.

It could have changed the game if there were a BAZ after f, but sadly there is not and I have no control over the said library header :(

There are other issues, albeit not as fatal, such as the UB of having preprocessor directives within macro definition or arguments.

Perhaps someday it would become possible to leverage the reflection TS to get all declared function names within a namespace as a consteval compile-time list and then iterate it with something along the lines of constexpr for, all in a semantic and type-safe manner... who knows

  • Related