• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2010 Joel de Guzman
3     Copyright (c) 2001-2010 Hartmut Kaiser
4 
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 ///////////////////////////////////////////////////////////////////////////////
9 //
10 //  A mini XML-like parser, Karma is used to print out the generated AST
11 //
12 //  [ JDG March 25, 2007 ]   spirit2
13 //  [ HK April 02, 2007  ]   spirit2
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 
17 #include <boost/config/warning_disable.hpp>
18 
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>
28 
29 #include <iostream>
30 #include <fstream>
31 #include <string>
32 #include <vector>
33 
34 using namespace boost::spirit;
35 using namespace boost::spirit::ascii;
36 
37 namespace fusion = boost::fusion;
38 namespace phoenix = boost::phoenix;
39 
40 using phoenix::at_c;
41 using phoenix::push_back;
42 
43 ///////////////////////////////////////////////////////////////////////////////
44 //  Our mini XML tree representation
45 ///////////////////////////////////////////////////////////////////////////////
46 struct mini_xml;
47 
48 typedef
49     boost::variant<
50         boost::recursive_wrapper<mini_xml>
51       , std::string
52     >
53 mini_xml_node;
54 
55 struct mini_xml
56 {
57     std::string name;                           // tag name
58     std::vector<mini_xml_node> children;        // children
59 };
60 
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(
64     mini_xml,
65     (std::string, name)
66     (std::vector<mini_xml_node>, children)
67 )
68 
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>
75 {
mini_xml_parsermini_xml_parser76     mini_xml_parser() : mini_xml_parser::base_type(xml)
77     {
78         text = lexeme[+(char_ - '<')        [_val += _1]];
79         node = (xml | text)                 [_val = _1];
80 
81         start_tag =
82                 '<'
83             >>  !lit('/')
84             >>  lexeme[+(char_ - '>')       [_val += _1]]
85             >>  '>'
86         ;
87 
88         end_tag =
89                 "</"
90             >>  lit(_r1)
91             >>  '>'
92         ;
93 
94         xml =
95                 start_tag                   [at_c<0>(_val) = _1]
96             >>  *node                       [push_back(at_c<1>(_val), _1)]
97             >>  end_tag(at_c<0>(_val))
98         ;
99     }
100 
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;
106 };
107 
108 ///////////////////////////////////////////////////////////////////////////////
109 //  A couple of phoenix functions helping to access the elements of the
110 //  generated AST
111 ///////////////////////////////////////////////////////////////////////////////
112 template <typename T>
113 struct get_element
114 {
115     template <typename T1>
116     struct result { typedef T const& type; };
117 
operator ()get_element118     T const& operator()(mini_xml_node const& node) const
119     {
120         return boost::get<T>(node);
121     }
122 };
123 
124 phoenix::function<get_element<std::string> > _string;
125 phoenix::function<get_element<mini_xml> > _xml;
126 
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()>
133 {
mini_xml_generatormini_xml_generator134     mini_xml_generator() : mini_xml_generator::base_type(xml)
135     {
136         node %= string | xml;
137         xml =
138                 '<'  << string[_1 = at_c<0>(_val)] << '>'
139             <<         (*node)[_1 = at_c<1>(_val)]
140             <<  "</" << string[_1 = at_c<0>(_val)] << '>'
141             ;
142     }
143 
144     karma::rule<OutputIterator, mini_xml()> xml;
145     karma::rule<OutputIterator, mini_xml_node()> node;
146 };
147 
148 ///////////////////////////////////////////////////////////////////////////////
149 //  Main program
150 ///////////////////////////////////////////////////////////////////////////////
main(int argc,char ** argv)151 int main(int argc, char **argv)
152 {
153     char const* filename;
154     if (argc > 1)
155     {
156         filename = argv[1];
157     }
158     else
159     {
160         std::cerr << "Error: No input file provided." << std::endl;
161         return 1;
162     }
163 
164     std::ifstream in(filename, std::ios_base::in);
165 
166     if (!in)
167     {
168         std::cerr << "Error: Could not open input file: "
169             << filename << std::endl;
170         return 1;
171     }
172 
173     std::string storage; // We will read the contents here.
174     in.unsetf(std::ios::skipws); // No white space skipping!
175     std::copy(
176         std::istream_iterator<char>(in),
177         std::istream_iterator<char>(),
178         std::back_inserter(storage));
179 
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
183 
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);
187 
188     if (r && iter == end)
189     {
190         std::cout << "-------------------------\n";
191         std::cout << "Parsing succeeded\n";
192         std::cout << "-------------------------\n";
193 
194         typedef std::back_insert_iterator<std::string> outiter_type;
195         typedef mini_xml_generator<outiter_type> mini_xml_generator;
196 
197         mini_xml_generator xmlout;                 //  Our grammar definition
198 
199         std::string generated;
200         outiter_type outit(generated);
201         bool r = karma::generate(outit, xmlout, ast);
202 
203         if (r)
204             std::cout << generated << std::endl;
205         return 0;
206     }
207     else
208     {
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";
218         return 1;
219     }
220 }
221 
222 
223