1 /*=============================================================================
2 Copyright (c) 2001-2010 Joel de Guzman
3 Copyright (c) 2001-2010 Hartmut Kaiser
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 ///////////////////////////////////////////////////////////////////////////////
10 // A mini XML-like parser, Karma is used to print out the generated AST
12 // [ JDG March 25, 2007 ] spirit2
13 // [ HK April 02, 2007 ] spirit2
15 ///////////////////////////////////////////////////////////////////////////////
17 #include <boost/config/warning_disable.hpp>
19 #include <boost/spirit/include/qi.hpp>
20 #include <boost/spirit/include/karma.hpp>
21 #include <boost/spirit/include/phoenix_core.hpp>
22 #include <boost/spirit/include/phoenix_operator.hpp>
23 #include <boost/spirit/include/phoenix_fusion.hpp>
24 #include <boost/spirit/include/phoenix_function.hpp>
25 #include <boost/spirit/include/phoenix_stl.hpp>
26 #include <boost/fusion/include/adapt_struct.hpp>
27 #include <boost/variant/recursive_variant.hpp>
34 using namespace boost::spirit
;
35 using namespace boost::spirit::ascii
;
37 namespace fusion
= boost::fusion
;
38 namespace phoenix
= boost::phoenix
;
41 using phoenix::push_back
;
43 ///////////////////////////////////////////////////////////////////////////////
44 // Our mini XML tree representation
45 ///////////////////////////////////////////////////////////////////////////////
50 boost::recursive_wrapper
<mini_xml
>
57 std::string name
; // tag name
58 std::vector
<mini_xml_node
> children
; // children
61 // We need to tell fusion about our mini_xml struct
62 // to make it a first-class fusion citizen
63 BOOST_FUSION_ADAPT_STRUCT(
66 (std::vector
<mini_xml_node
>, children
)
69 ///////////////////////////////////////////////////////////////////////////////
70 // Our mini XML grammar definition
71 ///////////////////////////////////////////////////////////////////////////////
72 template <typename Iterator
>
73 struct mini_xml_parser
:
74 qi::grammar
<Iterator
, mini_xml(), space_type
>
76 mini_xml_parser() : mini_xml_parser::base_type(xml
)
78 text
= lexeme
[+(char_
- '<') [_val
+= _1
]];
79 node
= (xml
| text
) [_val
= _1
];
84 >> lexeme
[+(char_
- '>') [_val
+= _1
]]
95 start_tag
[at_c
<0>(_val
) = _1
]
96 >> *node
[push_back(at_c
<1>(_val
), _1
)]
97 >> end_tag(at_c
<0>(_val
))
101 qi::rule
<Iterator
, mini_xml(), space_type
> xml
;
102 qi::rule
<Iterator
, mini_xml_node(), space_type
> node
;
103 qi::rule
<Iterator
, std::string(), space_type
> text
;
104 qi::rule
<Iterator
, std::string(), space_type
> start_tag
;
105 qi::rule
<Iterator
, void(std::string
), space_type
> end_tag
;
108 ///////////////////////////////////////////////////////////////////////////////
109 // A couple of phoenix functions helping to access the elements of the
111 ///////////////////////////////////////////////////////////////////////////////
112 template <typename T
>
115 template <typename T1
>
116 struct result
{ typedef T
const& type
; };
118 T
const& operator()(mini_xml_node
const& node
) const
120 return boost::get
<T
>(node
);
124 phoenix::function
<get_element
<std::string
> > _string
;
125 phoenix::function
<get_element
<mini_xml
> > _xml
;
127 ///////////////////////////////////////////////////////////////////////////////
128 // The output grammar defining the format of the generated data
129 ///////////////////////////////////////////////////////////////////////////////
130 template <typename OutputIterator
>
131 struct mini_xml_generator
132 : karma::grammar
<OutputIterator
, mini_xml()>
134 mini_xml_generator() : mini_xml_generator::base_type(xml
)
136 node
%= string
| xml
;
138 '<' << string
[_1
= at_c
<0>(_val
)] << '>'
139 << (*node
)[_1
= at_c
<1>(_val
)]
140 << "</" << string
[_1
= at_c
<0>(_val
)] << '>'
144 karma::rule
<OutputIterator
, mini_xml()> xml
;
145 karma::rule
<OutputIterator
, mini_xml_node()> node
;
148 ///////////////////////////////////////////////////////////////////////////////
150 ///////////////////////////////////////////////////////////////////////////////
151 int main(int argc
, char **argv
)
153 char const* filename
;
160 std::cerr
<< "Error: No input file provided." << std::endl
;
164 std::ifstream
in(filename
, std::ios_base::in
);
168 std::cerr
<< "Error: Could not open input file: "
169 << filename
<< std::endl
;
173 std::string storage
; // We will read the contents here.
174 in
.unsetf(std::ios::skipws
); // No white space skipping!
176 std::istream_iterator
<char>(in
),
177 std::istream_iterator
<char>(),
178 std::back_inserter(storage
));
180 typedef mini_xml_parser
<std::string::const_iterator
> mini_xml_parser
;
181 mini_xml_parser xmlin
; // Our grammar definition
182 mini_xml ast
; // our tree
184 std::string::const_iterator iter
= storage
.begin();
185 std::string::const_iterator end
= storage
.end();
186 bool r
= qi::phrase_parse(iter
, end
, xmlin
, space
, ast
);
188 if (r
&& iter
== end
)
190 std::cout
<< "-------------------------\n";
191 std::cout
<< "Parsing succeeded\n";
192 std::cout
<< "-------------------------\n";
194 typedef std::back_insert_iterator
<std::string
> outiter_type
;
195 typedef mini_xml_generator
<outiter_type
> mini_xml_generator
;
197 mini_xml_generator xmlout
; // Our grammar definition
199 std::string generated
;
200 outiter_type
outit(generated
);
201 bool r
= karma::generate(outit
, xmlout
, ast
);
204 std::cout
<< generated
<< std::endl
;
209 std::string::const_iterator begin
= storage
.begin();
210 std::size_t dist
= std::distance(begin
, iter
);
211 std::string::const_iterator some
=
212 iter
+ (std::min
)(storage
.size()-dist
, std::size_t(30));
213 std::string
context(iter
, some
);
214 std::cout
<< "-------------------------\n";
215 std::cout
<< "Parsing failed\n";
216 std::cout
<< "stopped at: \": " << context
<< "...\"\n";
217 std::cout
<< "-------------------------\n";