解析不带引号的字符串时应用 to_upper
Apply to_upper when parsing unquoted strings
在 Boost.Spirit X3 项目的 foo_def.hpp
文件中,我有解析器:
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
转换为全部大写,但在加引号时(变体中的第二种类型)保持大小写不变?
我尝试过使用语义操作,但没有成功获得 works/compiles。
编辑:感谢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]);
在 Boost.Spirit X3 项目的 foo_def.hpp
文件中,我有解析器:
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
转换为全部大写,但在加引号时(变体中的第二种类型)保持大小写不变?
我尝试过使用语义操作,但没有成功获得 works/compiles。
编辑:感谢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]);