2016-01-17 4 views
1

Я пишу парсер Qi для разбора IRC-сообщений, переписывая RFC 2812. Среди грамматика совершенно mundate альтернатива:Boost.Spirit.Qi alternative (|) parser issue

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

auto const prefix = hostname | nickUserHost; 

(Full code on Coliru here)

Я сбит с толку, чтобы видеть, что моя тестовая строка ("[email protected]") соответствует nickUserHost, но не prefix.

Единственная замечательная вещь, которую я вижу в том, что nickUserHost «s host сами определяются в терминах hostname, но я не знаю, как это будет влиять на разбор в любом случае.

ответ

2

При добавлении >> 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 = "[email protected]"; 

    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_("ABCDEF"); 
    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: '[email protected]' 
nickUserHost: true 
prefix: true 
-- remaining input: '[email protected]' 
+0

Это нарочно, потому что я ожидаю, что это соответствует весь вход. Это на самом деле влияет на поведение '|'? – Quentin

+0

@Quentin no, но 'hostname' преуспевает, не потребляя весь вход (и, соответственно,' nickUserHost' никогда не пробовали), а затем 'eoi' заставляет ваш синтаксический анализ терпеть неудачу. Вам нужно поместить 'eoi' в каждую ветвь' | '. – llonesmiz

+1

Erm. Я просто пропустил, что вы не используете Spirit X3. ** 'auto' не подходит для выражений парсера' ** См. https://stackoverflow.com/questions/26410498/undefined-behaviour-somewhere-in-boostspiritqiphrase-parse/26411266#26411266 – sehe