Как получить строку из парсера лексем Boost Spirit X3?

Каков самый простой способ сделать семантическое действие, которое извлекает строку из типичного синтаксического анализатора идентификаторов на основе boost::spirit::x3::lexeme?

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

Следующее дает output пустым. Я ожидал, что он будет содержать «foobar_hello».

namespace x3 = boost::spirit::x3;

using x3::_where;
using x3::lexeme;
using x3::alpha;

auto ctx_to_string = [&](auto& ctx) {
    _val(ctx) = std::string(_where(ctx).begin(), _where(ctx).end());
};

x3::rule<class identifier_rule_, std::string> const identifier_rule = "identifier_rule";
auto const identifier_rule_def = lexeme[(x3::alpha | '_') >> *(x3::alnum | '_')][ctx_to_string];
BOOST_SPIRIT_DEFINE(identifier_rule);

int main()
{
    std::string input = "foobar_hello";

    std::string output;
    auto result = x3::parse(input.begin(), input.end(), identifier_rule, output);
}

Нужно ли как-то извлекать строку из объектов boost::fusion в x3::_attr(ctx) или я что-то не так делаю?


person jwezorek    schedule 15.01.2020    source источник


Ответы (1)


Вы можете просто использовать автоматическое распространение атрибутов, что означает, что вам не нужно семантическое действие (1)

Жить на Coliru

#include <iostream>
#include <iomanip>
#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;

namespace P {
    x3::rule<class identifier_rule_, std::string> const identifier_rule = "identifier_rule";
    auto const identifier_rule_def = x3::lexeme[(x3::alpha | x3::char_('_')) >> *(x3::alnum | x3::char_('_'))];
    BOOST_SPIRIT_DEFINE(identifier_rule)
}

int main() {
    std::string const input = "foobar_hello";

    std::string output;
    auto result = x3::parse(input.begin(), input.end(), P::identifier_rule, output);
}

Отпечатки

<identifier_rule>
  <try>foobar_hello</try>
  <success></success>
  <attributes>[f, o, o, b, a, r, _, h, e, l, l, o]</attributes>
</identifier_rule>

Примечание. Я изменил '_' на x3::char_('_'), чтобы захватить символы подчеркивания (x3::lit не фиксирует то, что соответствует)

Если вы настаиваете на смысловых действиях,

  • рассмотрите возможность использования rule<..., std::string, true> для также принудительного автоматического распространения атрибутов
  • не думайте, что _where указывает на то, на что вы надеетесь: http://coliru.stacked-crooked.com/a/336c057dabc86a84
  • #P6#
    auto ctx_to_string = [](auto& ctx) {
        std::cout << "\nSA: '" << _attr(ctx) << "'" << std::endl;
        _val(ctx) = std::string(_attr(ctx).begin(), _attr(ctx).end());
    };
    
    x3::rule<class identifier_rule_, std::string> const identifier_rule = "identifier_rule";
    auto const identifier_rule_def = x3::raw[ lexeme[(x3::alpha | '_') >> *(x3::alnum | '_')] ] [ctx_to_string];
    BOOST_SPIRIT_DEFINE(identifier_rule)
    
    <блочная цитата> #P7#
  • рассмотрите возможность использования встроенных помощников атрибутов: http://coliru.stacked-crooked.com/a/3e3861330494e7c9

    auto ctx_to_string = [](auto& ctx) {
        using x3::traits::move_to;
        move_to(_attr(ctx), _val(ctx));
    };
    

    Обратите внимание, что это приближается к встроенному распространению атрибутов, хотя это гораздо менее гибко, чем позволить Spirit управлять им.

(1) обязательная ссылка: Boost Spirit: семантические действия - зло?

person sehe    schedule 16.01.2020
comment
Похоже, что семантические действия необходимы, если ваши выходные структуры не используют композицию на основе типов значений. Моя проблема сейчас в том, что это была минимальная воспроизводимая версия моей проблемы. Почему мне нужно семантическое действие, так это то, что я хочу динамически выделять объект класса T, используя строку, и чтобы shared_ptr‹T› был атрибутом правила. Я могу сделать это, используя распространение атрибутов с помощью двух правил и одного семантического действия, но это кажется многословным. Есть ли способ заставить дух сворачивать атрибуты в заданный тип до того, как будет вызвано семантическое действие? - person jwezorek; 16.01.2020
comment
О shared_ptr и т.п. см. те же предостережения, что и для Qi. Я думаю, вам нужен подход с двумя правилами, чтобы получить атрибут coercion. Вы можете обмануть и использовать этот трюк с as<> или, как вы знаете, make_shared<> в том же духе, что и здесь: stackoverflow.com/a/43093437/ 85371 - person sehe; 16.01.2020
comment
спасибо, ваш шаблон as‹› позволяет мне удалить несколько вспомогательных правил. авторы X3 философски против добавления его в Spirit, я так понимаю? - person jwezorek; 17.01.2020