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