原始碼如下,想基于boost::spirit的庫寫一個邏輯運算式的計算。下列的spirit代碼是從網上找到的一個數學運算式計算的原始碼改的。
原數學運算式的結構體operation中operator_變數是一個char,對應數學運算式中的 + - * /。現在我需要這個operator_支持 ==, >=, <=, >, <, &&,和||,所以char不滿足我的訴求,將operator_的型別改為std::string后,編譯可以通過 ( g++ -std==c++11 -g main.cc -o main.o) 但執行時會拋出例外,
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::spirit::qi::expectation_failure<__gnu_cxx::__normal_iterator<char const*, std::string> > > >'
what(): boost::spirit::qi::expectation_failure
Aborted
求大神幫忙看看這個型別需要怎么變化一下?
-------------------------------------------------------------
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <string>
#include <set>
namespace client {
namespace ast
{
struct nil {};
struct signed_;
struct program;
typedef boost::variant<
nil
, double
, boost::recursive_wrapper<signed_>
, boost::recursive_wrapper<program>
>
operand;
struct signed_
{
char sign;
operand operand_;
};
struct operation
{
std::string operator_;
operand operand_;
};
struct program
{
operand first;
std::list<operation> rest;
};
}
}
BOOST_FUSION_ADAPT_STRUCT(
client::ast::signed_,
(char, sign)
(client::ast::operand, operand_)
)
BOOST_FUSION_ADAPT_STRUCT(
client::ast::operation,
(std::string, operator_)
(client::ast::operand, operand_)
)
BOOST_FUSION_ADAPT_STRUCT(
client::ast::program,
(client::ast::operand, first)
(std::list<client::ast::operation>, rest)
)
namespace client {
namespace ast
{
struct eval
{
typedef double result_type;
double operator()(nil) const { BOOST_ASSERT(0); return 0; }
double operator()(double n) const { return n; }
double operator()(operation const& x, double lhs) const
{
double rhs = boost::apply_visitor(*this, x.operand_);
if(x.operator_ == "==") return lhs == rhs;
if(x.operator_ == "&&") return lhs && rhs;
if(x.operator_ == "||") return lhs || rhs;
if(x.operator_ == ">") return lhs > rhs;
if(x.operator_ == "<") return lhs < rhs;
BOOST_ASSERT(0);
return 0;
}
double operator()(signed_ const& x) const
{
{
double rhs = boost::apply_visitor(*this, x.operand_);
if(x.operator_ == "==") return lhs == rhs;
if(x.operator_ == "&&") return lhs && rhs;
if(x.operator_ == "||") return lhs || rhs;
if(x.operator_ == ">") return lhs > rhs;
if(x.operator_ == "<") return lhs < rhs;
BOOST_ASSERT(0);
return 0;
}
double operator()(signed_ const& x) const
{
double rhs = boost::apply_visitor(*this, x.operand_);
if(x.sign == '-') return -rhs;
if(x.sign == '+') return +rhs;
BOOST_ASSERT(0);
return 0;
}
double operator()(program const& x) const
{
double state = boost::apply_visitor(*this, x.first);
BOOST_FOREACH(operation const& oper, x.rest)
{
state = (*this)(oper, state);
}
return state;
}
};
}
}
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
struct calculator : qi::grammar<Iterator, ast::program(), ascii::space_type>
{
calculator(std::set<std::string>& collect_references) : calculator::base_type(expression)
{
qi::char_type char_;
qi::double_type doubleParser_;
symbolTable.add("ad", 0);
symbolTable.add("unlock", 1);
symbolTable.add("lock",0);
symbolTable.add("op", 0);
symbolTable.add("ena", 1);
namespace px = boost::phoenix;
expression =
term
>> *((char_("&&") > term)
| (char_("||") > term)
)
;
term =
factor
>> *((char_("==") > factor)
| (char_(">") > factor)
| (char_("<") > factor)
)
;
variable %=
&qi::as_string[qi::raw[symbolTable]]
[ px::insert(px::ref(collect_references), qi::_1) ]
>> symbolTable
;
factor =
doubleParser_
| variable
| ('(' > expression > ')')
| (char_("-") > factor)
| (char_("+") > factor)
;
}
private:
qi::symbols<char, double> symbolTable;
qi::rule<Iterator, double()> variable; // NOTE: also made it a lexeme (no skipper)
qi::rule<Iterator, ast::program(), ascii::space_type> expression;
qi::rule<Iterator, ast::program(), ascii::space_type> term;
qi::rule<Iterator, ast::operand(), ascii::space_type> factor;
};
}
/////////////////////////////////////////////////////////////////////////////
// Main program
/////////////////////////////////////////////////////////////////////////////
int
main()
{
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "Expression parser...\n\n";
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "Type an expression...or [q or Q] to quit\n\n";
typedef std::string::const_iterator iterator_type;
typedef client::calculator<iterator_type> calculator;
typedef client::ast::program ast_program;
typedef client::ast::eval ast_eval;
std::string str = "ad == lock || (ad == unlock && op == ena)";
std::set<std::string> collected_references;
calculator calc(collected_references); // Our grammar
ast_program program; // Our program (AST)
ast_eval eval; // Evaluates the program
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
boost::spirit::ascii::space_type space;
bool r = phrase_parse(iter, end, calc, space, program);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "References: ";
std::copy(collected_references.begin(), collected_references.end(),
std::ostream_iterator<std::string>(std::cout, " "));
std::cout << "\nResult: " << eval(program) << std::endl;
std::cout << "-------------------------\n";
}
else
{
std::string rest(iter, end);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
std::cout << "Bye... :-) \n\n";
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/22481.html
標籤:C++ 語言
上一篇:發生了什么?
