1 /*=============================================================================
2 Copyright (c) 2001-2014 Joel de Guzman
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 ///////////////////////////////////////////////////////////////////////////////
9 // A Calculator example demonstrating generation of AST. The AST,
10 // once created, is traversed, 1) To print its contents and
11 // 2) To evaluate the result.
13 // [ JDG April 28, 2008 ] For BoostCon 2008
14 // [ JDG February 18, 2011 ] Pure attributes. No semantic actions.
15 // [ JDG January 9, 2013 ] Spirit X3
17 ///////////////////////////////////////////////////////////////////////////////
20 # pragma warning(disable: 4345)
23 #include <boost/config/warning_disable.hpp>
24 #include <boost/spirit/home/x3.hpp>
25 #include <boost/spirit/home/x3/support/ast/variant.hpp>
26 #include <boost/fusion/include/adapt_struct.hpp>
33 namespace x3
= boost::spirit::x3
;
35 namespace client
{ namespace ast
37 ///////////////////////////////////////////////////////////////////////////
39 ///////////////////////////////////////////////////////////////////////////
44 struct operand
: x3::variant
<
47 , x3::forward_ast
<signed_
>
48 , x3::forward_ast
<program
>
51 using base_type::base_type
;
52 using base_type::operator=;
70 std::list
<operation
> rest
;
74 BOOST_FUSION_ADAPT_STRUCT(client::ast::signed_
,
78 BOOST_FUSION_ADAPT_STRUCT(client::ast::operation
,
82 BOOST_FUSION_ADAPT_STRUCT(client::ast::program
,
86 namespace client
{ namespace ast
88 ///////////////////////////////////////////////////////////////////////////
90 ///////////////////////////////////////////////////////////////////////////
93 typedef void result_type
;
95 void operator()(nil
) const {}
96 void operator()(unsigned int n
) const { std::cout
<< n
; }
98 void operator()(operation
const& x
) const
100 boost::apply_visitor(*this, x
.operand_
);
103 case '+': std::cout
<< " add"; break;
104 case '-': std::cout
<< " subt"; break;
105 case '*': std::cout
<< " mult"; break;
106 case '/': std::cout
<< " div"; break;
110 void operator()(signed_
const& x
) const
112 boost::apply_visitor(*this, x
.operand_
);
115 case '-': std::cout
<< " neg"; break;
116 case '+': std::cout
<< " pos"; break;
120 void operator()(program
const& x
) const
122 boost::apply_visitor(*this, x
.first
);
123 for (operation
const& oper
: x
.rest
)
131 ///////////////////////////////////////////////////////////////////////////
133 ///////////////////////////////////////////////////////////////////////////
136 typedef int result_type
;
138 int operator()(nil
) const { BOOST_ASSERT(0); return 0; }
139 int operator()(unsigned int n
) const { return n
; }
141 int operator()(int lhs
, operation
const& x
) const
143 int rhs
= boost::apply_visitor(*this, x
.operand_
);
146 case '+': return lhs
+ rhs
;
147 case '-': return lhs
- rhs
;
148 case '*': return lhs
* rhs
;
149 case '/': return lhs
/ rhs
;
155 int operator()(signed_
const& x
) const
157 int rhs
= boost::apply_visitor(*this, x
.operand_
);
160 case '-': return -rhs
;
161 case '+': return +rhs
;
167 int operator()(program
const& x
) const
169 return std::accumulate(
170 x
.rest
.begin(), x
.rest
.end()
171 , boost::apply_visitor(*this, x
.first
)
179 ///////////////////////////////////////////////////////////////////////////////
180 // The calculator grammar
181 ///////////////////////////////////////////////////////////////////////////////
182 namespace calculator_grammar
187 x3::rule
<class expression
, ast::program
> const expression("expression");
188 x3::rule
<class term
, ast::program
> const term("term");
189 x3::rule
<class factor
, ast::operand
> const factor("factor");
191 auto const expression_def
=
193 >> *( (char_('+') >> term
)
194 | (char_('-') >> term
)
198 auto const term_def
=
200 >> *( (char_('*') >> factor
)
201 | (char_('/') >> factor
)
205 auto const factor_def
=
207 | '(' >> expression
>> ')'
208 | (char_('-') >> factor
)
209 | (char_('+') >> factor
)
212 BOOST_SPIRIT_DEFINE(expression
, term
, factor
);
214 auto calculator
= expression
;
217 using calculator_grammar::calculator
;
221 ///////////////////////////////////////////////////////////////////////////////
223 ///////////////////////////////////////////////////////////////////////////////
227 std::cout
<< "/////////////////////////////////////////////////////////\n\n";
228 std::cout
<< "Expression parser...\n\n";
229 std::cout
<< "/////////////////////////////////////////////////////////\n\n";
230 std::cout
<< "Type an expression...or [q or Q] to quit\n\n";
232 typedef std::string::const_iterator iterator_type
;
233 typedef client::ast::program ast_program
;
234 typedef client::ast::printer ast_print
;
235 typedef client::ast::eval ast_eval
;
238 while (std::getline(std::cin
, str
))
240 if (str
.empty() || str
[0] == 'q' || str
[0] == 'Q')
243 auto& calc
= client::calculator
; // Our grammar
244 ast_program program
; // Our program (AST)
245 ast_print print
; // Prints the program
246 ast_eval eval
; // Evaluates the program
248 iterator_type iter
= str
.begin();
249 iterator_type end
= str
.end();
250 boost::spirit::x3::ascii::space_type space
;
251 bool r
= phrase_parse(iter
, end
, calc
, space
, program
);
253 if (r
&& iter
== end
)
255 std::cout
<< "-------------------------\n";
256 std::cout
<< "Parsing succeeded\n";
258 std::cout
<< "\nResult: " << eval(program
) << std::endl
;
259 std::cout
<< "-------------------------\n";
263 std::string
rest(iter
, end
);
264 std::cout
<< "-------------------------\n";
265 std::cout
<< "Parsing failed\n";
266 std::cout
<< "stopped at: \"" << rest
<< "\"\n";
267 std::cout
<< "-------------------------\n";
271 std::cout
<< "Bye... :-) \n\n";