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

#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 ARG1				phx::bind(&iterator_range<Iterator>::begin, qi::_1)
#define ARG2				phx::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;
		else
			cout << "syntax error" << endl;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值