当期望解析器失败时,避免抛出expectation_failure

时间:2015-07-22 04:32:02

标签: c++ boost-spirit boost-spirit-x3

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

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

function a() return one end

keyword是(zeroonefunctionreturnend等。

如果我使用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_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 X3 中完全避免x3::expectation_failure异常,但仍会中断整个代码的解析并让x3::phrase_parse返回false期望失败?

我怀疑是下一个:

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

1 个答案:

答案 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