c++17 - 解析不带引号的字符串时应用 to_upper
问题描述
在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
解析为 avariant
但随后折叠为单个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 >> '"'];
解决方案
这两个都可以只有一个std::string
属性,而不需要变体。
我认为最简单的方法可能是创建自己的all_caps
指令并将引用的替代方案包装在其中。
就像是..
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]);