当期望解析器失败时,如何避免抛出异常?
我有一个规则"function" > (!x3::lexeme[keyword >> !(x3::alnum | '_')] >> symbol) > ('(' > -lvalue_list > ')') > statements > "end"
来解析代码,如:
function a() return one end
keyword
是(zero
,one
,function
,return
,end
等。
如果我使用function one() return zero end
代码提供解析器,那么在此处抛出函数expect_directive::parse
异常:
if (!r)
{
boost::throw_exception(
expectation_failure<Iterator>(
first, what(this->subject)));
}
当它发生时,我得到程序意外结束。或中止(核心转储)(取决于使用的终端)。
调试代码时, gdb 会自动中断大括号&#39;}&#39;在boost::throw_exception
函数中,带有消息:
The inferior stopped because it received a signal from the Operating System.
Signal name :
SIGABRT
Signal meaning :
Aborted
当逐步执行上述功能时,可以看出throw enable_current_exception(enable_error_info(e));
行是信号发射前执行的最后一行。为什么没有用于异常处理程序搜索的堆栈展开?为什么立即中止(看起来像boost::throw_exception
有noexcept
说明符)?
我接受了try { ... } catch (x3::expectation_failure< input_iterator_type > const & ef) { ... }
x3::phrase_parse
函数调用。 x3::expectation_failure< input_iterator_type >
正好是boost::throw_exception
引发的预感。一切都没关系。
有没有办法在 Boost.Spirit X3 中完全避免x3::expectation_failure
异常,但仍会中断整个代码的解析并让x3::phrase_parse
返回false
期望失败?
我怀疑是下一个:
由于所有解析器的parse()
成员函数的常规返回值(如 X3 中的概念)为bool
,我怀疑报告失败的方法只有两种:异常xor返回代码(可能只有true
或false
,true
已经占用解析成功的结果报告)。它是 C ++ 中递归降序解析器实现的固有特性。但是,如果我们将parse
的结果类型从bool
更改为更广泛的范围,我们可以通过更灵活的方式在解析期间报告硬错误(或其他错误) - 通过不同的返回值代码。
答案 0 :(得分:4)
使用期望解析器时,无法避免抛出期望失败。这是该运营商的目的。
使用operator>>
表示“可追溯的期望”(即备选方案)。
当您使用期望点(operator>
)时,只需处理异常¹。
注意这看起来像一个拼写错误
('(' > -lvalue_list > '>')
应该是
('(' > -lvalue_list > ')')
return one end
与"begin" >> statements >> "end"
不匹配,无论statements
被定义为... {/ p>
修理东西:
Live With Rule Debugging (仅限c ++ 14)
#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/spirit/home/x3.hpp>
namespace SO {
namespace x3 = boost::spirit::x3;
x3::symbols<char> const keyword = []{
x3::symbols<char> kw;
kw += "for","begin","end","function","while","break","switch";
return kw;
}();
x3::rule<struct symbol_tag> const symbol ("symbol");
x3::rule<struct identifier_tag> const identifier ("identifier");
x3::rule<struct lvalue_list_tag> const lvalue_list("lvalue_list");
x3::rule<struct statements_tag> const statements ("statements");
x3::rule<struct rule_tag> const rule ("rule");
auto symbol_def = x3::lexeme[x3::alnum >> *(x3::alnum | '_')];
auto identifier_def = (!(x3::lexeme[keyword >> !(x3::alnum | '_')]) >> symbol);
auto lvalue_list_def = identifier % ',';
auto statements_def = *identifier;
auto rule_def = "function"
>> identifier
>> ('(' > -lvalue_list > ')')
>> ("begin" > statements > "end")
;
BOOST_SPIRIT_DEFINE(symbol, identifier, lvalue_list, statements, rule)
}
int main() {
std::string const sample = "function a() begin return one end";
auto f = sample.begin(), l = sample.end();
bool ok = phrase_parse(f, l, SO::rule, SO::x3::space);
if (ok)
std::cout << "Parse success\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
打印:
<rule>
<try>function a() begin r</try>
<identifier>
<try> a() begin return on</try>
<symbol>
<try> a() begin return on</try>
<success>() begin return one </success>
</symbol>
<success>() begin return one </success>
</identifier>
<lvalue_list>
<try>) begin return one e</try>
<identifier>
<try>) begin return one e</try>
<symbol>
<try>) begin return one e</try>
<fail/>
</symbol>
<fail/>
</identifier>
<fail/>
</lvalue_list>
<statements>
<try> return one end</try>
<identifier>
<try> return one end</try>
<symbol>
<try> return one end</try>
<success> one end</success>
</symbol>
<success> one end</success>
</identifier>
<identifier>
<try> one end</try>
<symbol>
<try> one end</try>
<success> end</success>
</symbol>
<success> end</success>
</identifier>
<identifier>
<try> end</try>
<fail/>
</identifier>
<success> end</success>
</statements>
<success></success>
</rule>
Parse success
它变得更简单:
Live On Coliru (g ++ / clang ++)
#include <boost/spirit/home/x3.hpp>
#include <iostream>
int main() {
namespace x3 = boost::spirit::x3;
x3::symbols<char> keyword;
keyword += "for","begin","end","function","while","break","switch";
static auto symbol = x3::lexeme[x3::alnum >> *(x3::alnum | '_')];
static auto identifier = (!(x3::lexeme[keyword >> !(x3::alnum | '_')]) >> symbol);
static auto lvalue_list = identifier % ',';
static auto statements = *identifier;
static auto rule = "function"
>> identifier
>> ('(' > -lvalue_list > ')')
>> ("begin" > statements > "end")
;
std::string const sample = "function a() begin return one end";
auto f = sample.begin(), l = sample.end();
bool ok = phrase_parse(f, l, rule, x3::space);
if (ok)
std::cout << "Parse success\n";
else
std::cout << "Parse failed\n";
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
只需打印
Parse success
¹只是为了告诉你可以处理期望失败就好了:Expectation Failure Handling