提升精神 x3 错误处理程序与期望
boost spirit x3 error handler with expectations
我想为基于行的文件创建一个使用boost::spirit::x3
的解析器,例如,每一行都具有相同的结构并且可以重复。此外,我想要一些详细的错误描述,以防出现错误。最后,文件应该有可能以换行符结尾。
现在我遇到了一些奇怪的行为,以防我在行的第一个元素上使用x3::expect
。错误处理程序打印错误,但整体分析不会失败。为什么会这样?以及如何修复它?如果我不期望该行的第一个元素,则不会得到详细的错误描述。
下面是重现此问题的示例:
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/utility/annotate_on_success.hpp>
#include <boost/spirit/home/x3/support/utility/error_reporting.hpp>
#include <boost/fusion/include/define_struct.hpp>
#include <iostream>
namespace x3 = boost::spirit::x3;
struct error_handler
{
template<typename Iterator, typename Exception, typename Context>
x3::error_handler_result on_error(Iterator& first, Iterator const& last,
Exception const& x,
Context const& context)
{
auto& error_handler = x3::get<x3::error_handler_tag>(context).get();
std::string message = "Error! Expecting: " + x.which() + " here:";
error_handler(x.where(), message);
return x3::error_handler_result::fail;
}
};
namespace boost::spirit::x3 {
template<>
struct get_info<int_type>
{
std::string operator()(int_type const&) const
{ return "integral number"; }
};
template<>
struct get_info<char_type>
{
std::string operator()(char_type const&) const
{ return "character"; }
};
} // namespace boost::spirit::x3
struct Line_tag : error_handler
{
};
struct File_tag : error_handler
{
};
BOOST_FUSION_DEFINE_STRUCT((), Data, (char, c)(int, x))
BOOST_FUSION_DEFINE_STRUCT((), DataContainer, (std::vector<Data>, data))
template<bool ExpectFirstElementOfLine>
DataContainer parse(std::string_view input)
{
auto iter = input.cbegin();
auto const end = input.cend();
const auto charParser = []() {
if constexpr (ExpectFirstElementOfLine)
return x3::expect[x3::char_("a-zA-Z")];
else
return x3::char_("a-zA-Z");
}();
const auto line = x3::rule<Line_tag, Data>{"line"} = charParser > x3::int_;
const auto file = x3::rule<File_tag, DataContainer>{"file"} = (line % x3::eol) >> -x3::eol >> x3::eoi;
x3::error_handler<decltype(iter)> error_handler(iter, end, std::cout);
DataContainer container;
if (parse(iter, end, x3::with<x3::error_handler_tag>(std::ref(error_handler))[file], container))
{
if (iter != end)
throw std::runtime_error("Remaining unparsed");
}
else
throw std::runtime_error("Parse failed");
return container;
}
template<bool ExpectFirstElementOfLine>
void testParse(std::string_view input)
{
try
{
std::cout << "=========================" << std::endl;
const auto container = parse<ExpectFirstElementOfLine>(input);
std::cout << "Parsed [OK]: " << container.data.size() << std::endl;
}
catch (const std::exception& ex)
{
std::cout << "EXCEPTION: " << ex.what() << std::endl;
}
}
int main()
{
const std::string_view input1 = "x1nx456";
const std::string_view input2 = "x1nx456n";
const std::string_view input3 = "x1n456n";
// OK
testParse<true>(input1);
testParse<false>(input1);
// parse succeeds but error handler prints message if expectation on first element of line is used
testParse<true>(input2);
testParse<false>(input2);
// parsing fails but detailed error description only works if first element of line was expected
testParse<true>(input3);
testParse<false>(input3);
}
这会产生:
=========================
Parsed [OK]: 2
=========================
Parsed [OK]: 2
=========================
In line 3:
Error! Expecting: char-set here:
^_
Parsed [OK]: 2
=========================
Parsed [OK]: 2
=========================
In line 2:
Error! Expecting: char-set here:
456
^_
EXCEPTION: Parse failed
=========================
EXCEPTION: Parse failed
-
为什么
testParse<true>("x1nx456n");
的期望失败?对于该输入,
(line % x3::eol)
将运行三次:- 尝试
line
-- 确定 (消耗x1
), 尝试x3::eol
-- 确定 (消耗n
), 重复 - 尝试
line
- 确定(消耗x456
),尝试x3::eol
- 确定(消耗n
),重复 - 尝试
line
,它尝试x3::expect[x3::char_("a-zA-Z")]
,但失败了——这是期望失败
错误 - 尝试
处理程序打印错误,但整体分析不会失败。为什么会这样?
当期望解析器失败时,它会抛出
expectation_failure
异常。但是,当您为规则设置错误处理程序时,该规则将为您捕获异常,并调用您的错误处理程序。错误处理程序通过返回error_handler_result
枚举类型的适当值来使用错误处理结果向规则发出信号。您的错误处理程序返回
error_handler_result::fail
- 这表示规则解析失败,有效地将expect[x]
转换为x
。换句话说,错误处理程序只是失败时的语义操作(而不是通常语义操作的成功)。列表解析器
line % x3::eol
只是line >> *(x3::eol >> line)
。由于错误处理程序会将任何预期失败转换为常规失败,因此很明显,在第一次成功解析line
之后,任何失败都不会使整个解析失败。以及如何修复它?
你没有提到你到底想要什么。如果您只想传播
expectation_failure
异常,请从错误处理程序返回一个error_handler_result::rethrow
。
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何在信号处理程序和普通函数中对全局变量进行互斥读写操作
- 为什么我的 IExtractIcon 处理程序没有被调用?
- 在遍历处理程序的向量时注册和注销处理程序
- 有可能在信号处理程序中设置promise吗
- 在信号处理程序中捕获C++未处理的异常并恢复应用程序
- 通过安装信号处理程序关闭多线程应用程序
- QDateTime::toString() 在退出处理程序中使用时失败
- 如何在 WindowProc 处理程序中区分箭头键和数字键盘?
- async_write完成处理程序最早何时完成?
- C++事件系统 - 多态事件和事件处理程序
- 具有shared_ptr的处理程序中的分段错误
- 为什么我的信号处理程序只执行一次?
- GTK C++:找不到信号处理程序 您是否使用 -rdynamic 进行了编译?
- 如何使用从处理程序调度的最终回调将响应异步返回给调用方on_read?
- C++ 在信号处理程序后继续执行
- wxWidgets 拖放文件事件处理程序初始化问题(无效static_cast)
- 某些 boost::asio 异步函数是否将处理程序连接到操作,以便处理程序被触发一次?
- 没有信号处理程序的POSIX定时器的目的是什么?
- 处理程序的模块列表中有一个错误的模块"WebSocketModule"