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