debug_node.hpp 9.9 KB

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