2013-07-06 3 views
2

Мне нужно разобрать строку, содержащую unsigned int, символ X, который должен быть отброшен, и строку, разделенную одним или несколькими пробелами. например, 1234 X abcdBoost.spirit: парсинг номер char и строка

bool a = qi::phrase_parse(first, last, 
     uint_[ref(num) = _1] >> lit('X') >> lexeme[+(char_ - ' ')], 
     space, parsed_str); 

Приведенный выше код разбирает три части, но строка заканчивается, содержащая вредную характер (�abcd) и имеющий размер 5, а не 4.

Что случилось с моим анализатором ? и почему в этой строке есть мусор?

ответ

9

То, что вы, вероятно, не поняли, является то, что синтаксический анализатор выражений прекратят автоматическое распространение атрибута в присутствии семантических действий*.

* Документация Backgound: How Do Rules Propagate Their Attributes?

Вы используете семантическое действие, чтобы 'вручную' распространять атрибут uint_ парсер:

[ref(num) = _1] // this is a Semantic Action 

Так самый простой способ исправить это, было бы также автоматически распространять num (способ, которым были привязаны API-интерфейсы qi::parse и qi::phrase_parse d):

bool ok = qi::phrase_parse(first, last,    // input iterators 
     uint_ >> lit('X') >> lexeme[+(char_ - ' ')], // parser expr 
     space,          // skipper 
     num, parsed_str);       // output attributes 

Или, обращаясь несколько не по теме очки, даже уборщик:

bool ok = qi::phrase_parse(first, last, 
     uint_ >> 'X' >> lexeme[+graph], 
     blank, 
     num, parsed_str); 

Как вы можете видеть, вы можете передать несколько lvalues ​​в качестве атрибутов вывода получателей. 1, 2

Смотреть это живой demo on Coliru (link)

Там целая много магии происходит, что на практике приводит к моему эмпирическому правилу:

Избегайте использования семантических действий в Дух Ци выражения, если вы абсолютно не должны

У меня об этом раньше, в ответ конкретно об этом: Boost Spirit: "Semantic actions are evil"?

По моему опыту, это почти всегда чище использовать атрибут Customization очки, чтобы настроить автоматическое распространения, чем отказаться от правил авто и прибегать к ручному атрибуту обработки.


Что технически происходит распространять эти атрибуты, что num и parsed_str будет «привязан» ко всему выражению синтаксического анализа в виде последовательности Fusion:

fusion::vector2<unsigned&, std::string&> 

и открытой атрибут правила:

fusion::vector2<unsigned, std::vector<char> > 

будет «tr в соответствии с этим во время присвоения. Правила совместимости атрибутов позволяют это преобразование и многие другие.


В качестве альтернативы, используйте семантические действия для обоих:

bool ok = qi::phrase_parse(first, last, 
     (uint_ >> 'X' >> as_string [ lexeme[+graph] ]) 
      [ phx::ref(num) = _1, phx::ref(parsed_str) = _2 ], 
     blank); 

Там в несколько тонкостей здесь:

  • нам нужно as_string здесь, чтобы выставить атрибут, как std::string вместо std::vector<char> (см. Выше)

  • мы должны квалифицировать phx::ref(parsed_str), поскольку даже using boost::phoenix::ref не будет достаточно, чтобы неоднозначность std::ref и phx::ref: ADL будет тянуться в std::ref, так как он из того же пространства имен, как тип parsed_str.

  • группировать семантическое действие для предотвращения частично назначенных результатов, например. следующий будет перезаписывать num даже если X может отсутствовать на входе:

    bool ok = qi::phrase_parse(first, last, 
         uint_ [ phx::ref(num) = _1 ] 
        >> 'X' 
        >> as_string [ lexeme[+graph] ] [ phx::ref(parsed_str) = _1 ], 
        blank); 
    

Все эти сложности могут быть скрыты от вашего зрения, если вы избежать распространения вручную атрибутов!

+0

Есть ли чистое решение для принудительного использования правила «разделение одним или несколькими пробелами»? У меня это до сих пор: 'uint_ >> + no_skip [''] >> 'X' >> + no_skip [''] >> lexeme [+ graph]'. Что может быть лучше? – Arlen

+6

+1 для святой-основательности-батмана – Borgleader

+0

@Arlen Mmm: в репозитории Spirit имеется ['отчетный'] (http://www.boost.org/doc/libs/1_54_0/libs/spirit/repository/doc/ HTML/spirit_repository/qi_components/директивы/distinct.html). На днях кто-то попросил меня исправить его грамматику, и я предложил [быстрый и грязный oneliner, который может дать вам идею тоже] (https://github.com/sehe/streampunk/commit/4c68c37de2a64d4836f931fb779a4f90298cb606). Надеюсь, это поможет! – sehe