Search code examples
c-preprocessormetaprogrammingpreprocessor-meta-program

C preprocessor metaprogramming: replace macro not in argument list


This question concerns "C preprocessor metaprogramming", i.e. stuff such as this, this, this, this, etc.

I'm writing a non-trivial C preprocessor metaprogram, which in particular needs to "call" macros recursively (using the standard DEFER/EVAL tricks), and these macros will need to declare variables:

#define F(x, y)        \
do {                   \
    int var;           \
                       \
    /* ... */          \
                       \
    DEFER(F)()(var, y) \
} while (0)

However, this creates a variable var shadowing those on the outer scopes, which is a problem if I need to pass var itself as one of the parameters to F() (i.e. the recursive "call" needed to access var in the preceding scope). The solution I found was to concatenate a symbol such as _ at each level of recursion:

#define CAT(x, y) CAT_IMPL(x, y)
#define CAT_IMPL(x, y) x##y

#define F(x, y, l)                               \
do {                                             \
    int CAT(var, l);                             \
                                                 \
    /* Code that uses CAT(var, l) extensively */ \
                                                 \
    DEFER(F)()(CAT(var, l), y, CAT(l, _));       \
} while (0)

So, assuming the initial "call" to F() is of the form F(x, y, _), then var_ will be declared; in the first recursion level, var__ will be declared; in the second, var___, and so on.

This is working, but the code is littered with occurrences of CAT(var, l) making it even more unreadable than such code usually already is. I'm looking for the most compact syntax possible to make the code a little less unreadable, i.e. something like V(var), without needing to spell out the , l part explicitly.

However, I'm having trouble writing a macro to make this work (assuming it is even possible).

Here is an MRE, which isn't even a valid C program, but will demonstrate what I'm looking for if run through the preprocessor alone, i.e. using gcc -E:

#define CAT(x, y) CAT_IMPL(x, y)
#define CAT_IMPL(x, y) x##y

#define F1(x, l) CAT(x, l)

#define CATL(x) CAT(x, l)

#define F2(x, l) CATL(x)

F1(var, _)
F2(var, _)

The result of preprocessing this (removing garbage at the beginning) is:

var_
varl

What I'd like is a version of CATL() with a single macro parameter (i.e. without explicitly passing l as a parameter) but that still "captured" l, so as to get the following output instead:

var_
var_

Solution

  • That is not possible, there is no "global stack" in preprocessor, and there is no state, the only stack is in the arguments. I do not see a way of capturing the current depth of the callstack except for passing a parameter.

    Consider using a different programming language for C code generation - M4, Jinja2, PHP, Python, shell.