提升精神,来自语义动作的返回值会干扰规则属性

时间:2014-07-04 23:23:12

标签: c++ boost boost-spirit

以下程序是一个人为的例子(从我正在工作的较大语法中减少)表现出一种奇怪的行为。

程序的输出按原样运行“hello”并且不正确。

如果我从quoted_string规则中删除(在此示例中无用)语义操作,则输出是预期的“foo = hello”。

#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <vector>
#include <string>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include "utils.hpp"

namespace t {
    using std::vector;
    using std::string;
    namespace qi = boost::spirit::qi;
    namespace phx = boost::phoenix;

    template <typename Iterator, typename Skipper=qi::space_type>
    struct G1 : qi::grammar<Iterator, string(), Skipper> {

        template <typename T>
        using rule = qi::rule<Iterator, T, Skipper>;

        qi::rule<Iterator, string(), qi::locals<char>> quoted_string;
        rule<string()> start;

        G1() : G1::base_type(start, "G1") {
            {
                using qi::_1;
                using qi::_a;

                using attr_signature = vector<char>;
                auto handler = [](attr_signature const& elements) -> string {
                    string output;
                    for(auto& e : elements) {
                        output += e;
                    }
                    return output;
                };
                quoted_string = (qi::omit[qi::char_("'\"")[_a = _1]]
                    >> +(qi::char_ - qi::char_(_a))
                    >> qi::lit(_a))[qi::_val = phx::bind(handler, _1)];
            }
            start = qi::string("foo") >> -(qi::string("=") >> quoted_string);
        }
    };

    string parse(string const input) {
        G1<string::const_iterator> g;
        string result;
        phrase_parse(begin(input), end(input), g, qi::standard::space, result);
        return result;
    }
};

int main() {
    using namespace std;
    auto r = t::parse("foo='hello'");
    cout << r << endl;
}

我绝对可以找到解决方法,但我会弄清楚我缺少什么

1 个答案:

答案 0 :(得分:2)

与@cv_and_he解释一样,您将使用handler(_1)的结果覆盖该属性。由于属性是通过引用传递的,因此会丢失原始值。

自动属性传播规则知道如何连接&#34;字符串&#34;容器值,那么为什么不使用默认实现?

    quoted_string %= qi::omit[qi::char_("'\"")[_a = _1]]
        >> +(qi::char_ - qi::char_(_a))
        >> qi::lit(_a);

请注意 %= ;即使存在语义操作,也会启用自动传播。

或者,您可以从SA内部推回:

 >> +(qi::char_ - qi::char_(_a)) [ phx::push_back(qi::_val, _1) ]

并且,如果您确实需要在handler中完成某些处理,请通过引用使其成为字符串:

auto handler = [](attr_signature const& elements, std::string& attr) {
    for(auto& e : elements) {
        attr += e;
    }
};
quoted_string = (qi::omit[qi::char_("'\"")[_a = _1]]
    >> +(qi::char_ - qi::char_(_a))
    >> qi::lit(_a)) [ phx::bind(handler, _1, qi::_val) ];

所有这些方法都有效。

对于非常重要的东西,我过去使用自定义字符串类型和boost :: spirit :: traits自定义点来进行转换: