【问题标题】:Boost.Spirit.Qi alternative ( | ) parser issueBoost.Spirit.Qi 替代 (|) 解析器问题
【发布时间】:2016-01-17 14:13:45
【问题描述】:

我正在编写一个 Qi 解析器来解析 IRC 消息,转录 RFC 2812。其中的语法是一个完全普通的替代方案:

auto const hostname = shortname >> *('.' >> shortname);
auto const nickUserHost = nickname >> -(-('!' >> user) >> '@' >> host);

auto const prefix = hostname | nickUserHost;

(Full code on Coliru here)

我很困惑地看到我的测试字符串 ("D-z!D-z@mib-A3A026FF.rev.sfr.net") 匹配 nickUserHost,但不匹配 prefix

我看到的唯一值得注意的是nickUserHosthost 本身是根据hostname 定义的,但我不确定它会如何影响解析。

【问题讨论】:

    标签: c++ parsing boost c++14 boost-spirit


    【解决方案1】:

    通过附加>> eoi,如果解析没有到达输入的末尾,则显式地使解析失败。

    Live On Coliru

    #include <string>
    #include <iostream>
    #include <iomanip>
    
    #include <boost/spirit/include/qi.hpp>
    
    namespace qi = boost::spirit::qi;
    
    template <typename Expr>
    void test(std::string name, Expr const& expr) {
        std::string const test = "D-z!D-z@mib-A3A026FF.rev.sfr.net";
    
        auto f = begin(test);
        bool ok = qi::parse(f, end(test), expr);
        std::cout << name << ": " << ok << "\n";
        if (f != end(test))
            std::cout << " -- remaining input: '" << std::string(f, end(test)) << "'\n";
    }
    
    int main() {
        auto const hexdigit = qi::char_("0123456789ABCDEF");
        auto const special = qi::char_("\x5b-\x60\x7b-\x7d");
    
        auto const oneToThreeDigits = qi::repeat(1, 3)[qi::digit];
        auto const ip4addr = oneToThreeDigits >> '.' >> oneToThreeDigits >> '.' >> oneToThreeDigits >> '.' >> oneToThreeDigits;
        auto const ip6addr = +(hexdigit >> qi::repeat(7)[':' >> +hexdigit]) | ("0:0:0:0:0:" >> (qi::lit('0') | "FFFF") >> ':' >> ip4addr);
        auto const hostaddr = ip4addr | ip6addr;
    
        auto const nickname = (qi::alpha | special) >> qi::repeat(0, 8)[qi::alnum | special | '-'];
        auto const user = +(~qi::char_("\x0d\x0a\x20\x40"));
    
        auto const shortname = qi::alnum >> *(qi::alnum | '-');
        auto const hostname = shortname >> *('.' >> shortname);
        auto const host = hostname | hostaddr;
    
        auto const nickUserHost = nickname >> -(-('!' >> user) >> '@' >> host);
    
        auto const prefix = hostname | nickUserHost; // The problematic alternative
    
        std::cout << std::boolalpha;
        test("hostname",     hostname);
        test("nickUserHost", nickUserHost);
        test("prefix",       prefix);
    }
    

    打印

    hostname: true
    -- remaining input: '!D-z@mib-A3A026FF.rev.sfr.net'
    nickUserHost: true
    prefix: true
    -- remaining input: '!D-z@mib-A3A026FF.rev.sfr.net'
    

    【讨论】:

    • 这是故意的,因为我希望它匹配整个输入。这真的会干扰| 的行为吗?
    • @Quentin 不,但是hostname 成功而不消耗整个输入(因此nickUserHost 从未尝试过)然后eoi 使您的解析失败。您需要将eoi 放在| 的每个分支中。
    • 呃。我只是想念你没有使用 Spirit X3。 auto 不适合解析器表达式`stackoverflow.com/questions/26410498/…
    • @sehe 是的,虽然在this case 中这并没有改变任何东西。
    • @cv_and_he 确实如此。 GCC 崩溃:coliru.stacked-crooked.com/a/135e931117b21948(UB 是 UB)。 Quentin:见 cv_and_he 提供的代码
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 2020-01-18
    相关资源
    最近更新 更多