]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/example/qi/mini_xml1.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / spirit / example / qi / mini_xml1.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/spirit/include/qi.hpp>
16 #include <boost/phoenix/core.hpp>
17 #include <boost/phoenix/operator.hpp>
18 #include <boost/phoenix/fusion.hpp>
19 #include <boost/phoenix/stl.hpp>
20 #include <boost/fusion/include/adapt_struct.hpp>
21 #include <boost/variant/recursive_variant.hpp>
22 #include <boost/foreach.hpp>
23
24 #include <iostream>
25 #include <fstream>
26 #include <string>
27 #include <vector>
28
29 namespace client
30 {
31 namespace fusion = boost::fusion;
32 namespace phoenix = boost::phoenix;
33 namespace qi = boost::spirit::qi;
34 namespace ascii = boost::spirit::ascii;
35
36 ///////////////////////////////////////////////////////////////////////////
37 // Our mini XML tree representation
38 ///////////////////////////////////////////////////////////////////////////
39 //[tutorial_xml1_structures
40 struct mini_xml;
41
42 typedef
43 boost::variant<
44 boost::recursive_wrapper<mini_xml>
45 , std::string
46 >
47 mini_xml_node;
48
49 struct mini_xml
50 {
51 std::string name; // tag name
52 std::vector<mini_xml_node> children; // children
53 };
54 //]
55 }
56
57 // We need to tell fusion about our mini_xml struct
58 // to make it a first-class fusion citizen
59 //[tutorial_xml1_adapt_structures
60 BOOST_FUSION_ADAPT_STRUCT(
61 client::mini_xml,
62 (std::string, name)
63 (std::vector<client::mini_xml_node>, children)
64 )
65 //]
66
67 namespace client
68 {
69 ///////////////////////////////////////////////////////////////////////////
70 // Print out the mini xml tree
71 ///////////////////////////////////////////////////////////////////////////
72 int const tabsize = 4;
73
74 void tab(int indent)
75 {
76 for (int i = 0; i < indent; ++i)
77 std::cout << ' ';
78 }
79
80 struct mini_xml_printer
81 {
82 mini_xml_printer(int indent = 0)
83 : indent(indent)
84 {
85 }
86
87 void operator()(mini_xml const& xml) const;
88
89 int indent;
90 };
91
92 struct mini_xml_node_printer : boost::static_visitor<>
93 {
94 mini_xml_node_printer(int indent = 0)
95 : indent(indent)
96 {
97 }
98
99 void operator()(mini_xml const& xml) const
100 {
101 mini_xml_printer(indent+tabsize)(xml);
102 }
103
104 void operator()(std::string const& text) const
105 {
106 tab(indent+tabsize);
107 std::cout << "text: \"" << text << '"' << std::endl;
108 }
109
110 int indent;
111 };
112
113 void mini_xml_printer::operator()(mini_xml const& xml) const
114 {
115 tab(indent);
116 std::cout << "tag: " << xml.name << std::endl;
117 tab(indent);
118 std::cout << '{' << std::endl;
119
120 BOOST_FOREACH(mini_xml_node const& node, xml.children)
121 {
122 boost::apply_visitor(mini_xml_node_printer(indent), node);
123 }
124
125 tab(indent);
126 std::cout << '}' << std::endl;
127 }
128
129 ///////////////////////////////////////////////////////////////////////////
130 // Our mini XML grammar definition
131 ///////////////////////////////////////////////////////////////////////////
132 //[tutorial_xml1_grammar
133 template <typename Iterator>
134 struct mini_xml_grammar : qi::grammar<Iterator, mini_xml(), ascii::space_type>
135 {
136 mini_xml_grammar() : mini_xml_grammar::base_type(xml)
137 {
138 using qi::lit;
139 using qi::lexeme;
140 using ascii::char_;
141 using ascii::string;
142 using namespace qi::labels;
143
144 using phoenix::at_c;
145 using phoenix::push_back;
146
147 text = lexeme[+(char_ - '<') [_val += _1]];
148 node = (xml | text) [_val = _1];
149
150 start_tag =
151 '<'
152 >> !lit('/')
153 >> lexeme[+(char_ - '>') [_val += _1]]
154 >> '>'
155 ;
156
157 end_tag =
158 "</"
159 >> lit(_r1)
160 >> '>'
161 ;
162
163 xml =
164 start_tag [at_c<0>(_val) = _1]
165 >> *node [push_back(at_c<1>(_val), _1)]
166 >> end_tag(at_c<0>(_val))
167 ;
168 }
169
170 qi::rule<Iterator, mini_xml(), ascii::space_type> xml;
171 qi::rule<Iterator, mini_xml_node(), ascii::space_type> node;
172 qi::rule<Iterator, std::string(), ascii::space_type> text;
173 qi::rule<Iterator, std::string(), ascii::space_type> start_tag;
174 qi::rule<Iterator, void(std::string), ascii::space_type> end_tag;
175 };
176 //]
177 }
178
179 ///////////////////////////////////////////////////////////////////////////////
180 // Main program
181 ///////////////////////////////////////////////////////////////////////////////
182 int main(int argc, char **argv)
183 {
184 char const* filename;
185 if (argc > 1)
186 {
187 filename = argv[1];
188 }
189 else
190 {
191 std::cerr << "Error: No input file provided." << std::endl;
192 return 1;
193 }
194
195 std::ifstream in(filename, std::ios_base::in);
196
197 if (!in)
198 {
199 std::cerr << "Error: Could not open input file: "
200 << filename << std::endl;
201 return 1;
202 }
203
204 std::string storage; // We will read the contents here.
205 in.unsetf(std::ios::skipws); // No white space skipping!
206 std::copy(
207 std::istream_iterator<char>(in),
208 std::istream_iterator<char>(),
209 std::back_inserter(storage));
210
211 typedef client::mini_xml_grammar<std::string::const_iterator> mini_xml_grammar;
212 mini_xml_grammar xml; // Our grammar
213 client::mini_xml ast; // Our tree
214
215 using boost::spirit::ascii::space;
216 std::string::const_iterator iter = storage.begin();
217 std::string::const_iterator end = storage.end();
218 bool r = phrase_parse(iter, end, xml, space, ast);
219
220 if (r && iter == end)
221 {
222 std::cout << "-------------------------\n";
223 std::cout << "Parsing succeeded\n";
224 std::cout << "-------------------------\n";
225 client::mini_xml_printer printer;
226 printer(ast);
227 return 0;
228 }
229 else
230 {
231 std::string::const_iterator some = iter + std::min(30, int(end - iter));
232 std::string context(iter, (some>end)?end:some);
233 std::cout << "-------------------------\n";
234 std::cout << "Parsing failed\n";
235 std::cout << "stopped at: \"" << context << "...\"\n";
236 std::cout << "-------------------------\n";
237 return 1;
238 }
239 }
240
241