In a foo_def.hpp
file for a Boost.Spirit X3 project, I have parsers:
auto const identifier_component_unrestricted =
lexeme[(alpha | '_') >> *(alnum | '_')];
auto const identifier_component_def =
((identifier_component_unrestricted - reserved_words) |
lexeme['"' >> identifier_component_unrestricted >> '"']);
The identifier_component
is parsed as a variant
but then collapses to a single std::string
.
How can I automatically convert the parsed identifier_component
into ALL CAPS when it is unquoted (first type in the variant) but keep the case untouched when it is quoted (second type in the variant)?
I've tried using semantic actions but haven't succeeded in getting something that works/compiles.
Edit: Thanks to rmawatson for the following solution.
Add file 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
In the original foo_def.hpp
just add the #include "to_upper.hpp"
and:
// 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 >> '"'];