Chris@16: /*============================================================================= Chris@16: Copyright (c) 2001-2003 Joel de Guzman Chris@16: Copyright (c) 2002-2003 Hartmut Kaiser Chris@16: Copyright (c) 2003 Gustavo Guerra Chris@16: http://spirit.sourceforge.net/ Chris@16: Chris@16: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: =============================================================================*/ Chris@16: #if !defined(BOOST_SPIRIT_DEBUG_NODE_HPP) Chris@16: #define BOOST_SPIRIT_DEBUG_NODE_HPP Chris@16: Chris@16: #if !defined(BOOST_SPIRIT_DEBUG_MAIN_HPP) Chris@16: #error "You must include boost/spirit/debug.hpp, not boost/spirit/debug/debug_node.hpp" Chris@16: #endif Chris@16: Chris@16: #if defined(BOOST_SPIRIT_DEBUG) Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include // for iscntrl_ Chris@16: Chris@16: namespace boost { namespace spirit { Chris@16: Chris@16: BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // Debug helper classes for rules, which ensure maximum non-intrusiveness of Chris@16: // the Spirit debug support Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: namespace impl { Chris@16: Chris@16: struct token_printer_aux_for_chars Chris@16: { Chris@16: template Chris@16: static void print(std::ostream& o, CharT c) Chris@16: { Chris@16: if (c == static_cast('\a')) Chris@16: o << "\\a"; Chris@16: Chris@16: else if (c == static_cast('\b')) Chris@16: o << "\\b"; Chris@16: Chris@16: else if (c == static_cast('\f')) Chris@16: o << "\\f"; Chris@16: Chris@16: else if (c == static_cast('\n')) Chris@16: o << "\\n"; Chris@16: Chris@16: else if (c == static_cast('\r')) Chris@16: o << "\\r"; Chris@16: Chris@16: else if (c == static_cast('\t')) Chris@16: o << "\\t"; Chris@16: Chris@16: else if (c == static_cast('\v')) Chris@16: o << "\\v"; Chris@16: Chris@16: else if (iscntrl_(c)) Chris@16: o << "\\" << static_cast(c); Chris@16: Chris@16: else Chris@16: o << static_cast(c); Chris@16: } Chris@16: }; Chris@16: Chris@16: // for token types where the comparison with char constants wouldn't work Chris@16: struct token_printer_aux_for_other_types Chris@16: { Chris@16: template Chris@16: static void print(std::ostream& o, CharT c) Chris@16: { Chris@16: o << c; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct token_printer_aux Chris@16: : mpl::if_< Chris@16: mpl::and_< Chris@16: is_convertible, Chris@16: is_convertible >, Chris@16: token_printer_aux_for_chars, Chris@16: token_printer_aux_for_other_types Chris@16: >::type Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: inline void token_printer(std::ostream& o, CharT c) Chris@16: { Chris@16: #if !defined(BOOST_SPIRIT_DEBUG_TOKEN_PRINTER) Chris@16: Chris@16: token_printer_aux::print(o, c); Chris@16: Chris@16: #else Chris@16: Chris@16: BOOST_SPIRIT_DEBUG_TOKEN_PRINTER(o, c); Chris@16: Chris@16: #endif Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // Dump infos about the parsing state of a rule Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES Chris@16: template Chris@16: inline void Chris@16: print_node_info(bool hit, int level, bool close, std::string const& name, Chris@16: IteratorT first, IteratorT last) Chris@16: { Chris@16: if (!name.empty()) Chris@16: { Chris@16: for (int i = 0; i < level; ++i) Chris@16: BOOST_SPIRIT_DEBUG_OUT << " "; Chris@16: if (close) Chris@16: { Chris@16: if (hit) Chris@16: BOOST_SPIRIT_DEBUG_OUT << "/"; Chris@16: else Chris@16: BOOST_SPIRIT_DEBUG_OUT << "#"; Chris@16: } Chris@16: BOOST_SPIRIT_DEBUG_OUT << name << ":\t\""; Chris@16: IteratorT iter = first; Chris@16: IteratorT ilast = last; Chris@16: for (int j = 0; j < BOOST_SPIRIT_DEBUG_PRINT_SOME; ++j) Chris@16: { Chris@16: if (iter == ilast) Chris@16: break; Chris@16: Chris@16: token_printer(BOOST_SPIRIT_DEBUG_OUT, *iter); Chris@16: ++iter; Chris@16: } Chris@16: BOOST_SPIRIT_DEBUG_OUT << "\"\n"; Chris@16: } Chris@16: } Chris@16: #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES Chris@16: Chris@16: #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES Chris@16: template Chris@16: inline ResultT & Chris@16: print_closure_info(ResultT &hit, int level, std::string const& name) Chris@16: { Chris@16: if (!name.empty()) Chris@16: { Chris@16: for (int i = 0; i < level-1; ++i) Chris@16: BOOST_SPIRIT_DEBUG_OUT << " "; Chris@16: Chris@16: // for now, print out the return value only Chris@16: BOOST_SPIRIT_DEBUG_OUT << "^" << name << ":\t"; Chris@16: if (hit.has_valid_attribute()) Chris@16: BOOST_SPIRIT_DEBUG_OUT << hit.value(); Chris@16: else Chris@16: BOOST_SPIRIT_DEBUG_OUT << "undefined attribute"; Chris@16: BOOST_SPIRIT_DEBUG_OUT << "\n"; Chris@16: } Chris@16: return hit; Chris@16: } Chris@16: #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES Chris@16: Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // Implementation note: The parser_context_linker, parser_scanner_linker and Chris@16: // closure_context_linker classes are wrapped by a PP constant to allow Chris@16: // redefinition of this classes outside of Spirit Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: #if !defined(BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED) Chris@16: #define BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // parser_context_linker is a debug wrapper for the ContextT template Chris@16: // parameter of the rule<>, subrule<> and the grammar<> classes Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct parser_context_linker : public ContextT Chris@16: { Chris@16: typedef ContextT base_t; Chris@16: Chris@16: template Chris@16: parser_context_linker(ParserT const& p) Chris@16: : ContextT(p) {} Chris@16: Chris@16: template Chris@16: void pre_parse(ParserT const& p, ScannerT &scan) Chris@16: { Chris@16: this->base_t::pre_parse(p, scan); Chris@16: Chris@16: #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES Chris@16: if (trace_parser(p.derived())) { Chris@16: impl::print_node_info( Chris@16: false, Chris@16: scan.get_level(), Chris@16: false, Chris@16: parser_name(p.derived()), Chris@16: scan.first, Chris@16: scan.last); Chris@16: } Chris@16: scan.get_level()++; Chris@16: #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES Chris@16: } Chris@16: Chris@16: template Chris@16: ResultT& post_parse(ResultT& hit, ParserT const& p, ScannerT &scan) Chris@16: { Chris@16: #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES Chris@16: --scan.get_level(); Chris@16: if (trace_parser(p.derived())) { Chris@16: impl::print_node_info( Chris@16: hit, Chris@16: scan.get_level(), Chris@16: true, Chris@16: parser_name(p.derived()), Chris@16: scan.first, Chris@16: scan.last); Chris@16: } Chris@16: #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES Chris@16: Chris@16: return this->base_t::post_parse(hit, p, scan); Chris@16: } Chris@16: }; Chris@16: Chris@16: #endif // !defined(BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED) Chris@16: Chris@16: #if !defined(BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED) Chris@16: #define BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // This class is to avoid linker problems and to ensure a real singleton Chris@16: // 'level' variable Chris@16: struct debug_support Chris@16: { Chris@16: int& get_level() Chris@16: { Chris@16: static int level = 0; Chris@16: return level; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct parser_scanner_linker : public ScannerT Chris@16: { Chris@16: parser_scanner_linker(ScannerT const &scan_) : ScannerT(scan_) Chris@16: {} Chris@16: Chris@16: int &get_level() Chris@16: { return debug.get_level(); } Chris@16: Chris@16: private: debug_support debug; Chris@16: }; Chris@16: Chris@16: #endif // !defined(BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED) Chris@16: Chris@16: #if !defined(BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED) Chris@16: #define BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // closure_context_linker is a debug wrapper for the closure template Chris@16: // parameter of the rule<>, subrule<> and grammar classes Chris@16: // Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: template Chris@16: struct closure_context_linker : public parser_context_linker Chris@16: { Chris@16: typedef parser_context_linker base_t; Chris@16: Chris@16: template Chris@16: closure_context_linker(ParserT const& p) Chris@16: : parser_context_linker(p) {} Chris@16: Chris@16: template Chris@16: void pre_parse(ParserT const& p, ScannerT &scan) Chris@16: { this->base_t::pre_parse(p, scan); } Chris@16: Chris@16: template Chris@16: ResultT& Chris@16: post_parse(ResultT& hit, ParserT const& p, ScannerT &scan) Chris@16: { Chris@16: #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES Chris@16: if (hit && trace_parser(p.derived())) { Chris@16: // for now, print out the return value only Chris@16: return impl::print_closure_info( Chris@16: this->base_t::post_parse(hit, p, scan), Chris@16: scan.get_level(), Chris@16: parser_name(p.derived()) Chris@16: ); Chris@16: } Chris@16: #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES Chris@16: Chris@16: return this->base_t::post_parse(hit, p, scan); Chris@16: } Chris@16: }; Chris@16: Chris@16: #endif // !defined(BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED) Chris@16: Chris@16: BOOST_SPIRIT_CLASSIC_NAMESPACE_END Chris@16: Chris@16: }} // namespace BOOST_SPIRIT_CLASSIC_NS Chris@16: Chris@16: #endif // defined(BOOST_SPIRIT_DEBUG) Chris@16: Chris@16: #endif // !defined(BOOST_SPIRIT_DEBUG_NODE_HPP) Chris@16: