// $Id$ // // Copyright (C) 2008 // Fraunhofer Institute for Open Communication Systems (FOKUS) // Competence Center NETwork research (NET), St. Augustin, GERMANY // Stefan Bund // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** \page parsermacro_expand_example Example macro-expansion of packet parser helper macros Debugging the packet parser makros is somwhat difficult since the makro expansion will place everything in a single line. To help pin down problems, I use
    $ g++ -DSENF_MPL_SLOT_NOEXPAND -o .ii -E -DSENF_DEBUG -Iinclude .cc
    $ sed -i -e 's/}/}\\n/g' -e '/^#.*$/d' .ii
    $ astyle --style=linux -b .ii
    
I normally just cut-and-paste the \c g++ command from a normal build and add -DSENF_MPL_SLOT_NOEXPAND. \c astyle is found at http://astyle.sourceforge.net/. If needed, I then reissue this file (the precessed \.ii file) back to the compiler using the original commandline (just replacing the \c .cc with \c .ii) to get error messages with meaningful line numbers. The following packet parser definition (taken from VariantParser.test.cc) has been subject to macro-expansion (and a lot of manual reformatting) to show the inner workings of the packet parser macros: \code struct TestParser : public senf::PacketParserBase { # include SENF_PARSER() SENF_PARSER_SKIP_BITS( 4 ); SENF_PARSER_BITFIELD_RO( type, 4, unsigned ); SENF_PARSER_PRIVATE_VARIANT( content_, type, ( novalue( nocontent, key(10, senf::VoidPacketParser)) ) ( id( content, SubParser ) ) ); SENF_PARSER_FINALIZE(TestParser); }; \endcode Here the reformated and sparsly commented expansion. I have left all the \c SENF_MPL_SLOT_ calls unexpanded, otherwise the code would be absolutely unreadable. This is quite a lot of source-code which however should create only a small amount of additional compiled code. Also remember, that all this code is generated by C++ makros. Some detours are needed to work around makro problems (e.g. templates with multiple arguments are parsed as seperate makro arguments at each komma, inability to redefine a makro from another makro ...). \code struct TestParser : public senf::PacketParserBase { //-///////////////////////////////////////////////////////////////////////// // #include SENF_PARSER() private: SENF_MPL_SLOT_INIT_ZERO(index); SENF_MPL_SLOT_INIT_ZERO(init_bytes); SENF_MPL_SLOT_INIT_ZERO(bit); SENF_MPL_SLOT_INIT_ZERO(bitfield_size); SENF_MPL_SLOT_INIT_ZERO(group); void init_chain (senf::mpl::rv <0> *) const {} size_type field_offset_ (senf::mpl::rv <0> *) const { return 0; } //-///////////////////////////////////////////////////////////////////////// // SENF_PARSER_SKIP_BITS( 4 ); SENF_MPL_SLOT_SET(bit, SENF_MPL_SLOT_GET(bit) + 4); //-///////////////////////////////////////////////////////////////////////// // SENF_PARSER_BITFIELD_RO( type, 4, unsigned ); public: static size_type const type_bit = SENF_MPL_SLOT_GET(bit); private: SENF_MPL_SLOT_SET(bit, type_bit + 4); typedef senf::UIntFieldParser type_bit_t; public: typedef type_bit_t type_t; static size_type const type_index = SENF_MPL_SLOT_GET(index) + 1; private: SENF_MPL_SLOT_SET(index, type_index); void init_chain (senf::mpl::rv *) const { init_chain (static_cast *>(0)); } public: size_type type_offset() const { return field_offset_(static_cast *>(0)) - SENF_MPL_SLOT_GET(bitfield_size); } static size_type const type_init_bytes = SENF_MPL_SLOT_GET(init_bytes) - SENF_MPL_SLOT_GET(bitfield_size); size_type type_next_offset () const { return type_offset() + type_t::fixed_bytes; } static size_type const type_next_init_bytes = type_init_bytes + type_t::fixed_bytes; private: size_type field_offset_(senf::mpl::rv *) const { return type_next_offset(); } SENF_MPL_SLOT_SET(init_bytes, type_next_init_bytes); static size_type const type_group = SENF_MPL_SLOT_GET(group) + 0; SENF_MPL_SLOT_SET(group, type_group); SENF_MPL_SLOT_SET(bitfield_size, type_t::fixed_bytes); type_t type_() const { return parse (type_offset ()); } public: type_t::value_type type() const { return type_(); } //-///////////////////////////////////////////////////////////////////////// // SENF_PARSER_PRIVATE_VARIANT( content_, type, // ( novalue( nocontent, key(10, senf::VoidPacketParser)) ) // ( id( content, SubParser ) ) // ); private: typedef boost::mpl::vector content__parsers; typedef type_t::value_type content__chooser_value_type; static content__chooser_value_type content__key_0 () { return 10; } static content__chooser_value_type content__key_1 () { return 1; } template struct content__key_value_template : public senf::detail::VariantKey {}; template friend class senf::detail::VariantKey; typedef senf::detail::VariantKeyTransform< content__chooser_value_type, boost::mpl::vector< content__key_value_template<&content__key_0>, content__key_value_template<&content__key_1> > > content__transform; typedef senf::detail::VariantParserTraits content__traits; // start SENF_PARSER_COLLECTION_I static bool const content__aux_fixed = (SENF_MPL_SLOT_GET(group) - type_group) == 0; typedef senf::detail::ParserAuxPolicySelect < type_t, SENF_MPL_SLOT_GET(init_bytes) - type_init_bytes, content__aux_fixed >::type content__aux_policy; typedef content__traits::parser::type content__collection_t; SENF_MPL_SLOT_SET(bit, 0); SENF_MPL_SLOT_SET(bitfield_size, 0); typedef content__collection_t content__t; static size_type const content__index = SENF_MPL_SLOT_GET(index) + 1; SENF_MPL_SLOT_SET(index, content__index); void init_chain (senf::mpl::rv *) const { init_chain (static_cast *>(0)); content_().init(); } size_type content__offset() const { return field_offset_ (static_cast *>(0)); } static size_type const content__init_bytes = SENF_MPL_SLOT_GET(init_bytes); size_type content__next_offset () const { return content__offset() + senf::bytes(content__()); } static size_type const content__next_init_bytes = content__init_bytes + senf::init_bytes::value; size_type field_offset_(senf::mpl::rv *) const { return content__next_offset(); } SENF_MPL_SLOT_SET(init_bytes, content__next_init_bytes); static size_type const content__group = SENF_MPL_SLOT_GET(group) + (senf::is_fixed::value ? 0 : 1); SENF_MPL_SLOET_SET(group, content__group); template < class T > T content__dispatch (boost::true_type) const { return parse(content__offset()); } template < class T > T content__dispatch(boost::false_type) const { return parse(type(), content__offset()); } content__t content__() const { return content__dispatch( boost::integral_constant()); } content__t content_() const { return content__ (); } // end SENF_PARSER_COLLECTION_I public: void nocontent() const { content_().init<0>(); } typedef SubParser content_t; SubParser content() const { return content_().get<1>(); } void init_content() const { content_().init<1>(); } bool has_content() const { return content_().variant() == 1; }; //-///////////////////////////////////////////////////////////////////////// // SENF_PARSER_FINALIZE(TestParser); void defaultInit() const { init_chain(static_cast *>(0)); } TestParser(data_iterator i, state_type s) : parser_base_type (i, s) {} private: template void init(T) const { defaultInit (); } public: void init() const { init (0); } size_type bytes() const { return field_offset_(static_cast *>(0)); } static size_type const init_bytes = SENF_MPL_SLOT_GET(init_bytes); }; \endcode */ // Local Variables: // mode: c++ // fill-column: 100 // comment-column: 40 // c-file-style: "senf" // indent-tabs-mode: nil // ispell-local-dictionary: "american" // compile-command: "scons -u test" // mode: flyspell // mode: auto-fill // End: