[英]Boost spirit parser not compiling
我试图用boost :: spirit编写一个简单的表达式解析器。 我从计算器示例开始(请参阅: http : //www.boost.org/doc/libs/1_41_0/libs/spirit/example/qi/calc2_ast.cpp ),并尝试添加“ ref”规则来表示对一个变量。 这是我的代码:
#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/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <iostream>
#include <vector>
#include <string>
namespace client{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
///////////////////////////////////////////////////////////////////////////
// Our AST
///////////////////////////////////////////////////////////////////////////
struct binary_op;
struct unary_op;
struct ref {
std::string name;
ref(const std::string& name) : name(name){}
};
struct nil {};
struct expression_ast
{
typedef
boost::variant<
nil // can't happen!
, unsigned int
, ref
, boost::recursive_wrapper<expression_ast>
, boost::recursive_wrapper<binary_op>
, boost::recursive_wrapper<unary_op>
>
type;
expression_ast()
: expr(nil()) {}
template <typename Expr>
expression_ast(Expr const& expr)
: expr(expr) {}
expression_ast& operator+=(expression_ast const& rhs);
expression_ast& operator-=(expression_ast const& rhs);
expression_ast& operator*=(expression_ast const& rhs);
expression_ast& operator/=(expression_ast const& rhs);
type expr;
};
struct binary_op
{
binary_op(
char op
, expression_ast const& left
, expression_ast const& right)
: op(op), left(left), right(right) {}
char op;
expression_ast left;
expression_ast right;
};
struct unary_op
{
unary_op(
char op
, expression_ast const& subject)
: op(op), subject(subject) {}
char op;
expression_ast subject;
};
expression_ast& expression_ast::operator+=(expression_ast const& rhs)
{
expr = binary_op('+', expr, rhs);
return *this;
}
expression_ast& expression_ast::operator-=(expression_ast const& rhs)
{
expr = binary_op('-', expr, rhs);
return *this;
}
expression_ast& expression_ast::operator*=(expression_ast const& rhs)
{
expr = binary_op('*', expr, rhs);
return *this;
}
expression_ast& expression_ast::operator/=(expression_ast const& rhs)
{
expr = binary_op('/', expr, rhs);
return *this;
}
// We should be using expression_ast::operator-. There's a bug
// in phoenix type deduction mechanism that prevents us from
// doing so. Phoenix will be switching to BOOST_TYPEOF. In the
// meantime, we will use a phoenix::function below:
struct negate_expr
{
template <typename T>
struct result { typedef T type; };
expression_ast operator()(expression_ast const& expr) const
{
return expression_ast(unary_op('-', expr));
}
};
struct ref_maker
{
template <typename T>
struct result { typedef T type; };
ref operator()(std::string const& expr) const
{
return expr;
}
};
boost::phoenix::function<negate_expr> neg;
boost::phoenix::function<ref_maker> make_ref;
///////////////////////////////////////////////////////////////////////////
// Walk the tree
///////////////////////////////////////////////////////////////////////////
struct ast_print
{
typedef void result_type;
void operator()(qi::info::nil) const {
}
void operator()(int n) const {
std::cout << n;
}
void operator()(expression_ast const& ast) const {
boost::apply_visitor(*this, ast.expr);
}
void operator()(binary_op const& expr) const {
std::cout << "op:" << expr.op << "(";
boost::apply_visitor(*this, expr.left.expr);
std::cout << ", ";
boost::apply_visitor(*this, expr.right.expr);
std::cout << ')';
}
void operator()(unary_op const& expr) const {
std::cout << "op:" << expr.op << "(";
boost::apply_visitor(*this, expr.subject.expr);
std::cout << ')';
}
void operator()(ref const& expr) const {
std::cout << "ref:" << expr.name ;
}
};
///////////////////////////////////////////////////////////////////////////
// Our calculator grammar
///////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct calculator : qi::grammar<Iterator, expression_ast(), ascii::space_type>
{
calculator() : calculator::base_type(expression)
{
using qi::_val;
using qi::_1;
using qi::uint_;
using qi::lit;
using ascii::alnum;
identifier = (alnum [_val += _1]);
expression =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1])
)
;
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1])
)
;
factor =
uint_ [_val = _1]
| identifier [_val = make_ref(_1)]
| '(' >> expression [_val = _1] >> ')'
| ('-' >> factor [_val = neg(_1)])
| ('+' >> factor [_val = _1])
;
}
qi::rule<Iterator, std::string(), ascii::space_type> identifier;
qi::rule<Iterator, expression_ast(), ascii::space_type> expression, term, 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";
using client::ascii::space;
using client::expression_ast;
using client::ast_print;
typedef std::string::const_iterator iterator_type;
typedef client::calculator<iterator_type> calculator;
calculator calc; // Our grammar
std::string str;
while (std::getline(std::cin, str))
{
if (str.empty() || str[0] == 'q' || str[0] == 'Q')
break;
std::string::const_iterator iter = str.begin();
std::string::const_iterator end = str.end();
expression_ast ast;
ast_print printer;
bool r = phrase_parse(iter, end, calc, space, ast);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
printer(ast);
std::cout << "\n-------------------------\n";
}
else
{
std::string rest(iter, end);
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "stopped at: \": " << rest << "\"\n";
std::cout << "-------------------------\n";
}
}
std::cout << "Bye... :-) \n\n";
return 0;
}
我对示例所做的唯一更改如下:
ref
结构和条目。 identifier
规则,该规则将单个变量名读取为string
make_ref
以从string
进行ref
factor
规则添加一个identifier
选项,该factor
规则调用make_ref
将identifier
string
转换为ref
。 该代码不起作用。 始终存在以下类型错误:
/usr/include/boost/spirit/home/phoenix/core/detail/function_eval.hpp:135:69: error: could not convert ‘bench::expr::ref_maker::operator()(const string&) const((*(const string*)boost::phoenix::detail::help_rvalue_deduction<std::basic_string<char> >((* &(& _0)->boost::spirit::argument<N>::eval<boost::phoenix::basic_environment<boost::fusion::vector1<std::basic_string<char>&>, boost::spirit::context<boost::fusion::cons<bench::expr::expression_ast&, boost::fusion::nil>, boost::fusion::vector0<> >, bool, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >((* & env))))))’ from ‘bench::expr::ref’ to ‘std::basic_string<char>’
凤凰似乎希望make_ref
返回一个string
而不是ref
,但这不是我想要的。 我在这里做错了什么?
ref_maker
的结果ref_maker
是ref
,与输入参数不同。 做了
struct ref_maker
{
template <typename T>
struct result { typedef ref type; }; // <-- here.
ref operator()(std::string const& expr) const
{
return expr;
}
};
另外,将main中的bench::expr::
替换为client::
,否则会出现名称空间bench::expr
不存在的错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.