Boost Spirit: как подсчитать вхождения определенных персонажей и затем поместить результат в AST? - PullRequest
0 голосов
/ 10 января 2019

Я бы хотел разобрать следующий текст:

group RGB
group RRGB
group GBBB
group RRGGG

Результирующий AST будет структурой, которая представляет количество каждого символа:

struct group
{
    int r;
    int g;
    int b;
};

Для входов выше это будет 1,1,1, 2,1,1, 0,1,3, 2,3,0.

Я не могу прийти с какой-либо грамматикой, которая бы удобно подсчитывала символы и обеспечивала их порядок (GBR должен не выполнять синтаксический анализ).

https://www.boost.org/doc/libs/develop/libs/spirit/doc/x3/html/spirit_x3/quick_reference/directive.html

Существует парсер x3::repeat, но он содержит только определенное количество символов, его атрибут является контейнером.

x3::matches[a] имеет атрибут bool, но я не знаю, сколько раз персонаж может появляться

Нет парсера, который бы считал появление и возвращал количество совпадений. Мне нужна грамматика типа x3::lit("group") >> count['R'] >> count['G'] >> count['B'], но я не знаю, как определить count.

На данный момент единственным рабочим решением, о котором я могу подумать, будет x3::lit("group") >> (*x3::char_['R'] >> *x3::char_['G'] >> *x3::char_['B'])[func], который затем вызывает func, который будет просто работать со строкой. ИМО, это не чистое решение, оно требует семантических действий и создает ненужные строки.

1 Ответ

0 голосов
/ 10 января 2019

Слегка модифицировав "x3 / directive / match.hpp", вы можете получить что-то вроде этого:

#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>

namespace not_boost { namespace not_spirit { namespace not_x3
{
    template <typename Subject>
    struct count_directive : boost::spirit::x3::unary_parser<Subject, count_directive<Subject>>
    {
        using base_type = boost::spirit::x3::unary_parser<Subject, count_directive<Subject>>;
        static bool const has_attribute = true;
        using attribute_type = int;

        count_directive(Subject const& subject) : base_type(subject) {}

        template <typename Iterator, typename Context
          , typename RContext, typename Attribute>
        bool parse(Iterator& first, Iterator const& last
          , Context const& context, RContext& rcontext, Attribute& attr) const
        {
            int count=0;
            while(this->subject.parse(first, last, context, rcontext, boost::spirit::x3::unused))
            {
                count++;
            }
            boost::spirit::x3::traits::move_to(count, attr);
            return true;
        }
    };

    struct count_gen
    {
        template <typename Subject>
        count_directive<typename boost::spirit::x3::extension::as_parser<Subject>::value_type>
        operator[](Subject const& subject) const
        {
            return { boost::spirit::x3::as_parser(subject) };
        }
    };

    auto const count = count_gen{};
}}}

Работает на Wandbox

...