Preprocessor Recursion

I'm trying to create a 'C' macro that will define and initialize static data. For example: STATIC_CONST_STRUCT ( A, a, MEMBER_DATA(CONST_STR, a, "Hello, a") MEMBER_DATA(CONST_STR, b, "Hello, b") MEMBER_STRUCT ( C, c, MEMBER_DATA(CONST_STR, d, "Hello, d") MEMBER_DATA(CONST_INT, e, 1) ) ); Would cause the 'C' preprocessor to create: static const struct A { CONST_STR a; CONST_STR b; struct C { CONST_STR d; CONST_INT e; } c; } = {"Hello, a", "Hello, b", {"Hello, d", 1}}; If I could use C++, this would be easy, but I'm using 'C' and it would be very helpful to have the initialization along with the declaration. I can't quite figure out how to make this work. My macros stop expanding. I suspect the recursive nature of the problem having an arbitrarily deep nesting is why. If it helps, I do have a maximum depth for the nesting. I've tried reading the docs and learn more about recursion, but I can't seem to find a solution. I suspect I'm close. Here's what I have so far (not claiming this is a good solution, so feel free to suggest anything that would make this better): #define MEMBER_DATA_TAG 0 #define MEMBER_STRUCT_TAG 1 #define MEMBER_TAG(MEMBER) BOOST_PP_SEQ_ELEM(0, MEMBER) #define MEMBER_DATA_TYPE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(1, MEMBER_DATA) #define MEMBER_DATA_NAME(MEMBER_DATA) BOOST_PP_SEQ_ELEM(2, MEMBER_DATA) #define MEMBER_DATA_VALUE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(3, MEMBER_DATA) #define MEMBER_STRUCT_TYPE(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(1, MEMBER_STRUCT) #define MEMBER_STRUCT_NAME(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(2, MEMBER_STRUCT) #define MEMBER_STRUCT_MEMBER_SEQ(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(3, MEMBER_STRUCT) #define MEMBER_DATA(TYPE, NAME, VALUE) ((MEMBER_DATA_TAG)(TYPE)(NAME)(VALUE)) #define MEMBER_STRUCT(TYPE, NAME, MEMBER_SEQ) ((MEMBER_STRUCT_TAG)(TYPE)(NAME)(MEMBER_SEQ)) #define IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM) BOOST_PP_EQUAL(MEMBER_TAG(MEMBER_SEQ_ELEM), MEMBER_STRUCT_TAG) #define MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) \ struct TYPE \ { \ BOOST_PP_SEQ_FOR_EACH(MEMBER_ELEM_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ) \ } NAME #define MEMBER_ELEM_DECLARE(_r, _data, MEMBER_SEQ_ELEM) \ BOOST_PP_IIF \ ( \ IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \ MEMBER_STRUCT_DECLARE \ ( \ MEMBER_STRUCT_TYPE(MEMBER_SEQ_ELEM), \ MEMBER_STRUCT_NAME(MEMBER_SEQ_ELEM), \ MEMBER_STRUCT_MEMBER_SEQ(MEMBER_SEQ_ELEM) \ ), \ MEMBER_DATA_DECLARE \ ( \ MEMBER_DATA_TYPE(MEMBER_SEQ_ELEM), \ MEMBER_DATA_NAME(MEMBER_SEQ_ELEM), \ MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \ ) \ ); #define MEMBER_DATA_DECLARE(TYPE, NAME, VALUE) TYPE NAME #define MEMBER_VALUE_INIT(MEMBER_SEQ) \ BOOST_PP_SEQ_FOR_EACH_I(MEMBER_VALUE_INIT_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ); #define MEMBER_VALUE_INIT_DECLARE(_r, _data, i, MEMBER_SEQ_ELEM) \ BOOST_PP_COMMA_IF(i) \ BOOST_PP_IIF \ ( \ IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \ {MEMBER_VALUE_INIT(MEMBER_SEQ_ELEM)}, \ MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \ ) #define STATIC_CONST_STRUCT(TYPE, NAME, MEMBER_SEQ) \ static const MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) = \ { \ MEMBER_VALUE_INIT(MEMBER_SEQ) \ } Thanks. -- "лось и белка"

On 10/25/2013 3:53 PM, Mitch Besser wrote:
I'm trying to create a 'C' macro that will define and initialize static data.
For example:
STATIC_CONST_STRUCT ( A, a, MEMBER_DATA(CONST_STR, a, "Hello, a") MEMBER_DATA(CONST_STR, b, "Hello, b") MEMBER_STRUCT ( C, c, MEMBER_DATA(CONST_STR, d, "Hello, d") MEMBER_DATA(CONST_INT, e, 1) ) );
Would cause the 'C' preprocessor to create:
static const struct A { CONST_STR a; CONST_STR b; struct C { CONST_STR d; CONST_INT e; } c; } = {"Hello, a", "Hello, b", {"Hello, d", 1}};
If I could use C++, this would be easy, but I'm using 'C' and it would be very helpful to have the initialization along with the declaration.
I can't quite figure out how to make this work. My macros stop expanding. I suspect the recursive nature of the problem having an arbitrarily deep nesting is why. If it helps, I do have a maximum depth for the nesting.
I've tried reading the docs and learn more about recursion, but I can't seem to find a solution. I suspect I'm close.
Here's what I have so far (not claiming this is a good solution, so feel free to suggest anything that would make this better):
#define MEMBER_DATA_TAG 0 #define MEMBER_STRUCT_TAG 1
#define MEMBER_TAG(MEMBER) BOOST_PP_SEQ_ELEM(0, MEMBER)
#define MEMBER_DATA_TYPE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(1, MEMBER_DATA) #define MEMBER_DATA_NAME(MEMBER_DATA) BOOST_PP_SEQ_ELEM(2, MEMBER_DATA) #define MEMBER_DATA_VALUE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(3, MEMBER_DATA)
#define MEMBER_STRUCT_TYPE(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(1, MEMBER_STRUCT) #define MEMBER_STRUCT_NAME(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(2, MEMBER_STRUCT) #define MEMBER_STRUCT_MEMBER_SEQ(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(3, MEMBER_STRUCT)
#define MEMBER_DATA(TYPE, NAME, VALUE) ((MEMBER_DATA_TAG)(TYPE)(NAME)(VALUE)) #define MEMBER_STRUCT(TYPE, NAME, MEMBER_SEQ) ((MEMBER_STRUCT_TAG)(TYPE)(NAME)(MEMBER_SEQ))
#define IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM) BOOST_PP_EQUAL(MEMBER_TAG(MEMBER_SEQ_ELEM), MEMBER_STRUCT_TAG)
#define MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) \ struct TYPE \ { \ BOOST_PP_SEQ_FOR_EACH(MEMBER_ELEM_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ) \ } NAME
#define MEMBER_ELEM_DECLARE(_r, _data, MEMBER_SEQ_ELEM) \ BOOST_PP_IIF \ ( \ IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \ MEMBER_STRUCT_DECLARE \ ( \ MEMBER_STRUCT_TYPE(MEMBER_SEQ_ELEM), \ MEMBER_STRUCT_NAME(MEMBER_SEQ_ELEM), \ MEMBER_STRUCT_MEMBER_SEQ(MEMBER_SEQ_ELEM) \ ), \ MEMBER_DATA_DECLARE \ ( \ MEMBER_DATA_TYPE(MEMBER_SEQ_ELEM), \ MEMBER_DATA_NAME(MEMBER_SEQ_ELEM), \ MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \ ) \ );
#define MEMBER_DATA_DECLARE(TYPE, NAME, VALUE) TYPE NAME
#define MEMBER_VALUE_INIT(MEMBER_SEQ) \ BOOST_PP_SEQ_FOR_EACH_I(MEMBER_VALUE_INIT_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ);
#define MEMBER_VALUE_INIT_DECLARE(_r, _data, i, MEMBER_SEQ_ELEM) \ BOOST_PP_COMMA_IF(i) \ BOOST_PP_IIF \ ( \ IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \ {MEMBER_VALUE_INIT(MEMBER_SEQ_ELEM)}, \ MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \ )
#define STATIC_CONST_STRUCT(TYPE, NAME, MEMBER_SEQ) \ static const MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) = \ { \ MEMBER_VALUE_INIT(MEMBER_SEQ) \ }
Thanks.
If you use the tracing facility of the Boost.Wave driver you will be able to see how your macros are expanded.
participants (2)
-
Edward Diener
-
Mitch Besser