布尔表达式的字符串不起作用c ++

string to Boolean expression is not working c++

我有以下代码根据字符串输入计算布尔字符串。

代码应该像这样工作:

Boolean string: "((0|1)&3);"

Sting input: "101"  

效果如何?输入字符串中的每个字符都应该被布尔字符串中的相应字符替换。

例如:

我知道这很令人困惑,我的问题是该代码适用于许多情况,但我不明白为什么它不适用于上述示例。

我添加了用于编辑的实时版本here

#include <iostream>
#include <fstream>
#include <vector>

#include <boost/lexical_cast.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/variant/recursive_wrapper.hpp>


namespace qi    = boost::spirit::qi;
namespace phx   = boost::phoenix;

struct op_or  {};
struct op_and {};
struct op_not {};

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_or> >
        > expr;

template <typename tag> struct binop
{
    explicit binop(const expr& l, const expr& r) : oper1(l), oper2(r) { }
    expr oper1, oper2;
};

template <typename tag> struct unop
{
    explicit unop(const expr& o) : oper1(o) { }
    expr oper1;
};

struct eval2 : boost::static_visitor<bool> 
{
    eval2(const std::string& pk): pkey(pk) { iter = 0; }

    //
    bool operator()(const var& v) const 
    { 
      std:: cout << "**** " << v << "\titer: " << iter << std::endl;
      iter ++;
      return boost::lexical_cast<bool>(pkey[iter-1]); 
    }

    bool operator()(const binop<op_and>& b) const
    {
        return recurse(b.oper1) && recurse(b.oper2);
    }
    bool operator()(const binop<op_or>& b) const
    {
        return recurse(b.oper1) || recurse(b.oper2);
    }
    bool operator()(const unop<op_not>& u) const
    {
        return !recurse(u.oper1);
    } 

    private:
    mutable int iter;
    const std::string pkey;
    template<typename T>
        bool recurse(T const& v) const 
        { return boost::apply_visitor(*this, v); }
};

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 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 << ")";
    } 
};

bool evaluate2(const expr& e, const std::string s) 
{ 
  return boost::apply_visitor(eval2(s), e); 
}

std::ostream& operator<<(std::ostream& os, const expr& e) 
{ boost::apply_visitor(printer(os), e); return os; }

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();

            or_  = (and_ >> '|'  >> or_ ) [ qi::_val = phx::construct<binop<op_or > >(qi::_1, qi::_2) ] | and_   [ qi::_val = qi::_1 ];
            and_ = (not_ >> '&' >> and_)  [ qi::_val = phx::construct<binop<op_and> >(qi::_1, qi::_2) ] | not_   [ qi::_val = qi::_1 ];
            not_ = ('!' > simple       )  [ qi::_val = phx::construct<unop <op_not> >(qi::_1)     ] | simple [ qi::_val = qi::_1 ];

            simple = (('(' > expr_ > ')') | var_);
            var_ = qi::lexeme[ +(alpha|digit) ];

            BOOST_SPIRIT_DEBUG_NODE(expr_);
            BOOST_SPIRIT_DEBUG_NODE(or_);
            BOOST_SPIRIT_DEBUG_NODE(and_);
            BOOST_SPIRIT_DEBUG_NODE(not_);
            BOOST_SPIRIT_DEBUG_NODE(simple);
            BOOST_SPIRIT_DEBUG_NODE(var_);
        }

        private:
        qi::rule<It, var() , Skipper> var_;
        qi::rule<It, expr(), Skipper> not_, and_, or_, simple, expr_; 
};

bool string2BooleanExe(std::string bStatement, std::string bKey)
{
  typedef std::string::const_iterator It;
  It f(bStatement.begin()), l(bStatement.end());
  parser<It> p;
  try
  {
      expr result;
      bool ok = qi::phrase_parse(f,l,p > ';',qi::space,result);
      if (!ok)
      std::cerr << "invalid input\n";
      else
      {
      std::cout << "result:\t" << result << "\n";
      bool returnResult = evaluate2(result, bKey);
      std::cout << "evaluated:\t" << returnResult << "\n";
      return returnResult;
      }

  } catch (const qi::expectation_failure<It>& e)
  {
      std::cerr << "expectation_failure at '" << std::string(e.first, e.last) << "'\n";
  }

  if (f!=l) std::cerr << "unparsed: '" << std::string(f,l) << "'\n";
  return false;
}

int main()
{
    bool res = string2BooleanExe("((0|1)&3);", "101");
    std::cout << "res: " << res << std::endl;
    return 0;
}

请注意我只能使用 C++03。

所以你需要变量。它们是隐含的。 你在表达式中用整数表示它们。是的,这令人困惑,但我想为什么不呢。

虽然语法表明变量可以是任意长度的字母数字字符。让我们这样做,并将样本固定为:

bool res = string2BooleanExe("((a|b)&c);", {
        { "a", true }, { "b", false }, { "c", true } }); // was: 101

现在在你的实现中有两个大问题:

  1. 您正在使用名称 012 作为源表达式中的占位符,但这些被忽略(这意味着 ((0|1)&2) 在功能上等同于 ((1|2)&0)...我怀疑这是任何人想要的)

  2. 您的 eval2¹ 访问者是有状态的。如果要保留状态,则需要通过引用传递和使用它。或者,确保您的复制构造函数实际复制了 iter

  3. 的值

这是我的看法,使用

typedef std::map<std::string, bool> VarMap;

让我们在 evaluator 访问者中使用它:

struct evaluator : boost::static_visitor<bool> 
{
    evaluator(VarMap const& pk) : pk(pk) { }

    bool operator()(const var& v) const { return pk.at(v); }
    bool operator()(const binop<op_and>& b) const { return recurse(b.oper1) && recurse(b.oper2); }
    bool operator()(const binop<op_or>&  b) const { return recurse(b.oper1) || recurse(b.oper2); }
    bool operator()(const unop<op_not>&  u) const { return !recurse(u.oper1); }

  private:
    template<typename T> bool recurse(T const& v) const { return boost::apply_visitor(*this, v); }
    const VarMap pk;
};

拆分 evaluateparse 函数:

static const parser<std::string::const_iterator> s_parser_instance;
expr parse(std::string const& bStatement) {
    std::string::const_iterator f = bStatement.begin(), l = bStatement.end();

    expr parsed;
    qi::parse(f, l, s_parser_instance, parsed);

    return parsed;
}

bool evaluate(expr const& e, VarMap const& vars) {
    return boost::apply_visitor(evaluator(vars), e); 
}

现在让我们看看完整的演示

完整演示

Live On Coliru

//#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <fstream>
#include <vector>

#include <boost/lexical_cast.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/variant/recursive_wrapper.hpp>

namespace qi  = boost::spirit::qi;
namespace phx = boost::phoenix;

typedef std::map<std::string, bool> VarMap;

struct op_or  {};
struct op_and {};
struct op_not {};

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_or> >
    > expr;

template <typename tag> struct binop {
    explicit binop(const expr& l, const expr& r) : oper1(l), oper2(r) { }
    expr oper1, oper2;
};

template <typename tag> struct unop {
    explicit unop(const expr& o) : oper1(o) { }
    expr oper1;
};

struct evaluator : boost::static_visitor<bool> 
{
    evaluator(VarMap const& pk) : pk(pk) { }

    bool operator()(const var& v) const { return pk.at(v); }
    bool operator()(const binop<op_and>& b) const { return recurse(b.oper1) && recurse(b.oper2); }
    bool operator()(const binop<op_or>&  b) const { return recurse(b.oper1) || recurse(b.oper2); }
    bool operator()(const unop<op_not>&  u) const { return !recurse(u.oper1); }

  private:
    template<typename T> bool recurse(T const& v) const { return boost::apply_visitor(*this, v); }
    const VarMap pk;
};

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 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; }

template <typename It>
struct parser : qi::grammar<It, expr()>
{
    parser() : parser::base_type(start) {
        using namespace qi;

        start  = skip(space) [expr_ > ';' > eoi];

        expr_  = or_.alias();
        or_    = (and_ >> '|'  >> or_ ) [ _val = phx::construct<binop<op_or > >(_1, _2) ] | and_   [ _val = _1 ];
        and_   = (not_ >> '&' >> and_)  [ _val = phx::construct<binop<op_and> >(_1, _2) ] | not_   [ _val = _1 ];
        not_   = ('!' > simple       )  [ _val = phx::construct<unop <op_not> >(_1) ]     | simple [ _val = _1 ];

        simple = ('(' > expr_ > ')') | var_;
        var_   = lexeme[ +(alpha|digit) ];

        BOOST_SPIRIT_DEBUG_NODES((expr_) (or_) (and_) (not_) (simple) (var_));
    }

  private:
    qi::rule<It, expr()> start;
    qi::rule<It, var() , qi::space_type> var_;
    qi::rule<It, expr(), qi::space_type> not_, and_, or_, simple, expr_; 
};

static const parser<std::string::const_iterator> s_parser_instance;
expr parse(std::string const& bStatement) {
    std::string::const_iterator f = bStatement.begin(), l = bStatement.end();

    expr parsed;
    qi::parse(f, l, s_parser_instance, parsed);

    return parsed;
}

bool evaluate(expr const& e, VarMap const& vars) {
    return boost::apply_visitor(evaluator(vars), e); 
}

void test(std::string const& expression, VarMap const& vars, bool expected) {
    try {
        std::cout << "'" << expression << "'";

        expr parsed = parse(expression);
        std::cout << " -> " << parsed;

        bool actual = evaluate(parsed, vars);
        std::cout 
            << " - evaluates to " << std::boolalpha << actual
            << (expected == actual? " Correct." : " INCORRECT!!!")
            << "\n";

    } catch(std::exception const& e) {
        std::cout << " EXCEPTION(" << e.what() << ")\n";
    }
}

int main() {
    VarMap vars;
    vars["a"] = true;
    vars["b"] = false;
    vars["c"] = true;

    test("a;", vars, true);
    test("b;", vars, false);
    test("c;", vars, true);

    test("((a|b)&c);", vars, true);

    vars["c"] = false;
    test("((a|b)&c);", vars, false);

    // let's use an undefined variable - should throw
    test("((z|y)&x);", vars, false|true);

    // you CAN still use confusing numeric placeholders:
    vars["0"] = true;
    vars["1"] = false;
    vars["2"] = true;
    test("((0|1)&2);", vars, true);
    test("((2|0)&1);", vars, false);
    test("((1|0)&2);", vars, true);

    // note you can also have "special variables"; no need for single-letter names
    vars["TRUE"] = true;
    vars["FALSE"] = false;
    test("TRUE | FALSE;", vars, true);
    test("TRUE & FALSE;", vars, false);
}

打印:

'a;' -> a - evaluates to true Correct.
'b;' -> b - evaluates to false Correct.
'c;' -> c - evaluates to true Correct.
'((a|b)&c);' -> ((a | b) & c) - evaluates to true Correct.
'((a|b)&c);' -> ((a | b) & c) - evaluates to false Correct.
'((z|y)&x);' -> ((z | y) & x) EXCEPTION(map::at)
'((0|1)&2);' -> ((0 | 1) & 2) - evaluates to true Correct.
'((2|0)&1);' -> ((2 | 0) & 1) - evaluates to false Correct.
'((1|0)&2);' -> ((1 | 0) & 2) - evaluates to true Correct.
'TRUE | FALSE;' -> (TRUE | FALSE) - evaluates to true Correct.
'TRUE & FALSE;' -> (TRUE & FALSE) - evaluates to false Correct.

¹ 修复错误命名。另外,单一职责。创建一个 parse 函数和一个 evaluate 函数。将 ';' 和船长放在语法中。检查语法中的 qi::eoi。传播异常,而不是在 parse/evaluate 函数中执行神奇的控制台输出。