C++ 字符串到布尔表达式不起作用c++;

C++ 字符串到布尔表达式不起作用c++;,c++,boost-spirit,boost-variant,boost-phoenix,C++,Boost Spirit,Boost Variant,Boost Phoenix,我有一个基于字符串输入计算布尔字符串的代码 代码应该是这样工作的: Boolean string: "((0|1)&3);" Sting input: "101" 工作怎么样?输入字符串中的每个字符都应该被布尔字符串中相应的字符替换 例如: 输入字符串中的1乘以布尔字符串中的0 输入字符串中的0乘以布尔字符串中的1 输入字符串中的1乘以布尔字符串中的3 我知道这很让人困惑,我的问题是代码在很多情况下都可以使用,但我不明白为什么上面的例子中它不起作用 我添加了实时版本进行编辑

我有一个基于字符串输入计算布尔字符串的代码

代码应该是这样工作的:

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

Sting input: "101"  
工作怎么样?输入字符串中的每个字符都应该被布尔字符串中相应的字符替换

例如:

  • 输入字符串中的1乘以布尔字符串中的0

  • 输入字符串中的0乘以布尔字符串中的1

  • 输入字符串中的1乘以布尔字符串中的3

我知道这很让人困惑,我的问题是代码在很多情况下都可以使用,但我不明白为什么上面的例子中它不起作用

我添加了实时版本进行编辑

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
名称空间qi=boost::spirit::qi;
名称空间phx=boost::phoenix;
结构op_或{};
结构op_和{};
结构op_not{};
typedef std::string变量;
模板结构binop;
模板结构unop;
typedef boost::variant expr;
模板结构binop
{
显式binop(const-expr&l,const-expr&r):oper1(l),oper2(r){}
expr oper1、oper2;
};
模板结构unop
{
显式unop(const expr&o):oper1(o){}
expr-oper1;
};
结构eval2:boost::static\u visitor
{
eval2(const std::string&pk):pkey(pk){iter=0;}
//
布尔运算符()
{ 

std::cout所以您需要变量,并且它们是隐式的。 在表达式中用整数表示它们。是的,这很混乱,但我想为什么不呢

语法建议变量可以是任意长度的字母数字字符。让我们这样做,并将示例修改为:

bool res = string2BooleanExe("((a|b)&c);", {
        { "a", true }, { "b", false }, { "c", true } }); // was: 101
现在在您的实现中有两个大问题:

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

  • 您的
    eval2
    imk visitor是有状态的。如果要保留状态,您需要通过引用传递并使用它。或者,请确保您的复制构造函数实际复制了
    iter

  • 以下是我对事物的看法,使用

    typedef std::map<std::string, bool> VarMap;
    
    拆分
    求值
    解析
    函数:

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


    “”“修复错误的命名。此外,单一责任。创建一个
    解析
    函数和一个
    求值
    函数。将
    ';”
    和跳过程序放在语法中。检查语法中的
    qi::eoi
    。传播异常,而不是在
    解析/求值
    函数中执行神奇的控制台输出。

    这非常令人困惑。不知何故,您混淆了字符串迭代和表达式求值。如果您摆脱了
    iter
    ,而使用了@melpomene所说的
    v
    ^,那么效果会更好。我将在几分钟后展示一个示例这里有一个简单的示例也失败了:
    string2BooleanExe(“0&0;”,“10”)
    @melpomene对于string2BooleanExe(“0&0;”,“10”)=0@H'H期望
    “0&0;”
    在使用
    0
    的两次时都替换为true更有意义。请参阅我的答案。
    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;
    };
    
    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); 
    }
    
    //#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.