]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/classic/test/ast_calc_tests.cpp
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / boost / libs / spirit / classic / test / ast_calc_tests.cpp
1 /*=============================================================================
2 Copyright (c) 2001-2003 Daniel Nuffer
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 // JDG 4-16-03 Modified from ast_calc.cpp as a test
10
11 #include <boost/spirit/include/classic_core.hpp>
12 #include <boost/spirit/include/classic_ast.hpp>
13 #include <boost/spirit/include/classic_tree_to_xml.hpp>
14 #include <boost/detail/workaround.hpp>
15
16 #include <iostream>
17 #include <stack>
18 #include <functional>
19 #include <string>
20 #include <boost/detail/lightweight_test.hpp>
21
22 using namespace BOOST_SPIRIT_CLASSIC_NS;
23
24 ////////////////////////////////////////////////////////////////////////////
25 //
26 // Our calculator grammar
27 //
28 ////////////////////////////////////////////////////////////////////////////
29 struct calculator : public grammar<calculator>
30 {
31 static const int integerID = 1;
32 static const int factorID = 2;
33 static const int termID = 3;
34 static const int expressionID = 4;
35
36 template <typename ScannerT>
37 struct definition
38 {
39 definition(calculator const& /*self*/)
40 {
41 // Start grammar definition
42 integer = leaf_node_d[real_p]; // we're not really using a real
43 // but just for compile checking
44 // the AST tree match code...
45 factor = integer
46 | inner_node_d[ch_p('(') >> expression >> ch_p(')')]
47 | (root_node_d[ch_p('-')] >> factor);
48
49 term = factor >>
50 *( (root_node_d[ch_p('*')] >> factor)
51 | (root_node_d[ch_p('/')] >> factor)
52 );
53
54 expression = term >>
55 *( (root_node_d[ch_p('+')] >> term)
56 | (root_node_d[ch_p('-')] >> term)
57 );
58 // End grammar definition
59 }
60
61 rule<ScannerT, parser_context<>, parser_tag<expressionID> > expression;
62 rule<ScannerT, parser_context<>, parser_tag<termID> > term;
63 rule<ScannerT, parser_context<>, parser_tag<factorID> > factor;
64 rule<ScannerT, parser_context<>, parser_tag<integerID> > integer;
65
66 rule<ScannerT, parser_context<>, parser_tag<expressionID> > const&
67 start() const { return expression; }
68 };
69 };
70
71 ////////////////////////////////////////////////////////////////////////////
72 //
73 // Our calculator grammar, but with dynamically assigned rule ID's
74 //
75 ////////////////////////////////////////////////////////////////////////////
76 struct dyn_calculator : public grammar<dyn_calculator>
77 {
78 static const int integerID = 1;
79 static const int factorID = 2;
80 static const int termID = 3;
81 static const int expressionID = 4;
82
83 template <typename ScannerT>
84 struct definition
85 {
86 definition(dyn_calculator const& /*self*/)
87 {
88 expression.set_id(expressionID);
89 term.set_id(termID);
90 factor.set_id(factorID);
91 integer.set_id(integerID);
92
93 // Start grammar definition
94 integer = leaf_node_d[real_p]; // we're not really using a real
95 // but just for compile checking
96 // the AST tree match code...
97 factor = integer
98 | inner_node_d[ch_p('(') >> expression >> ch_p(')')]
99 | (root_node_d[ch_p('-')] >> factor);
100
101 term = factor >>
102 *( (root_node_d[ch_p('*')] >> factor)
103 | (root_node_d[ch_p('/')] >> factor)
104 );
105
106 expression = term >>
107 *( (root_node_d[ch_p('+')] >> term)
108 | (root_node_d[ch_p('-')] >> term)
109 );
110 // End grammar definition
111 }
112
113 rule<ScannerT, parser_context<>, dynamic_parser_tag> expression;
114 rule<ScannerT, parser_context<>, dynamic_parser_tag> term;
115 rule<ScannerT, parser_context<>, dynamic_parser_tag> factor;
116 rule<ScannerT, parser_context<>, dynamic_parser_tag> integer;
117
118 rule<ScannerT, parser_context<>, dynamic_parser_tag> const&
119 start() const { return expression; }
120 };
121 };
122
123 ////////////////////////////////////////////////////////////////////////////
124 using namespace std;
125 using namespace BOOST_SPIRIT_CLASSIC_NS;
126
127 typedef char const* parser_iterator_t;
128 typedef tree_match<parser_iterator_t> parse_tree_match_t;
129 typedef parse_tree_match_t::tree_iterator iter_t;
130
131 ////////////////////////////////////////////////////////////////////////////
132 long evaluate(parse_tree_match_t hit);
133 long eval_expression(iter_t const& i);
134
135 long evaluate(tree_parse_info<> info)
136 {
137 return eval_expression(info.trees.begin());
138 }
139
140 long eval_expression(iter_t const& i)
141 {
142 switch (i->value.id().to_long())
143 {
144 case calculator::integerID:
145 {
146 BOOST_TEST(i->children.size() == 0);
147 // extract integer (not always delimited by '\0')
148 #if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003))
149 // std::string(iter,iter) constructor has a bug in MWCW 8.3:
150 // in some situations, the null terminator won't be added
151 // and c_str() will return bogus data. Conservatively, I
152 // activate this workaround up to version 8.3.
153 std::vector<char> value(i->value.begin(), i->value.end());
154 value.push_back('\0');
155 return strtol(&value[0], 0, 10);
156 #else
157 string integer(i->value.begin(), i->value.end());
158 return strtol(integer.c_str(), 0, 10);
159 #endif
160 }
161
162 case calculator::factorID:
163 {
164 // factor can only be unary minus
165 BOOST_TEST(*i->value.begin() == '-');
166 return - eval_expression(i->children.begin());
167 }
168
169 case calculator::termID:
170 {
171 if (*i->value.begin() == '*')
172 {
173 BOOST_TEST(i->children.size() == 2);
174 return eval_expression(i->children.begin()) *
175 eval_expression(i->children.begin()+1);
176 }
177 else if (*i->value.begin() == '/')
178 {
179 BOOST_TEST(i->children.size() == 2);
180 return eval_expression(i->children.begin()) /
181 eval_expression(i->children.begin()+1);
182 }
183 else
184 BOOST_TEST(0);
185 }
186
187 case calculator::expressionID:
188 {
189 if (*i->value.begin() == '+')
190 {
191 BOOST_TEST(i->children.size() == 2);
192 return eval_expression(i->children.begin()) +
193 eval_expression(i->children.begin()+1);
194 }
195 else if (*i->value.begin() == '-')
196 {
197 BOOST_TEST(i->children.size() == 2);
198 return eval_expression(i->children.begin()) -
199 eval_expression(i->children.begin()+1);
200 }
201 else
202 BOOST_TEST(0);
203 }
204
205 default:
206 BOOST_TEST(0); // error
207 }
208
209 return 0;
210 }
211
212 ////////////////////////////////////////////////////////////////////////////
213 int
214 parse(char const* str)
215 {
216 calculator calc;
217 tree_parse_info<> info = ast_parse(str, calc, space_p);
218
219 if (info.full)
220 return evaluate(info);
221 else
222 return -1;
223 }
224
225 int
226 parse_dyn(char const* str)
227 {
228 dyn_calculator calc;
229 tree_parse_info<> info = ast_parse(str, calc, space_p);
230
231 if (info.full)
232 return evaluate(info);
233 else
234 return -1;
235 }
236
237 int
238 main()
239 {
240 // test the calculator with statically assigned rule ID's
241 BOOST_TEST(parse("12345") == 12345);
242 BOOST_TEST(parse("-12345") == -12345);
243 BOOST_TEST(parse("1 + 2") == 1 + 2);
244 BOOST_TEST(parse("1 * 2") == 1 * 2);
245 BOOST_TEST(parse("1/2 + 3/4") == 1/2 + 3/4);
246 BOOST_TEST(parse("1 + 2 + 3 + 4") == 1 + 2 + 3 + 4);
247 BOOST_TEST(parse("1 * 2 * 3 * 4") == 1 * 2 * 3 * 4);
248 BOOST_TEST(parse("(1 + 2) * (3 + 4)") == (1 + 2) * (3 + 4));
249 BOOST_TEST(parse("(-1 + 2) * (3 + -4)") == (-1 + 2) * (3 + -4));
250 BOOST_TEST(parse("1 + ((6 * 200) - 20) / 6") == 1 + ((6 * 200) - 20) / 6);
251 BOOST_TEST(parse("(1 + (2 + (3 + (4 + 5))))") == (1 + (2 + (3 + (4 + 5)))));
252 BOOST_TEST(parse("1 + 2 + 3 + 4 + 5") == 1 + 2 + 3 + 4 + 5);
253 BOOST_TEST(parse("(12 * 22) + (36 + -4 + 5)") == (12 * 22) + (36 + -4 + 5));
254 BOOST_TEST(parse("(12 * 22) / (5 - 10 + 15)") == (12 * 22) / (5 - 10 + 15));
255 BOOST_TEST(parse("12 * 6 * 15 + 5 - 25") == 12 * 6 * 15 + 5 - 25);
256
257 // test the calculator with dynamically assigned rule ID's
258 BOOST_TEST(parse_dyn("12345") == 12345);
259 BOOST_TEST(parse_dyn("-12345") == -12345);
260 BOOST_TEST(parse_dyn("1 + 2") == 1 + 2);
261 BOOST_TEST(parse_dyn("1 * 2") == 1 * 2);
262 BOOST_TEST(parse_dyn("1/2 + 3/4") == 1/2 + 3/4);
263 BOOST_TEST(parse_dyn("1 + 2 + 3 + 4") == 1 + 2 + 3 + 4);
264 BOOST_TEST(parse_dyn("1 * 2 * 3 * 4") == 1 * 2 * 3 * 4);
265 BOOST_TEST(parse_dyn("(1 + 2) * (3 + 4)") == (1 + 2) * (3 + 4));
266 BOOST_TEST(parse_dyn("(-1 + 2) * (3 + -4)") == (-1 + 2) * (3 + -4));
267 BOOST_TEST(parse_dyn("1 + ((6 * 200) - 20) / 6") == 1 + ((6 * 200) - 20) / 6);
268 BOOST_TEST(parse_dyn("(1 + (2 + (3 + (4 + 5))))") == (1 + (2 + (3 + (4 + 5)))));
269 BOOST_TEST(parse_dyn("1 + 2 + 3 + 4 + 5") == 1 + 2 + 3 + 4 + 5);
270 BOOST_TEST(parse_dyn("(12 * 22) + (36 + -4 + 5)") == (12 * 22) + (36 + -4 + 5));
271 BOOST_TEST(parse_dyn("(12 * 22) / (5 - 10 + 15)") == (12 * 22) / (5 - 10 + 15));
272 BOOST_TEST(parse_dyn("12 * 6 * 15 + 5 - 25") == 12 * 6 * 15 + 5 - 25);
273
274 return boost::report_errors();
275 }
276
277