
On Sat, Jan 14, 2012 at 9:58 PM, paul Fultz <pfultz2@yahoo.com> wrote:
It is very impressive. I wonder if a library could be built for writing DSLs using the preprocessor. Much like Boost.Proto lets you write DSLs using C++ operators, another library could be used to build grammars and define transformations based on preprocessor tokens.
Indeed, my library uses the pp to defined a DSEL for function declarations with contracts, concepts, named parameters, and some C++11 declaration extensions (override, final, etc). Some generalization of the tools used by my library should be possible maybe along the lines of Proto (but I have not looked at implementing such generalization). For now the library implementation performs the following /distinct/ steps: 1) Parse the class and function declarations into their traits (preprocessor-meta-traits) using the pp (pp metaprogramming). 2) Expand the macros based on the parsed function pp-meta-traits generating code for contract, concept, named parameter, etc using the both the pp and the compiler (pp and template metaprogramming, plus C++ programming). These steps are distinct so you can replace step 2 to generate some feature other than contracts, concepts, or named parameters. But step 1) always parses the syntax of the DSEL for declarations with contracts, concepts, and named parameters. So step 1) should be broken down into subtools (maybe like a Preprocessor/Proto)... For example, imagine you want to program a DSEL where a virtual function shall never be public: #define VFUNC_(f) ... // expand to RESULT_TYPE(f) NAME(f) ( PARAMS(f) ) ... #define VFUNC_(f) \ /* if !EMPTY(virtual) && ACCESS == public then error */ \ BOOST_PP_IIF(BOOST_PP_AND( BOOST_COMPL(BOOST_PP_IS_EMPTY(CONTRACT_PP_FUNC_TRAITS_VIRTUAL(f))), CONTRACT_PP_KEYWORD_IS_PUBLIC_FRONT(CONTRACT_PP_FUNC_TRAITS_ACCESS(f))), static_assert(false, "virtual functions cannot be public"); BOOST_PP_TUPLE_EAT(1) \ , \ VFUNC_DECL_ \ )(f) #define VFUNC(sign) \ VFUNC_(CONTRACT_PP_FUNC_TRAITS(sign)) struct x { VFUNC( public int (id) ( int x ) ) { return x; } // ok VFUNC( virtual public int (add) ( int x, int y ) ) { return x + y; } // error- expand to the static assert }; Note that the function pp-meta-traits "f" parsed by step 1) contain /all/ traits of a function declaration because they are parsed using pp metaprogramming so they are not limited by the compiler (which unfortunately does not allow us to detect virtual, public, and other function traits). This is what allows me for example to program "if a function is public then check the class invariants; otherwise do not check class invariants for protected and private functions" (this is a Contract Programming requirement that, without language support, it is perhaps impossible to program unless you use the pp the way I do it here). --Lorenzo