boost::spirit::qi 奇怪的属性打印出来

boost::spirit::qi strange attribute print out

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;

namespace test {
    template< typename Rng,typename Expr >
    bool parse(Rng const& rng,Expr const& expr) noexcept {
        auto itBegin = boost::begin(rng);
        auto itEnd = boost::end(rng);
        try {
            return qi::parse(itBegin,itEnd,expr);
        } catch(qi::expectation_failure<decltype(itBegin)> const& exfail) {
            exfail;
            return false;
        }
    }
    template< typename Rng,typename Expr,typename Attr >
    bool parse(Rng const& rng,Expr const& expr,Attr& attr) noexcept {
        auto itBegin = boost::begin(rng);
        auto itEnd = boost::end(rng);
        try {
            return qi::parse(itBegin,itEnd,expr,attr);
        } catch(qi::expectation_failure<decltype(itBegin)> const&) {
            return false;
        }
    }
}

void print1(std::string const& s) {
    std::cout<<"n1 = "<<s<<std::endl;
}

void print2(std::string const& s) {
    std::cout<<"n2 = "<<s<<std::endl;
}

int main() {
    qi::rule<std::string::const_iterator, std::string()> number = +qi::digit;
    std::string input = "1+2";
    std::string result;
    if( test::parse(input, number[print1] >> *( qi::char_("+-") >> number[print2]) >> qi::eoi, result) ) {
        std::cout<<"Match! result = "<<result<<std::endl;
    } else {
        std::cout<<"Not match!"<<std::endl; 
    }
    return 0;
}

我希望这个程序的输出是,

n1 = 1
n2 = 2
Match! result = 1+2

但是n2的输出其实很奇怪,

n1 = 1
n2 = 1+2
Match! result = 1+2

为什么第二个数字的属性是“1+2”而不是“2”?

我知道还有一些其他方法可以解析此表达式,例如使用 qi::int_。我只是想知道为什么我会从中得到这个奇怪的属性。谢谢!

回溯不会撤消对容器属性的更改。相邻的兼容解析器表达式绑定到相同的容器属性。

两个属性都绑定到相同的容器属性 (result),这意味着您正在打印相同的变量两次。

如果您不想这样,请明确说明,例如

Live On Coliru

std::string result;
std::vector<std::string> v;
if( test::parse(input, number[px::bind(print1, qi::_1)] >> *qi::as_string[qi::char_("+-") >> number[print2]] >> qi::eoi, result, v) ) {
    std::cout<<"Match! result = "<<result<<std::endl;
    for (auto s : v)
        std::cout << s << "\n";
} else {

版画

n1 = 1
n2 = +2
Match! result = 1
+2

现在我不知道你想要实现什么,但这可能很接近:

if (test::parse(input, qi::raw [number[print_("n1",_1)] > *(qi::char_("+-") >> number[print_("n2",_1)]) ] >> qi::eoi, result)) {

Live On Coliru

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix.hpp>

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

namespace test {
    template< typename Rng,typename Expr,typename... Attr >
    bool parse(Rng const& rng,Expr const& expr,Attr&... attr) noexcept {
        auto itBegin = boost::begin(rng);
        auto itEnd   = boost::end(rng);
        try {
            return qi::parse(itBegin,itEnd,expr,attr...);
        } catch(qi::expectation_failure<decltype(itBegin)> const&) {
            return false;
        }
    }
}

void printn(std::string const& label, std::string const& s) {
    std::cout << label << " = " << s << std::endl;
}

BOOST_PHOENIX_ADAPT_FUNCTION(void, print_, printn, 2)

int main() {
    qi::rule<std::string::const_iterator, std::string()> number = +qi::digit;
    std::string input = "1+2";
    std::string result;
    using qi::_1;

    if (test::parse(input, qi::raw [number[print_("n1",_1)] > *(qi::char_("+-") >> number[print_("n2",_1)]) ] >> qi::eoi, result)) {
        std::cout<<"Match! result = "<<result<<std::endl;
    } else {
        std::cout<<"Not match!"<<std::endl; 
    }
    return 0;
}

版画

n1 = 1
n2 = 2
Match! result = 1+2

奖金

多一点关注点分离:

Live On Coliru

void printn(int n, std::string const& s) {
    std::cout << "n" << n << " = " << s << std::endl;
}

BOOST_PHOENIX_ADAPT_FUNCTION(void, print_, printn, 2)

int main() {
    qi::rule<std::string::const_iterator, std::string()> number;

    int n = 1;
    number %= qi::as_string[+qi::digit] [print_(px::ref(n)++, qi::_1)];

    std::string input = "1+2";
    std::string result;

    if (test::parse(input, qi::raw [number > *(qi::char_("+-") >> number) ] >> qi::eoi, result)) {
        std::cout << "Match! result = " << result << std::endl;
    } else {
        std::cout << "Not match!" << std::endl;
    }
    return 0;
}