Применить to_upper при разборе строк без кавычек - PullRequest
1 голос
/ 10 ноября 2019

В foo_def.hpp файле для проекта Boost.Spirit X3 у меня есть парсеры:

auto const identifier_component_unrestricted =
    lexeme[(alpha | '_') >> *(alnum | '_')];

auto const identifier_component_def =
    ((identifier_component_unrestricted - reserved_words) |
    lexeme['"' >> identifier_component_unrestricted >> '"']);

identifier_component анализируется как variant, но затем сворачивается в один std::string.

Как я могу автоматически преобразовать проанализированный identifier_component во ВСЕ ЗАГЛАВКИ, когда он не заключен в кавычки (первый тип в варианте), но сохранить регистр без изменений, когда он заключен в кавычки (второй тип в варианте)?

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


Редактировать : Благодаря rmawatson для следующего решения.

Добавить файл to_upper.hpp:

#pragma once

#include <boost/algorithm/string.hpp>

namespace parser {

using namespace boost::spirit::x3;

template <typename Subject>
struct ToUpperDirective : unary_parser<Subject, ToUpperDirective<Subject>> {
  using base_type = unary_parser<Subject, ToUpperDirective<Subject>>;
  using attribute_type = typename extension::as_parser<Subject>::value_type;
  static bool const has_attribute = true;
  using subject_type = Subject;

  ToUpperDirective(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 {
    auto result = this->subject.parse(first, last, context, rcontext, attr);
    boost::to_upper(attr);
    return result;
  }
};

struct ToUpper {
  template <typename Subject>
  ToUpperDirective<typename extension::as_parser<Subject>::value_type>
      operator[](Subject const& subject) const {
    return {as_parser(subject)};
  }
};

ToUpper const to_upper;

}  // namespace parser

В исходном foo_def.hpp просто добавить #include "to_upper.hpp" и:

// Convert unquoted identifier_components to upper case; keep quoted unchanged.
auto const identifier_component_def =
    to_upper[identifier_component_unrestricted - reserved_words] |
    lexeme['"' >> identifier_component_unrestricted >> '"'];

1 Ответ

1 голос
/ 11 ноября 2019

Оба они могут просто иметь атрибут std::string, без необходимости варианта.

Я думаю, что самый простой способ - это создать собственную директиву all_caps и просто заключить в кавычки альтернативуthis.

Что-то вроде ..

template <typename Subject>
struct all_caps_directive : x3::unary_parser<Subject, all_caps_directive<Subject>>
{
    using base_type = x3::unary_parser<Subject, all_caps_directive<Subject> >;
    using attribute_type = typename x3::extension::as_parser<Subject>::value_type;
    static bool const has_attribute = true;
    using subject_type = Subject;

    all_caps_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
    {
        auto result = this->subject.parse(first, last, context, rcontext, attr);
        boost::to_upper(attr);
        return result;
    }
};

struct all_caps_gen
{
    template <typename Subject>
    all_caps_directive<typename x3::extension::as_parser<Subject>::value_type>
        operator[](Subject const& subject) const
    {
        return { as_parser(subject) };
    }
};

auto const all_caps = all_caps_gen{};

Затем используйте его как

auto const identifier_component_def =
    (identifier_component_unrestricted |
    all_caps[lexeme['"' >> identifier_component_unrestricted >> '"']]);

Демо

В ответ наВаш комментарий для чего-то более простого, вот версия семантического действия. Я думаю, что это менее ясно и не так хорошо, как я.

 auto all_caps = []( auto &ctx )
        {
            boost::to_upper( x3::_attr(ctx));
            x3::_val(ctx) = x3::_attr(ctx);
        };

и использовать как ..

auto const identifier_component_def =
    (identifier_component_unrestricted |
    lexeme['"' >> identifier_component_unrestricted >> '"'][all_caps]);

Демо

...