C++ 从语义动作更新合成属性值

C++ 从语义动作更新合成属性值,c++,boost,boost-spirit-qi,boost-phoenix,C++,Boost,Boost Spirit Qi,Boost Phoenix,我想知道在“精神”和“气”的掩护下到底发生了什么。假设我们有一个简单的解析器,可以解析和计算由数字和加法/减法运算组成的表达式: int main() { std::string INPUT_DATA = "12e-1 + 3.4 - .67"; typedef std::string::iterator iterator_type; iterator_type begin = std::begin(INPUT_DATA); iterator_type end =

我想知道在“精神”和“气”的掩护下到底发生了什么。假设我们有一个简单的解析器,可以解析和计算由数字和加法/减法运算组成的表达式:

int main()
{
    std::string INPUT_DATA = "12e-1 + 3.4 - .67";
    typedef std::string::iterator iterator_type;
    iterator_type begin = std::begin(INPUT_DATA);
    iterator_type end = std::end(INPUT_DATA);

    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::qi::ascii;

    auto parser = qi::double_[qi::_val = qi::_1]                      // (1)
        >> *(
                (qi::lit('+') >> qi::double_[qi::_val += qi::_1])     // (2)
                |
                (qi::lit('-') >> qi::double_[qi::_val -= qi::_1])     // (3)
            );

    double result;
    bool ok = qi::phrase_parse(begin, end, parser, ascii::space, result);

    if ( ok  && begin == end)
    {
        std::cout << "parsed, result = " << result << std::endl;
    }
    else
    {
        std::cout << "not parsed" << std::endl;
    }

    return 0;
}
intmain()
{
std::string INPUT_DATA=“12e-1+3.4-.67”;
typedef std::string::iterator iterator_type;
迭代器类型begin=std::begin(输入数据);
迭代器类型end=std::end(输入数据);
名称空间qi=boost::spirit::qi;
名称空间ascii=boost::spirit::qi::ascii;
自动解析器=qi::double_qi::_val=qi::_1]/(1)
>> *(
(qi::lit(+)>>qi::double.[qi::[u val+=qi::[u 1])/(2)
|
(qi::lit('-')>>qi::double.[qi::[u val-=qi::[u 1])/(3)
);
双重结果;
bool ok=qi::phrase_parse(开始、结束、解析器、ascii::空格、结果);
如果(确定&开始==结束)
{

std::cout除了评论中提供的精致的低级信息之外,让我向您展示精神的方式

当然,我将以一个不使用语义动作的演示结束。是的,它涉及更多的代码,但它也将解析与评估分离。这在更复杂的情况下是很好的(想想那些回溯的解析器)

1. 从稍微简化代码开始:


2. 当然,您可以对函数使用常规绑定:


3. 现在,使用BOOST_PHOENIX_ADAPT_功能使它稍微漂亮一些:


4. 或者您可以使用函子:

我们使用
eval
函数打印结果:

std::cout << "parsed, result = " << eval(result) << std::endl;
std::cout>double;
parser=double_>>*(添加_项|子项);
ok=短语解析(开始、结束、解析器、ascii::空格、结果);
}
如果(确定&开始==结束)

std::academicRobot的cout是帮助我理解这一点的人。@cv_和_he将其作为一个答案发布是……习惯性的:)@sehe这只是一个例子,答案是链接的。如果你认为你能给出一个更关注这个问题的答案,请随意自己给出答案。答案非常好,非常详尽。也许你应该为了将所有可能的方法都包含在一个答案中,我们还将包括academicRobot答案中的“低级”解决方案。嗯。我可能只会链接到academicRobot的“经典”文章答案。不过,我得晚一点。制作晚餐:/感谢您抽出时间来写这个答案。
void add_operand(double& lhs, double rhs) { lhs += rhs; }
void sub_operand(double& lhs, double rhs) { lhs -= rhs; }

auto parser = 
       double_                  [_val  = _1]
    >> *(   (lit('+') >> double_[bind(add_operand, _val, _1)])
          | (lit('-') >> double_[bind(sub_operand, _val, _1)])
        );
BOOST_PHOENIX_ADAPT_FUNCTION(void, add_, add_operand, 2)
BOOST_PHOENIX_ADAPT_FUNCTION(void, sub_, sub_operand, 2)

       double_                  [_val  = _1]
    >> *(   (lit('+') >> double_[add_(_val, _1)])
          | (lit('-') >> double_[sub_(_val, _1)])
        );
struct add_operand { 
    template<typename...> struct result { typedef void type; };
    template<typename L, typename R>
    void operator()(L& lhs, R rhs) const { lhs += rhs; } 
};

struct sub_operand { 
    template<typename...> struct result { typedef void type; };
    template<typename L, typename R>
    void operator()(L& lhs, R rhs) const { lhs -= rhs; } 
};

    auto parser = 
           double_                  [_val  = _1]
        >> *(   (lit('+') >> double_[bind(add_operand(), _val, _1)])
              | (lit('-') >> double_[bind(sub_operand(), _val, _1)])
            );
phx::function<add_operand> add_;
phx::function<sub_operand> sub_;

auto parser = 
       double_                  [_val  = _1]
    >> *(   (lit('+') >> double_[add_(_val, _1)])
          | (lit('-') >> double_[sub_(_val, _1)])
        );
rule<iterator_type, term<add>()     , ascii::space_type> add_term;
rule<iterator_type, term<subtract>(), ascii::space_type> sub_term;
rule<iterator_type, expression()    , ascii::space_type> parser;

add_term = '+' >> double_;
sub_term = '-' >> double_;
parser   = double_ >> *(add_term|sub_term);
expression result;
ok = phrase_parse(begin, end, parser, ascii::space, result);
std::cout << "parsed, result = " << eval(result) << std::endl;
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>

/////////////////
// AST
template <typename> struct term {
    term(double value=0) : value(value) {}
    double value;
};

using operation = boost::variant<term<struct add>, term<struct subtract> >;

struct expression
{
    double initial;
    std::vector<operation> operations;
};

BOOST_FUSION_ADAPT_STRUCT(expression, (double, initial)(std::vector<operation>,operations))
// End of AST
/////////////////

double eval(expression const& e)
{
    double result = e.initial;

    struct visitor : boost::static_visitor<> {
        double& _v; visitor(double& ref) : _v(ref) {}
        void operator()(term<add>      const& rhs) const { _v += rhs.value; }
        void operator()(term<subtract> const& rhs) const { _v -= rhs.value; }
    };

    for(auto& o : e.operations)
        boost::apply_visitor(visitor(result), o);
    return result;
}

int main()
{
    const std::string INPUT_DATA = "12e-1 + 3.4 - .67";
    typedef std::string::const_iterator iterator_type;
    iterator_type begin = std::begin(INPUT_DATA);
    iterator_type end   = std::end(INPUT_DATA);

    namespace qi    = boost::spirit::qi;
    namespace ascii = boost::spirit::qi::ascii;

    bool ok;
    expression result;
    {
        using namespace qi;

        rule<iterator_type, term<add>()     , ascii::space_type> add_term;
        rule<iterator_type, term<subtract>(), ascii::space_type> sub_term;
        rule<iterator_type, expression()    , ascii::space_type> parser;

        add_term = '+' >> double_;
        sub_term = '-' >> double_;
        parser   = double_ >> *(add_term|sub_term);

        ok = phrase_parse(begin, end, parser, ascii::space, result);
    }

    if (ok  && begin == end)
        std::cout << "parsed, result = " << eval(result) << std::endl;
    else
        std::cout << "not parsed" << std::endl;
}