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マニピュレータが使えるんですね
参照: