]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/spirit/classic/test/ast_calc_tests.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / spirit / classic / test / ast_calc_tests.cpp
CommitLineData
7c673cae
FG
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>
1e59de90 20#include <boost/core/lightweight_test.hpp>
7c673cae
FG
21
22using namespace BOOST_SPIRIT_CLASSIC_NS;
23
24////////////////////////////////////////////////////////////////////////////
25//
26// Our calculator grammar
27//
28////////////////////////////////////////////////////////////////////////////
29struct 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////////////////////////////////////////////////////////////////////////////
76struct 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////////////////////////////////////////////////////////////////////////////
124using namespace std;
125using namespace BOOST_SPIRIT_CLASSIC_NS;
126
11fdf7f2
TL
127typedef char const* parser_iterator_t;
128typedef tree_match<parser_iterator_t> parse_tree_match_t;
7c673cae
FG
129typedef parse_tree_match_t::tree_iterator iter_t;
130
131////////////////////////////////////////////////////////////////////////////
132long evaluate(parse_tree_match_t hit);
133long eval_expression(iter_t const& i);
134
135long evaluate(tree_parse_info<> info)
136{
137 return eval_expression(info.trees.begin());
138}
139
140long 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
92f5a8d4 184 std::abort();
7c673cae
FG
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
92f5a8d4 202 std::abort();
7c673cae
FG
203 }
204
205 default:
92f5a8d4 206 std::abort(); // error
7c673cae
FG
207 }
208
92f5a8d4 209#if defined(_MSC_VER) && (_MSC_VER < 1700)
7c673cae 210 return 0;
92f5a8d4 211#endif
7c673cae
FG
212}
213
214////////////////////////////////////////////////////////////////////////////
215int
216parse(char const* str)
217{
218 calculator calc;
219 tree_parse_info<> info = ast_parse(str, calc, space_p);
220
221 if (info.full)
222 return evaluate(info);
223 else
224 return -1;
225}
226
227int
228parse_dyn(char const* str)
229{
230 dyn_calculator calc;
231 tree_parse_info<> info = ast_parse(str, calc, space_p);
232
233 if (info.full)
234 return evaluate(info);
235 else
236 return -1;
237}
238
239int
240main()
241{
242// test the calculator with statically assigned rule ID's
243 BOOST_TEST(parse("12345") == 12345);
244 BOOST_TEST(parse("-12345") == -12345);
245 BOOST_TEST(parse("1 + 2") == 1 + 2);
246 BOOST_TEST(parse("1 * 2") == 1 * 2);
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 + 2) * (3 + 4)") == (1 + 2) * (3 + 4));
251 BOOST_TEST(parse("(-1 + 2) * (3 + -4)") == (-1 + 2) * (3 + -4));
252 BOOST_TEST(parse("1 + ((6 * 200) - 20) / 6") == 1 + ((6 * 200) - 20) / 6);
253 BOOST_TEST(parse("(1 + (2 + (3 + (4 + 5))))") == (1 + (2 + (3 + (4 + 5)))));
254 BOOST_TEST(parse("1 + 2 + 3 + 4 + 5") == 1 + 2 + 3 + 4 + 5);
255 BOOST_TEST(parse("(12 * 22) + (36 + -4 + 5)") == (12 * 22) + (36 + -4 + 5));
256 BOOST_TEST(parse("(12 * 22) / (5 - 10 + 15)") == (12 * 22) / (5 - 10 + 15));
257 BOOST_TEST(parse("12 * 6 * 15 + 5 - 25") == 12 * 6 * 15 + 5 - 25);
258
259// test the calculator with dynamically assigned rule ID's
260 BOOST_TEST(parse_dyn("12345") == 12345);
261 BOOST_TEST(parse_dyn("-12345") == -12345);
262 BOOST_TEST(parse_dyn("1 + 2") == 1 + 2);
263 BOOST_TEST(parse_dyn("1 * 2") == 1 * 2);
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 + 2) * (3 + 4)") == (1 + 2) * (3 + 4));
268 BOOST_TEST(parse_dyn("(-1 + 2) * (3 + -4)") == (-1 + 2) * (3 + -4));
269 BOOST_TEST(parse_dyn("1 + ((6 * 200) - 20) / 6") == 1 + ((6 * 200) - 20) / 6);
270 BOOST_TEST(parse_dyn("(1 + (2 + (3 + (4 + 5))))") == (1 + (2 + (3 + (4 + 5)))));
271 BOOST_TEST(parse_dyn("1 + 2 + 3 + 4 + 5") == 1 + 2 + 3 + 4 + 5);
272 BOOST_TEST(parse_dyn("(12 * 22) + (36 + -4 + 5)") == (12 * 22) + (36 + -4 + 5));
273 BOOST_TEST(parse_dyn("(12 * 22) / (5 - 10 + 15)") == (12 * 22) / (5 - 10 + 15));
274 BOOST_TEST(parse_dyn("12 * 6 * 15 + 5 - 25") == 12 * 6 * 15 + 5 - 25);
275
276 return boost::report_errors();
277}
278
279