如何在错误消息 'distinct' 可能的符号中获得提升精神?
how to get boost spirit build in error message 'distinct' possible symbols?
我有一个规则集条目的关键字语法。
下面的一些伪代码.. 如果有人现在写“XPUBLIC”作为输入,解析器会在 'boost::spirit::qi::expectation_failureparser::Iterator::what_' 的捕获处理程序中创建一个 'distinct' 异常。
这没关系,但解析器也可以 return 该节点的可能条目列表。 on_error 处理程序也获得相等的输入。有没有办法在解析器失败时获取可能的条目符号?在这个示例中,我喜欢得到“PUBLIC”,“PRIVATE”..
#define nocaselit(p) distinct(boost::spirit::standard_wide::alnum | L'_')[no_case[p]]
rule=
nocaselit(L"PUBLIC")
| nocaselit(L"PRIVATE")
| nocaselit(L"PROTECTED")
| nocaselit(L"SHARED")
当我们简化情况以跳过 distinct
指令时,这就是您可以从预期失败中处理 info
以提取备选方案的方法:
#include <boost/spirit/include/qi.hpp>
namespace enc = boost::spirit::standard_wide;
namespace qi = boost::spirit::qi;
using It = std::wstring::const_iterator;
#define kw(p) qi::lit(p)
int main() {
qi::rule<It> rule;
rule
= qi::eps >
( kw(L"PUBLIC")
| kw(L"PRIVATE")
| kw(L"PROTECTED")
| kw(L"SHARED")
)
;
for (std::wstring const input : {
L"PUBLIC",
L"PRIVATE",
L"PROTECTED",
L"SHARED",
L"XPUBLIC", // obviously no match
L"PUBLICX", // actually test of distinct
})
try {
It f = begin(input), l = end(input);
auto ok = qi::parse(f, l, rule);
std::wcout << input << " " << std::boolalpha << ok << std::endl;
} catch(qi::expectation_failure<It> const& ef) {
auto value = ef.what_.value;
auto elements = boost::get<std::list<boost::spirit::info> >(value);
std::ostringstream oss;
oss << ef.what_.tag << "(";
for (auto el : elements) oss << " " << el;
oss << " )";
std::wcout << input << " -> Expected " << oss.str().c_str() << std::endl;
}
}
版画
PUBLIC true
PRIVATE true
PROTECTED true
SHARED true
XPUBLIC -> Expected alternative( "PUBLIC" "PRIVATE" "PROTECTED" "SHARED" )
PUBLICX true
Note that the internals of spirit::info
assume std::string
in UTF8 encoding. I'm not overly explicit here with codecvt facets. I'll leave a reliable conversion to wide strings as an exercise to the reader.
与distinct()
天真的方法将导致此输出:
PUBLIC true
PRIVATE true
PROTECTED true
SHARED true
XPUBLIC -> Expected alternative( <distinct> <distinct> <distinct> <disti
nct> )
PUBLICX -> Expected alternative( <distinct> <distinct> <distinct> <disti
nct> )
遗憾的是,这可能不是您想要的。更糟糕的是,这也在存储库指令中进行了硬编码:
template <typename Context>
info what(Context& /*ctx*/) const
{
return info("distinct");
}
如果我们可以只需将其更改为:
template <typename Context>
info what(Context& ctx) const
{
return info("distinct", subject.what(ctx));
}
我们本来可以解决问题的。为了不过多影响库的实现细节,让我们将 distinct
指令子类化为 my_distinct
到:
template <typename Subject, typename Tail, typename Modifier>
struct my_distinct_parser
: distinct_parser<Subject, Tail, Modifier>
{
using distinct_parser<Subject, Tail, Modifier>::distinct_parser;
template <typename Context> info what(Context& ctx) const {
return info("my_distinct", this->subject.what(ctx));
}
};
遗憾的是,我们需要更多的繁文缛节来让解析器编译和组合机制注册:
my_distinct.hpp
#pragma once
#include <boost/spirit/repository/home/qi/directive/distinct.hpp>
namespace boost::spirit::repository {
BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(( my_distinct, my_distinct_type ))
}
namespace boost::spirit {
template <typename Tail>
struct use_directive<qi::domain
, terminal_ex<repository::tag::my_distinct, fusion::vector1<Tail> > >
: mpl::true_ {};
template <>
struct use_lazy_directive<qi::domain, repository::tag::my_distinct, 1>
: mpl::true_ {};
}
namespace boost::spirit::repository::qi {
using repository::my_distinct;
using repository::my_distinct_type;
template <typename Subject, typename Tail, typename Modifier>
struct my_distinct_parser
: distinct_parser<Subject, Tail, Modifier>
{
using distinct_parser<Subject, Tail, Modifier>::distinct_parser;
template <typename Context> info what(Context& ctx) const {
return info("my_distinct", this->subject.what(ctx));
}
};
}
namespace boost::spirit::qi {
template <typename Tail, typename Subject, typename Modifiers>
struct make_directive<
terminal_ex<repository::tag::my_distinct, fusion::vector1<Tail> >
, Subject, Modifiers>
{
typedef typename result_of::compile<qi::domain, Tail, Modifiers>::type
tail_type;
typedef repository::qi::my_distinct_parser<
Subject, tail_type, Modifiers> result_type;
template <typename Terminal>
result_type operator()(Terminal const& term, Subject const& subject
, Modifiers const& modifiers) const
{
return result_type(subject
, compile<qi::domain>(fusion::at_c<0>(term.args), modifiers));
}
};
}
namespace boost::spirit::traits {
template <typename Subject, typename Tail, typename Modifier>
struct has_semantic_action<
repository::qi::my_distinct_parser<Subject, Tail, Modifier> >
: unary_has_semantic_action<Subject> {};
}
现场演示
#include <boost/spirit/include/qi.hpp>
#include "my_distinct.hpp"
namespace enc = boost::spirit::standard_wide;
namespace qi = boost::spirit::qi;
namespace qr = boost::spirit::repository::qi;
using It = std::wstring::const_iterator;
#define kw(p) qr::my_distinct(enc::alnum | L'_') \
[ enc::no_case[p] ]
int main() {
qr::my_distinct(enc::alnum | L'_');
qi::rule<It> rule;
rule
= qi::eps >
( kw(L"public")
| kw(L"private")
| kw(L"protected")
| kw(L"shared")
)
;
for (std::wstring const input : {
L"PUBLIC",
L"private",
L"PROTECTED",
L"shared",
L"XPUBLIC", // obviously no match
L"PUBLICX", // actually test of my_distinct
})
try {
It f = begin(input), l = end(input);
auto ok = qi::parse(f, l, rule);
std::wcout << input << " " << std::boolalpha << ok << std::endl;
} catch(qi::expectation_failure<It> const& ef) {
auto value = ef.what_.value;
auto elements = boost::get<std::list<boost::spirit::info> >(value);
std::ostringstream oss;
oss << ef.what_.tag << "(";
for (auto el : elements) oss << " " << el;
oss << " )";
std::wcout << input << " -> Expected " << oss.str().c_str() << std::endl;
}
}
版画
PUBLIC true
private true
PROTECTED true
shared true
XPUBLIC -> Expected alternative( "public" "private" "protected" "shared" )
PUBLICX -> Expected alternative( "public" "private" "protected" "shared" )
我有一个规则集条目的关键字语法。
下面的一些伪代码.. 如果有人现在写“XPUBLIC”作为输入,解析器会在 'boost::spirit::qi::expectation_failureparser::Iterator::what_' 的捕获处理程序中创建一个 'distinct' 异常。 这没关系,但解析器也可以 return 该节点的可能条目列表。 on_error 处理程序也获得相等的输入。有没有办法在解析器失败时获取可能的条目符号?在这个示例中,我喜欢得到“PUBLIC”,“PRIVATE”..
#define nocaselit(p) distinct(boost::spirit::standard_wide::alnum | L'_')[no_case[p]]
rule=
nocaselit(L"PUBLIC")
| nocaselit(L"PRIVATE")
| nocaselit(L"PROTECTED")
| nocaselit(L"SHARED")
当我们简化情况以跳过 distinct
指令时,这就是您可以从预期失败中处理 info
以提取备选方案的方法:
#include <boost/spirit/include/qi.hpp>
namespace enc = boost::spirit::standard_wide;
namespace qi = boost::spirit::qi;
using It = std::wstring::const_iterator;
#define kw(p) qi::lit(p)
int main() {
qi::rule<It> rule;
rule
= qi::eps >
( kw(L"PUBLIC")
| kw(L"PRIVATE")
| kw(L"PROTECTED")
| kw(L"SHARED")
)
;
for (std::wstring const input : {
L"PUBLIC",
L"PRIVATE",
L"PROTECTED",
L"SHARED",
L"XPUBLIC", // obviously no match
L"PUBLICX", // actually test of distinct
})
try {
It f = begin(input), l = end(input);
auto ok = qi::parse(f, l, rule);
std::wcout << input << " " << std::boolalpha << ok << std::endl;
} catch(qi::expectation_failure<It> const& ef) {
auto value = ef.what_.value;
auto elements = boost::get<std::list<boost::spirit::info> >(value);
std::ostringstream oss;
oss << ef.what_.tag << "(";
for (auto el : elements) oss << " " << el;
oss << " )";
std::wcout << input << " -> Expected " << oss.str().c_str() << std::endl;
}
}
版画
PUBLIC true
PRIVATE true
PROTECTED true
SHARED true
XPUBLIC -> Expected alternative( "PUBLIC" "PRIVATE" "PROTECTED" "SHARED" )
PUBLICX true
Note that the internals of
spirit::info
assumestd::string
in UTF8 encoding. I'm not overly explicit here with codecvt facets. I'll leave a reliable conversion to wide strings as an exercise to the reader.
与distinct()
天真的方法将导致此输出:
PUBLIC true
PRIVATE true
PROTECTED true
SHARED true
XPUBLIC -> Expected alternative( <distinct> <distinct> <distinct> <disti
nct> )
PUBLICX -> Expected alternative( <distinct> <distinct> <distinct> <disti
nct> )
遗憾的是,这可能不是您想要的。更糟糕的是,这也在存储库指令中进行了硬编码:
template <typename Context>
info what(Context& /*ctx*/) const
{
return info("distinct");
}
如果我们可以只需将其更改为:
template <typename Context>
info what(Context& ctx) const
{
return info("distinct", subject.what(ctx));
}
我们本来可以解决问题的。为了不过多影响库的实现细节,让我们将 distinct
指令子类化为 my_distinct
到:
template <typename Subject, typename Tail, typename Modifier>
struct my_distinct_parser
: distinct_parser<Subject, Tail, Modifier>
{
using distinct_parser<Subject, Tail, Modifier>::distinct_parser;
template <typename Context> info what(Context& ctx) const {
return info("my_distinct", this->subject.what(ctx));
}
};
遗憾的是,我们需要更多的繁文缛节来让解析器编译和组合机制注册:
my_distinct.hpp
#pragma once
#include <boost/spirit/repository/home/qi/directive/distinct.hpp>
namespace boost::spirit::repository {
BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(( my_distinct, my_distinct_type ))
}
namespace boost::spirit {
template <typename Tail>
struct use_directive<qi::domain
, terminal_ex<repository::tag::my_distinct, fusion::vector1<Tail> > >
: mpl::true_ {};
template <>
struct use_lazy_directive<qi::domain, repository::tag::my_distinct, 1>
: mpl::true_ {};
}
namespace boost::spirit::repository::qi {
using repository::my_distinct;
using repository::my_distinct_type;
template <typename Subject, typename Tail, typename Modifier>
struct my_distinct_parser
: distinct_parser<Subject, Tail, Modifier>
{
using distinct_parser<Subject, Tail, Modifier>::distinct_parser;
template <typename Context> info what(Context& ctx) const {
return info("my_distinct", this->subject.what(ctx));
}
};
}
namespace boost::spirit::qi {
template <typename Tail, typename Subject, typename Modifiers>
struct make_directive<
terminal_ex<repository::tag::my_distinct, fusion::vector1<Tail> >
, Subject, Modifiers>
{
typedef typename result_of::compile<qi::domain, Tail, Modifiers>::type
tail_type;
typedef repository::qi::my_distinct_parser<
Subject, tail_type, Modifiers> result_type;
template <typename Terminal>
result_type operator()(Terminal const& term, Subject const& subject
, Modifiers const& modifiers) const
{
return result_type(subject
, compile<qi::domain>(fusion::at_c<0>(term.args), modifiers));
}
};
}
namespace boost::spirit::traits {
template <typename Subject, typename Tail, typename Modifier>
struct has_semantic_action<
repository::qi::my_distinct_parser<Subject, Tail, Modifier> >
: unary_has_semantic_action<Subject> {};
}
现场演示
#include <boost/spirit/include/qi.hpp>
#include "my_distinct.hpp"
namespace enc = boost::spirit::standard_wide;
namespace qi = boost::spirit::qi;
namespace qr = boost::spirit::repository::qi;
using It = std::wstring::const_iterator;
#define kw(p) qr::my_distinct(enc::alnum | L'_') \
[ enc::no_case[p] ]
int main() {
qr::my_distinct(enc::alnum | L'_');
qi::rule<It> rule;
rule
= qi::eps >
( kw(L"public")
| kw(L"private")
| kw(L"protected")
| kw(L"shared")
)
;
for (std::wstring const input : {
L"PUBLIC",
L"private",
L"PROTECTED",
L"shared",
L"XPUBLIC", // obviously no match
L"PUBLICX", // actually test of my_distinct
})
try {
It f = begin(input), l = end(input);
auto ok = qi::parse(f, l, rule);
std::wcout << input << " " << std::boolalpha << ok << std::endl;
} catch(qi::expectation_failure<It> const& ef) {
auto value = ef.what_.value;
auto elements = boost::get<std::list<boost::spirit::info> >(value);
std::ostringstream oss;
oss << ef.what_.tag << "(";
for (auto el : elements) oss << " " << el;
oss << " )";
std::wcout << input << " -> Expected " << oss.str().c_str() << std::endl;
}
}
版画
PUBLIC true
private true
PROTECTED true
shared true
XPUBLIC -> Expected alternative( "public" "private" "protected" "shared" )
PUBLICX -> Expected alternative( "public" "private" "protected" "shared" )