]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/spirit/classic/test/ast_calc_tests.cpp
1 /*=============================================================================
2 Copyright (c) 2001-2003 Daniel Nuffer
3 http://spirit.sourceforge.net/
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
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>
20 #include <boost/detail/lightweight_test.hpp>
22 using namespace BOOST_SPIRIT_CLASSIC_NS
;
24 ////////////////////////////////////////////////////////////////////////////
26 // Our calculator grammar
28 ////////////////////////////////////////////////////////////////////////////
29 struct calculator
: public grammar
<calculator
>
31 static const int integerID
= 1;
32 static const int factorID
= 2;
33 static const int termID
= 3;
34 static const int expressionID
= 4;
36 template <typename ScannerT
>
39 definition(calculator
const& /*self*/)
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...
46 | inner_node_d
[ch_p('(') >> expression
>> ch_p(')')]
47 | (root_node_d
[ch_p('-')] >> factor
);
50 *( (root_node_d
[ch_p('*')] >> factor
)
51 | (root_node_d
[ch_p('/')] >> factor
)
55 *( (root_node_d
[ch_p('+')] >> term
)
56 | (root_node_d
[ch_p('-')] >> term
)
58 // End grammar definition
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
;
66 rule
<ScannerT
, parser_context
<>, parser_tag
<expressionID
> > const&
67 start() const { return expression
; }
71 ////////////////////////////////////////////////////////////////////////////
73 // Our calculator grammar, but with dynamically assigned rule ID's
75 ////////////////////////////////////////////////////////////////////////////
76 struct dyn_calculator
: public grammar
<dyn_calculator
>
78 static const int integerID
= 1;
79 static const int factorID
= 2;
80 static const int termID
= 3;
81 static const int expressionID
= 4;
83 template <typename ScannerT
>
86 definition(dyn_calculator
const& /*self*/)
88 expression
.set_id(expressionID
);
90 factor
.set_id(factorID
);
91 integer
.set_id(integerID
);
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...
98 | inner_node_d
[ch_p('(') >> expression
>> ch_p(')')]
99 | (root_node_d
[ch_p('-')] >> factor
);
102 *( (root_node_d
[ch_p('*')] >> factor
)
103 | (root_node_d
[ch_p('/')] >> factor
)
107 *( (root_node_d
[ch_p('+')] >> term
)
108 | (root_node_d
[ch_p('-')] >> term
)
110 // End grammar definition
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
;
118 rule
<ScannerT
, parser_context
<>, dynamic_parser_tag
> const&
119 start() const { return expression
; }
123 ////////////////////////////////////////////////////////////////////////////
125 using namespace BOOST_SPIRIT_CLASSIC_NS
;
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
;
131 ////////////////////////////////////////////////////////////////////////////
132 long evaluate(parse_tree_match_t hit
);
133 long eval_expression(iter_t
const& i
);
135 long evaluate(tree_parse_info
<> info
)
137 return eval_expression(info
.trees
.begin());
140 long eval_expression(iter_t
const& i
)
142 switch (i
->value
.id().to_long())
144 case calculator::integerID
:
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);
157 string
integer(i
->value
.begin(), i
->value
.end());
158 return strtol(integer
.c_str(), 0, 10);
162 case calculator::factorID
:
164 // factor can only be unary minus
165 BOOST_TEST(*i
->value
.begin() == '-');
166 return - eval_expression(i
->children
.begin());
169 case calculator::termID
:
171 if (*i
->value
.begin() == '*')
173 BOOST_TEST(i
->children
.size() == 2);
174 return eval_expression(i
->children
.begin()) *
175 eval_expression(i
->children
.begin()+1);
177 else if (*i
->value
.begin() == '/')
179 BOOST_TEST(i
->children
.size() == 2);
180 return eval_expression(i
->children
.begin()) /
181 eval_expression(i
->children
.begin()+1);
187 case calculator::expressionID
:
189 if (*i
->value
.begin() == '+')
191 BOOST_TEST(i
->children
.size() == 2);
192 return eval_expression(i
->children
.begin()) +
193 eval_expression(i
->children
.begin()+1);
195 else if (*i
->value
.begin() == '-')
197 BOOST_TEST(i
->children
.size() == 2);
198 return eval_expression(i
->children
.begin()) -
199 eval_expression(i
->children
.begin()+1);
206 BOOST_TEST(0); // error
212 ////////////////////////////////////////////////////////////////////////////
214 parse(char const* str
)
217 tree_parse_info
<> info
= ast_parse(str
, calc
, space_p
);
220 return evaluate(info
);
226 parse_dyn(char const* str
)
229 tree_parse_info
<> info
= ast_parse(str
, calc
, space_p
);
232 return evaluate(info
);
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);
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);
274 return boost::report_errors();