Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/spirit/test/ast_calc_tests.cpp @ 33

Last change on this file since 33 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 9.9 KB
Line 
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/core.hpp>
12#include <boost/spirit/tree/ast.hpp>
13#include <boost/spirit/tree/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
22using namespace boost::spirit;
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;
126
127typedef char const*                         iterator_t;
128typedef tree_match<iterator_t>              parse_tree_match_t;
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
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////////////////////////////////////////////////////////////////////////////
213int
214parse(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
225int
226parse_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
237int
238main()
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
Note: See TracBrowser for help on using the repository browser.