避免在期望解析器失败时抛出 expectation_failure
Avoid throwing expectation_failure when expectation parser fails
期望解析器失败时如何避免抛出异常?
我有一个规则 "function" > (!x3::lexeme[keyword >> !(x3::alnum | '_')] >> symbol) > ('(' > -lvalue_list > ')') > statements > "end"
来解析如下代码:
function a() return one end
keyword
s 是(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 在 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
到 return false
预期失败?
接下来我的怀疑是:
由于所有解析器的 parse()
成员函数的常规 return 值(如 X3 中的概念)是 bool
,我怀疑报错只有两种方式:exception xor return code(只能是true
或false
,true
already occupied for Parse成功 结果报告)。它是 C++ 中递归递减解析器实现所固有的。但是,如果我们将 parse
的结果类型从 bool
更改为更广泛的类型,我们可以在解析期间以更灵活的方式区分报告硬错误或软错误(或其他)——通过不同的 return代码。
使用期望解析器时无法避免抛出期望失败。这就是这个运算符的目的。
对"back-trackable expectations"使用operator>>
(即备选方案)。
当您使用期望点 (operator>
) 时,也只需处理异常¹。
Note This looks like a typo
('(' > -lvalue_list > '>')
should probably be
('(' > -lvalue_list > ')')
此外 return one end
与 "begin" >> statements >> "end"
不匹配,无论 statements
定义为...
修复问题:
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
期望解析器失败时如何避免抛出异常?
我有一个规则 "function" > (!x3::lexeme[keyword >> !(x3::alnum | '_')] >> symbol) > ('(' > -lvalue_list > ')') > statements > "end"
来解析如下代码:
function a() return one end
keyword
s 是(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 在 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
到 return false
预期失败?
接下来我的怀疑是:
由于所有解析器的 parse()
成员函数的常规 return 值(如 X3 中的概念)是 bool
,我怀疑报错只有两种方式:exception xor return code(只能是true
或false
,true
already occupied for Parse成功 结果报告)。它是 C++ 中递归递减解析器实现所固有的。但是,如果我们将 parse
的结果类型从 bool
更改为更广泛的类型,我们可以在解析期间以更灵活的方式区分报告硬错误或软错误(或其他)——通过不同的 return代码。
使用期望解析器时无法避免抛出期望失败。这就是这个运算符的目的。
对"back-trackable expectations"使用operator>>
(即备选方案)。
当您使用期望点 (operator>
) 时,也只需处理异常¹。
Note This looks like a typo
('(' > -lvalue_list > '>')
should probably be
('(' > -lvalue_list > ')')
此外 return one end
与 "begin" >> statements >> "end"
不匹配,无论 statements
定义为...
修复问题:
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