我如何更改此示例中的语法以解析"AND ( (OR (a b c)) (NOT (d)))
How do i change the grammar from this example to parse "AND ( (OR (a b c)) (NOT (d)))
c++布尔表达式(语法)解析器
我正在尝试修改上面由"sehe"提供的示例中的语法,以解析以下表达式。"AND (OR (a, b, c)) (NOT (d)) "
有三种操作符AND/OR/NOT, NOT是一元的,但是AND和OR可以作用于多个操作数。
谢谢
修改后的语法实际上要简单得多,因为它避开了操作符优先级的问题。这是语法的"lisp"方法:)
然而,既然你问了,我给你,修改后的解析器来解析你修改后的语法:
struct op_or {};
struct op_and {};
struct op_xor {};
struct op_not {};
typedef std::string var;
template <typename tag> struct combination_op;
template <typename tag> struct unop;
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<combination_op<op_and> >,
boost::recursive_wrapper<combination_op<op_xor> >,
boost::recursive_wrapper<combination_op<op_or> >
> expr;
template <typename tag> struct combination_op
{
typedef std::vector<expr> operands_t;
combination_op() = default;
combination_op(operands_t const& operands) : operands(operands) { }
operands_t operands;
};
template <typename tag> struct unop
{
unop() = default;
unop(const expr& o) : operand(o) { }
expr operand;
};
//////////////////////////////////////////////////
// Parser grammar
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, expr(), Skipper>
{
parser() : parser::base_type(expr_)
{
using namespace qi;
or_ = no_case [ "OR" ] > '(' > expr_list > ')';
xor_ = no_case [ "XOR" ] > '(' > expr_list > ')';
and_ = no_case [ "AND" ] > '(' > expr_list > ')';
not_ = no_case [ "NOT" ] > '(' > expr_ > ')';
var_ = qi::lexeme[ +alpha ];
expr_list = +expr_;
expr_ = xor_ | and_ | or_ | not_ | var_;
on_error<fail> ( expr_, std::cout
<< phx::val("Error! Expecting ") << _4 << phx::val(" here: "")
<< phx::construct<std::string>(_3, _2) << phx::val(""n"));
}
private:
template <typename Attr> using Rule = qi::rule<It, Attr(), Skipper>;
Rule<var> var_;
Rule<unop<op_not>> not_;
Rule<combination_op<op_and>> and_;
Rule<combination_op<op_xor>> xor_;
Rule<combination_op<op_or>> or_;
Rule<std::vector<expr>> expr_list;
Rule<expr> expr_;
};
如果你也想求值:
//////////////////////////////////////////////////
// Evaluation
struct eval : boost::static_visitor<bool>
{
eval() {}
//
bool operator()(const var& v) const
{
if (v=="T" || v=="t" || v=="true" || v=="True")
return true;
else if (v=="F" || v=="f" || v=="false" || v=="False")
return false;
return boost::lexical_cast<bool>(v);
}
bool operator()(const combination_op<op_and>& b) const
{
return std::accumulate(begin(b.operands), end(b.operands), true,
[this](bool a, expr const& b) { return a && recurse(b); });
}
bool operator()(const combination_op<op_xor>& b) const
{
return std::accumulate(begin(b.operands), end(b.operands), false,
[this](bool a, expr const& b) { return a != recurse(b); });
}
bool operator()(const combination_op<op_or>& b) const
{
return std::accumulate(begin(b.operands), end(b.operands), false,
[this](bool a, expr const& b) { return a || recurse(b); });
}
bool operator()(const unop<op_not>& u) const
{
return !recurse(u.operand);
}
private:
template<typename T>
bool recurse(T const& v) const
{ return boost::apply_visitor(*this, v); }
};
bool evaluate(const expr& e)
{
return boost::apply_visitor(eval(), e);
}
可以使用
打印计算结果 std::cout << "eval: " << evaluate(result) << "n";
输出:tree: XOR (AND (true NOT (T)) OR (AND (T T) AND (F T)))
eval: 1
(注意:树是使用镜像业力语法打印的,参见下面的"完整代码示例")
附加材料:
你可能已经注意到语法在拐角处变得非常对称。这正是因为优先级问题已经消失了。因此,进一步简化语法是有意义的:simplified.cpp
完整代码示例
也在github上:straight_forward.cpp
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/lexical_cast.hpp>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;
struct op_or {};
struct op_and {};
struct op_xor {};
struct op_not {};
typedef std::string var;
template <typename tag> struct combination_op;
template <typename tag> struct unop;
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<combination_op<op_and> >,
boost::recursive_wrapper<combination_op<op_xor> >,
boost::recursive_wrapper<combination_op<op_or> >
> expr;
template <typename tag> struct combination_op
{
typedef std::vector<expr> operands_t;
combination_op() = default;
combination_op(operands_t const& operands) : operands(operands) { }
operands_t operands;
};
template <typename tag> struct unop
{
unop() = default;
unop(const expr& o) : operand(o) { }
expr operand;
};
//////////////////////////////////////////////////
// Evaluation
struct eval : boost::static_visitor<bool>
{
eval() {}
//
bool operator()(const var& v) const
{
if (v=="T" || v=="t" || v=="true" || v=="True")
return true;
else if (v=="F" || v=="f" || v=="false" || v=="False")
return false;
return boost::lexical_cast<bool>(v);
}
bool operator()(const combination_op<op_and>& b) const
{
return std::accumulate(begin(b.operands), end(b.operands), true,
[this](bool a, expr const& b) { return a && recurse(b); });
}
bool operator()(const combination_op<op_xor>& b) const
{
return std::accumulate(begin(b.operands), end(b.operands), false,
[this](bool a, expr const& b) { return a != recurse(b); });
}
bool operator()(const combination_op<op_or>& b) const
{
return std::accumulate(begin(b.operands), end(b.operands), false,
[this](bool a, expr const& b) { return a || recurse(b); });
}
bool operator()(const unop<op_not>& u) const
{
return !recurse(u.operand);
}
private:
template<typename T>
bool recurse(T const& v) const
{ return boost::apply_visitor(*this, v); }
};
bool evaluate(const expr& e)
{
return boost::apply_visitor(eval(), e);
}
//////////////////////////////////////////////////
// Parser grammar
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, expr(), Skipper>
{
parser() : parser::base_type(expr_)
{
using namespace qi;
or_ = no_case [ "OR" ] > '(' > expr_list > ')';
xor_ = no_case [ "XOR" ] > '(' > expr_list > ')';
and_ = no_case [ "AND" ] > '(' > expr_list > ')';
not_ = no_case [ "NOT" ] > '(' > expr_ > ')';
var_ = qi::lexeme[ +alpha ];
expr_list = +expr_;
expr_ = xor_ | and_ | or_ | not_ | var_;
on_error<fail> ( expr_, std::cout
<< phx::val("Error! Expecting ") << _4 << phx::val(" here: "")
<< phx::construct<std::string>(_3, _2) << phx::val(""n"));
}
private:
template <typename Attr> using Rule = qi::rule<It, Attr(), Skipper>;
Rule<var> var_;
Rule<unop<op_not>> not_;
Rule<combination_op<op_and>> and_;
Rule<combination_op<op_xor>> xor_;
Rule<combination_op<op_or>> or_;
Rule<std::vector<expr>> expr_list;
Rule<expr> expr_;
};
//////////////////////////////////////////////////
// Output generator
template <typename It>
struct generator : karma::grammar<It, expr()>
{
generator() : generator::base_type(expr_)
{
using namespace karma;
or_ = lit("OR ") << '(' << expr_list[ _1 = phx::bind(&combination_op<op_or >::operands, _val) ] << ')';
xor_ = lit("XOR ") << '(' << expr_list[ _1 = phx::bind(&combination_op<op_xor>::operands, _val) ] << ')';
and_ = lit("AND ") << '(' << expr_list[ _1 = phx::bind(&combination_op<op_and>::operands, _val) ] << ')';
not_ = lit("NOT ") << '(' << expr_ [ _1 = phx::bind(&unop<op_not> ::operand, _val) ] << ')';
var_ = karma::string;
expr_list = expr_ % ' ';
expr_ = var_ | not_ | xor_ | and_ | or_ | not_;
}
private:
template <typename Attr> using Rule = karma::rule<It, Attr()>;
Rule<var> var_;
Rule<unop<op_not>> not_;
Rule<combination_op<op_and>> and_;
Rule<combination_op<op_xor>> xor_;
Rule<combination_op<op_or>> or_;
Rule<std::vector<expr>> expr_list;
Rule<expr> expr_;
};
int main()
{
const std::string input("xor (and (true not(T)) or (and (T T) and (F T)));");
auto f(std::begin(input)), l(std::end(input));
const static parser<decltype(f)> p;
expr result;
bool ok = qi::phrase_parse(f,l,p > ';',qi::space,result);
if (!ok)
std::cout << "invalid inputn";
else
{
const static generator<boost::spirit::ostream_iterator> g;
std::cout << "tree: " << karma::format(g, result) << "n";
std::cout << "eval: " << evaluate(result) << "n";
}
if (f!=l) std::cout << "unparsed: '" << std::string(f,l) << "'n";
}
相关文章:
- C++核心准则 C35 对于接口类"A base class destructor should be either public and virtual, or protected and nonv
- 这在C++ "It does not own the underlying data, and so is cheap to copy or assign"中意味着什么
- 为什么按位 OR 和 AND 逻辑无法按预期工作?
- 按位函数 AND、OR 和 XOR 在 C++ 中使用十六进制字符串
- 为什么下面的 while 循环与 AND 一起使用,而不是 OR
- "not"、"and"和"or"是什么样的运营商C++
- 关于正则表达式与Boost的逻辑AND和OR匹配的说明
- C++中的"and"、"or"等关键字的目的是什么?
- 按位 AND/OR 运算符正在追加
- 为什么在c++中不应重载逗号、地址、逻辑AND和逻辑OR运算符
- C++:for 循环中的多个退出条件(多个变量):AND -ed 或 OR -ed
- Web Services and C++ (or C++/CLI)
- 在c++中用布尔AND和OR代替
- AND OR Operator
- 我如何更改此示例中的语法以解析"AND ( (OR (a b c)) (NOT (d)))
- 未定义关键字"and"、"or"和"not"
- IF语句中的多个OR或AND条件
- Send() and recv() double or int
- 有没有像"std::and"或"std::or"的东西?
- 如何在C++中实现AND和OR运算