It seems like doing this in C++ is overly complex. In language's like Nim where you can just executed ordinary code at compile-time it would be far simpler.
D has this use case solved in a really nice way. All you have to do is write a function that converts the DSL into D code and then do something like `mixin(my_dsl_converter('foobar'))`.
This may not be quite what the original poster is looking for, but boost::spirit allows one to build DSLs directly in the code. The DSL is then used to parse constructs and execute the results.