1 /*=============================================================================
2 Copyright (c) 2001-2003 Dan Nuffer
3 Copyright (c) 2002-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 using STL functors with debugging enabled.
13 // This is discussed in the "Functional" chapter in the Spirit User's Guide
14 // and the Debugging chapter.
15 //
16 // Ported to Spirit v1.5 from v1.2/1.3 example by Dan Nuffer
17 // [ JDG 9/18/2002 ]
18 // [ JDG 7/29/2004 ]
19 //
20 ////////////////////////////////////////////////////////////////////////////
21
22 #define BOOST_SPIRIT_DEBUG
23 #include <boost/spirit/include/classic_core.hpp>
24 #include <iostream>
25 #include <stack>
26 #include <functional>
27 #include <string>
28
29 ////////////////////////////////////////////////////////////////////////////
30 using namespace std;
31 using namespace BOOST_SPIRIT_CLASSIC_NS;
32
33 ////////////////////////////////////////////////////////////////////////////
34 //
35 // Semantic actions
36 //
37 ////////////////////////////////////////////////////////////////////////////
38 struct push_int
39 {
push_intpush_int40 push_int(stack<long>& eval_)
41 : eval(eval_) {}
42
operator ()push_int43 void operator()(char const* str, char const* /*end*/) const
44 {
45 long n = strtol(str, 0, 10);
46 eval.push(n);
47 cout << "push\t" << long(n) << endl;
48 }
49
50 stack<long>& eval;
51 };
52
53 template <typename op>
54 struct do_op
55 {
do_opdo_op56 do_op(op const& the_op, stack<long>& eval_)
57 : m_op(the_op), eval(eval_) {}
58
operator ()do_op59 void operator()(char const*, char const*) const
60 {
61 long rhs = eval.top();
62 eval.pop();
63 long lhs = eval.top();
64 eval.pop();
65
66 cout << "popped " << lhs << " and " << rhs << " from the stack. ";
67 cout << "pushing " << m_op(lhs, rhs) << " onto the stack.\n";
68 eval.push(m_op(lhs, rhs));
69 }
70
71 op m_op;
72 stack<long>& eval;
73 };
74
75 template <class op>
76 do_op<op>
make_op(op const & the_op,stack<long> & eval)77 make_op(op const& the_op, stack<long>& eval)
78 {
79 return do_op<op>(the_op, eval);
80 }
81
82 struct do_negate
83 {
do_negatedo_negate84 do_negate(stack<long>& eval_)
85 : eval(eval_) {}
86
operator ()do_negate87 void operator()(char const*, char const*) const
88 {
89 long lhs = eval.top();
90 eval.pop();
91
92 cout << "popped " << lhs << " from the stack. ";
93 cout << "pushing " << -lhs << " onto the stack.\n";
94 eval.push(-lhs);
95 }
96
97 stack<long>& eval;
98 };
99
100 ////////////////////////////////////////////////////////////////////////////
101 //
102 // Our calculator grammar
103 //
104 ////////////////////////////////////////////////////////////////////////////
105 struct calculator : public grammar<calculator>
106 {
calculatorcalculator107 calculator(stack<long>& eval_)
108 : eval(eval_) {}
109
110 template <typename ScannerT>
111 struct definition
112 {
definitioncalculator::definition113 definition(calculator const& self)
114 {
115 integer =
116 lexeme_d[ (+digit_p)[push_int(self.eval)] ]
117 ;
118
119 factor =
120 integer
121 | '(' >> expression >> ')'
122 | ('-' >> factor)[do_negate(self.eval)]
123 | ('+' >> factor)
124 ;
125
126 term =
127 factor
128 >> *( ('*' >> factor)[make_op(multiplies<long>(), self.eval)]
129 | ('/' >> factor)[make_op(divides<long>(), self.eval)]
130 )
131 ;
132
133 expression =
134 term
135 >> *( ('+' >> term)[make_op(plus<long>(), self.eval)]
136 | ('-' >> term)[make_op(minus<long>(), self.eval)]
137 )
138 ;
139
140 BOOST_SPIRIT_DEBUG_NODE(integer);
141 BOOST_SPIRIT_DEBUG_NODE(factor);
142 BOOST_SPIRIT_DEBUG_NODE(term);
143 BOOST_SPIRIT_DEBUG_NODE(expression);
144 }
145
146 rule<ScannerT> expression, term, factor, integer;
147 rule<ScannerT> const&
startcalculator::definition148 start() const { return expression; }
149 };
150
151 stack<long>& eval;
152 };
153
154 ////////////////////////////////////////////////////////////////////////////
155 //
156 // Main program
157 //
158 ////////////////////////////////////////////////////////////////////////////
159 int
main()160 main()
161 {
162 cout << "/////////////////////////////////////////////////////////\n\n";
163 cout << "\t\tThe simplest working calculator...\n\n";
164 cout << "/////////////////////////////////////////////////////////\n\n";
165 cout << "Type an expression...or [q or Q] to quit\n\n";
166
167 stack<long> eval;
168 calculator calc(eval); // Our parser
169 BOOST_SPIRIT_DEBUG_NODE(calc);
170
171 string str;
172 while (getline(cin, str))
173 {
174 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
175 break;
176
177 parse_info<> info = parse(str.c_str(), calc, space_p);
178
179 if (info.full)
180 {
181 cout << "-------------------------\n";
182 cout << "Parsing succeeded\n";
183 cout << "result = " << calc.eval.top() << endl;
184 cout << "-------------------------\n";
185 }
186 else
187 {
188 cout << "-------------------------\n";
189 cout << "Parsing failed\n";
190 cout << "stopped at: \": " << info.stop << "\"\n";
191 cout << "-------------------------\n";
192 }
193 }
194
195 cout << "Bye... :-) \n\n";
196 return 0;
197 }
198
199
200