1 /*=============================================================================
2 Copyright (c) 2001-2003 Hartmut Kaiser
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 // This sample shows, how to use Phoenix for implementing a
13 // simple (RPN style) calculator [ demonstrating phoenix ]
14 //
15 // [ HKaiser 2001 ]
16 // [ JDG 6/29/2002 ]
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19 #include <boost/spirit/include/classic_core.hpp>
20 #include <boost/spirit/include/classic_attribute.hpp>
21 #include <boost/spirit/include/phoenix1_functions.hpp>
22 #include <iostream>
23 #include <string>
24
25 ///////////////////////////////////////////////////////////////////////////////
26 using namespace std;
27 using namespace BOOST_SPIRIT_CLASSIC_NS;
28 using namespace phoenix;
29
30 ///////////////////////////////////////////////////////////////////////////////
31 //
32 // Our RPN calculator grammar using phoenix to do the semantics
33 // The class 'RPNCalculator' implements a polish reverse notation
34 // calculator which is equivalent to the following YACC description.
35 //
36 // exp:
37 // NUM { $$ = $1; }
38 // | exp exp '+' { $$ = $1 + $2; }
39 // | exp exp '-' { $$ = $1 - $2; }
40 // | exp exp '*' { $$ = $1 * $2; }
41 // | exp exp '/' { $$ = $1 / $2; }
42 // | exp exp '^' { $$ = pow ($1, $2); } /* Exponentiation */
43 // | exp 'n' { $$ = -$1; } /* Unary minus */
44 // ;
45 //
46 // The different notation results from the requirement of LL parsers not to
47 // allow left recursion in their grammar (would lead to endless recursion).
48 // Therefore the left recursion in the YACC script before is transformated
49 // into iteration. To some, this is less intuitive, but once you get used
50 // to it, it's very easy to follow.
51 //
52 // Note: The top rule propagates the expression result (value) upwards
53 // to the calculator grammar self.val closure member which is
54 // then visible outside the grammar (i.e. since self.val is the
55 // member1 of the closure, it becomes the attribute passed by
56 // the calculator to an attached semantic action. See the
57 // driver code that uses the calculator below).
58 //
59 ///////////////////////////////////////////////////////////////////////////////
60 struct pow_
61 {
62 template <typename X, typename Y>
63 struct result { typedef X type; };
64
65 template <typename X, typename Y>
operator ()pow_66 X operator()(X x, Y y) const
67 {
68 using namespace std;
69 return pow(x, y);
70 }
71 };
72
73 // Notice how power(x, y) is lazily implemented using Phoenix function.
74 function<pow_> power;
75
76 struct calc_closure : BOOST_SPIRIT_CLASSIC_NS::closure<calc_closure, double, double>
77 {
78 member1 x;
79 member2 y;
80 };
81
82 struct calculator : public grammar<calculator, calc_closure::context_t>
83 {
84 template <typename ScannerT>
85 struct definition {
86
definitioncalculator::definition87 definition(calculator const& self)
88 {
89 top = expr [self.x = arg1];
90 expr =
91 real_p [expr.x = arg1]
92 >> *(
93 expr [expr.y = arg1]
94 >> (
95 ch_p('+') [expr.x += expr.y]
96 | ch_p('-') [expr.x -= expr.y]
97 | ch_p('*') [expr.x *= expr.y]
98 | ch_p('/') [expr.x /= expr.y]
99 | ch_p('^') [expr.x = power(expr.x, expr.y)]
100 )
101 | ch_p('n') [expr.x = -expr.x]
102 )
103 ;
104 }
105
106 typedef rule<ScannerT, calc_closure::context_t> rule_t;
107 rule_t expr;
108 rule<ScannerT> top;
109
110 rule<ScannerT> const&
startcalculator::definition111 start() const { return top; }
112 };
113 };
114
115 ///////////////////////////////////////////////////////////////////////////////
116 //
117 // Main program
118 //
119 ///////////////////////////////////////////////////////////////////////////////
120 int
main()121 main()
122 {
123 cout << "/////////////////////////////////////////////////////////\n\n";
124 cout << "\t\tExpression parser using Phoenix...\n\n";
125 cout << "/////////////////////////////////////////////////////////\n\n";
126 cout << "Type an expression...or [q or Q] to quit\n\n";
127
128 calculator calc; // Our parser
129
130 string str;
131 while (getline(cin, str))
132 {
133 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
134 break;
135
136 double n = 0;
137 parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p);
138
139 // calc[var(n) = arg1] invokes the calculator and extracts
140 // the result of the computation. See calculator grammar
141 // note above.
142
143 if (info.full)
144 {
145 cout << "-------------------------\n";
146 cout << "Parsing succeeded\n";
147 cout << "result = " << n << endl;
148 cout << "-------------------------\n";
149 }
150 else
151 {
152 cout << "-------------------------\n";
153 cout << "Parsing failed\n";
154 cout << "stopped at: \": " << info.stop << "\"\n";
155 cout << "-------------------------\n";
156 }
157 }
158
159 cout << "Bye... :-) \n\n";
160 return 0;
161 }
162
163
164