Étant donné une expression booléenne sous la forme : "a et b xor (c et d ou a et b);", le but est de analysez-le dans un arbre, en respectant les règles de préséance (pas, et, xor, ou).
Boost Spirit peut être utilisé pour créer un analyseur de descente récursif basé sur des modèles d'expression. Voici l'implémentation :
struct op_or {}; // tag struct op_and {}; // tag struct op_xor {}; // tag struct op_not {}; // tag typedef std::string var; template <typename tag> struct binop; template <typename tag> struct unop; typedef boost::variant<var, boost::recursive_wrapper<unop <op_not> >, boost::recursive_wrapper<binop<op_and> >, boost::recursive_wrapper<binop<op_xor> >, boost::recursive_wrapper<binop<op_or> > > expr;
template <typename It, typename Skipper = qi::space_type> struct parser : qi::grammar<It, expr(), Skipper> { parser() : parser::base_type(expr_) { using namespace qi; expr_ = or_.alias(); not_ = ("not" > simple ) [ _val = phx::construct<unop <op_not>>(_1) ] | simple [ _val = _1 ]; #ifdef RIGHT_ASSOCIATIVE or_ = (xor_ >> "or" >> or_ ) [ _val = phx::construct<binop<op_or >>(_1, _2) ] | xor_ [ _val = _1 ]; xor_ = (and_ >> "xor" >> xor_) [ _val = phx::construct<binop<op_xor>>(_1, _2) ] | and_ [ _val = _1 ]; and_ = (not_ >> "and" >> and_) [ _val = phx::construct<binop<op_and>>(_1, _2) ] | not_ [ _val = _1 ]; #else or_ = xor_ [ _val = _1 ] >> *("or" >> xor_ [ _val = phx::construct<binop<op_or>> (_val, _1) ]); xor_ = and_ [ _val = _1 ] >> *("xor" >> and_ [ _val = phx::construct<binop<op_xor>>(_val, _1) ]); and_ = not_ [ _val = _1 ] >> *("and" >> not_ [ _val = phx::construct<binop<op_and>>(_val, _1) ]); #endif simple = (('(' > expr_ > ')') | var_); var_ = qi::lexeme[ +alpha ]; } private: qi::rule<It, var() , Skipper> var_; qi::rule<It, expr(), Skipper> not_, and_, xor_, or_, simple, expr_; };
Pour parcourir et imprimer la syntaxe arbre :
struct printer : boost::static_visitor<void> { printer(std::ostream& os) : _os(os) {} std::ostream& _os; // void operator()(const var& v) const { _os << v; } void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); } void operator()(const binop<op_or >& b) const { print(" | ", b.oper1, b.oper2); } void operator()(const binop<op_xor>& b) const { print(" ^ ", b.oper1, b.oper2); } void print(const std::string& op, const expr& l, const expr& r) const { _os << "("; boost::apply_visitor(*this, l); _os << op; boost::apply_visitor(*this, r); _os << ")"; } void operator()(const unop<op_not>& u) const { _os << "("; _os << "!"; boost::apply_visitor(*this, u.oper1); _os << ")"; } }; std::ostream& operator<<(std::ostream& os, const expr& e) { boost::apply_visitor(printer(os), e); return os; }
Le l'analyseur gère correctement les règles de préséance et les sorties :
result: ((a & b) ^ ((c & d) | (a & b))) result: ((a & b) ^ ((c & d) | (a & b))) result: (a & b) result: (a | b) result: (a ^ b) result: (!a) result: ((!a) & b) result: (!(a & b)) result: ((a | b) | c)
[Cliquez ici pour essayer de voir le code complet sur Coliru](https://coliru.stacked-crooked.com/a/a795dea9a310e79bb12db3fe86fa61cf)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!