#if (defined(_DEBUG) && !defined(MBLQI_DONT_DEBUG_RULES)) || defined(MBLQI_DEBUG_RULES) # define MBL_QI_DEBUG_PARSER( pdbg, pname, ppos ) \ ::mbl::debug_position( pdbg, pname, ppos ) # define MBL_QI_DEBUG_PARSER_( pdbg, pname, ppos ) MBL_QI_DEBUG_PARSER( pdbg, pname, ppos ) >> # define _MBL_QI_DEBUG_PARSER( pdbg, pname, ppos ) >> MBL_QI_DEBUG_PARSER( pdbg, pname, ppos ) #else # define MBL_QI_DEBUG_PARSER( pdbg, pname, ppos ) # define MBL_QI_DEBUG_PARSER_( pdbg, pname, ppos ) # define _MBL_QI_DEBUG_PARSER( pdbg, pname, ppos ) #endif #define MBL_QI_DEBUG_MSG_START "" #define MBL_QI_DEBUG_MSG_END "" #define MBL_QI_DEBUG_PARSER_START( pdbg, pname ) MBL_QI_DEBUG_PARSER_( pdbg, pname, MBL_QI_DEBUG_MSG_START ) #define MBL_QI_DEBUG_PARSER_END( pdbg, pname ) _MBL_QI_DEBUG_PARSER( pdbg, pname, MBL_QI_DEBUG_MSG_END ) namespace mbl { struct parser_debugger { // could be virtual, but I want my type to be POD bool (*report)( parser_debugger*, char const* parserName, char const* msg, std::string const& pos ); }; static bool report_impl_base( parser_debugger*, char const* pname, char const* msg, std::string const& pos, std::ostream& os, size_t line_size, size_t pname_len, size_t msg_len ) { size_t n = strlen( msg ); std::string pad; if( n < msg_len ) pad.assign( (msg_len - n) / 2, ' ' ); std::ios_base::fmtflags f = os.flags(); os.flags( f | std::ios_base::left ); os << std::setw(pname_len) << pname << '(' << pad << std::setw(msg_len - pad.size()) << msg << "): "; os.flags( f ); bool sp = false; std::size_t cnt = (std::max)(strlen(pname), pname_len) + (std::max)(n, msg_len) + 4; for( auto i = pos.begin(); i != pos.end(); i++ ) { char c = *i; if( ::isspace(c) ) { if( sp ) continue; sp = true; c = ' '; } else { sp = false; } if( cnt++ >= line_size ) { os << "..."; break; } else { os << c; } } os << std::endl; return true; } static bool report_impl( parser_debugger* pd, char const* pname, char const* msg, std::string const& pos ) { return report_impl_base( pd, pname, msg, pos, std::clog, 100, 20, 10 ); } static parser_debugger& default_parser_debugger() { static parser_debugger res = { {&report_impl} }; return res; } BOOST_SPIRIT_TERMINAL_EX( debug_position ); struct debug_position_parser : qi::primitive_parser { debug_position_parser( parser_debugger* pdebugger, char const* pname, char const* msg ) : pdebugger_( pdebugger ), pname_( pname ), msg_( msg ) {} template< typename ContextT, typename IteratorT > struct attribute { typedef spirit::unused_type type; }; template< typename IteratorT, typename ContextT, typename SkipperT, typename AttributeT > bool parse( IteratorT& first, IteratorT const& last, ContextT& context, SkipperT const& skipper, AttributeT& attr ) const { typedef std::iterator_traits::value_type char_type; typedef std::basic_string string_type; qi::skip_over( first, last, skipper ); if( !pdebugger_ ) return true; pdebugger_->report( pdebugger_, pname_, msg_, boost::locale::conv::utf_to_utf(string_type(first, last)) ); return true; } template< class ContextT > spirit::info what( ContextT& context ) const { return spirit::info( "debug_position", expression_ ); } char const* pname_; char const* msg_; parser_debugger* pdebugger_; }; } namespace boost { namespace spirit { template<> struct use_terminal : mpl::true_ {}; // enable debug_position template< typename A0, typename A1, typename A2 > struct use_terminal > > : is_convertible {}; // enable debug_position( debugger, name, pos ) template<> struct use_lazy_terminal : mpl::true_ {}; // enable lazy support for debug_position namespace qi { template< typename A0, typename A1, typename A2, typename ModifiersT > struct make_primitive< terminal_ex >, ModifiersT > { typedef mbl::debug_position_parser result_type; template< typename TerminalT > result_type operator()( TerminalT const& term, unused_type ) const { return result_type( fusion::at_c<0>(term.args), fusion::at_c<1>(term.args), fusion::at_c<2>(term.args) ); } }; } } }