• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2007 Hartmut Kaiser
3     Copyright (c) 2020 Nikita Kniazev
4     http://spirit.sourceforge.net/
5 
6     Use, modification and distribution is subject to the Boost Software
7     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8     http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10 
11 #include <boost/detail/lightweight_test.hpp>
12 #include <boost/preprocessor/cat.hpp>
13 #include <boost/spirit/include/classic_core.hpp>
14 #include <boost/spirit/include/classic_ast.hpp>
15 #include <boost/spirit/include/classic_tree_to_xml.hpp>
16 
17 #include <iostream>
18 #include <iterator>
19 #include <fstream>
20 #include <ostream>
21 #include <string>
22 
23 using namespace BOOST_SPIRIT_CLASSIC_NS;
24 
25 ///////////////////////////////////////////////////////////////////////////////
26 struct calculator : public grammar<calculator>
27 {
28     static const int integerID = 1;
29     static const int factorID = 2;
30     static const int termID = 3;
31     static const int expressionID = 4;
32 
33     template <typename ScannerT>
34     struct definition
35     {
definitioncalculator::definition36         definition(calculator const& /*self*/)
37         {
38             //  Start grammar definition
39             integer     =   leaf_node_d[ lexeme_d[
40                                 (!ch_p('-') >> +digit_p)
41                             ] ];
42 
43             factor      =   integer
44                         |   inner_node_d[ch_p('(') >> expression >> ch_p(')')]
45                         |   (root_node_d[ch_p('-')] >> factor);
46 
47             term        =   factor >>
48                             *(  (root_node_d[ch_p('*')] >> factor)
49                               | (root_node_d[ch_p('/')] >> factor)
50                             );
51 
52             expression  =   term >>
53                             *(  (root_node_d[ch_p('+')] >> term)
54                               | (root_node_d[ch_p('-')] >> term)
55                             );
56             //  End grammar definition
57 
58             // turn on the debugging info.
59             BOOST_SPIRIT_DEBUG_RULE(integer);
60             BOOST_SPIRIT_DEBUG_RULE(factor);
61             BOOST_SPIRIT_DEBUG_RULE(term);
62             BOOST_SPIRIT_DEBUG_RULE(expression);
63         }
64 
65         rule<ScannerT, parser_context<>, parser_tag<expressionID> >   expression;
66         rule<ScannerT, parser_context<>, parser_tag<termID> >         term;
67         rule<ScannerT, parser_context<>, parser_tag<factorID> >       factor;
68         rule<ScannerT, parser_context<>, parser_tag<integerID> >      integer;
69 
70         rule<ScannerT, parser_context<>, parser_tag<expressionID> > const&
startcalculator::definition71         start() const { return expression; }
72     };
73 };
74 
75 ///////////////////////////////////////////////////////////////////////////////
76 /// a streambuf implementation that sinks characters to output iterator
77 template <typename OutputIterator, typename Char>
78 struct psbuf : std::basic_streambuf<Char>
79 {
80     template <typename T>
psbufpsbuf81     psbuf(T& sink) : sink_(sink) {}
82 
83     // silence MSVC warning C4512: assignment operator could not be generated
84     BOOST_DELETED_FUNCTION(psbuf& operator=(psbuf const&))
85 
86 protected:
overflowpsbuf87     typename psbuf::int_type overflow(typename psbuf::int_type ch) BOOST_OVERRIDE
88     {
89         if (psbuf::traits_type::eq_int_type(ch, psbuf::traits_type::eof()))
90             return psbuf::traits_type::not_eof(ch);
91 
92         *sink_ = psbuf::traits_type::to_char_type(ch);
93         ++sink_;
94         return ch;
95     }
96 
97 private:
98     OutputIterator sink_;
99 };
100 
101 ///////////////////////////////////////////////////////////////////////////////
102 #define EXPECTED_XML_OUTPUT "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n\
103 <!DOCTYPE parsetree SYSTEM \"parsetree.dtd\">\n\
104 <!-- 1+2 -->\n\
105 <parsetree version=\"1.0\">\n\
106     <parsenode>\n\
107         <value>+</value>\n\
108         <parsenode>\n\
109             <value>1</value>\n\
110         </parsenode>\n\
111         <parsenode>\n\
112             <value>2</value>\n\
113         </parsenode>\n\
114     </parsenode>\n\
115 </parsetree>\n"
116 
117 #define EXPECTED_XML_OUTPUT_WIDE BOOST_PP_CAT(L, EXPECTED_XML_OUTPUT)
118 
test(wchar_t const * text)119 bool test(wchar_t const *text)
120 {
121     typedef std::basic_string<wchar_t>::iterator iterator_t;
122 
123     std::basic_string<wchar_t> input(text);
124     calculator calc;
125     tree_parse_info<iterator_t> ast_info =
126         ast_parse(iterator_t(input.begin()), iterator_t(input.end()),
127             calc >> end_p, space_p);
128 
129     std::basic_string<wchar_t> out;
130     {
131         psbuf<std::back_insert_iterator<std::wstring>, wchar_t> buf(out);
132         std::wostream outsink(&buf);
133         basic_tree_to_xml<wchar_t>(outsink, ast_info.trees, input);
134     }
135     return out == EXPECTED_XML_OUTPUT_WIDE;
136 }
137 
test(char const * text)138 bool test(char const *text)
139 {
140     typedef std::string::iterator iterator_t;
141 
142     std::string input(text);
143     calculator calc;
144     tree_parse_info<iterator_t> ast_info =
145         ast_parse(iterator_t(input.begin()), iterator_t(input.end()),
146             calc >> end_p, space_p);
147 
148     std::string out;
149     {
150         psbuf<std::back_insert_iterator<std::string>, char> buf(out);
151         std::ostream outsink(&buf);
152         basic_tree_to_xml<char>(outsink, ast_info.trees, input);
153     }
154     return out == EXPECTED_XML_OUTPUT;
155 }
156 
main()157 int main()
158 {
159     BOOST_TEST(test("1+2"));
160     if (std::has_facet<std::ctype<wchar_t> >(std::locale()))
161     {
162         BOOST_TEST(test(L"1+2"));
163     }
164     return boost::report_errors();
165 }
166