Spirit.Qi エラーハンドリング

Qiでは、パース時のエラーハンドリングを、qi::on_error()を使用して設定することができます。

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

template <class Rule, class Result>
bool parse(const std::string& s, const Rule& rule, Result& result)
{
    std::string::const_iterator first = s.begin();
    return qi::parse(first, s.end(), rule, result);
}

void test(const std::string& s)
{
    typedef int result_type;
    qi::rule<std::string::const_iterator, result_type()> r = '(' > qi::int_ > ')';

    qi::on_error<qi::fail>(
        r,
        std::cout << phx::val("parse failed : ") << phx::_4 << std::endl
    );

    result_type result;
    parse(s, r, result);

    std::cout << result << std::endl;
}

int main()
{
    test("(123)");
    test("(xyz)");
}
123
parse failed : <integer>
4498249(不定値)

qi::on_error()を使用する上で注意する点は、ruleを記述する際の演算子にoperator>>()ではなくoperator>()を使用するということです。

operatpr>>()はマッチしなかった場合に次のruleを見に行きますが、operator>()はマッチしなかった場合にエラーとなります。operator>>()を指定した場合、ハンドラは呼ばれません。


qi::on_error()に指定できるアクションは以下の4つ:

  • fail : 失敗としてno_matchを返す
  • retry : イテレータの位置を動かし、エラーからの回復を試みる
  • accept : 適切にイテレータの位置を動かし、強制的に成功とする
  • rethrow : エラーを再スロー

アクションを指定しなかった場合、デフォルトでfailになります。



また、ここではエラー時のログ出力にSpirit.Phoenixのラムダ式を使用していますが、
ここで指定する関数オブジェクトには以下の4つのパラメータが渡されます。

  • 第1パラメータ first : parse()に渡されたfirstイテレータ
  • 第2パラメータ last : parse()に渡されたendイテレータ
  • 第3パラメータ error-pos : エラー発生時の位置のイテレータ
  • 第4パラメータ what : 失敗した理由の文字列


# PhoenixのラムダはIOマニピュレータが使えるんですね



参照:

Mini XML - Error Handling

Sequence (a >> b)

Expectation (a > b)