2013-08-10 4 views
3

Я определил правило для идентификатора: начните с альфа-символа, за которым следует любое количество буквенно-цифровых символов. У меня есть разные результаты, когда я анализирую непосредственно в std::string по сравнению с адаптированной структурой, содержащей один std::string.Почему Boost.Spirit правильно анализирует идентификатор в std :: string, но не в адаптированную структуру, состоящую исключительно из std :: string?

Если атрибут для моей грамматики равен std::string, Qi правильно адаптирует последовательность символов в нее. Но со структурой сохраняется только первый символ. Я не совсем понимаю, почему это так. (Обратите внимание, что это не имеет никакого значения, если структура будет «действительно» адаптированный, или если он был определен Fusion инлайн.)

Вот SSCCE, конфигурируемый для отладки:

// Options: 
//#define DEFINE_STRUCT_INLINE 
//#define DEBUG_RULE 

#define BOOST_SPIRIT_USE_PHOENIX_V3 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 

#include <boost/fusion/adapted/struct/define_struct_inline.hpp> 
#include <boost/fusion/include/define_struct_inline.hpp> 

#include <boost/fusion/adapted/struct/adapt_struct.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 

#include <iostream> 
#include <string> 

namespace qi = boost::spirit::qi; 

#ifdef DEFINE_STRUCT_INLINE 
    namespace example 
    { 
     BOOST_FUSION_DEFINE_STRUCT_INLINE(
      identifier_result, 
      (std::string, name) 
      ) 
    } 
#else 
    namespace example 
    { 
     struct identifier_result 
     { 
      std::string name; 
     }; 
    } 

    BOOST_FUSION_ADAPT_STRUCT(
     example::identifier_result, 
     (std::string, name) 
     ) 
#endif 

namespace example 
{ 
    typedef std::string identifier_result_str; 

    template <typename Iterator, typename Result> 
    struct identifier_parser : qi::grammar<Iterator, Result()> 
    { 
     identifier_parser() : 
     identifier_parser::base_type(identifier, "identifier_parser") 
     { 
      identifier %= 
       qi::alpha >> 
       *qi::alnum 
       ; 

      identifier.name("identifier"); 

      #ifdef DEBUG_RULE 
       debug(identifier); 
      #endif 
     } 

     qi::rule<Iterator, Result()> identifier; 
    }; 
} 

std::string strip(example::identifier_result identifier) 
{ 
    return identifier.name; 
} 

std::string strip(std::string str) 
{ 
    return str; 
} 

template <typename Result> 
void test_parse(const std::string& input) 
{ 
    using namespace example; 

    auto&& first = input.cbegin(); 
    auto&& last = input.cend(); 

    auto&& parser = identifier_parser<std::string::const_iterator, Result>(); 
    auto&& skipper = qi::space; 

    Result result; 
    qi::phrase_parse(first, last, parser, skipper, result); 

    std::cout << "Result of the parse is: \'" 
       << strip(result) << "\'" << std::endl; 
} 

int main() 
{ 
    using namespace example; 

    test_parse<identifier_result>(" validId1 "); 
    test_parse<identifier_result>(" %error1% "); 

    test_parse<identifier_result_str>(" validId2 "); 
    test_parse<identifier_result_str>(" %error2% "); 
} 

Выход:

Результат синтаксического анализа является: «v»
Результат синтаксического анализа является: «»
Результат синтаксического анализа является: «» validId2
Результат синтаксического анализа является: «»

Как и ожидалось, оба случая ошибок не совпадают. Но в первом случае моя структура захватывает только первый символ. Я хотел бы сохранить структуру для целей организации.

Если я отлаживать узел, я получаю этот выход:

<identifier> 
    <try>validId1 </try> 
    <success> </success> 
    <attributes>[[[v]]]</attributes> 
</identifier> 

[ ... ] 

<identifier> 
    <try>validId2 </try> 
    <success> </success> 
    <attributes>[[v, a, l, i, d, I, d, 2]]</attributes> 
</identifier> 

Так что я могу видеть это правило потребляя весь идентификатор, он просто не хранить его правильно. Единственный «намек», который у меня есть на разнице, заключается в том, что v в первом случае вложен в [[[.]]], а в правильном случае - [[.]]. Но я не знаю, что с этим делать. :)

Почему такое поведение происходит?

ответ

4

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

Я не знаю точное объяснение, но то, что вы хотите сделать, это разбор строки с последовательностью парсеров char. С string как тип атрибута qi может использовать атрибут в качестве контейнера для хранения нескольких символов, а структура просто не знает, как это сделать. Возможно, это поможет предоставить свойства контейнера структуры, но у меня нет опыта здесь. И для просто синтаксического анализа строки, которая может быть переполнена.

Просто изменяя ваш парсер помогает здесь:

namespace example 
{ 
    typedef std::string identifier_result_str; 

    template <typename Iterator, typename Result> 
    struct identifier_parser : qi::grammar<Iterator, Result()> 
    { 
     identifier_parser() : 
     identifier_parser::base_type(identifier, "identifier_parser") 
     { 
      string %= 
       qi::alpha >> 
       *qi::alnum 
       ; 

      identifier = string; 
      identifier.name("identifier"); 

      #ifdef DEBUG_RULE 
       debug(identifier); 
      #endif 
     } 

     qi::rule<Iterator, Result()> identifier; 
     qi::rule<Iterator, std::string()> string; 
    }; 
} 
+0

Да, я придумал эту работу, а также вокруг. Хорошо бы перечислить здесь, но мне все еще любопытно, почему это косвенное действие необходимо. Я не вижу способ, которым значение struct может быть заполнено, не пройдя сначала 'std :: string'. Я дам это +1, как только появится полный ответ, но пока это только дополнительная информация. – GManNickG

+0

Как сказано, вы разбираете последовательность символов, а не строку в духе, и поэтому ваш атрибут должен иметь свойства контейнера. –

+0

Извините, я этого не покупаю. Атрибут должен быть 'tuple >', который конвертируется в 'vector ', который конвертируется в 'string'.Как Qi получает из 'tuple >' в мою структуру, не проходя через 'string'? Он не будет (или не должен) просто отбрасывать вторую половину кортежа. Не то чтобы вы ошибались (возможно, я просто плотный), но я ищу формальные причины, а не эвристику. – GManNickG

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

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