Как переписать парсеры qi с унаследованными атрибутами в x3?

Если унаследованные атрибуты используются в семантических действиях, мы можем использовать директиву x3::with.

Что, если мы хотим использовать атрибуты как часть парсера? Например, простой синтаксический анализатор сопоставляет 1 или более символов алфавита, кроме символа из набора параметров char.

qi::rule<std::string::const_iterator, qi::unused_type(char const*)> rule =
    +(qi::alpha - qi::char_(qi::_r1));

Или набор символов параметра можно использовать как ленивый синтаксический анализатор.

qi::rule<std::string::const_iterator, qi::unused_type(char const*)> rule =
    +(qi::alpha - qi::lazy(qi::_r1));

Директива x3::with помещает это локальное значение в контекст. Я не уверен, что мы могли бы использовать этот контекст вне семантического действия и в конечном итоге сгенерировать синтаксический анализатор.


person Han    schedule 31.03.2017    source источник


Ответы (1)


Просто отпустите старую привычку все регламентировать.

#include <boost/spirit/home/x3.hpp>
#include <iostream>

namespace x3 = boost::spirit::x3;

template <typename... Args>
auto negate(Args&&... p) {
    return +(x3::char_ - x3::char_(std::forward<Args>(p)...));
};

int main() {
    std::string input("all the king's men and all the king's horses"), parsed;
    if (parse(input.begin(), input.end(), negate("horse"), parsed))
        std::cout << "'" << input << "' -> '" << parsed << "'\n";
}

Прямой эфир на Coliru, печатает:

'all the king's men and all the king's horses' -> 'all t'

Второй вкус:

#include <boost/spirit/home/x3.hpp>
#include <iostream>

namespace x3 = boost::spirit::x3;

template <typename Sub>
auto negate(Sub p) {
    return +(x3::char_ - x3::as_parser(p));
};

int main() {
    std::string input("all the king's men and all the king's horses"), parsed;
    if (parse(input.begin(), input.end(), negate("horse"), parsed))
        std::cout << "'" << input << "' -> '" << parsed << "'\n";
}

Жить на Coliru, печатает:

'all the king's men and all the king's horses' -> 'all the king's men and all the king's '

Более сложные вещи

Вы также можете агрегировать подпарсеры в пользовательском парсере:

Если вам нужны ресурсивные правила с обходом, я бы предложил x3::with<> (хотя я не уверен, что контексты создают повторно-входное состояние для with<>, вам нужно проверить точную семантику, если вы не можете найти для нее документацию)

person sehe    schedule 31.03.2017