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