3

期待パーサーが失敗したときに例外をスローしないようにするにはどうすればよいですか?

"function" > (!x3::lexeme[keyword >> !(x3::alnum | '_')] >> symbol) > ('(' > -lvalue_list > ')') > statements > "end"次のようなコードを解析するルールがあります。

function a() return one end

keywords は ( zeroonefunctionreturnなどend) です。

パーサーにfunction one() return zero endコードを入力すると、expect_directive::parseここから関数例外がスローされます。

if (!r)
{
    boost::throw_exception(
        expectation_failure<Iterator>(
        first, what(this->subject)));
}

それが起こったとき、私はプログラムが予期せず終了しました。または中止 (コアダンプ) (使用する端末によって異なります)。

コードをデバッグすると、gdbboost::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 X3x3::expectation_failureで例外を完全に回避する方法はありますが、それでもコード全体の解析を中断し、予想の失敗に戻るようにする方法はありますか?x3::phrase_parsefalse

私の疑惑は次のとおりです。

すべてのパーサー ( X3parse()の概念として)のメンバー関数の従来の戻り値が であるため、失敗について報告する方法は 2 つしかないのではないかと思います:)。これは、 C++での再帰的な降順パーサーの実装に固有のものです。しかし、結果の型をより広いものに変更すると、解析中にハードエラーまたはソフトエラー (またはその他のもの) をより柔軟な方法で区別できます — リターンコードの値を変えることで。booltruefalsetrueparsebool

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 に答える