X3 newbie here. Two questions:
- Why the result contains repeated "1,1,1"s, like so:
<attributes>[[1, 9, 2, ., 1, 6, 8, ., 1, 1, 1, ., 1, 1, 1], [8, 0]]</attributes>
, when I expect something like this<attributes>[[1, 9, 2, ., 1, 6, 8, ., 1, ., 1], [8, 0]]</attributes>
- What would be not-so-awkward way to define a single char to be expanded to (treated like ?) a sequence in dec_octet rule. I've used
x3::repeat(1)[x3::digit]
, but this seems wrong and probably causes errors of first question. (x3::repeat(1)[x3::digit]
is used because it seems I can'not just use x3::digit instead, because it would fail rule collapsing ?)
#include <iostream>
#include <string>
#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace x3 = boost::spirit::x3;
namespace ast
{
struct ip_port
{
std::string host;
boost::optional<std::string> port;
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::ip_port, host, port)
namespace parser
{
template <typename T> auto as = [](auto name, auto p) { return x3::rule<struct _, T> {name} = p; };
const auto dec_octet = as<std::string>("dec_octet",
(
x3::char_('2') >> x3::char_('5') >> x3::char_('0', '5')
| x3::char_('2') >> x3::char_('0', '4') >> x3::digit
| x3::char_('1') >> x3::digit >> x3::digit
| x3::char_('1', '9') >> x3::digit
| x3::repeat(1)[x3::digit] // awkward way to force sequence from single char, but can't use x3::digit
)
);
const auto ipv4address = as<std::string>("ipv4address",
dec_octet >> x3::char_('.') >> dec_octet >> x3::char_('.') >> dec_octet >> x3::char_('.') >> dec_octet
);
const auto ip = as<std::string>("host", ipv4address);
const auto port = as<std::string>("port", +x3::digit);
const auto ip_port = as<ast::ip_port>("ip_port", ip >> -((':') >> port));
}
template <typename T, typename Parser>
bool parse(const std::string& in, const Parser& p)
{
T parsed;
auto iter = in.begin();
auto end_iter = in.end();
bool res = x3::parse(iter, end_iter, p, parsed);
return res && (iter == end_iter);
}
int main()
{
std::cerr << std::boolalpha << parse<ast::ip_port>(std::string{"192.168.1.1:80"}, parser::ip_port) << '\n';
return EXIT_SUCCESS;
}
Debug output:
<ip_port>
<try>192.168.1.1:80</try>
<host>
<try>192.168.1.1:80</try>
<ipv4address>
<try>192.168.1.1:80</try>
<dec_octet>
<try>192.168.1.1:80</try>
<success>.168.1.1:80</success>
<attributes>[1, 9, 2]</attributes>
</dec_octet>
<dec_octet>
<try>168.1.1:80</try>
<success>.1.1:80</success>
<attributes>[1, 6, 8]</attributes>
</dec_octet>
<dec_octet>
<try>1.1:80</try>
<success>.1:80</success>
<attributes>[1, 1, 1]</attributes>
</dec_octet>
<dec_octet>
<try>1:80</try>
<success>:80</success>
<attributes>[1, 1, 1]</attributes>
</dec_octet>
<success>:80</success>
<attributes>[1, 9, 2, ., 1, 6, 8, ., 1, 1, 1, ., 1, 1, 1]</attributes>
</ipv4address>
<success>:80</success>
<attributes>[1, 9, 2, ., 1, 6, 8, ., 1, 1, 1, ., 1, 1, 1]</attributes>
</host>
<port>
<try>80</try>
<success></success>
<attributes>[8, 0]</attributes>
</port>
<success></success>
<attributes>[[1, 9, 2, ., 1, 6, 8, ., 1, 1, 1, ., 1, 1, 1], [8, 0]]</attributes>
</ip_port>
true
Thanks.