Парсер Boost.Spirit не соответствует

Мне трудно понять, почему следующий синтаксический анализатор не может проанализировать test. После вызова qi::phrase_parse, result истинно, it2 указывает на конец строки, но mynr по-прежнему 0:

std::string test = "#define   SOMEMACRO 8.0";
  auto it2 = test.begin();
  auto endIt2 = test.end();
  double mynr = 0;
  bool result = 
    qi::phrase_parse(
      it2, 
      endIt2, 
      ("#define" >> (*qi::alnum) >> qi::double_[ref(mynr) = qi::_1]), 
      qi::space);

Я подозреваю, что это как-то связано с qi::alnum и пропуском пробелов.

Я попытался свести корпус к отдельным компонентам. Я проверил эти три парсера по отдельности и обнаружил, что:

  • "#define" действительно потребляет "#define"
  • (*qi::alnum) может потреблять SOMEMACRO
  • qi::double_ может потреблять 8.0

По отдельности каждый парсер работает нормально, но вместе взятые в приведенной выше форме работают странно. Дальнейшие небольшие тесты, казалось, показали мне (*qi::alnum), когда я использую его так, как я использую, кажется, что он потребляет больше, чем просто SOMEMACRO, но и остальная часть строки тоже.


person Ed Rowlett-Barbu    schedule 22.03.2013    source источник


Ответы (1)


Ваши обновления действительно заставили меня понять, что происходит. И вы правы, *alnum ест больше, чем вы хотите.

("#define" >> lexeme[*qi::alnum] >> (qi::double_)[boost::phoenix::ref(mynr) = boost::spirit::_1])

Это работает.

*alnum использует буквенно-цифровые символы и пропускает пробелы между ними. Так что он на самом деле съел SOMEMACRO 8. Затем, когда я предположил, что это сработало при употреблении 8.0 в конце, это произошло потому, что двойной синтаксический анализатор потреблял .0.

Новый синтаксический анализатор наверху требует, чтобы в *alnum не было пробелов в середине.

Вот что нужно знать о грамматике:

  1. Я включил семантическое действие для хранения значения типа double. Он хранит его в двойном формате mynr.
  2. Я завернул *alnum в _ 10_. Это заставляет синтаксический анализатор не пропускать символы внутри.
  3. С этой правильной грамматикой он может анализировать "#define SOMEMACRO 8.0" и "#define SOMEMACRO 8"
person Bill Lynch    schedule 22.03.2013
comment
Я попробовал, и он действительно потребляет всю строку, когда вместо этого используется 8.0. Однако я не думаю, что он разбирает его так, как я ожидал. Я обновил свой вопрос своими выводами. - person Ed Rowlett-Barbu; 22.03.2013
comment
Ваше семантическое действие должно быть: [boost::phoenix::ref(mynr) = boost::spirit::_1]. - person Bill Lynch; 22.03.2013
comment
Теперь это правильно для меня, я пропустил, что * alnum также делал предварительные пропуски. - person Bill Lynch; 22.03.2013
comment
Что это значит, что он пропускает? Означает ли это, что он использует параметр пропуска в parse_phrase, чтобы пропустить то, что предшествует alnum char? Кроме того, почему было необходимо eps? Потому что eps не делает предварительных запросов? - person Ed Rowlett-Barbu; 22.03.2013
comment
Итак, я немного изменил его, чтобы упростить. lexeme в этом случае работает лучше, чем no_skip. Я попытаюсь объяснить и то, и другое. В вашем исходном случае ваша грамматика была такой же, как *space >> #define >> *space >> *(*space >> alnum) >> *space >> double >> *space. Мы хотели преобразовать это в область #define >> *space >> *alnum >> *space >> double >> *space. Note that the only difference is the * alnum`. Лексема вызывает это изменение. - person Bill Lynch; 22.03.2013
comment
позвольте нам продолжить обсуждение в чате - person Bill Lynch; 22.03.2013