Я пытаюсь написать boost::uuids::uuid
синтаксический анализатор с boost::spirit::qi
, чтобы использовать его хорошо с другими qi
синтаксическими анализаторами и получить хороший унифицированный API синтаксического анализатора.
Моей первой идеей было написать пользовательский qi::grammar
, который бы использовал boost::conversion::try_lexical_convert<boost::uuids::uuid &, const std::string &>
, однако при этом возникла бы проблема с правильной установкой начального итератора в занятую позицию, поскольку boost::conversion::try_lexical_convert<boost::uuids::uuid &, const std::string &>
не только соответствовал бы вводу длиной 16 символов но также с закрывающими скобками или без черточек.
Мой второй подход - использовать boost::spirit::qi::rule
(или CRTP грамматики, полученный из boost::spirit::qi::grammar::base_type
, если хотите), но затем я получил ошибки компиляции, вероятно, из выражения BOOST_FUSION_ADAPT_STRUCT
:
#include <iostream>
#include <string>
#include <cstdint>
#include <boost/uuid/uuid.hpp>
#include <boost/spirit/include/qi.hpp>
BOOST_FUSION_ADAPT_STRUCT(
boost::uuids::uuid,
(uint8_t, data[0])
(uint8_t, data[1])
(uint8_t, data[2])
(uint8_t, data[3])
(uint8_t, data[4])
(uint8_t, data[5])
(uint8_t, data[6])
(uint8_t, data[7])
(uint8_t, data[8])
(uint8_t, data[9])
(uint8_t, data[10])
(uint8_t, data[11])
(uint8_t, data[12])
(uint8_t, data[13])
(uint8_t, data[14])
(uint8_t, data[15])
)
template<typename Iterator>
boost::spirit::qi::rule<Iterator, boost::uuids::uuid>
uuid_internal_{
boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
//time-low
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> -boost::spirit::qi::lit("-")
//time-mid
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> -boost::spirit::qi::lit("-")
//time-high-and-version
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> -boost::spirit::qi::lit("-")
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>() //clock-seq-and-reserved
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>() //clock-seq-low
>> -boost::spirit::qi::lit("-")
//node
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
};
template<typename Iterator>
struct uuid_
: ::boost::spirit::qi::grammar<Iterator, boost::uuids::uuid()>{
uuid_() : uuid_::base_type(start) {
start %= (boost::spirit::qi::lit("{") >> uuid_internal_ >> boost::spirit::qi::lit("}")) |
uuid_internal_ ;
}
boost::spirit::qi::rule<Iterator, boost::uuids::uuid()> start;
boost::spirit::qi::rule<Iterator, boost::uuids::uuid()>
uuid_internal_{
boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
//time-low
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> -boost::spirit::qi::lit("-")
//time-mid
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> -boost::spirit::qi::lit("-")
//time-high-and-version
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> -boost::spirit::qi::lit("-")
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>() //clock-seq-and-reserved
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>() //clock-seq-low
>> -boost::spirit::qi::lit("-")
//node
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
>> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
};
};
int main() {
std::string input;
std::cin >> input;
uuid_<std::string::const_iterator> uuid_{};
boost::uuids::uuid uuid{};
auto begin = input.begin(), end = input.end();
const bool success = boost::spirit::qi::parse(begin, end, uuid_, uuid);
if (!success || begin != end)
throw std::runtime_error("Parsing failed");
return 0;
}
/ opt / local / include / boost / spirit / home / support / container.hpp: 292: 15: ошибка: нет элемента с именем 'insert' в 'boost :: uuids :: uuid'
c.insert (c.end (), val);
Кажется, что был выпущен сгенерированным boost::spirit::qi::detail::pass_through_container
, однако мой подход с BOOST_FUSION_ADAPT_ADT
в сочетании с *(obj.begin()+n)
также не удался с несколькими ошибками.