• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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