1 /*=============================================================================
2 Copyright (c) 2001-2003 Dan Nuffer
3 Copyright (c) 2001-2003 Joel de Guzman
4 http://spirit.sourceforge.net/
5
6 Use, modification and distribution is subject to the Boost Software
7 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10 ///////////////////////////////////////////////////////////////////////////////
11 //
12 // Full calculator example with variables
13 // [ JDG 9/18/2002 ]
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 #include <boost/spirit/include/classic_core.hpp>
17 #include <boost/spirit/include/classic_symbols.hpp>
18 #include <iostream>
19 #include <stack>
20 #include <functional>
21 #include <string>
22
23 using namespace std;
24 using namespace BOOST_SPIRIT_CLASSIC_NS;
25
26 ///////////////////////////////////////////////////////////////////////////////
27 //
28 // Semantic actions
29 //
30 ///////////////////////////////////////////////////////////////////////////////
31 struct push_num
32 {
push_numpush_num33 push_num(stack<double>& eval_)
34 : eval(eval_) {}
35
operator ()push_num36 void operator()(double n) const
37 {
38 eval.push(n);
39 cout << "push\t" << n << endl;
40 }
41
42 stack<double>& eval;
43 };
44
45 template <typename op>
46 struct do_op
47 {
do_opdo_op48 do_op(op const& the_op, stack<double>& eval_)
49 : m_op(the_op), eval(eval_) {}
50
operator ()do_op51 void operator()(char const*, char const*) const
52 {
53 double rhs = eval.top();
54 eval.pop();
55 double lhs = eval.top();
56 eval.pop();
57
58 cout << "popped " << lhs << " and " << rhs << " from the stack. ";
59 cout << "pushing " << m_op(lhs, rhs) << " onto the stack.\n";
60 eval.push(m_op(lhs, rhs));
61 }
62
63 op m_op;
64 stack<double>& eval;
65 };
66
67 template <class op>
68 do_op<op>
make_op(op const & the_op,stack<double> & eval)69 make_op(op const& the_op, stack<double>& eval)
70 {
71 return do_op<op>(the_op, eval);
72 }
73
74 struct do_negate
75 {
do_negatedo_negate76 do_negate(stack<double>& eval_)
77 : eval(eval_) {}
78
operator ()do_negate79 void operator()(char const*, char const*) const
80 {
81 double lhs = eval.top();
82 eval.pop();
83
84 cout << "popped " << lhs << " from the stack. ";
85 cout << "pushing " << -lhs << " onto the stack.\n";
86 eval.push(-lhs);
87 }
88
89 stack<double>& eval;
90 };
91
92 struct get_var
93 {
get_varget_var94 get_var(stack<double>& eval_)
95 : eval(eval_) {}
96
operator ()get_var97 void operator()(double n) const
98 {
99 eval.push(n);
100 cout << "push\t" << n << endl;
101 }
102
103 stack<double>& eval;
104 };
105
106 struct set_var
107 {
set_varset_var108 set_var(double*& var_)
109 : var(var_) {}
110
operator ()set_var111 void operator()(double& n) const
112 {
113 var = &n;
114 }
115
116 double*& var;
117 };
118
119 struct redecl_var
120 {
operator ()redecl_var121 void operator()(double& /*n*/) const
122 {
123 cout << "Warning. You are attempting to re-declare a var.\n";
124 }
125 };
126
127 struct do_assign
128 {
do_assigndo_assign129 do_assign(double*& var_, stack<double>& eval_)
130 : var(var_), eval(eval_) {}
131
operator ()do_assign132 void operator()(char const*, char const*) const
133 {
134 if (var != 0)
135 {
136 *var = eval.top();
137 cout << "assigning\n";
138 }
139 }
140
141 double*& var;
142 stack<double>& eval;
143 };
144
145 ///////////////////////////////////////////////////////////////////////////////
146 //
147 // Our calculator grammar
148 //
149 ///////////////////////////////////////////////////////////////////////////////
150 struct calculator : public grammar<calculator>
151 {
calculatorcalculator152 calculator(stack<double>& eval_)
153 : eval(eval_) {}
154
155 template <typename ScannerT>
156 struct definition
157 {
definitioncalculator::definition158 definition(calculator const& self)
159 {
160 factor =
161 real_p[push_num(self.eval)]
162 | vars[get_var(self.eval)]
163 | '(' >> expression >> ')'
164 | ('-' >> factor)[do_negate(self.eval)]
165 ;
166
167 term =
168 factor
169 >> *( ('*' >> factor)[make_op(multiplies<double>(), self.eval)]
170 | ('/' >> factor)[make_op(divides<double>(), self.eval)]
171 )
172 ;
173
174 expression =
175 term
176 >> *( ('+' >> term)[make_op(plus<double>(), self.eval)]
177 | ('-' >> term)[make_op(minus<double>(), self.eval)]
178 )
179 ;
180
181 assignment =
182 vars[set_var(self.var)]
183 >> '=' >> expression[do_assign(self.var, self.eval)]
184 ;
185
186 var_decl =
187 lexeme_d
188 [
189 ((alpha_p >> *(alnum_p | '_'))
190 - vars[redecl_var()])[vars.add]
191 ]
192 ;
193
194 declaration =
195 lexeme_d["var" >> space_p] >> var_decl >> *(',' >> var_decl)
196 ;
197
198 statement =
199 declaration | assignment | '?' >> expression
200 ;
201 }
202
203 symbols<double> vars;
204 rule<ScannerT> statement, declaration, var_decl,
205 assignment, expression, term, factor;
206
207 rule<ScannerT> const&
startcalculator::definition208 start() const { return statement; }
209 };
210
211 mutable double* var;
212 stack<double>& eval;
213 };
214
215 ///////////////////////////////////////////////////////////////////////////////
216 //
217 // Main program
218 //
219 ///////////////////////////////////////////////////////////////////////////////
220 int
main()221 main()
222 {
223 cout << "/////////////////////////////////////////////////////////\n\n";
224 cout << "\t\tThe calculator with variables...\n\n";
225 cout << "/////////////////////////////////////////////////////////\n\n";
226 cout << "Type a statement...or [q or Q] to quit\n\n";
227 cout << "Variables may be declared:\t\tExample: var i, j, k\n";
228 cout << "Assigning to a variable:\t\tExample: i = 10 * j\n";
229 cout << "To evaluate an expression:\t\tExample: ? i * 3.33E-3\n\n";
230
231 stack<double> eval;
232 calculator calc(eval); // Our parser
233
234 string str;
235 while (getline(cin, str))
236 {
237 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
238 break;
239
240 parse_info<> info = parse(str.c_str(), calc, space_p);
241
242 if (info.full)
243 {
244 cout << "-------------------------\n";
245 cout << "Parsing succeeded\n";
246 cout << "-------------------------\n";
247 }
248 else
249 {
250 cout << "-------------------------\n";
251 cout << "Parsing failed\n";
252 cout << "stopped at: \": " << info.stop << "\"\n";
253 cout << "-------------------------\n";
254 }
255 }
256
257 cout << "Bye... :-) \n\n";
258 return 0;
259 }
260
261
262