Question

Is it possible to define a preprocessor macro that will expand in the following way.

MACRO1(x) (y,z,w)
--> MACRO2(x,y,z,w)

Can the expansion of MACRO1 somehow consume the left parenthesis of the list that follows the macro invocation and replace it with MACRO2(x, so that the preprocessor accepts the result as a valid macro invocation (assuming MACRO2 is defined) and not raise an unterminated argument list error?

I've tried to do something like this

#define STRANGE_MACRO(...) __VA_ARGS__
#define STRIP_PAREN(...) __VA_ARGS__)
#define PREPEND_AND_APPLY_STRANGE(x) STRANGE_MACRO(x,STRIP_PAREN

Calling it like this:

PREPEND_AND_APPLY_STRANGE(x) (y,z,w)

produces the unerminated argument list error. Is there a way to make it work?

As for the reason I'd like to have this behavior, it is for esetics, I think it looks better to have macro invocation like this

MACRO1(identifier) (
    more
    complex
    arguments
)

than

MACRO2(identifier,
    more
    complex
    arguments
)

I vould just like the former to be transfromed into the later. If it is not possible within the preprocessor rules, no big deal, I'll live with it, but if it is, I'd like to know the trick.

Was it helpful?

Solution

If you want to incorporate an unmatched opening parenthesis in a replacement list, you need to add a layer of indirection:

#define LPAREN (

#define PREPEND_AND_APPLY_STRANGE(x) STRANGE_MACRO LPAREN x,STRIP_PAREN

This way the parenthesis won't be considered part of an invocation until the correct syntax is complete.

Unfortunately there's a limitation to this technique: by the time the call to STRANGE_MACRO is fully constructed, it's past the point where it would be eligible for rescanning - since the start and end of the expression were built across two different calls that took place at the same level, the whole thing never appeared in one rescan list - and will never actually expand; you'll just get STRANGE_MACRO ( x,y,z,w) dumped in your output. You need to force a rescan at the top level:

#define EXPAND(...) __VA_ARGS__

The macro does nothing, but does mean its argument gets to be put in a rescan list as a complete unit and will thus finally expand. So the closest you can get to your desired syntax would be this:

EXPAND(

MACRO1(identifier) (
    ....
)
MACRO1(identifier) (
    ....
)

)

...so you don't need to disfigure each of your custom blocks with its own EXPAND, but you do need to wrap the whole program in one. And no you can't hide the wrapper by putting an #include directive within EXPAND, as directives can't appear within invocations. (Still, perhaps you can make something useful of it by reinventing namespace or something similar that your syntax might need.)

This also has the disadvantage that the C compiler will perceive your entire program as being on one line, which will hurt error reporting somewhat - although you were already halfway to this problem, as each declaration block would also have seemed to be on only one line had the original version worked.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top