为什么会这样?Spirit x3规则正确地使用尖括号解析,但不正确地使用引号

Why does this Boost.Spirit x3 rule parse correctly with angle brackets, but incorrectly with quotes?

本文关键字:正确地 不正确 x3 Spirit 规则 为什么      更新时间:2023-10-16

下面的程序尝试解析c++头包含字符串,例如"my/file.hpp"<my/file.hpp>。由于我不理解的原因,我的代码无法解析"标头。这是Spirit的一个bug,还是我错过了什么明显的东西?

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <cassert>
using namespace boost::spirit::x3;
int main() {
    auto header_name_brackets = '<' >> *(~char_('>')) >> '>';
    auto header_name_quotes   = '"' >> *(~char_('>')) >> '"'; 
    {
        auto s = std::string{"<my/file.hpp>"};
        std::string parsed;
        assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
    }
    {
        auto s = std::string{""my/file.hpp""};
        std::string parsed;
        // this assert fails, but I don't know why.
        assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
    }
}

既然你已经有了更多的答案(:)),这是我的0.02美元:

template <typename Prefix, typename Postfix>
static auto quoted_(Prefix const& prefix, Postfix const& postfix) {
    using namespace boost::spirit::x3;
    return rule<struct _, std::string, true> {} = omit[prefix] >> *(char_ - postfix) >> omit[postfix];
}

现在你可以写

auto header_name_brackets = quoted_('<', '>');
auto header_name_quotes   = quoted_('"');

第二个假设了明显的便利过载。

另一个错误

事实上,我认为有一个跳过分隔符内的空白的错误。通过添加lexeme[]:

修复它
template <typename Prefix, typename Postfix>
static auto quoted_(Prefix const& prefix, Postfix const& postfix) {
    using namespace boost::spirit::x3;
    return rule<struct _, std::string, true> {} = lexeme [ 
        omit[prefix] >> *(char_ - postfix) >> omit[postfix] 
    ];
}

查看完整演示:

Live On Coliru

#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <cassert>
template <typename Prefix, typename Postfix>
static auto quoted_(Prefix const& prefix, Postfix const& postfix) {
    using namespace boost::spirit::x3;
    return rule<struct _, std::string, true> {} = lexeme [ 
        omit[prefix] >> *(char_ - postfix) >> omit[postfix] 
    ];
}
template <typename Prefix>
static auto quoted_(Prefix const& prefix) { return quoted_(prefix, prefix); }
int main() {
    using boost::spirit::x3::space;
    auto header_name_brackets = quoted_('<', '>');
    auto header_name_quotes   = quoted_('"');
    {
        auto s = std::string{"<my/file.hpp>"};
        std::string parsed;
        assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
    }
    {
        auto s = std::string{""my/file.hpp""};
        std::string parsed;
        assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
    }
    std::cout << "Byen";
}

这个适合我:

#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <cassert>
using namespace boost::spirit::x3;
int main() {
    auto header_name_brackets = '<' >> *(~char_('>')) >> '>';
    auto header_name_quotes   = '"' >> *(~char_('"')) >> '"'; 
    {
        auto s = std::string{"<my/file.hpp>"};
        std::string parsed;
        assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
    }
    {
        auto s = std::string{""my/file.hpp""};
        std::string parsed;
        // this assert fails, but I don't know why.
        assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
    }
}

请注意,在第二种情况下,您需要匹配除"以外的所有字符,就像在第一种情况下匹配>一样。

你需要改变这个规则:

auto header_name_quotes   = '"' >> *(~char_('>')) >> '"'; 

auto header_name_quotes   = '"' >> *(~char_('"')) >> '"';