]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2001-2007 Hartmut Kaiser | |
20effc67 | 3 | Copyright (c) 2020 Nikita Kniazev |
7c673cae FG |
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> | |
7c673cae FG |
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> | |
20effc67 | 18 | #include <iterator> |
7c673cae | 19 | #include <fstream> |
20effc67 | 20 | #include <ostream> |
7c673cae FG |
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 | { | |
36 | 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& | |
71 | start() const { return expression; } | |
72 | }; | |
73 | }; | |
74 | ||
75 | /////////////////////////////////////////////////////////////////////////////// | |
20effc67 TL |
76 | /// a streambuf implementation that sinks characters to output iterator |
77 | template <typename OutputIterator, typename Char> | |
78 | struct psbuf : std::basic_streambuf<Char> | |
7c673cae | 79 | { |
20effc67 TL |
80 | template <typename T> |
81 | 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: | |
87 | typename psbuf::int_type overflow(typename psbuf::int_type ch) BOOST_OVERRIDE | |
7c673cae | 88 | { |
20effc67 TL |
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; | |
7c673cae FG |
95 | } |
96 | ||
7c673cae | 97 | private: |
20effc67 | 98 | OutputIterator sink_; |
7c673cae FG |
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 | ||
119 | bool test(wchar_t const *text) | |
120 | { | |
121 | typedef std::basic_string<wchar_t>::iterator iterator_t; | |
7c673cae FG |
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 | { | |
20effc67 TL |
131 | psbuf<std::back_insert_iterator<std::wstring>, wchar_t> buf(out); |
132 | std::wostream outsink(&buf); | |
7c673cae FG |
133 | basic_tree_to_xml<wchar_t>(outsink, ast_info.trees, input); |
134 | } | |
135 | return out == EXPECTED_XML_OUTPUT_WIDE; | |
136 | } | |
137 | ||
138 | bool test(char const *text) | |
139 | { | |
140 | typedef std::string::iterator iterator_t; | |
7c673cae FG |
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 | { | |
20effc67 TL |
150 | psbuf<std::back_insert_iterator<std::string>, char> buf(out); |
151 | std::ostream outsink(&buf); | |
7c673cae FG |
152 | basic_tree_to_xml<char>(outsink, ast_info.trees, input); |
153 | } | |
154 | return out == EXPECTED_XML_OUTPUT; | |
155 | } | |
156 | ||
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 | } |