Разбор с Boost :: Spirit (V2.4) в контейнер - PullRequest
2 голосов
/ 12 октября 2010

Я только начал копаться в Boost :: Spirit, последняя версия к настоящему времени - V2.4.Суть моей проблемы заключается в следующем:

Я бы хотел разобрать строки типа "1a2" или"3b4".Таким образом, я использую правило:

  (double_ >> lit('b') >> double_)
| (double_ >> lit('a') >> double_);

Атрибутом правила должно быть «вектор ».И я читаю его в контейнер.

Полный код:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <cstring>

int main(int argc, char * argv[])
{
    using namespace std;
    using namespace boost::spirit;
    using namespace boost::spirit::qi;
    using boost::phoenix::arg_names::arg1;

    char const * first = "1a2";
    char const * last  = first + std::strlen(first);
    vector<double> h;

    rule<char const *, vector<double>()> or_test;
    or_test %=    (double_ >> lit('b') >> double_) 
            | (double_ >> lit('a') >> double_);

    if (parse(first, last, or_test,h)) {
           cout << "parse success: "; 
           for_each(h.begin(), h.end(), (cout << arg1 << " "));
           cout << "end\n";
    } else cout << "parse error\n" << endl;
    return 0;
 }

Я компилирую его с помощью g ++ 4.4.3.И он возвращает «1 1 2».Хотя я ожидаю «1 2».

Насколько я понимаю, это происходит потому, что парсер:

  • переходит к первому варианту
  • читает double_ и сохраняет егов контейнере
  • затем останавливается на «а», ожидая, что горит («b»)
  • переходит ко второму варианту
  • читает еще два двойных

Мой вопрос - это правильное поведение, и если да, то почему?

1 Ответ

4 голосов
/ 12 октября 2010

Это ожидаемое поведение. Во время возврата Дух не «отменяет» изменения атрибутов. Следовательно, вы должны использовать директиву hold[], явно заставляющую анализатор удерживать копию атрибута (позволяющую откатить любое изменение атрибута):

or_test =    
        hold[double_ >> lit('b') >> double_)]
    |   (double_ >> lit('a') >> double_)
    ; 

Эта директива должна применяться ко всем альтернативам, изменяющим атрибут, кроме последнего.

...