3

当期望解析器失败时,如何避免抛出异常?

我有一个规则"function" > (!x3::lexeme[keyword >> !(x3::alnum | '_')] >> symbol) > ('(' > -lvalue_list > ')') > statements > "end"来解析代码,例如:

function a() return one end

keywords 是 ( 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_exceptionnoexcept说明符)?

我已经接受了try { ... } catch (x3::expectation_failure< input_iterator_type > const & ef) { ... } x3::phrase_parse函数调用。x3::expectation_failure< input_iterator_type >正是从boost::throw_exception. 一切都无所谓。

有没有办法完全避免Boost.Spirit X3x3::expectation_failure中的异常,但仍然会中断整体代码解析并在预期失败时返回?x3::phrase_parsefalse

接下来是我的怀疑:

由于parse()所有解析器的成员函数的常规返回值(作为X3中的概念)是bool,我怀疑只有两种方法可以报告失败:异常 xor 返回码(只能是trueor false,并且true已经占用了Parse 成功的结果报告)。它是C++中递归降序解析器实现所固有的。但是如果我们将结果类型parse从 from更改bool为更广泛的内容,我们可以在解析期间以更灵活的方式区分报告硬错误或软错误(或其他内容)——通过返回代码的不同值。

4

1 回答 1

4

使用期望解析器时,您无法避免抛出期望失败。这是该运算符的目的。

用于operator>>“可追溯的期望”(即替代方案)。

当您使用期望点 ( operator>) 时,也只需处理异常¹。

注意这看起来像一个错字

('(' > -lvalue_list > '>')

应该是

('(' > -lvalue_list > ')')

无论定义为...return one end也不匹配"begin" >> statements >> "end"statements

修理东西:

使用规则调试(仅限 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

¹ 并且只是为了表明您可以很好地处理期望失败:期望失败处理

于 2015-07-22T12:29:47.050 回答