Я определил правило для идентификатора: начните с альфа-символа, за которым следует любое количество буквенно-цифровых символов. У меня есть разные результаты, когда я анализирую непосредственно в 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
в первом случае вложен в [[[.]]]
, а в правильном случае - [[.]]
. Но я не знаю, что с этим делать. :)
Почему такое поведение происходит?
Да, я придумал эту работу, а также вокруг. Хорошо бы перечислить здесь, но мне все еще любопытно, почему это косвенное действие необходимо. Я не вижу способ, которым значение struct может быть заполнено, не пройдя сначала 'std :: string'. Я дам это +1, как только появится полный ответ, но пока это только дополнительная информация. – GManNickG
Как сказано, вы разбираете последовательность символов, а не строку в духе, и поэтому ваш атрибут должен иметь свойства контейнера. –
Извините, я этого не покупаю. Атрибут должен быть 'tuple>', который конвертируется в 'vector ', который конвертируется в 'string'.Как Qi получает из 'tuple >' в мою структуру, не проходя через 'string'? Он не будет (или не должен) просто отбрасывать вторую половину кортежа. Не то чтобы вы ошибались (возможно, я просто плотный), но я ищу формальные причины, а не эвристику. –
GManNickG