1/*=============================================================================
2 Copyright (c) 2001-2003 Daniel Nuffer
3 Copyright (c) 2001-2007 Hartmut Kaiser
4 Revised 2007, Copyright (c) Tobias Schwinger
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#ifndef BOOST_SPIRIT_TREE_COMMON_HPP
11#define BOOST_SPIRIT_TREE_COMMON_HPP
12
13#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
14#include <vector>
15#else
16#include <list>
17#endif
18
19#if defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES)
20#include <boost/pool/pool_alloc.hpp>
21#endif
22
23#include <algorithm>
24
25#include <boost/ref.hpp>
26#include <boost/call_traits.hpp>
27#include <boost/spirit/home/classic/namespace.hpp>
28#include <boost/spirit/home/classic/core.hpp>
29#include <boost/assert.hpp>
30
31#if defined(BOOST_SPIRIT_DEBUG) && \
32 (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES)
33#include <iostream>
34#include <boost/spirit/home/classic/debug/debug_node.hpp>
35#endif
36
37#include <boost/spirit/home/classic/tree/common_fwd.hpp>
38
39#include <iterator> // for std::iterator_traits, std::distance
40
41namespace boost { namespace spirit {
42
43BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
44
45template <typename T>
46void swap(tree_node<T>& a, tree_node<T>& b);
47
48template <typename T, typename V>
49void swap(node_iter_data<T, V>& a, node_iter_data<T, V>& b);
50
51namespace impl {
52 template <typename T>
53 inline void cp_swap(T& t1, T& t2);
54}
55
56template <typename T>
57struct tree_node
58{
59 typedef T parse_node_t;
60
61#if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES)
62 typedef std::allocator<tree_node<T> > allocator_type;
63#elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
64 typedef boost::pool_allocator<tree_node<T> > allocator_type;
65#else
66 typedef boost::fast_pool_allocator<tree_node<T> > allocator_type;
67#endif
68
69#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
70 typedef std::vector<tree_node<T>, allocator_type> children_t;
71#else
72 typedef std::list<tree_node<T>, allocator_type> children_t;
73#endif // BOOST_SPIRIT_USE_LIST_FOR_TREES
74
75 typedef typename children_t::iterator tree_iterator;
76 typedef typename children_t::const_iterator const_tree_iterator;
77
78 T value;
79 children_t children;
80
81 tree_node()
82 : value()
83 , children()
84 {}
85
86 explicit tree_node(T const& v)
87 : value(v)
88 , children()
89 {}
90
91 tree_node(T const& v, children_t const& c)
92 : value(v)
93 , children(c)
94 {}
95
96 void swap(tree_node<T>& x)
97 {
98 impl::cp_swap(value, x.value);
99 impl::cp_swap(children, x.children);
100 }
101};
102
103#if defined(BOOST_SPIRIT_DEBUG) && \
104 (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES)
105template <typename T>
106inline std::ostream&
107operator<<(std::ostream& o, tree_node<T> const& n)
108{
109 static int depth = 0;
110 o << "\n";
111 for (int i = 0; i <= depth; ++i)
112 {
113 o << "\t";
114 }
115 o << "(depth = " << depth++ << " value = " << n.value;
116 int c = 0;
117 for (typename tree_node<T>::children_t::const_iterator it = n.children.begin();
118 it != n.children.end(); ++it)
119 {
120 o << " children[" << c++ << "] = " << *it;
121 }
122 o << ")";
123 --depth;
124 return o;
125}
126#endif
127
128//////////////////////////////////
129template <typename IteratorT, typename ValueT>
130struct node_iter_data
131{
132 typedef IteratorT iterator_t;
133 typedef IteratorT /*const*/ const_iterator_t;
134
135 node_iter_data()
136 : first(), last(), is_root_(false), parser_id_(), value_()
137 {}
138
139 node_iter_data(IteratorT const& _first, IteratorT const& _last)
140 : first(_first), last(_last), is_root_(false), parser_id_(), value_()
141 {}
142
143 void swap(node_iter_data& x)
144 {
145 impl::cp_swap(first, x.first);
146 impl::cp_swap(last, x.last);
147 impl::cp_swap(t1&: parser_id_, t2&: x.parser_id_);
148 impl::cp_swap(t1&: is_root_, t2&: x.is_root_);
149 impl::cp_swap(value_, x.value_);
150 }
151
152 IteratorT begin()
153 {
154 return first;
155 }
156
157 IteratorT const& begin() const
158 {
159 return first;
160 }
161
162 IteratorT end()
163 {
164 return last;
165 }
166
167 IteratorT const& end() const
168 {
169 return last;
170 }
171
172 bool is_root() const
173 {
174 return is_root_;
175 }
176
177 void is_root(bool b)
178 {
179 is_root_ = b;
180 }
181
182 parser_id id() const
183 {
184 return parser_id_;
185 }
186
187 void id(parser_id r)
188 {
189 parser_id_ = r;
190 }
191
192 ValueT const& value() const
193 {
194 return value_;
195 }
196
197 void value(ValueT const& v)
198 {
199 value_ = v;
200 }
201private:
202 IteratorT first, last;
203 bool is_root_;
204 parser_id parser_id_;
205 ValueT value_;
206
207public:
208};
209
210#if defined(BOOST_SPIRIT_DEBUG) && \
211 (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES)
212// value is default nil_t, so provide an operator<< for nil_t
213inline std::ostream&
214operator<<(std::ostream& o, nil_t const&)
215{
216 return o;
217}
218
219template <typename IteratorT, typename ValueT>
220inline std::ostream&
221operator<<(std::ostream& o, node_iter_data<IteratorT, ValueT> const& n)
222{
223 o << "(id = " << n.id() << " text = \"";
224 typedef typename node_iter_data<IteratorT, ValueT>::const_iterator_t
225 iterator_t;
226 for (iterator_t it = n.begin(); it != n.end(); ++it)
227 impl::token_printer(o, *it);
228 o << "\" is_root = " << n.is_root()
229 << /*" value = " << n.value() << */")";
230 return o;
231}
232#endif
233
234//////////////////////////////////
235template <typename IteratorT = char const*, typename ValueT = nil_t>
236struct node_val_data
237{
238 typedef
239 typename std::iterator_traits<IteratorT>::value_type
240 value_type;
241
242#if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES)
243 typedef std::allocator<value_type> allocator_type;
244#elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
245 typedef boost::pool_allocator<value_type> allocator_type;
246#else
247 typedef boost::fast_pool_allocator<value_type> allocator_type;
248#endif
249
250#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
251 typedef std::vector<value_type, allocator_type> container_t;
252#else
253 typedef std::list<value_type, allocator_type> container_t;
254#endif
255
256 typedef typename container_t::iterator iterator_t;
257 typedef typename container_t::const_iterator const_iterator_t;
258
259 node_val_data()
260 : text(), is_root_(false), parser_id_(), value_()
261 {}
262
263#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
264 node_val_data(IteratorT const& _first, IteratorT const& _last)
265 : text(), is_root_(false), parser_id_(), value_()
266 {
267 std::copy(_first, _last, std::inserter(text, text.end()));
268 }
269
270 // This constructor is for building text out of iterators
271 template <typename IteratorT2>
272 node_val_data(IteratorT2 const& _first, IteratorT2 const& _last)
273 : text(), is_root_(false), parser_id_(), value_()
274 {
275 std::copy(_first, _last, std::inserter(text, text.end()));
276 }
277#else
278 node_val_data(IteratorT const& _first, IteratorT const& _last)
279 : text(_first, _last), is_root_(false), parser_id_(), value_()
280 {}
281
282 // This constructor is for building text out of iterators
283 template <typename IteratorT2>
284 node_val_data(IteratorT2 const& _first, IteratorT2 const& _last)
285 : text(_first, _last), is_root_(false), parser_id_(), value_()
286 {}
287#endif
288
289 void swap(node_val_data& x)
290 {
291 impl::cp_swap(text, x.text);
292 impl::cp_swap(t1&: is_root_, t2&: x.is_root_);
293 impl::cp_swap(t1&: parser_id_, t2&: x.parser_id_);
294 impl::cp_swap(value_, x.value_);
295 }
296
297 typename container_t::iterator begin()
298 {
299 return text.begin();
300 }
301
302 typename container_t::const_iterator begin() const
303 {
304 return text.begin();
305 }
306
307 typename container_t::iterator end()
308 {
309 return text.end();
310 }
311
312 typename container_t::const_iterator end() const
313 {
314 return text.end();
315 }
316
317 bool is_root() const
318 {
319 return is_root_;
320 }
321
322 void is_root(bool b)
323 {
324 is_root_ = b;
325 }
326
327 parser_id id() const
328 {
329 return parser_id_;
330 }
331
332 void id(parser_id r)
333 {
334 parser_id_ = r;
335 }
336
337 ValueT const& value() const
338 {
339 return value_;
340 }
341
342 void value(ValueT const& v)
343 {
344 value_ = v;
345 }
346
347private:
348 container_t text;
349 bool is_root_;
350 parser_id parser_id_;
351 ValueT value_;
352};
353
354#if defined(BOOST_SPIRIT_DEBUG) && \
355 (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES)
356template <typename IteratorT, typename ValueT>
357inline std::ostream&
358operator<<(std::ostream& o, node_val_data<IteratorT, ValueT> const& n)
359{
360 o << "(id = " << n.id() << " text = \"";
361 typedef typename node_val_data<IteratorT, ValueT>::const_iterator_t
362 iterator_t;
363 for (iterator_t it = n.begin(); it != n.end(); ++it)
364 impl::token_printer(o, *it);
365 o << "\" is_root = " << n.is_root()
366 << " value = " << n.value() << ")";
367 return o;
368}
369#endif
370
371template <typename T>
372inline void
373swap(tree_node<T>& a, tree_node<T>& b)
374{
375 a.swap(b);
376}
377
378template <typename T, typename V>
379inline void
380swap(node_iter_data<T, V>& a, node_iter_data<T, V>& b)
381{
382 a.swap(b);
383}
384
385//////////////////////////////////
386template <typename ValueT>
387class node_iter_data_factory
388{
389public:
390 // This inner class is so that node_iter_data_factory can simulate
391 // a template template parameter
392 template <typename IteratorT>
393 class factory
394 {
395 public:
396 typedef IteratorT iterator_t;
397 typedef node_iter_data<iterator_t, ValueT> node_t;
398
399 static node_t create_node(iterator_t const& first, iterator_t const& last,
400 bool /*is_leaf_node*/)
401 {
402 return node_t(first, last);
403 }
404
405 static node_t empty_node()
406 {
407 return node_t();
408 }
409
410 // precondition: ContainerT contains a tree_node<node_t>. And all
411 // iterators in the container point to the same sequence.
412 template <typename ContainerT>
413 static node_t group_nodes(ContainerT const& nodes)
414 {
415 return node_t(nodes.begin()->value.begin(),
416 nodes.back().value.end());
417 }
418 };
419};
420
421//////////////////////////////////
422template <typename ValueT>
423class node_val_data_factory
424{
425public:
426 // This inner class is so that node_val_data_factory can simulate
427 // a template template parameter
428 template <typename IteratorT>
429 class factory
430 {
431 public:
432 typedef IteratorT iterator_t;
433 typedef node_val_data<iterator_t, ValueT> node_t;
434
435 static node_t create_node(iterator_t const& first, iterator_t const& last,
436 bool is_leaf_node)
437 {
438 if (is_leaf_node)
439 return node_t(first, last);
440 else
441 return node_t();
442 }
443
444 static node_t empty_node()
445 {
446 return node_t();
447 }
448
449 template <typename ContainerT>
450 static node_t group_nodes(ContainerT const& nodes)
451 {
452 typename node_t::container_t c;
453 typename ContainerT::const_iterator i_end = nodes.end();
454 // copy all the nodes text into a new one
455 for (typename ContainerT::const_iterator i = nodes.begin();
456 i != i_end; ++i)
457 {
458 // See docs: reduced_node_d cannot be used with a
459 // rule inside the [].
460 BOOST_ASSERT(i->children.size() == 0);
461 c.insert(c.end(), i->value.begin(), i->value.end());
462 }
463 return node_t(c.begin(), c.end());
464 }
465 };
466};
467
468//////////////////////////////////
469template <typename ValueT>
470class node_all_val_data_factory
471{
472public:
473 // This inner class is so that node_all_val_data_factory can simulate
474 // a template template parameter
475 template <typename IteratorT>
476 class factory
477 {
478 public:
479 typedef IteratorT iterator_t;
480 typedef node_val_data<iterator_t, ValueT> node_t;
481
482 static node_t create_node(iterator_t const& first, iterator_t const& last,
483 bool /*is_leaf_node*/)
484 {
485 return node_t(first, last);
486 }
487
488 static node_t empty_node()
489 {
490 return node_t();
491 }
492
493 template <typename ContainerT>
494 static node_t group_nodes(ContainerT const& nodes)
495 {
496 typename node_t::container_t c;
497 typename ContainerT::const_iterator i_end = nodes.end();
498 // copy all the nodes text into a new one
499 for (typename ContainerT::const_iterator i = nodes.begin();
500 i != i_end; ++i)
501 {
502 BOOST_ASSERT(i->children.size() == 0);
503 c.insert(c.end(), i->value.begin(), i->value.end());
504 }
505 return node_t(c.begin(), c.end());
506 }
507 };
508};
509
510namespace impl {
511
512 ///////////////////////////////////////////////////////////////////////////
513 // can't call unqualified swap from within classname::swap
514 // as Koenig lookup rules will find only the classname::swap
515 // member function not the global declaration, so use cp_swap
516 // as a forwarding function (JM):
517 template <typename T>
518 inline void cp_swap(T& t1, T& t2)
519 {
520 using std::swap;
521 using BOOST_SPIRIT_CLASSIC_NS::swap;
522 swap(t1, t2);
523 }
524}
525
526//////////////////////////////////
527template <typename IteratorT, typename NodeFactoryT, typename T>
528class tree_match : public match<T>
529{
530public:
531
532 typedef typename NodeFactoryT::template factory<IteratorT> node_factory_t;
533 typedef typename node_factory_t::node_t parse_node_t;
534 typedef tree_node<parse_node_t> node_t;
535 typedef typename node_t::children_t container_t;
536 typedef typename container_t::iterator tree_iterator;
537 typedef typename container_t::const_iterator const_tree_iterator;
538
539 typedef T attr_t;
540 typedef typename boost::call_traits<T>::param_type param_type;
541 typedef typename boost::call_traits<T>::reference reference;
542 typedef typename boost::call_traits<T>::const_reference const_reference;
543
544 tree_match()
545 : match<T>(), trees()
546 {}
547
548 explicit
549 tree_match(std::size_t length_)
550 : match<T>(length_), trees()
551 {}
552
553 tree_match(std::size_t length_, parse_node_t const& n)
554 : match<T>(length_), trees()
555 {
556 trees.push_back(node_t(n));
557 }
558
559 tree_match(std::size_t length_, param_type val, parse_node_t const& n)
560 : match<T>(length_, val), trees()
561 {
562#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
563 trees.reserve(10); // this is more or less an arbitrary number...
564#endif
565 trees.push_back(node_t(n));
566 }
567
568 // attention, these constructors will change the second parameter!
569 tree_match(std::size_t length_, container_t& c)
570 : match<T>(length_), trees()
571 {
572 impl::cp_swap(trees, c);
573 }
574
575 tree_match(std::size_t length_, param_type val, container_t& c)
576 : match<T>(length_, val), trees()
577 {
578 impl::cp_swap(trees, c);
579 }
580
581 template <typename T2>
582 tree_match(match<T2> const& other)
583 : match<T>(other), trees()
584 {}
585
586 template <typename T2, typename T3, typename T4>
587 tree_match(tree_match<T2, T3, T4> const& other)
588 : match<T>(other), trees()
589 { impl::cp_swap(trees, other.trees); }
590
591 template <typename T2>
592 tree_match&
593 operator=(match<T2> const& other)
594 {
595 match<T>::operator=(other);
596 return *this;
597 }
598
599 template <typename T2, typename T3, typename T4>
600 tree_match&
601 operator=(tree_match<T2, T3, T4> const& other)
602 {
603 match<T>::operator=(other);
604 impl::cp_swap(trees, other.trees);
605 return *this;
606 }
607
608 tree_match(tree_match const& x)
609 : match<T>(x), trees()
610 {
611 // use auto_ptr like ownership for the trees data member
612 impl::cp_swap(trees, x.trees);
613 }
614
615 tree_match& operator=(tree_match const& x)
616 {
617 tree_match tmp(x);
618 this->swap(x&: tmp);
619 return *this;
620 }
621
622 void swap(tree_match& x)
623 {
624 match<T>::swap(x);
625 impl::cp_swap(trees, x.trees);
626 }
627
628 mutable container_t trees;
629};
630
631#if defined(BOOST_SPIRIT_DEBUG) && \
632 (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES)
633template <typename IteratorT, typename NodeFactoryT, typename T>
634inline std::ostream&
635operator<<(std::ostream& o, tree_match<IteratorT, NodeFactoryT, T> const& m)
636{
637 typedef
638 typename tree_match<IteratorT, NodeFactoryT, T>::container_t::iterator
639 iterator;
640
641 o << "(length = " << (int)m.length();
642 int c = 0;
643 for (iterator i = m.trees.begin(); i != m.trees.end(); ++i)
644 {
645 o << " trees[" << c++ << "] = " << *i;
646 }
647 o << "\n)";
648 return o;
649}
650#endif
651
652//////////////////////////////////
653struct tree_policy
654{
655 template <typename FunctorT, typename MatchT>
656 static void apply_op_to_match(FunctorT const& /*op*/, MatchT& /*m*/)
657 {}
658
659 template <typename MatchT, typename Iterator1T, typename Iterator2T>
660 static void group_match(MatchT& /*m*/, parser_id const& /*id*/,
661 Iterator1T const& /*first*/, Iterator2T const& /*last*/)
662 {}
663
664 template <typename MatchT>
665 static void concat(MatchT& /*a*/, MatchT const& /*b*/)
666 {}
667};
668
669//////////////////////////////////
670template <
671 typename MatchPolicyT,
672 typename IteratorT,
673 typename NodeFactoryT,
674 typename TreePolicyT,
675 typename T
676>
677struct common_tree_match_policy : public match_policy
678{
679 common_tree_match_policy()
680 {
681 }
682
683 template <typename PolicyT>
684 common_tree_match_policy(PolicyT const & policies)
685 : match_policy((match_policy const &)policies)
686 {
687 }
688
689 template <typename U>
690 struct result { typedef tree_match<IteratorT, NodeFactoryT, U> type; };
691
692 typedef tree_match<IteratorT, NodeFactoryT, T> match_t;
693 typedef IteratorT iterator_t;
694 typedef TreePolicyT tree_policy_t;
695 typedef NodeFactoryT factory_t;
696
697 static const match_t no_match() { return match_t(); }
698 static const match_t empty_match()
699 { return match_t(0, tree_policy_t::empty_node()); }
700
701 template <typename AttrT, typename Iterator1T, typename Iterator2T>
702 static tree_match<IteratorT, NodeFactoryT, AttrT> create_match(
703 std::size_t length,
704 AttrT const& val,
705 Iterator1T const& first,
706 Iterator2T const& last)
707 {
708#if defined(BOOST_SPIRIT_DEBUG) && \
709 (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES)
710
711 BOOST_SPIRIT_DEBUG_OUT << "\n>>> create_node(begin) <<<\n"
712 "creating node text: \"";
713 for (Iterator1T it = first; it != last; ++it)
714 impl::token_printer(BOOST_SPIRIT_DEBUG_OUT, *it);
715 BOOST_SPIRIT_DEBUG_OUT << "\"\n";
716 BOOST_SPIRIT_DEBUG_OUT << ">>> create_node(end) <<<\n\n";
717#endif
718 return tree_match<IteratorT, NodeFactoryT, AttrT>(length, val,
719 tree_policy_t::create_node(length, first, last, true));
720 }
721
722 template <typename Match1T, typename Match2T>
723 static void concat_match(Match1T& a, Match2T const& b)
724 {
725#if defined(BOOST_SPIRIT_DEBUG) && \
726 (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES)
727
728 BOOST_SPIRIT_DEBUG_OUT << "\n>>> concat_match(begin) <<<\n";
729 BOOST_SPIRIT_DEBUG_OUT << "tree a:\n" << a << "\n";
730 BOOST_SPIRIT_DEBUG_OUT << "tree b:\n" << b << "\n";
731 BOOST_SPIRIT_DEBUG_OUT << ">>> concat_match(end) <<<\n\n";
732#endif
733 BOOST_SPIRIT_ASSERT(a && b);
734 if (a.length() == 0)
735 {
736 a = b;
737 return;
738 }
739 else if (b.length() == 0
740#ifdef BOOST_SPIRIT_NO_TREE_NODE_COLLAPSING
741 && !b.trees.begin()->value.id().to_long()
742#endif
743 )
744 {
745 return;
746 }
747 a.concat(b);
748 tree_policy_t::concat(a, b);
749 }
750
751 template <typename MatchT, typename IteratorT2>
752 void
753 group_match(
754 MatchT& m,
755 parser_id const& id,
756 IteratorT2 const& first,
757 IteratorT2 const& last) const
758 {
759 if (!m) return;
760
761#if defined(BOOST_SPIRIT_DEBUG) && \
762 (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_TREES)
763
764 BOOST_SPIRIT_DEBUG_OUT << "\n>>> group_match(begin) <<<\n"
765 "new node(" << id << ") \"";
766 for (IteratorT2 it = first; it != last; ++it)
767 impl::token_printer(BOOST_SPIRIT_DEBUG_OUT, *it);
768 BOOST_SPIRIT_DEBUG_OUT << "\"\n";
769 BOOST_SPIRIT_DEBUG_OUT << "new child tree (before grouping):\n" << m << "\n";
770
771 tree_policy_t::group_match(m, id, first, last);
772
773 BOOST_SPIRIT_DEBUG_OUT << "new child tree (after grouping):\n" << m << "\n";
774 BOOST_SPIRIT_DEBUG_OUT << ">>> group_match(end) <<<\n\n";
775#else
776 tree_policy_t::group_match(m, id, first, last);
777#endif
778 }
779};
780
781//////////////////////////////////
782template <typename MatchPolicyT, typename NodeFactoryT>
783struct common_tree_tree_policy
784{
785 typedef typename MatchPolicyT::iterator_t iterator_t;
786 typedef typename MatchPolicyT::match_t match_t;
787 typedef typename NodeFactoryT::template factory<iterator_t> factory_t;
788 typedef typename factory_t::node_t node_t;
789
790 template <typename Iterator1T, typename Iterator2T>
791 static node_t
792 create_node(std::size_t /*length*/, Iterator1T const& first,
793 Iterator2T const& last, bool leaf_node)
794 {
795 return factory_t::create_node(first, last, leaf_node);
796 }
797
798 static node_t
799 empty_node()
800 {
801 return factory_t::empty_node();
802 }
803
804 template <typename FunctorT>
805 static void apply_op_to_match(FunctorT const& op, match_t& m)
806 {
807 op(m);
808 }
809};
810
811//////////////////////////////////
812// directives to modify how the parse tree is generated
813
814struct no_tree_gen_node_parser_gen;
815
816template <typename T>
817struct no_tree_gen_node_parser
818: public unary<T, parser<no_tree_gen_node_parser<T> > >
819{
820 typedef no_tree_gen_node_parser<T> self_t;
821 typedef no_tree_gen_node_parser_gen parser_generator_t;
822 typedef unary_parser_category parser_category_t;
823
824 no_tree_gen_node_parser(T const& a)
825 : unary<T, parser<no_tree_gen_node_parser<T> > >(a) {}
826
827 template <typename ScannerT>
828 typename parser_result<self_t, ScannerT>::type
829 parse(ScannerT const& scanner) const
830 {
831 typedef typename ScannerT::iteration_policy_t iteration_policy_t;
832 typedef match_policy match_policy_t;
833 typedef typename ScannerT::action_policy_t action_policy_t;
834 typedef scanner_policies<
835 iteration_policy_t,
836 match_policy_t,
837 action_policy_t
838 > policies_t;
839
840 return this->subject().parse(scanner.change_policies(policies_t(scanner)));
841 }
842};
843
844struct no_tree_gen_node_parser_gen
845{
846 template <typename T>
847 struct result {
848
849 typedef no_tree_gen_node_parser<T> type;
850 };
851
852 template <typename T>
853 static no_tree_gen_node_parser<T>
854 generate(parser<T> const& s)
855 {
856 return no_tree_gen_node_parser<T>(s.derived());
857 }
858
859 template <typename T>
860 no_tree_gen_node_parser<T>
861 operator[](parser<T> const& s) const
862 {
863 return no_tree_gen_node_parser<T>(s.derived());
864 }
865};
866
867const no_tree_gen_node_parser_gen no_node_d = no_tree_gen_node_parser_gen();
868
869//////////////////////////////////
870
871struct leaf_node_parser_gen;
872
873template<typename T>
874struct leaf_node_parser
875: public unary<T, parser<leaf_node_parser<T> > >
876{
877 typedef leaf_node_parser<T> self_t;
878 typedef leaf_node_parser_gen parser_generator_t;
879 typedef unary_parser_category parser_category_t;
880
881 leaf_node_parser(T const& a)
882 : unary<T, parser<leaf_node_parser<T> > >(a) {}
883
884 template <typename ScannerT>
885 typename parser_result<self_t, ScannerT>::type
886 parse(ScannerT const& scanner) const
887 {
888 typedef scanner_policies< typename ScannerT::iteration_policy_t,
889 match_policy, typename ScannerT::action_policy_t > policies_t;
890
891 typedef typename ScannerT::iterator_t iterator_t;
892 typedef typename parser_result<self_t, ScannerT>::type result_t;
893 typedef typename result_t::node_factory_t factory_t;
894
895 iterator_t from = scanner.first;
896 result_t hit = impl::contiguous_parser_parse<result_t>(this->subject(),
897 scanner.change_policies(policies_t(scanner,match_policy(),scanner)),
898 scanner);
899
900 if (hit)
901 return result_t(hit.length(),
902 factory_t::create_node(from, scanner.first, true));
903 else
904 return result_t(hit.length());
905 }
906};
907
908struct leaf_node_parser_gen
909{
910 template <typename T>
911 struct result {
912
913 typedef leaf_node_parser<T> type;
914 };
915
916 template <typename T>
917 static leaf_node_parser<T>
918 generate(parser<T> const& s)
919 {
920 return leaf_node_parser<T>(s.derived());
921 }
922
923 template <typename T>
924 leaf_node_parser<T>
925 operator[](parser<T> const& s) const
926 {
927 return leaf_node_parser<T>(s.derived());
928 }
929};
930
931const leaf_node_parser_gen leaf_node_d = leaf_node_parser_gen();
932const leaf_node_parser_gen token_node_d = leaf_node_parser_gen();
933
934//////////////////////////////////
935namespace impl {
936
937 template <typename MatchPolicyT>
938 struct tree_policy_selector
939 {
940 typedef tree_policy type;
941 };
942
943} // namespace impl
944
945//////////////////////////////////
946template <typename NodeParserT>
947struct node_parser_gen;
948
949template <typename T, typename NodeParserT>
950struct node_parser
951: public unary<T, parser<node_parser<T, NodeParserT> > >
952{
953 typedef node_parser<T, NodeParserT> self_t;
954 typedef node_parser_gen<NodeParserT> parser_generator_t;
955 typedef unary_parser_category parser_category_t;
956
957 node_parser(T const& a)
958 : unary<T, parser<node_parser<T, NodeParserT> > >(a) {}
959
960 template <typename ScannerT>
961 struct result
962 {
963 typedef typename parser_result<T, ScannerT>::type type;
964 };
965
966 template <typename ScannerT>
967 typename parser_result<self_t, ScannerT>::type
968 parse(ScannerT const& scanner) const
969 {
970 typename parser_result<self_t, ScannerT>::type hit = this->subject().parse(scanner);
971 if (hit)
972 {
973 impl::tree_policy_selector<typename ScannerT::match_policy_t>::type::apply_op_to_match(NodeParserT(), hit);
974 }
975 return hit;
976 }
977};
978
979template <typename NodeParserT>
980struct node_parser_gen
981{
982 template <typename T>
983 struct result {
984
985 typedef node_parser<T, NodeParserT> type;
986 };
987
988 template <typename T>
989 static node_parser<T, NodeParserT>
990 generate(parser<T> const& s)
991 {
992 return node_parser<T, NodeParserT>(s.derived());
993 }
994
995 template <typename T>
996 node_parser<T, NodeParserT>
997 operator[](parser<T> const& s) const
998 {
999 return node_parser<T, NodeParserT>(s.derived());
1000 }
1001};
1002//////////////////////////////////
1003struct reduced_node_op
1004{
1005 template <typename MatchT>
1006 void operator()(MatchT& m) const
1007 {
1008 if (m.trees.size() == 1)
1009 {
1010 m.trees.begin()->children.clear();
1011 }
1012 else if (m.trees.size() > 1)
1013 {
1014 typedef typename MatchT::node_factory_t node_factory_t;
1015 m = MatchT(m.length(), node_factory_t::group_nodes(m.trees));
1016 }
1017 }
1018};
1019
1020const node_parser_gen<reduced_node_op> reduced_node_d =
1021 node_parser_gen<reduced_node_op>();
1022
1023
1024struct discard_node_op
1025{
1026 template <typename MatchT>
1027 void operator()(MatchT& m) const
1028 {
1029 m.trees.clear();
1030 }
1031};
1032
1033const node_parser_gen<discard_node_op> discard_node_d =
1034 node_parser_gen<discard_node_op>();
1035
1036struct infix_node_op
1037{
1038 template <typename MatchT>
1039 void operator()(MatchT& m) const
1040 {
1041 typedef typename MatchT::container_t container_t;
1042 typedef typename MatchT::container_t::iterator iter_t;
1043 typedef typename MatchT::container_t::value_type value_t;
1044
1045 using std::swap;
1046 using BOOST_SPIRIT_CLASSIC_NS::swap;
1047
1048 // copying the tree nodes is expensive, since it may copy a whole
1049 // tree. swapping them is cheap, so swap the nodes we want into
1050 // a new container of children.
1051 container_t new_children;
1052 std::size_t length = 0;
1053 std::size_t tree_size = m.trees.size();
1054
1055 // the infix_node_d[] make no sense for nodes with no subnodes
1056 BOOST_SPIRIT_ASSERT(tree_size >= 1);
1057
1058 bool keep = true;
1059#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
1060 new_children.reserve((tree_size+1)/2);
1061#endif
1062 iter_t i_end = m.trees.end();
1063 for (iter_t i = m.trees.begin(); i != i_end; ++i)
1064 {
1065 if (keep) {
1066 // adjust the length
1067 length += std::distance((*i).value.begin(), (*i).value.end());
1068
1069 // move the child node
1070 new_children.push_back(value_t());
1071 swap(new_children.back(), *i);
1072 keep = false;
1073 }
1074 else {
1075 // ignore this child node
1076 keep = true;
1077 }
1078 }
1079
1080 m = MatchT(length, new_children);
1081 }
1082};
1083
1084const node_parser_gen<infix_node_op> infix_node_d =
1085 node_parser_gen<infix_node_op>();
1086
1087struct discard_first_node_op
1088{
1089 template <typename MatchT>
1090 void operator()(MatchT& m) const
1091 {
1092 typedef typename MatchT::container_t container_t;
1093 typedef typename MatchT::container_t::iterator iter_t;
1094 typedef typename MatchT::container_t::value_type value_t;
1095
1096 using std::swap;
1097 using BOOST_SPIRIT_CLASSIC_NS::swap;
1098
1099 // copying the tree nodes is expensive, since it may copy a whole
1100 // tree. swapping them is cheap, so swap the nodes we want into
1101 // a new container of children, instead of saying
1102 // m.trees.erase(m.trees.begin()) because, on a container_t that will
1103 // cause all the nodes afterwards to be copied into the previous
1104 // position.
1105 container_t new_children;
1106 std::size_t length = 0;
1107 std::size_t tree_size = m.trees.size();
1108
1109 // the discard_first_node_d[] make no sense for nodes with no subnodes
1110 BOOST_SPIRIT_ASSERT(tree_size >= 1);
1111
1112 if (tree_size > 1) {
1113#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
1114 new_children.reserve(tree_size - 1);
1115#endif
1116 iter_t i = m.trees.begin(), i_end = m.trees.end();
1117 for (++i; i != i_end; ++i)
1118 {
1119 // adjust the length
1120 length += std::distance((*i).value.begin(), (*i).value.end());
1121
1122 // move the child node
1123 new_children.push_back(value_t());
1124 swap(new_children.back(), *i);
1125 }
1126 }
1127 else {
1128 // if there was a tree and now there isn't any, insert an empty node
1129 iter_t i = m.trees.begin();
1130
1131 // This isn't entirely correct, since the empty node will reference
1132 // the end of the discarded node, but I currently don't see any way to
1133 // get at the begin of the node following this subnode.
1134 // This should be safe anyway because the it shouldn't get dereferenced
1135 // under any circumstances.
1136 typedef typename value_t::parse_node_t::iterator_t iterator_type;
1137 iterator_type it = (*i).value.end();
1138
1139 new_children.push_back(
1140 value_t(typename value_t::parse_node_t(it, it)));
1141 }
1142
1143 m = MatchT(length, new_children);
1144 }
1145};
1146
1147const node_parser_gen<discard_first_node_op> discard_first_node_d =
1148 node_parser_gen<discard_first_node_op>();
1149
1150struct discard_last_node_op
1151{
1152 template <typename MatchT>
1153 void operator()(MatchT& m) const
1154 {
1155 typedef typename MatchT::container_t container_t;
1156 typedef typename MatchT::container_t::iterator iter_t;
1157 typedef typename MatchT::container_t::value_type value_t;
1158
1159 using std::swap;
1160 using BOOST_SPIRIT_CLASSIC_NS::swap;
1161
1162 // copying the tree nodes is expensive, since it may copy a whole
1163 // tree. swapping them is cheap, so swap the nodes we want into
1164 // a new container of children, instead of saying
1165 // m.trees.erase(m.trees.begin()) because, on a container_t that will
1166 // cause all the nodes afterwards to be copied into the previous
1167 // position.
1168 container_t new_children;
1169 std::size_t length = 0;
1170 std::size_t tree_size = m.trees.size();
1171
1172 // the discard_last_node_d[] make no sense for nodes with no subnodes
1173 BOOST_SPIRIT_ASSERT(tree_size >= 1);
1174
1175 if (tree_size > 1) {
1176 m.trees.pop_back();
1177#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
1178 new_children.reserve(tree_size - 1);
1179#endif
1180 iter_t i_end = m.trees.end();
1181 for (iter_t i = m.trees.begin(); i != i_end; ++i)
1182 {
1183 // adjust the length
1184 length += std::distance((*i).value.begin(), (*i).value.end());
1185
1186 // move the child node
1187 new_children.push_back(value_t());
1188 swap(new_children.back(), *i);
1189 }
1190 }
1191 else {
1192 // if there was a tree and now there isn't any, insert an empty node
1193 iter_t i = m.trees.begin();
1194
1195 typedef typename value_t::parse_node_t::iterator_t iterator_type;
1196 iterator_type it = (*i).value.begin();
1197
1198 new_children.push_back(
1199 value_t(typename value_t::parse_node_t(it, it)));
1200 }
1201
1202 m = MatchT(length, new_children);
1203 }
1204};
1205
1206const node_parser_gen<discard_last_node_op> discard_last_node_d =
1207 node_parser_gen<discard_last_node_op>();
1208
1209struct inner_node_op
1210{
1211 template <typename MatchT>
1212 void operator()(MatchT& m) const
1213 {
1214 typedef typename MatchT::container_t container_t;
1215 typedef typename MatchT::container_t::iterator iter_t;
1216 typedef typename MatchT::container_t::value_type value_t;
1217
1218 using std::swap;
1219 using BOOST_SPIRIT_CLASSIC_NS::swap;
1220
1221 // copying the tree nodes is expensive, since it may copy a whole
1222 // tree. swapping them is cheap, so swap the nodes we want into
1223 // a new container of children, instead of saying
1224 // m.trees.erase(m.trees.begin()) because, on a container_t that will
1225 // cause all the nodes afterwards to be copied into the previous
1226 // position.
1227 container_t new_children;
1228 std::size_t length = 0;
1229 std::size_t tree_size = m.trees.size();
1230
1231 // the inner_node_d[] make no sense for nodes with less then 2 subnodes
1232 BOOST_SPIRIT_ASSERT(tree_size >= 2);
1233
1234 if (tree_size > 2) {
1235 m.trees.pop_back(); // erase the last element
1236#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES)
1237 new_children.reserve(tree_size - 1);
1238#endif
1239 iter_t i = m.trees.begin(); // skip over the first element
1240 iter_t i_end = m.trees.end();
1241 for (++i; i != i_end; ++i)
1242 {
1243 // adjust the length
1244 length += std::distance((*i).value.begin(), (*i).value.end());
1245
1246 // move the child node
1247 new_children.push_back(value_t());
1248 swap(new_children.back(), *i);
1249 }
1250 }
1251 else {
1252 // if there was a tree and now there isn't any, insert an empty node
1253 iter_t i = m.trees.begin(); // skip over the first element
1254
1255 typedef typename value_t::parse_node_t::iterator_t iterator_type;
1256 iterator_type it = (*++i).value.begin();
1257
1258 new_children.push_back(
1259 value_t(typename value_t::parse_node_t(it, it)));
1260 }
1261
1262 m = MatchT(length, new_children);
1263 }
1264};
1265
1266const node_parser_gen<inner_node_op> inner_node_d =
1267 node_parser_gen<inner_node_op>();
1268
1269
1270//////////////////////////////////
1271// action_directive_parser and action_directive_parser_gen
1272// are meant to be used as a template to create directives that
1273// generate action classes. For example access_match and
1274// access_node. The ActionParserT template parameter must be
1275// a class that has an innter class called action that is templated
1276// on the parser type and the action type.
1277template <typename ActionParserT>
1278struct action_directive_parser_gen;
1279
1280template <typename T, typename ActionParserT>
1281struct action_directive_parser
1282: public unary<T, parser<action_directive_parser<T, ActionParserT> > >
1283{
1284 typedef action_directive_parser<T, ActionParserT> self_t;
1285 typedef action_directive_parser_gen<ActionParserT> parser_generator_t;
1286 typedef unary_parser_category parser_category_t;
1287
1288 action_directive_parser(T const& a)
1289 : unary<T, parser<action_directive_parser<T, ActionParserT> > >(a) {}
1290
1291 template <typename ScannerT>
1292 struct result
1293 {
1294 typedef typename parser_result<T, ScannerT>::type type;
1295 };
1296
1297 template <typename ScannerT>
1298 typename parser_result<self_t, ScannerT>::type
1299 parse(ScannerT const& scanner) const
1300 {
1301 return this->subject().parse(scanner);
1302 }
1303
1304 template <typename ActionT>
1305 typename ActionParserT::template action<action_directive_parser<T, ActionParserT>, ActionT>
1306 operator[](ActionT const& actor) const
1307 {
1308 typedef typename
1309 ActionParserT::template action<action_directive_parser, ActionT>
1310 action_t;
1311 return action_t(*this, actor);
1312 }
1313};
1314
1315//////////////////////////////////
1316template <typename ActionParserT>
1317struct action_directive_parser_gen
1318{
1319 template <typename T>
1320 struct result {
1321
1322 typedef action_directive_parser<T, ActionParserT> type;
1323 };
1324
1325 template <typename T>
1326 static action_directive_parser<T, ActionParserT>
1327 generate(parser<T> const& s)
1328 {
1329 return action_directive_parser<T, ActionParserT>(s.derived());
1330 }
1331
1332 template <typename T>
1333 action_directive_parser<T, ActionParserT>
1334 operator[](parser<T> const& s) const
1335 {
1336 return action_directive_parser<T, ActionParserT>(s.derived());
1337 }
1338};
1339
1340//////////////////////////////////
1341// Calls the attached action passing it the match from the parser
1342// and the first and last iterators.
1343// The inner template class is used to simulate template-template parameters
1344// (declared in common_fwd.hpp).
1345template <typename ParserT, typename ActionT>
1346struct access_match_action::action
1347: public unary<ParserT, parser<access_match_action::action<ParserT, ActionT> > >
1348{
1349 typedef action_parser_category parser_category;
1350 typedef action<ParserT, ActionT> self_t;
1351
1352 template <typename ScannerT>
1353 struct result
1354 {
1355 typedef typename parser_result<ParserT, ScannerT>::type type;
1356 };
1357
1358 action( ParserT const& subject,
1359 ActionT const& actor_);
1360
1361 template <typename ScannerT>
1362 typename parser_result<self_t, ScannerT>::type
1363 parse(ScannerT const& scanner) const;
1364
1365 ActionT const &predicate() const;
1366
1367 private:
1368 ActionT actor;
1369};
1370
1371//////////////////////////////////
1372template <typename ParserT, typename ActionT>
1373access_match_action::action<ParserT, ActionT>::action(
1374 ParserT const& subject,
1375 ActionT const& actor_)
1376: unary<ParserT, parser<access_match_action::action<ParserT, ActionT> > >(subject)
1377, actor(actor_)
1378{}
1379
1380//////////////////////////////////
1381template <typename ParserT, typename ActionT>
1382template <typename ScannerT>
1383typename parser_result<access_match_action::action<ParserT, ActionT>, ScannerT>::type
1384access_match_action::action<ParserT, ActionT>::
1385parse(ScannerT const& scan) const
1386{
1387 typedef typename ScannerT::iterator_t iterator_t;
1388 typedef typename parser_result<self_t, ScannerT>::type result_t;
1389 if (!scan.at_end())
1390 {
1391 iterator_t save = scan.first;
1392 result_t hit = this->subject().parse(scan);
1393 actor(hit, save, scan.first);
1394 return hit;
1395 }
1396 return scan.no_match();
1397}
1398
1399//////////////////////////////////
1400template <typename ParserT, typename ActionT>
1401ActionT const &access_match_action::action<ParserT, ActionT>::predicate() const
1402{
1403 return actor;
1404}
1405
1406//////////////////////////////////
1407const action_directive_parser_gen<access_match_action> access_match_d
1408 = action_directive_parser_gen<access_match_action>();
1409
1410
1411
1412//////////////////////////////////
1413// Calls the attached action passing it the node from the parser
1414// and the first and last iterators
1415// The inner template class is used to simulate template-template parameters
1416// (declared in common_fwd.hpp).
1417template <typename ParserT, typename ActionT>
1418struct access_node_action::action
1419: public unary<ParserT, parser<access_node_action::action<ParserT, ActionT> > >
1420{
1421 typedef action_parser_category parser_category;
1422 typedef action<ParserT, ActionT> self_t;
1423
1424 template <typename ScannerT>
1425 struct result
1426 {
1427 typedef typename parser_result<ParserT, ScannerT>::type type;
1428 };
1429
1430 action( ParserT const& subject,
1431 ActionT const& actor_);
1432
1433 template <typename ScannerT>
1434 typename parser_result<self_t, ScannerT>::type
1435 parse(ScannerT const& scanner) const;
1436
1437 ActionT const &predicate() const;
1438
1439 private:
1440 ActionT actor;
1441};
1442
1443//////////////////////////////////
1444template <typename ParserT, typename ActionT>
1445access_node_action::action<ParserT, ActionT>::action(
1446 ParserT const& subject,
1447 ActionT const& actor_)
1448: unary<ParserT, parser<access_node_action::action<ParserT, ActionT> > >(subject)
1449, actor(actor_)
1450{}
1451
1452//////////////////////////////////
1453template <typename ParserT, typename ActionT>
1454template <typename ScannerT>
1455typename parser_result<access_node_action::action<ParserT, ActionT>, ScannerT>::type
1456access_node_action::action<ParserT, ActionT>::
1457parse(ScannerT const& scan) const
1458{
1459 typedef typename ScannerT::iterator_t iterator_t;
1460 typedef typename parser_result<self_t, ScannerT>::type result_t;
1461 if (!scan.at_end())
1462 {
1463 iterator_t save = scan.first;
1464 result_t hit = this->subject().parse(scan);
1465 if (hit && hit.trees.size() > 0)
1466 actor(*hit.trees.begin(), save, scan.first);
1467 return hit;
1468 }
1469 return scan.no_match();
1470}
1471
1472//////////////////////////////////
1473template <typename ParserT, typename ActionT>
1474ActionT const &access_node_action::action<ParserT, ActionT>::predicate() const
1475{
1476 return actor;
1477}
1478
1479//////////////////////////////////
1480const action_directive_parser_gen<access_node_action> access_node_d
1481 = action_directive_parser_gen<access_node_action>();
1482
1483
1484
1485//////////////////////////////////
1486
1487///////////////////////////////////////////////////////////////////////////////
1488//
1489// tree_parse_info
1490//
1491// Results returned by the tree parse functions:
1492//
1493// stop: points to the final parse position (i.e parsing
1494// processed the input up to this point).
1495//
1496// match: true if parsing is successful. This may be full:
1497// the parser consumed all the input, or partial:
1498// the parser consumed only a portion of the input.
1499//
1500// full: true when we have a full match (i.e the parser
1501// consumed all the input.
1502//
1503// length: The number of characters consumed by the parser.
1504// This is valid only if we have a successful match
1505// (either partial or full). A negative value means
1506// that the match is unsuccessful.
1507//
1508// trees: Contains the root node(s) of the tree.
1509//
1510///////////////////////////////////////////////////////////////////////////////
1511template <
1512 typename IteratorT,
1513 typename NodeFactoryT,
1514 typename T
1515>
1516struct tree_parse_info
1517{
1518 IteratorT stop;
1519 bool match;
1520 bool full;
1521 std::size_t length;
1522 typename tree_match<IteratorT, NodeFactoryT, T>::container_t trees;
1523
1524 tree_parse_info()
1525 : stop()
1526 , match(false)
1527 , full(false)
1528 , length(0)
1529 , trees()
1530 {}
1531
1532 template <typename IteratorT2>
1533 tree_parse_info(tree_parse_info<IteratorT2> const& pi)
1534 : stop(pi.stop)
1535 , match(pi.match)
1536 , full(pi.full)
1537 , length(pi.length)
1538 , trees()
1539 {
1540 using std::swap;
1541 using BOOST_SPIRIT_CLASSIC_NS::swap;
1542
1543 // use auto_ptr like ownership for the trees data member
1544 swap(trees, pi.trees);
1545 }
1546
1547 tree_parse_info(
1548 IteratorT stop_,
1549 bool match_,
1550 bool full_,
1551 std::size_t length_,
1552 typename tree_match<IteratorT, NodeFactoryT, T>::container_t trees_)
1553 : stop(stop_)
1554 , match(match_)
1555 , full(full_)
1556 , length(length_)
1557 , trees()
1558 {
1559 using std::swap;
1560 using BOOST_SPIRIT_CLASSIC_NS::swap;
1561
1562 // use auto_ptr like ownership for the trees data member
1563 swap(trees, trees_);
1564 }
1565};
1566
1567BOOST_SPIRIT_CLASSIC_NAMESPACE_END
1568
1569}} // namespace BOOST_SPIRIT_CLASSIC_NS
1570
1571#endif
1572
1573

source code of boost/libs/spirit/include/boost/spirit/home/classic/tree/common.hpp