趣味编程:用Boost.Spirit 2.x 编写四则运算器

来源:互联网 发布:淘宝好吃的零食排行榜 编辑:程序博客网 时间:2024/05/22 15:01
#include <iostream>#include <stack>#include <boost/lexical_cast.hpp>#include <boost/config/warning_disable.hpp>//#define BOOST_SPIRIT_DEBUG#include <boost/spirit/include/qi.hpp>#include <boost/spirit/include/phoenix.hpp>using namespace std;namespace phx = boost::phoenix;namespace qi = boost::spirit::qi;namespace ascii = boost::spirit::ascii;struct calculator{bool interpret(const string& s);void do_neg();void do_add();void do_sub();void do_mul();void do_div();void do_number(const char* first, const char* last);int val() const;private:stack<int> values_;int *pn1_, n2_;void pop_1();void pop_2();};template <typename Iterator>struct calc_grammar : qi::grammar<Iterator, ascii::space_type>{calc_grammar(calculator& calc): calc_grammar::base_type(add_sub_expr){using namespace qi;using boost::iterator_range;#define ARG1phx::bind(&iterator_range<Iterator>::begin, qi::_1)#define ARG2phx::bind(&iterator_range<Iterator>::end, qi::_1)#define LAZY_FUN0(f)phx::bind(&calculator::f, calc)#define LAZY_FUN2(f)phx::bind(&calculator::f, calc, ARG1, ARG2)add_sub_expr =(-lit('+') >> mul_div_expr |(lit('-') >> mul_div_expr)[LAZY_FUN0(do_neg)]) >>*(lit('+') >> mul_div_expr[LAZY_FUN0(do_add)] |lit('-') >> mul_div_expr[LAZY_FUN0(do_sub)]);mul_div_expr =basic_expr >>*( lit('*') >> basic_expr[LAZY_FUN0(do_mul)] |lit('/') >> basic_expr[LAZY_FUN0(do_div)]);basic_expr =raw[number][LAZY_FUN2(do_number)] |lit('(') >> add_sub_expr >> lit(')');number = lexeme[+digit];BOOST_SPIRIT_DEBUG_NODE(add_sub_expr);BOOST_SPIRIT_DEBUG_NODE(mul_div_expr);BOOST_SPIRIT_DEBUG_NODE(basic_expr);BOOST_SPIRIT_DEBUG_NODE(number);}qi::rule<Iterator, ascii::space_type> add_sub_expr, mul_div_expr, basic_expr, number;};bool calculator::interpret(const string& s){calc_grammar<char*> g(*this);char* first = const_cast<char*>(s.c_str());char* last = first + s.length();return qi::phrase_parse(first, last, g, ascii::space) && first == last;}void calculator::pop_1(){pn1_ = &values_.top();}void calculator::pop_2(){n2_ = values_.top();values_.pop();pop_1();}void calculator::do_number(const char* first, const char* last){string str(first, last);int n = boost::lexical_cast<int>(str);values_.push(n);}void calculator::do_neg(){pop_1();*pn1_ = -*pn1_;}void calculator::do_add(){pop_2();*pn1_ += n2_;}void calculator::do_sub(){pop_2();*pn1_ -= n2_;}void calculator::do_mul(){pop_2();*pn1_ *= n2_;}void calculator::do_div(){pop_2();*pn1_ /= n2_;}int calculator::val() const{assert(values_.size() == 1);return values_.top();}int main(){for(;;){cout << ">>> ";string s;getline(cin, s);if(s.empty()) break;calculator calc;if(calc.interpret(s))cout << calc.val() << endl;elsecout << "syntax error" << endl;}}