spirit

なんかやろうとして飽きた↓
http://morihyphen.hp.infoseek.co.jp/files/sexpr-spirit.tar.gz


飽きたのを置いとくというのもアレなんだけど…
まあ、つまり、boost::spiritすばらしいです。というような。

integer = int_p[ integer.val = construct_<TaggedVal>(arg1) ];
symbol = (+(alpha_p | ch_p('-') | ch_p('_')))[ symbol.val = phoenix::bind(&symval)(arg1,arg2) ];

list_elem =
	(sexp[list_elem.val = arg1] >>
	 list_elem[list_elem.val = construct_<TaggedVal>(list_elem.val,arg1) ])
	| (ch_p('.') >> sexp[ list_elem.val = arg1 ])
	| (eps_p[ list_elem.val = construct_<TaggedVal>()] )
	;

list_expr = ch_p('(') >> list_elem[list_expr.val=arg1] >> ch_p(')') ;
sexp = integer[sexp.val=arg1] |
	symbol[sexp.val=arg1] |
	list_expr[sexp.val=arg1];

toplev = sexp[ assign_a(self.ret_val) ];

C++で書いたS式パーサ。
いや、読めるようになると、大変読みやすいのだけど…


とりあえず、クロージャがもはや何が起こってるかわからないあたりが素敵。
上のソースコードを見てもらえばわかると思うが、(もちろん、わかるわけがないが)、再帰した文法でも、勝手にどっかにスタック作って値を保存しといてくれるというなんかそんな。


spiritのよいところは、非常に気軽に使えるところだろうか。例えば、

10<->40

こういうのから、(10,40)をとってくるのは、

int main(int argc, char**argv)
{
	int begin;
	int end;
	parse_info<const char*> info = parse( argv[1], int_p[ var(begin) = arg1 ] >> chseq_p("<->") >> int_p[ var(end) = arg1 ] );

	if ( info.full ) {
		printf("%d,%d\n",begin,end);
	} else {
		puts("era-");
	}
}

これだけでいける。実際処理してるコードは、たった一行である!
bisonとかだと、*.yつくって、*.tab.cと*.hをmvするMakefile書いて、*.yから*.cをつくるMakefile書いて…とかになるわけだが、spiritならそんなこといらない。include boost spiritするだけだ。


というのは全部嘘で、ちょろっと間違えただけで、大量のエラーメッセージが出てきて楽しくなってくるので、あんまり気軽には使えないのだった。あとコンパイル遅くなる。

コンパイルが通っただけで、嬉しかった日々を思い出してみませんか?

思い出したくないです。


いや、でも、なんか、コンパイルエラーもわかってきたよ。

	parse_info<const char*> info = parse( argv[1], int_p[ var(begin) = arg1 ] >> chseq_p("<->") >> int_p[ assign_a(end,arg1) ] );

例えば、↑だと、↓

/usr/include/boost/spirit/actor/assign_actor.hpp: In member function ‘void boost::spirit::assign_action::act(T&, const ValueT&) const [with T = int, ValueT = phoenix::actor<phoenix::argument<0> >]’:
/usr/include/boost/spirit/actor/ref_const_ref_actor.hpp:57:   instantiated from ‘void boost::spirit::ref_const_ref_actor<T, ValueT, ActionT>::operator()(const T2&) const [with T2 = int, T = int, ValueT = phoenix::actor<phoenix::argument<0> >, ActionT = boost::spirit::assign_action]’
/usr/include/boost/spirit/core/scanner/scanner.hpp:128:   instantiated from ‘static void boost::spirit::attributed_action_policy<AttrT>::call(const ActorT&, AttrT&, const IteratorT&, const IteratorT&) [with ActorT = boost::spirit::ref_const_ref_actor<int, phoenix::actor<phoenix::argument<0> >, boost::spirit::assign_action>, IteratorT = const char*, AttrT = const int]’
/usr/include/boost/spirit/core/scanner/scanner.hpp:159:   instantiated from ‘void boost::spirit::action_policy::do_action(const ActorT&, AttrT&, const IteratorT&, const IteratorT&) const [with ActorT = boost::spirit::ref_const_ref_actor<int, phoenix::actor<phoenix::argument<0> >, boost::spirit::assign_action>, AttrT = const int, IteratorT = const char*]’
/usr/include/boost/spirit/core/composite/actions.hpp:109:   instantiated from ‘typename boost::spirit::parser_result<boost::spirit::action<ParserT, ActionT>, ScannerT>::type boost::spirit::action<ParserT, ActionT>::parse(const ScannerT&) const [with ScannerT = boost::spirit::scanner<const char*, boost::spirit::scanner_policies<boost::spirit::iteration_policy, boost::spirit::match_policy, boost::spirit::action_policy> >, ParserT = boost::spirit::int_parser<int, 10, 1u, -0x000000001>, ActionT = boost::spirit::ref_const_ref_actor<int, phoenix::actor<phoenix::argument<0> >, boost::spirit::assign_action>]’
/usr/include/boost/spirit/core/composite/sequence.hpp:54:   instantiated from ‘typename boost::spirit::parser_result<boost::spirit::sequence<A, B>, ScannerT>::type boost::spirit::sequence<A, B>::parse(const ScannerT&) const [with ScannerT = boost::spirit::scanner<const char*, boost::spirit::scanner_policies<boost::spirit::iteration_policy, boost::spirit::match_policy, boost::spirit::action_policy> >, A = boost::spirit::sequence<boost::spirit::action<boost::spirit::int_parser<int, 10, 1u, -0x000000001>, phoenix::actor<phoenix::composite<phoenix::assign_op, phoenix::actor<phoenix::variable<int> >, phoenix::actor<phoenix::argument<0> >, phoenix::nil_t, phoenix::nil_t> > >, boost::spirit::chseq<const char*> >, B = boost::spirit::action<boost::spirit::int_parser<int, 10, 1u, -0x000000001>, boost::spirit::ref_const_ref_actor<int, phoenix::actor<phoenix::argument<0> >, boost::spirit::assign_action> >]’
/usr/include/boost/spirit/core/impl/parser.ipp:28:   instantiated from ‘boost::spirit::parse_info<IteratorT> boost::spirit::parse(const IteratorT&, const IteratorT&, const boost::spirit::parser<DerivedT>&) [with IteratorT = const char*, DerivedT = boost::spirit::sequence<boost::spirit::sequence<boost::spirit::action<boost::spirit::int_parser<int, 10, 1u, -0x000000001>, phoenix::actor<phoenix::composite<phoenix::assign_op, phoenix::actor<phoenix::variable<int> >, phoenix::actor<phoenix::argument<0> >, phoenix::nil_t, phoenix::nil_t> > >, boost::spirit::chseq<const char*> >, boost::spirit::action<boost::spirit::int_parser<int, 10, 1u, -0x000000001>, boost::spirit::ref_const_ref_actor<int, phoenix::actor<phoenix::argument<0> >, boost::spirit::assign_action> > >]’
/usr/include/boost/spirit/core/impl/parser.ipp:45:   instantiated from ‘boost::spirit::parse_info<const CharT*> boost::spirit::parse(const CharT*, const boost::spirit::parser<DerivedT>&) [with CharT = char, DerivedT = boost::spirit::sequence<boost::spirit::sequence<boost::spirit::action<boost::spirit::int_parser<int, 10, 1u, -0x000000001>, phoenix::actor<phoenix::composite<phoenix::assign_op, phoenix::actor<phoenix::variable<int> >, phoenix::actor<phoenix::argument<0> >, phoenix::nil_t, phoenix::nil_t> > >, boost::spirit::chseq<const char*> >, boost::spirit::action<boost::spirit::int_parser<int, 10, 1u, -0x000000001>, boost::spirit::ref_const_ref_actor<int, phoenix::actor<phoenix::argument<0> >, boost::spirit::assign_action> > >]’
nanka.cpp:11:   instantiated from here  # ← 問題なのはこの部分だ!
/usr/include/boost/spirit/actor/assign_actor.hpp:46: error: cannot convert ‘const phoenix::actor<phoenix::argument<0> >’ to ‘int’ in assignment

コツは、"instantiated from"の行はあんまり読まないことだ!!

  1. instantiated from の行を読み飛ばす
  2. error: の行まできて、そのコードが、自分で書いたコードだったらそれがエラー
  3. 違うかったら、上下2行ぐらい調べれば、そこらへんがエラー