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

时间:2016-12-27 15:50:18

标签: c++ boost-spirit boost-spirit-qi

#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

为什么第二个数字属性&#34; 1 + 2&#34;而不只是&#34; 2&#34;?

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

1 个答案:

答案 0 :(得分:3)

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

两个属性都绑定到同一个容器属性(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;
}