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 #include <boost/spirit/include/classic_core.hpp>
10 #include <boost/spirit/include/classic_ast.hpp>
11 #include <boost/assert.hpp>
12
13 #include <iostream>
14 #include <stack>
15 #include <functional>
16 #include <string>
17
18 // This example shows how to use an AST and tree_iter_node instead of
19 // tree_val_node
20 ////////////////////////////////////////////////////////////////////////////
21 using namespace std;
22 using namespace BOOST_SPIRIT_CLASSIC_NS;
23
24 typedef char const* iterator_t;
25 typedef tree_match<iterator_t, node_iter_data_factory<> >
26 parse_tree_match_t;
27
28 typedef parse_tree_match_t::tree_iterator iter_t;
29
30 typedef ast_match_policy<iterator_t, node_iter_data_factory<> > match_policy_t;
31 typedef scanner<iterator_t, scanner_policies<iter_policy_t, match_policy_t> > scanner_t;
32 typedef rule<scanner_t> rule_t;
33
34
35 // grammar rules
36 rule_t expression, term, factor, integer;
37
38 ////////////////////////////////////////////////////////////////////////////
39 long evaluate(parse_tree_match_t hit);
40 long eval_expression(iter_t const& i);
41 long eval_term(iter_t const& i);
42 long eval_factor(iter_t const& i);
43 long eval_integer(iter_t const& i);
44
evaluate(parse_tree_match_t hit)45 long evaluate(parse_tree_match_t hit)
46 {
47 return eval_expression(hit.trees.begin());
48 }
49
eval_expression(iter_t const & i)50 long eval_expression(iter_t const& i)
51 {
52 cout << "In eval_expression. i->value = " <<
53 string(i->value.begin(), i->value.end()) <<
54 " i->children.size() = " << i->children.size() << endl;
55
56 cout << "ID: " << i->value.id().to_long() << endl;
57
58 if (i->value.id() == integer.id())
59 {
60 BOOST_ASSERT(i->children.size() == 0);
61 return strtol(i->value.begin(), 0, 10);
62 }
63 else if (i->value.id() == factor.id())
64 {
65 // factor can only be unary minus
66 BOOST_ASSERT(*i->value.begin() == '-');
67 return - eval_expression(i->children.begin());
68 }
69 else if (i->value.id() == term.id())
70 {
71 if (*i->value.begin() == '*')
72 {
73 BOOST_ASSERT(i->children.size() == 2);
74 return eval_expression(i->children.begin()) *
75 eval_expression(i->children.begin()+1);
76 }
77 else if (*i->value.begin() == '/')
78 {
79 BOOST_ASSERT(i->children.size() == 2);
80 return eval_expression(i->children.begin()) /
81 eval_expression(i->children.begin()+1);
82 }
83 else
84 BOOST_ASSERT(0);
85 }
86 else if (i->value.id() == expression.id())
87 {
88 if (*i->value.begin() == '+')
89 {
90 BOOST_ASSERT(i->children.size() == 2);
91 return eval_expression(i->children.begin()) +
92 eval_expression(i->children.begin()+1);
93 }
94 else if (*i->value.begin() == '-')
95 {
96 BOOST_ASSERT(i->children.size() == 2);
97 return eval_expression(i->children.begin()) -
98 eval_expression(i->children.begin()+1);
99 }
100 else
101 BOOST_ASSERT(0);
102 }
103 else
104 BOOST_ASSERT(0); // error
105
106 return 0;
107 }
108
109 ////////////////////////////////////////////////////////////////////////////
110 int
main()111 main()
112 {
113 BOOST_SPIRIT_DEBUG_RULE(integer);
114 BOOST_SPIRIT_DEBUG_RULE(factor);
115 BOOST_SPIRIT_DEBUG_RULE(term);
116 BOOST_SPIRIT_DEBUG_RULE(expression);
117 // Start grammar definition
118 integer = leaf_node_d[ lexeme_d[ (!ch_p('-') >> +digit_p) ] ];
119 factor = integer
120 | inner_node_d[ch_p('(') >> expression >> ch_p(')')]
121 | (root_node_d[ch_p('-')] >> factor);
122 term = factor >>
123 *( (root_node_d[ch_p('*')] >> factor)
124 | (root_node_d[ch_p('/')] >> factor)
125 );
126 expression = term >>
127 *( (root_node_d[ch_p('+')] >> term)
128 | (root_node_d[ch_p('-')] >> term)
129 );
130 // End grammar definition
131
132
133 cout << "/////////////////////////////////////////////////////////\n\n";
134 cout << "\t\tThe simplest working calculator...\n\n";
135 cout << "/////////////////////////////////////////////////////////\n\n";
136 cout << "Type an expression...or [q or Q] to quit\n\n";
137
138 string str;
139 while (getline(cin, str))
140 {
141 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
142 break;
143
144 const char* str_begin = str.c_str();
145 const char* str_end = str.c_str();
146 while (*str_end)
147 ++str_end;
148
149 scanner_t scan(str_begin, str_end);
150
151 parse_tree_match_t hit = expression.parse(scan);
152
153
154 if (hit && str_begin == str_end)
155 {
156 #if defined(BOOST_SPIRIT_DUMP_PARSETREE_AS_XML)
157 // dump parse tree as XML
158 std::map<rule_id, std::string> rule_names;
159 rule_names[&integer] = "integer";
160 rule_names[&factor] = "factor";
161 rule_names[&term] = "term";
162 rule_names[&expression] = "expression";
163 tree_to_xml(cout, hit.trees, str.c_str(), rule_names);
164 #endif
165
166 // print the result
167 cout << "parsing succeeded\n";
168 cout << "result = " << evaluate(hit) << "\n\n";
169 }
170 else
171 {
172 cout << "parsing failed\n";
173 }
174 }
175
176 cout << "Bye... :-) \n\n";
177 return 0;
178 }
179
180
181