1 /*============================================================================= 2 Copyright (c) 2001-2003 Joel de Guzman 3 Copyright (c) 2002-2003 Hartmut Kaiser 4 Copyright (c) 2003 Gustavo Guerra 5 http://spirit.sourceforge.net/ 6 7 Distributed under the Boost Software License, Version 1.0. (See accompanying 8 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 =============================================================================*/ 10 #if !defined(BOOST_SPIRIT_DEBUG_NODE_HPP) 11 #define BOOST_SPIRIT_DEBUG_NODE_HPP 12 13 #if !defined(BOOST_SPIRIT_DEBUG_MAIN_HPP) 14 #error "You must include boost/spirit/debug.hpp, not boost/spirit/debug/debug_node.hpp" 15 #endif 16 17 #if defined(BOOST_SPIRIT_DEBUG) 18 19 #include <string> 20 21 #include <boost/type_traits/is_convertible.hpp> 22 #include <boost/mpl/if.hpp> 23 #include <boost/mpl/and.hpp> 24 #include <boost/spirit/home/classic/namespace.hpp> 25 #include <boost/spirit/home/classic/core/primitives/primitives.hpp> // for iscntrl_ 26 27 namespace boost { namespace spirit { 28 29 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN 30 31 /////////////////////////////////////////////////////////////////////////////// 32 // 33 // Debug helper classes for rules, which ensure maximum non-intrusiveness of 34 // the Spirit debug support 35 // 36 /////////////////////////////////////////////////////////////////////////////// 37 38 namespace impl { 39 40 struct token_printer_aux_for_chars 41 { 42 template<typename CharT> printboost::spirit::impl::token_printer_aux_for_chars43 static void print(std::ostream& o, CharT c) 44 { 45 if (c == static_cast<CharT>('\a')) 46 o << "\\a"; 47 48 else if (c == static_cast<CharT>('\b')) 49 o << "\\b"; 50 51 else if (c == static_cast<CharT>('\f')) 52 o << "\\f"; 53 54 else if (c == static_cast<CharT>('\n')) 55 o << "\\n"; 56 57 else if (c == static_cast<CharT>('\r')) 58 o << "\\r"; 59 60 else if (c == static_cast<CharT>('\t')) 61 o << "\\t"; 62 63 else if (c == static_cast<CharT>('\v')) 64 o << "\\v"; 65 66 else if (iscntrl_(c)) 67 o << "\\" << static_cast<int>(c); 68 69 else 70 o << static_cast<char>(c); 71 } 72 }; 73 74 // for token types where the comparison with char constants wouldn't work 75 struct token_printer_aux_for_other_types 76 { 77 template<typename CharT> printboost::spirit::impl::token_printer_aux_for_other_types78 static void print(std::ostream& o, CharT c) 79 { 80 o << c; 81 } 82 }; 83 84 template <typename CharT> 85 struct token_printer_aux 86 : mpl::if_< 87 mpl::and_< 88 is_convertible<CharT, char>, 89 is_convertible<char, CharT> >, 90 token_printer_aux_for_chars, 91 token_printer_aux_for_other_types 92 >::type 93 { 94 }; 95 96 template<typename CharT> token_printer(std::ostream & o,CharT c)97 inline void token_printer(std::ostream& o, CharT c) 98 { 99 #if !defined(BOOST_SPIRIT_DEBUG_TOKEN_PRINTER) 100 101 token_printer_aux<CharT>::print(o, c); 102 103 #else 104 105 BOOST_SPIRIT_DEBUG_TOKEN_PRINTER(o, c); 106 107 #endif 108 } 109 110 /////////////////////////////////////////////////////////////////////////////// 111 // 112 // Dump infos about the parsing state of a rule 113 // 114 /////////////////////////////////////////////////////////////////////////////// 115 116 #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES 117 template <typename IteratorT> 118 inline void print_node_info(bool hit,int level,bool close,std::string const & name,IteratorT first,IteratorT last)119 print_node_info(bool hit, int level, bool close, std::string const& name, 120 IteratorT first, IteratorT last) 121 { 122 if (!name.empty()) 123 { 124 for (int i = 0; i < level; ++i) 125 BOOST_SPIRIT_DEBUG_OUT << " "; 126 if (close) 127 { 128 if (hit) 129 BOOST_SPIRIT_DEBUG_OUT << "/"; 130 else 131 BOOST_SPIRIT_DEBUG_OUT << "#"; 132 } 133 BOOST_SPIRIT_DEBUG_OUT << name << ":\t\""; 134 IteratorT iter = first; 135 IteratorT ilast = last; 136 for (int j = 0; j < BOOST_SPIRIT_DEBUG_PRINT_SOME; ++j) 137 { 138 if (iter == ilast) 139 break; 140 141 token_printer(BOOST_SPIRIT_DEBUG_OUT, *iter); 142 ++iter; 143 } 144 BOOST_SPIRIT_DEBUG_OUT << "\"\n"; 145 } 146 } 147 #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES 148 149 #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES 150 template <typename ResultT> 151 inline ResultT & print_closure_info(ResultT & hit,int level,std::string const & name)152 print_closure_info(ResultT &hit, int level, std::string const& name) 153 { 154 if (!name.empty()) 155 { 156 for (int i = 0; i < level-1; ++i) 157 BOOST_SPIRIT_DEBUG_OUT << " "; 158 159 // for now, print out the return value only 160 BOOST_SPIRIT_DEBUG_OUT << "^" << name << ":\t"; 161 if (hit.has_valid_attribute()) 162 BOOST_SPIRIT_DEBUG_OUT << hit.value(); 163 else 164 BOOST_SPIRIT_DEBUG_OUT << "undefined attribute"; 165 BOOST_SPIRIT_DEBUG_OUT << "\n"; 166 } 167 return hit; 168 } 169 #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES 170 171 } 172 173 /////////////////////////////////////////////////////////////////////////////// 174 // 175 // Implementation note: The parser_context_linker, parser_scanner_linker and 176 // closure_context_linker classes are wrapped by a PP constant to allow 177 // redefinition of this classes outside of Spirit 178 // 179 /////////////////////////////////////////////////////////////////////////////// 180 #if !defined(BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED) 181 #define BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED 182 183 /////////////////////////////////////////////////////////////////////////// 184 // 185 // parser_context_linker is a debug wrapper for the ContextT template 186 // parameter of the rule<>, subrule<> and the grammar<> classes 187 // 188 /////////////////////////////////////////////////////////////////////////// 189 template<typename ContextT> 190 struct parser_context_linker : public ContextT 191 { 192 typedef ContextT base_t; 193 194 template <typename ParserT> parser_context_linkerboost::spirit::parser_context_linker195 parser_context_linker(ParserT const& p) 196 : ContextT(p) {} 197 198 template <typename ParserT, typename ScannerT> pre_parseboost::spirit::parser_context_linker199 void pre_parse(ParserT const& p, ScannerT &scan) 200 { 201 this->base_t::pre_parse(p, scan); 202 203 #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES 204 if (trace_parser(p.derived())) { 205 impl::print_node_info( 206 false, 207 scan.get_level(), 208 false, 209 parser_name(p.derived()), 210 scan.first, 211 scan.last); 212 } 213 scan.get_level()++; 214 #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES 215 } 216 217 template <typename ResultT, typename ParserT, typename ScannerT> post_parseboost::spirit::parser_context_linker218 ResultT& post_parse(ResultT& hit, ParserT const& p, ScannerT &scan) 219 { 220 #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES 221 --scan.get_level(); 222 if (trace_parser(p.derived())) { 223 impl::print_node_info( 224 hit, 225 scan.get_level(), 226 true, 227 parser_name(p.derived()), 228 scan.first, 229 scan.last); 230 } 231 #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES 232 233 return this->base_t::post_parse(hit, p, scan); 234 } 235 }; 236 237 #endif // !defined(BOOST_SPIRIT_PARSER_CONTEXT_LINKER_DEFINED) 238 239 #if !defined(BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED) 240 #define BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED 241 242 /////////////////////////////////////////////////////////////////////////////// 243 // This class is to avoid linker problems and to ensure a real singleton 244 // 'level' variable 245 struct debug_support 246 { get_levelboost::spirit::debug_support247 int& get_level() 248 { 249 static int level = 0; 250 return level; 251 } 252 }; 253 254 template<typename ScannerT> 255 struct parser_scanner_linker : public ScannerT 256 { parser_scanner_linkerboost::spirit::parser_scanner_linker257 parser_scanner_linker(ScannerT const &scan_) : ScannerT(scan_) 258 {} 259 get_levelboost::spirit::parser_scanner_linker260 int &get_level() 261 { return debug.get_level(); } 262 263 private: debug_support debug; 264 }; 265 266 #endif // !defined(BOOST_SPIRIT_PARSER_SCANNER_LINKER_DEFINED) 267 268 #if !defined(BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED) 269 #define BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED 270 271 /////////////////////////////////////////////////////////////////////////// 272 // 273 // closure_context_linker is a debug wrapper for the closure template 274 // parameter of the rule<>, subrule<> and grammar classes 275 // 276 /////////////////////////////////////////////////////////////////////////// 277 278 template<typename ContextT> 279 struct closure_context_linker : public parser_context_linker<ContextT> 280 { 281 typedef parser_context_linker<ContextT> base_t; 282 283 template <typename ParserT> closure_context_linkerboost::spirit::closure_context_linker284 closure_context_linker(ParserT const& p) 285 : parser_context_linker<ContextT>(p) {} 286 287 template <typename ParserT, typename ScannerT> pre_parseboost::spirit::closure_context_linker288 void pre_parse(ParserT const& p, ScannerT &scan) 289 { this->base_t::pre_parse(p, scan); } 290 291 template <typename ResultT, typename ParserT, typename ScannerT> 292 ResultT& post_parseboost::spirit::closure_context_linker293 post_parse(ResultT& hit, ParserT const& p, ScannerT &scan) 294 { 295 #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES 296 if (hit && trace_parser(p.derived())) { 297 // for now, print out the return value only 298 return impl::print_closure_info( 299 this->base_t::post_parse(hit, p, scan), 300 scan.get_level(), 301 parser_name(p.derived()) 302 ); 303 } 304 #endif // BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES 305 306 return this->base_t::post_parse(hit, p, scan); 307 } 308 }; 309 310 #endif // !defined(BOOST_SPIRIT_CLOSURE_CONTEXT_LINKER_DEFINED) 311 312 BOOST_SPIRIT_CLASSIC_NAMESPACE_END 313 314 }} // namespace BOOST_SPIRIT_CLASSIC_NS 315 316 #endif // defined(BOOST_SPIRIT_DEBUG) 317 318 #endif // !defined(BOOST_SPIRIT_DEBUG_NODE_HPP) 319 320