]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2001-2011 Hartmut Kaiser | |
3 | Copyright (c) 2001-2011 Joel de Guzman | |
4 | ||
5 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
6 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
7 | =============================================================================*/ | |
8 | /////////////////////////////////////////////////////////////////////////////// | |
9 | // | |
10 | // Plain calculator example demonstrating the grammar. The parser is a | |
11 | // syntax checker only and does not do any semantic evaluation. | |
12 | // | |
13 | // [ JDG May 10, 2002 ] spirit1 | |
14 | // [ JDG March 4, 2007 ] spirit2 | |
15 | // [ HK November 30, 2010 ] spirit2/utree | |
16 | // | |
17 | /////////////////////////////////////////////////////////////////////////////// | |
18 | ||
19 | // #define BOOST_SPIRIT_DEBUG | |
20 | ||
7c673cae FG |
21 | #include <boost/spirit/include/support_utree.hpp> |
22 | #include <boost/spirit/include/qi.hpp> | |
1e59de90 TL |
23 | #include <boost/phoenix/operator.hpp> |
24 | #include <boost/phoenix/function.hpp> | |
7c673cae FG |
25 | |
26 | #include <iostream> | |
27 | #include <string> | |
28 | ||
29 | namespace client | |
30 | { | |
31 | namespace qi = boost::spirit::qi; | |
32 | namespace ascii = boost::spirit::ascii; | |
33 | namespace spirit = boost::spirit; | |
34 | ||
35 | struct expr | |
36 | { | |
37 | template <typename T1, typename T2 = void> | |
38 | struct result { typedef void type; }; | |
39 | ||
40 | expr(char op) : op(op) {} | |
41 | ||
42 | void operator()(spirit::utree& expr, spirit::utree const& rhs) const | |
43 | { | |
44 | spirit::utree lhs; | |
45 | lhs.swap(expr); | |
46 | expr.push_back(spirit::utf8_symbol_range_type(&op, &op+1)); | |
47 | expr.push_back(lhs); | |
48 | expr.push_back(rhs); | |
49 | } | |
50 | ||
51 | char const op; | |
52 | }; | |
53 | boost::phoenix::function<expr> const plus = expr('+'); | |
54 | boost::phoenix::function<expr> const minus = expr('-'); | |
55 | boost::phoenix::function<expr> const times = expr('*'); | |
56 | boost::phoenix::function<expr> const divide = expr('/'); | |
57 | ||
58 | struct negate_expr | |
59 | { | |
60 | template <typename T1, typename T2 = void> | |
61 | struct result { typedef void type; }; | |
62 | ||
63 | void operator()(spirit::utree& expr, spirit::utree const& rhs) const | |
64 | { | |
65 | char const op = '-'; | |
66 | expr.clear(); | |
67 | expr.push_back(spirit::utf8_symbol_range_type(&op, &op+1)); | |
68 | expr.push_back(rhs); | |
69 | } | |
70 | }; | |
71 | boost::phoenix::function<negate_expr> neg; | |
72 | ||
73 | /////////////////////////////////////////////////////////////////////////////// | |
74 | // Our calculator grammar | |
75 | /////////////////////////////////////////////////////////////////////////////// | |
76 | template <typename Iterator> | |
77 | struct calculator : qi::grammar<Iterator, ascii::space_type, spirit::utree()> | |
78 | { | |
79 | calculator() : calculator::base_type(expression) | |
80 | { | |
81 | using qi::uint_; | |
82 | using qi::_val; | |
83 | using qi::_1; | |
84 | ||
85 | expression = | |
86 | term [_val = _1] | |
87 | >> *( ('+' >> term [plus(_val, _1)]) | |
88 | | ('-' >> term [minus(_val, _1)]) | |
89 | ) | |
90 | ; | |
91 | ||
92 | term = | |
93 | factor [_val = _1] | |
94 | >> *( ('*' >> factor [times(_val, _1)]) | |
95 | | ('/' >> factor [divide(_val, _1)]) | |
96 | ) | |
97 | ; | |
98 | ||
99 | factor = | |
100 | uint_ [_val = _1] | |
101 | | '(' >> expression [_val = _1] >> ')' | |
102 | | ('-' >> factor [neg(_val, _1)]) | |
103 | | ('+' >> factor [_val = _1]) | |
104 | ; | |
105 | ||
106 | BOOST_SPIRIT_DEBUG_NODE(expression); | |
107 | BOOST_SPIRIT_DEBUG_NODE(term); | |
108 | BOOST_SPIRIT_DEBUG_NODE(factor); | |
109 | } | |
110 | ||
111 | qi::rule<Iterator, ascii::space_type, spirit::utree()> expression, term, factor; | |
112 | }; | |
113 | } | |
114 | ||
115 | /////////////////////////////////////////////////////////////////////////////// | |
116 | // Main program | |
117 | /////////////////////////////////////////////////////////////////////////////// | |
118 | int main() | |
119 | { | |
120 | std::cout << "/////////////////////////////////////////////////////////\n\n"; | |
121 | std::cout << "Expression parser...\n\n"; | |
122 | std::cout << "/////////////////////////////////////////////////////////\n\n"; | |
123 | std::cout << "Type an expression...or [q or Q] to quit\n\n"; | |
124 | ||
125 | using boost::spirit::ascii::space; | |
126 | using boost::spirit::utree; | |
127 | typedef std::string::const_iterator iterator_type; | |
128 | typedef client::calculator<iterator_type> calculator; | |
129 | ||
130 | calculator calc; // Our grammar | |
131 | ||
132 | std::string str; | |
133 | while (std::getline(std::cin, str)) | |
134 | { | |
135 | if (str.empty() || str[0] == 'q' || str[0] == 'Q') | |
136 | break; | |
137 | ||
138 | std::string::const_iterator iter = str.begin(); | |
139 | std::string::const_iterator end = str.end(); | |
140 | utree ut; | |
141 | bool r = phrase_parse(iter, end, calc, space, ut); | |
142 | ||
143 | if (r && iter == end) | |
144 | { | |
145 | std::cout << "-------------------------\n"; | |
146 | std::cout << "Parsing succeeded: " << ut << "\n"; | |
147 | std::cout << "-------------------------\n"; | |
148 | } | |
149 | else | |
150 | { | |
151 | std::string rest(iter, end); | |
152 | std::cout << "-------------------------\n"; | |
153 | std::cout << "Parsing failed\n"; | |
154 | std::cout << "stopped at: \": " << rest << "\"\n"; | |
155 | std::cout << "-------------------------\n"; | |
156 | } | |
157 | } | |
158 | ||
159 | std::cout << "Bye... :-) \n\n"; | |
160 | return 0; | |
161 | } | |
162 | ||
163 |