On 9/14/2014 10:58 AM, pfultz2 wrote:
One could do better for this low-level part with registrations such as (without a BOOST_VMD_ prefix for brevity)
#define IDENTIFIER_CIRCLE (CIRCLE), #define IDENTIFIER_SQUARE (SQUARE), #define IDENTIFIER_TRIANGLE (TRIANGLE), #define IDENTIFIER_RECTANGLE (RECTANGLE),
Is the ending comma there for a reason ?
Yes, though I think you already figured it out. The parentheses are there so that you can detect that your prefix token-pasting did something, the "v-identifier" is there so you can extract it, and the comma is there to separate the "v-identifier" from the rest of a "v-sequence".
There is no need for the commas though. Its easy enough to insert them in. Since we take sequence of tokens first:
CIRCLE SQUARE
And then we concat the identifiers, which gives us this:
(CIRCLE) SQUARE
Then we could use this:
#define APPEND_COMMA_I(...) (__VA_ARGS__), #define APPEND_COMMA(...) APPEND_COMMA_I __VA_ARGS__
APPEND_COMMA((CIRCLE) SQUARE) // Expands to (CIRCLE), SQUARE
It does require a little bit more for the implementation, however, this helps to simplify the "interface", I think.
The point is, however, that you don't know that the concatenation will produce a tuple when you call your APPEND_COMMA. If it does not and just produces an identifier of the form IDENTIFIER_XXX then your APPEND_COMMA(IDENTIFIER_XXX SQUARE) will end up as 'APPEND_COMMA_I IDENTIFIER_XXX SQUARE' which you do not want. Actually I realized that the comma is not be needed at all in Paul's IDENTIFIER macros above. There is already code in VMD that can split a sequence beginning with a tuple into the beginning tuple and the rest of the sequence ( BOOST_VMD_TUPLE ). So the logic of parsing for an identifier at the beginning of a sequence is to start by looking for a beginning tuple in the sequence, if not found test for an identifier through concatenation, and if the subsequent sequence after concatenation now starts with a beginning tuple, the code can separate the beginning tuple from the remainder of the sequence and extract the v-identifier.
I think it is possible. The main difficulty will be VC++ because you will have to bend over backwards to get those macro-generated commas to form an argument separator in a variety of situations (if I recall correctly).
I actually use this `MSVC_INVOKE` macro to help in those situations:
#define MSVC_INVOKE BOOST_PP_CAT(MSVC_INVOKE_, BOOST_PP_AUTO_REC(DETAIL_MSVC_INVOKE_P, 16))
#define DETAIL_MSVC_INVOKE_P(n) BOOST_PP_IS_NULLARY( MSVC_INVOKE_ ## n((),) )
#define MSVC_INVOKE_1(macro, args) MSVC_INVOKE_I_1(macro, args) #define MSVC_INVOKE_2(macro, args) MSVC_INVOKE_I_2(macro, args) ... #define MSVC_INVOKE_16(macro, args) MSVC_INVOKE_I_16(macro, args)
#define MSVC_INVOKE_I_1(macro, args) MSVC_INVOKE_X_1(macro args) #define MSVC_INVOKE_I_2(macro, args) MSVC_INVOKE_X_2(macro args) ... #define MSVC_INVOKE_I_16(macro, args) MSVC_INVOKE_X_16(macro args)
#define MSVC_INVOKE_X_1(x) x #define MSVC_INVOKE_X_2(x) x ... #define MSVC_INVOKE_X_16(x) x
Sorry I can't follow this or udnerstand what you are doing. I don't know what BOOST_PP_AUTO_REC does even when I look at its code <g>.
Of course, I made it re-entrant which could slow down the preprocessor for MSVC, however, it helps simplify when I need to workaround MSVC. So if I need to call a macro with vardiac args, I can just call it like this:
#define HEAD(x, ...) x MSVC_INVOKE(HEAD, (1,2,3,4)) // Expands to 1
Are you passing '1,2,3,4' to HEAD ?
Unfortunately, there are still times where this fails as well, but most of the time this will work.
Finally, when I have done this DSL like parser(like in LINQ for example), I would convert the string of tokens to a sequence and then process them afterwards using the algorithms for a sequence. So I would essentially transform this:
#define STRING_from (from) #define STRING_where (where) #define STRING_select (select)
STRING_TO_SEQ(from(x, numbers) where(x < 3) select(x * x))
That then expands to:
(from)((x, numbers))(where)((x < 3))(select)((x * x))
You might find this expansion easier with VMD. With Paul's suggestion and my realization that the final comma is not needed, I will be reprogramming the VMD v-sequence macros so that you should be able to take a v-sequence, like your 'string' of 'from(x, numbers) where(x < 3) select(x * x)' and break it down into its constituent v-types without the limitations current VMD incurs. In fact I intend to add a VMD macro, something like BOOT_VMD_SEQUENCE(vsequence) which will return all the v-types in some way ( probably a tuple, seq, or just variadic data, I have yet to decide ).