【发布时间】:2020-02-25 03:36:56
【问题描述】:
我想用or、and 和not 运算符解析一个常见的布尔值,我想我已经使用下面的 Boost Spirit 完成了。在第 2 阶段(或者可能是解析本身的一部分),我希望将布尔值的 AST 转换为 disjunctive canonical normal form,这实质上“扁平化”了表达式并删除了所有分组运算符。
在我的一次尝试中,我创建了下面的 Boost static_visitor,命名为 Transformer。如果子节点和父节点都不是运算符,我首先尝试通过将子节点分配给它的祖父节点来消除双重非运算符。我的问题是指当前节点的父节点。似乎没有办法引用当前节点的父节点,因为一旦访问了一个节点,访问函数就会重载“变体”的内部类型,从而丢弃对象的variant 性质。任何帮助表示赞赏。
struct op_or {};
struct op_and {};
struct op_not {};
typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct uniop;
typedef boost::variant
<
var,
boost::recursive_wrapper<uniop<op_not>>,
boost::recursive_wrapper<binop<op_and>>,
boost::recursive_wrapper<binop<op_or>>
>
expr;
template <typename tag> struct uniop
{
explicit uniop(expr const& o) : exp_u(o) { }
expr exp_u;
};
template <typename tag> struct binop
{
explicit binop(expr const& l, expr const& r) : exp_l(l), exp_r(r) { }
expr exp_l, exp_r;
};
struct transformer : boost::static_visitor<void>
{
std::deque<std::reference_wrapper<expr>> stk;
transformer(expr & e)
{
stk.push_back(e);
}
void operator()(var const& v) const { }
void operator()(uniop<op_not> & u)
{
if (boost::get<uniop<op_not>>(&stk.back().get()) != nullptr)
{
stk.back() = u.exp_u;
}
else
{
stk.push_back(std::ref(u)); // <<=== Fails with "no matching function for call"
boost::apply_visitor(*this, u.exp_u);
stk.pop_back();
}
}
void operator()(binop<op_and> & b)
{
stk.push_back(std::ref(u));
boost::apply_visitor(*this, b.exp_l);
boost::apply_visitor(*this, b.exp_r);
stk.pop_back();
}
void operator()(binop<op_or> & b)
{
stk.push_back(std::ref(u));
boost::apply_visitor(*this, b.exp_l);
boost::apply_visitor(*this, b.exp_r);
stk.pop_back();
}
};
template <typename It, typename Skipper = boost::spirit::qi::space_type>
struct parser : boost::spirit::qi::grammar<It, expr(), Skipper>
{
parser() : parser::base_type(expr_)
{
using namespace boost::phoenix;
using namespace boost::spirit::qi;
using boost::spirit::qi::_1;
expr_ = or_.alias();
or_ = and_ [ _val = _1 ] >> *("or" >> and_ [ _val = construct<binop<op_or>>(_val, _1) ]);
and_ = not_ [ _val = _1 ] >> *("and" >> not_ [ _val = construct<binop<op_and>>(_val, _1) ]);
not_ = "not" > simple [ _val = construct<uniop<op_not>>(_1) ] | simple [ _val = _1 ];
simple = '(' > expr_ > ')' | var_;
var_ = lexeme[ +alpha ];
}
private:
boost::spirit::qi::rule<It, var() , Skipper> var_;
boost::spirit::qi::rule<It, expr(), Skipper> not_, and_, or_, simple, expr_;
};
【问题讨论】:
标签: c++ grammar boost-spirit