1 /*=============================================================================
2 Copyright (c) 2002-2003 Hartmut Kaiser
3 http://spirit.sourceforge.net/
4
5 Use, modification and distribution is subject to the Boost Software
6 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 ///////////////////////////////////////////////////////////////////////////////
10 //
11 // Full calculator example
12 // [ demonstrating phoenix and subrules ]
13 //
14 // [ Hartmut Kaiser 10/8/2002 ]
15 //
16 ///////////////////////////////////////////////////////////////////////////////
17
18 //#define BOOST_SPIRIT_DEBUG // define this for debug output
19
20 #include <boost/spirit/include/classic_core.hpp>
21 #include <boost/spirit/include/classic_attribute.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 calculator grammar using phoenix to do the semantics and subrule's
33 // as it's working horses
34 //
35 // Note: The top rule propagates the expression result (value) upwards
36 // to the calculator grammar self.val closure member which is
37 // then visible outside the grammar (i.e. since self.val is the
38 // member1 of the closure, it becomes the attribute passed by
39 // the calculator to an attached semantic action. See the
40 // driver code that uses the calculator below).
41 //
42 ///////////////////////////////////////////////////////////////////////////////
43 struct calc_closure : BOOST_SPIRIT_CLASSIC_NS::closure<calc_closure, double>
44 {
45 member1 val;
46 };
47
48 struct calculator : public grammar<calculator, calc_closure::context_t>
49 {
50 template <typename ScannerT>
51 struct definition
52 {
definitioncalculator::definition53 definition(calculator const& self)
54 {
55 top = (
56 expression =
57 term[self.val = arg1]
58 >> *( ('+' >> term[self.val += arg1])
59 | ('-' >> term[self.val -= arg1])
60 )
61 ,
62
63 term =
64 factor[term.val = arg1]
65 >> *( ('*' >> factor[term.val *= arg1])
66 | ('/' >> factor[term.val /= arg1])
67 )
68 ,
69
70 factor
71 = ureal_p[factor.val = arg1]
72 | '(' >> expression[factor.val = arg1] >> ')'
73 | ('-' >> factor[factor.val = -arg1])
74 | ('+' >> factor[factor.val = arg1])
75 );
76
77 BOOST_SPIRIT_DEBUG_NODE(top);
78 BOOST_SPIRIT_DEBUG_NODE(expression);
79 BOOST_SPIRIT_DEBUG_NODE(term);
80 BOOST_SPIRIT_DEBUG_NODE(factor);
81 }
82
83 subrule<0, calc_closure::context_t> expression;
84 subrule<1, calc_closure::context_t> term;
85 subrule<2, calc_closure::context_t> factor;
86
87 rule<ScannerT> top;
88
89 rule<ScannerT> const&
startcalculator::definition90 start() const { return top; }
91 };
92 };
93
94 ///////////////////////////////////////////////////////////////////////////////
95 //
96 // Main program
97 //
98 ///////////////////////////////////////////////////////////////////////////////
99 int
main()100 main()
101 {
102 cout << "/////////////////////////////////////////////////////////\n\n";
103 cout << "\t\tExpression parser using Phoenix...\n\n";
104 cout << "/////////////////////////////////////////////////////////\n\n";
105 cout << "Type an expression...or [q or Q] to quit\n\n";
106
107 calculator calc; // Our parser
108
109 string str;
110 while (getline(cin, str))
111 {
112 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
113 break;
114
115 double n = 0;
116 parse_info<> info = parse(str.c_str(), calc[var(n) = arg1], space_p);
117
118 // calc[var(n) = arg1] invokes the calculator and extracts
119 // the result of the computation. See calculator grammar
120 // note above.
121
122 if (info.full)
123 {
124 cout << "-------------------------\n";
125 cout << "Parsing succeeded\n";
126 cout << "result = " << n << endl;
127 cout << "-------------------------\n";
128 }
129 else
130 {
131 cout << "-------------------------\n";
132 cout << "Parsing failed\n";
133 cout << "stopped at: \": " << info.stop << "\"\n";
134 cout << "-------------------------\n";
135 }
136 }
137
138 cout << "Bye... :-) \n\n";
139 return 0;
140 }
141
142
143