Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / spirit / classic / test / tree_to_xml.cpp
1 /*=============================================================================
2     Copyright (c) 2001-2007 Hartmut Kaiser
3     http://spirit.sourceforge.net/
4
5     Use, modification and distribution is subject to the Boost Software
6     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7     http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9
10 #include <boost/detail/lightweight_test.hpp>
11 #include <boost/preprocessor/cat.hpp>
12 #include <boost/spirit/include/classic_core.hpp> 
13 #include <boost/spirit/include/classic_ast.hpp> 
14 #include <boost/spirit/include/classic_tree_to_xml.hpp> 
15
16 #ifdef _MSC_VER
17 # pragma warning(push)
18 # pragma warning(disable: 4702) // unreachable code
19 #endif
20 #include <boost/iostreams/stream.hpp>
21 #ifdef _MSC_VER
22 # pragma warning(pop)
23 #endif
24
25 #include <iostream>
26 #include <fstream>
27 #include <string>
28
29 using namespace BOOST_SPIRIT_CLASSIC_NS; 
30
31 ///////////////////////////////////////////////////////////////////////////////
32 struct calculator : public grammar<calculator>
33 {
34     static const int integerID = 1;
35     static const int factorID = 2;
36     static const int termID = 3;
37     static const int expressionID = 4;
38
39     template <typename ScannerT>
40     struct definition
41     {
42         definition(calculator const& /*self*/)
43         {
44             //  Start grammar definition
45             integer     =   leaf_node_d[ lexeme_d[
46                                 (!ch_p('-') >> +digit_p)
47                             ] ];
48
49             factor      =   integer
50                         |   inner_node_d[ch_p('(') >> expression >> ch_p(')')]
51                         |   (root_node_d[ch_p('-')] >> factor);
52
53             term        =   factor >>
54                             *(  (root_node_d[ch_p('*')] >> factor)
55                               | (root_node_d[ch_p('/')] >> factor)
56                             );
57
58             expression  =   term >>
59                             *(  (root_node_d[ch_p('+')] >> term)
60                               | (root_node_d[ch_p('-')] >> term)
61                             );
62             //  End grammar definition
63
64             // turn on the debugging info.
65             BOOST_SPIRIT_DEBUG_RULE(integer);
66             BOOST_SPIRIT_DEBUG_RULE(factor);
67             BOOST_SPIRIT_DEBUG_RULE(term);
68             BOOST_SPIRIT_DEBUG_RULE(expression);
69         }
70
71         rule<ScannerT, parser_context<>, parser_tag<expressionID> >   expression;
72         rule<ScannerT, parser_context<>, parser_tag<termID> >         term;
73         rule<ScannerT, parser_context<>, parser_tag<factorID> >       factor;
74         rule<ScannerT, parser_context<>, parser_tag<integerID> >      integer;
75
76         rule<ScannerT, parser_context<>, parser_tag<expressionID> > const&
77         start() const { return expression; }
78     };
79 };
80
81 ///////////////////////////////////////////////////////////////////////////////
82 /// this is a Boost.IoStreams source device usable to create a istream on 
83 /// top of a random access container (i.e. vector<>)
84 template<typename Container>
85 class container_device 
86 {
87 public:
88     typedef typename Container::value_type char_type;
89     typedef boost::iostreams::sink_tag category;
90     
91     container_device(Container& container) 
92       : container_(container), pos_(0)
93     {}
94
95     /// Write up to n characters to the underlying data sink into the 
96     /// buffer s, returning the number of characters written
97     std::streamsize write(const char_type* s, std::streamsize n)
98     {
99         std::streamsize result = 0;
100         if (pos_ != container_.size()) {
101             std::streamsize amt = 
102                 static_cast<std::streamsize>(container_.size() - pos_);
103             result = (std::min)(n, amt);
104             std::copy(s, s + result, container_.begin() + pos_);
105             pos_ += static_cast<size_type>(result);
106         }
107         if (result < n) {
108             container_.insert(container_.end(), s, s + n);
109             pos_ = container_.size();
110         }
111         return n;
112     }
113
114     Container& container() { return container_; }
115     
116 private:
117     typedef typename Container::size_type size_type;
118     Container& container_;
119     size_type pos_;
120 };
121
122 ///////////////////////////////////////////////////////////////////////////////
123 #define EXPECTED_XML_OUTPUT "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n\
124 <!DOCTYPE parsetree SYSTEM \"parsetree.dtd\">\n\
125 <!-- 1+2 -->\n\
126 <parsetree version=\"1.0\">\n\
127     <parsenode>\n\
128         <value>+</value>\n\
129         <parsenode>\n\
130             <value>1</value>\n\
131         </parsenode>\n\
132         <parsenode>\n\
133             <value>2</value>\n\
134         </parsenode>\n\
135     </parsenode>\n\
136 </parsetree>\n"
137
138 #define EXPECTED_XML_OUTPUT_WIDE BOOST_PP_CAT(L, EXPECTED_XML_OUTPUT)
139
140 bool test(wchar_t const *text)
141 {
142     typedef std::basic_string<wchar_t>::iterator iterator_t; 
143
144     std::basic_string<wchar_t> input(text); 
145     calculator calc; 
146     tree_parse_info<iterator_t> ast_info = 
147         ast_parse(iterator_t(input.begin()), iterator_t(input.end()), 
148             calc >> end_p, space_p); 
149
150     std::basic_string<wchar_t> out;
151     {
152         typedef container_device<std::basic_string<wchar_t> > device_type;
153         boost::iostreams::stream<device_type> outsink(out);
154         basic_tree_to_xml<wchar_t>(outsink, ast_info.trees, input); 
155     }
156     return out == EXPECTED_XML_OUTPUT_WIDE;
157
158
159 bool test(char const *text)
160 {
161     typedef std::string::iterator iterator_t; 
162
163     std::string input(text); 
164     calculator calc; 
165     tree_parse_info<iterator_t> ast_info = 
166         ast_parse(iterator_t(input.begin()), iterator_t(input.end()), 
167             calc >> end_p, space_p); 
168
169     std::string out;
170     {
171         typedef container_device<std::string> device_type;
172         boost::iostreams::stream<device_type> outsink(out);
173         basic_tree_to_xml<char>(outsink, ast_info.trees, input); 
174     }
175     return out == EXPECTED_XML_OUTPUT;
176
177
178 int main() 
179
180     BOOST_TEST(test("1+2"));
181     if (std::has_facet<std::ctype<wchar_t> >(std::locale()))
182     {
183         BOOST_TEST(test(L"1+2"));
184     }
185     return boost::report_errors();
186 }