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