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