以下代码不会编译 BOOST_SPIRIT_DEBUG_NODE( expression ) ,其中 expression 是一个变体节点(不过,我不是 100% 某些变体节点与它有任何关系)。
如果我注释掉这一行,一切似乎都运行正常。
对编译错误进行眼球分析,我看到:
/usr/local/include/boost/spirit/home/support/attributes.hpp:1203:13: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
如果这还不足以告诉我们错误的原因,请编译下面的代码,以获得详细的编译转储。
请注意,代码与文档中的示例 95% 相同。
我只是std::string
在变体类型中添加了一个并尝试添加有用的 BOOST_SPIRIT_DEBUG_NODE() 以便我可以看到发生了什么。
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/classic_symbols.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp> // std::regex not fully implemented in stdc++ yet
#include <string>
#include <map>
#include <utility>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct binary_op;
struct unary_op;
struct nil {};
struct expression_ast
{
typedef
boost::variant<
nil // can't happen!
, double
, std::string
, boost::recursive_wrapper<expression_ast>
, boost::recursive_wrapper<binary_op>
, boost::recursive_wrapper<unary_op>
>
type;
expression_ast()
: m_expr(nil()) {}
template <typename Expr>
expression_ast(Expr const& expr)
: m_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 m_expr;
};
struct binary_op
{
binary_op(
char op
, expression_ast const& left
, expression_ast const& right)
: m_op(op), m_left(left), m_right(right) {}
char m_op;
expression_ast m_left;
expression_ast m_right;
};
struct unary_op
{
unary_op(
char op
, expression_ast const& subject)
: m_op(op), m_subject(subject) {}
char m_op;
expression_ast m_subject;
};
expression_ast& expression_ast::operator+=(expression_ast const& rhs)
{
m_expr = binary_op('+', m_expr, rhs);
return *this;
}
expression_ast& expression_ast::operator-=(expression_ast const& rhs)
{
m_expr = binary_op('-', m_expr, rhs);
return *this;
}
expression_ast& expression_ast::operator*=(expression_ast const& rhs)
{
m_expr = binary_op('*', m_expr, rhs);
return *this;
}
expression_ast& expression_ast::operator/=(expression_ast const& rhs)
{
m_expr = binary_op('/', m_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));
}
};
static boost::phoenix::function<negate_expr> neg;
struct ast_print
{
typedef std::string result_type;
std::string operator()(qi::info::nil) const
{
return "";
}
std::string operator()(std::string const& str) const
{
return str;
}
std::string operator()(double d) const
{
std::ostringstream oss;
oss << d;
return oss.str();
}
std::string operator()(expression_ast const& ast) const
{
return boost::apply_visitor(*this, ast.m_expr);
}
std::string operator()(binary_op const& expr) const
{
std::ostringstream oss;
oss << "op:" << expr.m_op << "(";
oss << boost::apply_visitor(*this, expr.m_left.m_expr);
oss << ", ";
oss << boost::apply_visitor(*this, expr.m_right.m_expr);
oss << ')';
return oss.str();
}
std::string operator()(unary_op const& expr) const
{
std::ostringstream oss;
oss << "op:" << expr.m_op << "(";
oss << boost::apply_visitor(*this, expr.m_subject.m_expr);
oss << ')';
return oss.str();
}
};
template <typename Iterator>
struct ParserGenerator : qi::grammar<Iterator, expression_ast(), ascii::space_type>
{
ParserGenerator() : ParserGenerator::base_type(expression)
{
using qi::_val;
using qi::_1;
using qi::double_;
using qi::iso8859_1::char_;
using qi::iso8859_1::space;
using qi::eol;
comment =
space >> ("//" >> *(char_ - eol) >> eol)
;
expression =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1])
)
;
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1])
)
;
factor =
symbol [_val = _1]
| double_ [_val = _1]
| '(' >> expression [_val = _1] >> ')'
| ('-' >> factor [_val = neg(_1)])
| ('+' >> factor [_val = _1])
;
symbol %= boost::spirit::lexeme[ +(qi::char_ - qi::char_("()-+*/")) ]
;
BOOST_SPIRIT_DEBUG_NODE(expression); // <--- TROUBLE COMPILING THIS LINE
BOOST_SPIRIT_DEBUG_NODE(symbol);
}
qi::rule<Iterator, expression_ast(), ascii::space_type>
expression, term, factor, comment;
qi::rule<Iterator, std::string(), ascii::space_type>
symbol;
};
}
int main(int argc, char* argv[])
{
using boost::spirit::ascii::space;
using client::expression_ast;
using client::ast_print;
typedef std::string::const_iterator iterator_type;
typedef client::ParserGenerator<iterator_type> ParserGenerator;
ParserGenerator pg; // our grammar
std::string predicate( "i_.c+x[0]" );
expression_ast ast;
ast_print printer;
iterator_type iter = predicate.begin(), end = predicate.end();
if ( phrase_parse( iter, end, pg, space, ast ))
{
std::cerr << printer( ast ) << std::endl;
}
return 0;
}