2014-10-26 2 views
4

У меня есть qi::symbol<char, std::string>escapedDoubleQuote, который преобразует двойной "" в \".boost :: spirit: как написать парсер, который анализирует 2 строки и объединить их в одну?

Я пытаюсь использовать это в более сложном синтаксическом анализаторе и хочу, чтобы результат оставался одной строкой. Но не получилось. Я пробовал с и без qi::lexeme, qi::as_string и qi::as<std::string>.

#include <iostream> 
#include <boost/spirit/home/qi.hpp> 
#include <vector> 
#include <string> 

namespace qi = boost::spirit::qi; 
namespace ascii = boost::spirit::ascii; 

struct escapedDoubleQuote_ : qi::symbols<char, std::string > 
{ 
    escapedDoubleQuote_() 
    { 
     add("\"\"", "\\\""); 
    } 
} escapedDoubleQuote; 

template<typename Iterator> 
struct MyGrammar : qi::grammar<Iterator, std::string()> 
{ 
    MyGrammar() : MyGrammar::base_type(escapedField) 
    { 
     subField = +(~qi::char_("\"")); 
     escapedField = 
       qi::lexeme[ // or qi::as<std::string> ... both seems to do nothing. 
        subField 
        >> -(escapedDoubleQuote >> escapedField) 
       ]; 
    } 

    qi::rule<Iterator, std::string()> subField; 
    qi::rule<Iterator, std::string()> escapedField; 
}; 

int main() 
{ 
    typedef std::string::const_iterator iterator_type; 
    typedef MyGrammar<iterator_type> parser_type; 
    parser_type parser; 

    std::string input = "123\"\"456\"\"789"; 
    std::string output; 
    iterator_type it = input.begin(); 
    bool parsed = parse(
      it, 
      input.cend(), 
      parser, 
      output 
    ); 

    if(parsed && it == input.end()) 
    { 
     std::cout << output << std::endl; 
     // expected: 123\"456\"789 
     // actual : \"789 
    } 

    return 0; 
} 

В конце концов, я хочу использовать анализатор и иметь выход один std::string. В примере 123\"\"456\"\"789 должен выводиться номер 123\"456\"789.


Примечание: Я знаю, что могу определить escapedDoubleQuote, как qi::symbols<char, std::vector<char> > так, что результат будет достигнут, но я хочу понять, если и как можно объединить строки.

+0

Когда вы «назначаете контейнер из значения», и оба контейнера и значения одного типа, Дух перезаписывает контейнер со значением (см. «boost/spirit/home/qi/detail/assign_to.hpp "поиск' struct assign_to_container_from_value <Атрибут, Атрибут> '). Если вы используете 'vector ' в «символах», типы не совпадают, а другой путь выбран, чтобы достичь «void append_to_string (Attribute & attr, Iterator begin, Iterator end)», который делает то, что вы ожидаете. [Этот хак] (http://coliru.stacked-crooked.com/a/97d43835f2dc1123) обходит проблему, но может сломать что-то еще. – llonesmiz

+0

@cv_and_he Да, это выглядит слишком хаки. Лично я не буду трогать черты встроенных типов. Хорошее место на включении, хотя/cc OP: обратите внимание! – sehe

ответ

0

Как было предложено @cv_and_he, «атомарное» поведение назначения связано с преобразованием открытого типа атрибута (std::vector<char>) в std::string.

В частности, речь идет о заявленной атрибуте escapedField, потому что, когда она рекурсивно вызывается, он создает несовместимые синтезируемые комбинации атрибутов: [std::vector<char>, std::string, std::string]

Если вы можете сохранить атрибуты «равно» вы исправить проблему:

MyGrammar() : MyGrammar::base_type(start) 
{ 
    subField  = +(~qi::char_("\"")); 
    escapedField = subField >> -(escapedDoubleQuote >> escapedField); 
    start  = escapedField; 
} 

qi::rule<Iterator, std::vector<char>()> subField, escapedField; 
qi::rule<Iterator, std::string()> start; 

Посмотреть Live On Coliru

(я удалил lexeme потому что вы были нет шкипера в примере кода, см. Boost spirit skipper issues)

+0

Обратите внимание, что если вы добавите атрибут 'символы'' vector '[он не работает снова] (http://coliru.stacked-crooked.com/a/ddffd0e029be59c1). Таким образом, он работает только тогда, когда атрибуты в каждой конкатенации различны (в вашем случае у вас есть вектор vector , который объединяется с результатом 'string' и' vector ', который является' string'). Я думаю, что это ошибка, но я действительно не уверен, возможно, это необходимо в другом случае. – llonesmiz

+0

@cv_and_he ooh. Вы совершенно правы. Это раздражает. Я оставлю его в ОП, хочет ли он сообщить об этом в списке рассылки [spirit-general]. – sehe

+0

hm, так что нет реального решения (пока)? Я не понимаю внутренности boost :: spirit достаточно, чтобы сказать, что это ошибка или предполагаемое поведение. –

 Смежные вопросы

  • Нет связанных вопросов^_^