]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/example/qi/mini_xml3.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / spirit / example / qi / mini_xml3.cpp
1 /*=============================================================================
2 Copyright (c) 2001-2010 Joel de Guzman
3
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 ///////////////////////////////////////////////////////////////////////////////
8 //
9 // A mini XML-like parser
10 //
11 // [ JDG March 25, 2007 ] spirit2
12 //
13 ///////////////////////////////////////////////////////////////////////////////
14
15 #include <boost/config/warning_disable.hpp>
16 #include <boost/spirit/include/qi.hpp>
17 #include <boost/spirit/include/phoenix_core.hpp>
18 #include <boost/spirit/include/phoenix_operator.hpp>
19 #include <boost/spirit/include/phoenix_fusion.hpp>
20 #include <boost/spirit/include/phoenix_stl.hpp>
21 #include <boost/spirit/include/phoenix_object.hpp>
22 #include <boost/fusion/include/adapt_struct.hpp>
23 #include <boost/variant/recursive_variant.hpp>
24 #include <boost/foreach.hpp>
25
26 #include <iostream>
27 #include <fstream>
28 #include <string>
29 #include <vector>
30
31 namespace client
32 {
33 namespace fusion = boost::fusion;
34 namespace phoenix = boost::phoenix;
35 namespace qi = boost::spirit::qi;
36 namespace ascii = boost::spirit::ascii;
37
38 ///////////////////////////////////////////////////////////////////////////
39 // Our mini XML tree representation
40 ///////////////////////////////////////////////////////////////////////////
41 struct mini_xml;
42
43 typedef
44 boost::variant<
45 boost::recursive_wrapper<mini_xml>
46 , std::string
47 >
48 mini_xml_node;
49
50 struct mini_xml
51 {
52 std::string name; // tag name
53 std::vector<mini_xml_node> children; // children
54 };
55 }
56
57 // We need to tell fusion about our mini_xml struct
58 // to make it a first-class fusion citizen
59 BOOST_FUSION_ADAPT_STRUCT(
60 client::mini_xml,
61 (std::string, name)
62 (std::vector<client::mini_xml_node>, children)
63 )
64
65 namespace client
66 {
67 ///////////////////////////////////////////////////////////////////////////
68 // Print out the mini xml tree
69 ///////////////////////////////////////////////////////////////////////////
70 int const tabsize = 4;
71
72 void tab(int indent)
73 {
74 for (int i = 0; i < indent; ++i)
75 std::cout << ' ';
76 }
77
78 struct mini_xml_printer
79 {
80 mini_xml_printer(int indent = 0)
81 : indent(indent)
82 {
83 }
84
85 void operator()(mini_xml const& xml) const;
86
87 int indent;
88 };
89
90 struct mini_xml_node_printer : boost::static_visitor<>
91 {
92 mini_xml_node_printer(int indent = 0)
93 : indent(indent)
94 {
95 }
96
97 void operator()(mini_xml const& xml) const
98 {
99 mini_xml_printer(indent+tabsize)(xml);
100 }
101
102 void operator()(std::string const& text) const
103 {
104 tab(indent+tabsize);
105 std::cout << "text: \"" << text << '"' << std::endl;
106 }
107
108 int indent;
109 };
110
111 void mini_xml_printer::operator()(mini_xml const& xml) const
112 {
113 tab(indent);
114 std::cout << "tag: " << xml.name << std::endl;
115 tab(indent);
116 std::cout << '{' << std::endl;
117
118 BOOST_FOREACH(mini_xml_node const& node, xml.children)
119 {
120 boost::apply_visitor(mini_xml_node_printer(indent), node);
121 }
122
123 tab(indent);
124 std::cout << '}' << std::endl;
125 }
126
127 ///////////////////////////////////////////////////////////////////////////
128 // Our mini XML grammar definition
129 ///////////////////////////////////////////////////////////////////////////
130 //[tutorial_xml3_grammar
131 template <typename Iterator>
132 struct mini_xml_grammar
133 : qi::grammar<Iterator, mini_xml(), qi::locals<std::string>, ascii::space_type>
134 {
135 mini_xml_grammar()
136 : mini_xml_grammar::base_type(xml, "xml")
137 {
138 using qi::lit;
139 using qi::lexeme;
140 using qi::on_error;
141 using qi::fail;
142 using ascii::char_;
143 using ascii::string;
144 using namespace qi::labels;
145
146 using phoenix::construct;
147 using phoenix::val;
148
149 text %= lexeme[+(char_ - '<')];
150 node %= xml | text;
151
152 start_tag %=
153 '<'
154 >> !lit('/')
155 > lexeme[+(char_ - '>')]
156 > '>'
157 ;
158
159 end_tag =
160 "</"
161 > lit(_r1)
162 > '>'
163 ;
164
165 xml %=
166 start_tag[_a = _1]
167 > *node
168 > end_tag(_a)
169 ;
170
171 xml.name("xml");
172 node.name("node");
173 text.name("text");
174 start_tag.name("start_tag");
175 end_tag.name("end_tag");
176
177 on_error<fail>
178 (
179 xml
180 , std::cout
181 << val("Error! Expecting ")
182 << _4 // what failed?
183 << val(" here: \"")
184 << construct<std::string>(_3, _2) // iterators to error-pos, end
185 << val("\"")
186 << std::endl
187 );
188 }
189
190 qi::rule<Iterator, mini_xml(), qi::locals<std::string>, ascii::space_type> xml;
191 qi::rule<Iterator, mini_xml_node(), ascii::space_type> node;
192 qi::rule<Iterator, std::string(), ascii::space_type> text;
193 qi::rule<Iterator, std::string(), ascii::space_type> start_tag;
194 qi::rule<Iterator, void(std::string), ascii::space_type> end_tag;
195 };
196 //]
197 }
198
199 ///////////////////////////////////////////////////////////////////////////////
200 // Main program
201 ///////////////////////////////////////////////////////////////////////////////
202 int main(int argc, char **argv)
203 {
204 char const* filename;
205 if (argc > 1)
206 {
207 filename = argv[1];
208 }
209 else
210 {
211 std::cerr << "Error: No input file provided." << std::endl;
212 return 1;
213 }
214
215 std::ifstream in(filename, std::ios_base::in);
216
217 if (!in)
218 {
219 std::cerr << "Error: Could not open input file: "
220 << filename << std::endl;
221 return 1;
222 }
223
224 std::string storage; // We will read the contents here.
225 in.unsetf(std::ios::skipws); // No white space skipping!
226 std::copy(
227 std::istream_iterator<char>(in),
228 std::istream_iterator<char>(),
229 std::back_inserter(storage));
230
231 typedef client::mini_xml_grammar<std::string::const_iterator> mini_xml_grammar;
232 mini_xml_grammar xml; // Our grammar
233 client::mini_xml ast; // Our tree
234
235 using boost::spirit::ascii::space;
236 std::string::const_iterator iter = storage.begin();
237 std::string::const_iterator end = storage.end();
238 bool r = phrase_parse(iter, end, xml, space, ast);
239
240 if (r && iter == end)
241 {
242 std::cout << "-------------------------\n";
243 std::cout << "Parsing succeeded\n";
244 std::cout << "-------------------------\n";
245 client::mini_xml_printer printer;
246 printer(ast);
247 return 0;
248 }
249 else
250 {
251 std::cout << "-------------------------\n";
252 std::cout << "Parsing failed\n";
253 std::cout << "-------------------------\n";
254 return 1;
255 }
256 }
257
258