大量の意味不明なエラーメッセージと格闘した結果
今回のターゲット文法は
epxr ::= int_lit | '(' op expr expr ')' int_lit ::= token(int_lit_s) op ::= token(op_s) int_lit_s ::= digit digit* op ::= alpha alpha* token(T) ::= T ' '*
token(T)はジェネリックなルールであり、Tに対してTの後ろの空白文字を食ってしまうルール。
パーザのソース
#include <iostream> #include <string> #include <boost/lexical_cast.hpp> #include <boost/function.hpp> #include "peg.hpp" using namespace peg; using namespace std; template<class T> struct token : public T { void action(const T& t, const rep<peg::ws>&) { *static_cast<T*>(this) = t; } }; struct int_lit_s { int v; void action(digit x, const rep<digit>& y) { string s; s += x; s.append(y.begin(), y.end()); v = boost::lexical_cast<int>(s); } }; typedef token<int_lit_s> int_lit; struct op_s { boost::function<int(int,int)> v; void action(alpha x, const rep<alpha>& name) { string s; s += x; s.append(name.begin(), name.end()); if (s == "add") { v = std::plus<int>(); } else { v = std::minus<int>(); } } }; typedef token<op_s> op; typedef token<ch<'('>::type> open_paren; typedef token<ch<')'>::type> close_paren; struct expr { int v; void action(int_lit e, sor orr, open_paren, op o, const expr& e1, const expr& e2, close_paren) { if (orr.left) { v = e.v; } else { v = o.v(e1.v, e2.v); } } }; void test(const string& s) { cout << s << " ---> "; parser<expr> parser; expr e; if (!parser.parse(e, s.begin(), s.end())) { cout << "parse error" << endl; } else { cout << e.v << endl; } } int main() { test("1"); test("42"); test("(add 10 23)"); test("(add 100 (sub 20 5))"); test("(add (add 10 20) (add 5 13))"); test("(add)"); return 0; }
実行結果
1 ---> 1 42 ---> 42 (add 10 23) ---> 33 (add 100 (sub 20 5)) ---> 115 (add (add 10 20) (add 5 13)) ---> 48 (add) ---> parse error
例によって、少しでも間違えると意味不明なエラーメッセージが大量に出る。
例えば、const参照で受け取るべき引数を参照にしてしまっていたら…
/home/kik/include/boost/fusion/functional/invocation/invoke.hpp: In static member function ‘static typename boost::function_types::result_type<Function>::type boost::fusion::detail::invoke_mem_fn<Function, Sequence, 8, false>::call(F&, Sequence&) [with F = void (expr::*)(int_lit, peg::sor, open_paren, op, expr&, const expr&, close_paren), Function = void (expr::*)(int_lit, peg::sor, open_paren, op, expr&, const expr&, close_paren), Sequence = const boost::fusion::joint_view<const boost::fusion::single_view<expr*>, const boost::fusion::vector<token<int_lit_s>, peg::sor, token<peg::chr<peg::chr_range_constraint<'(', '('> > >, token<op_s>, expr, expr, token<peg::chr<peg::chr_range_constraint<')', ')'> > >, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >]’: /home/kik/include/boost/fusion/functional/invocation/invoke.hpp:178: instantiated from ‘typename boost::fusion::result_of::invoke<Function, const Sequence>::type boost::fusion::invoke(Function, const Sequence&) [with Function = void (expr::*)(int_lit, peg::sor, open_paren, op, expr&, const expr&, close_paren), Sequence = boost::fusion::joint_view<const boost::fusion::single_view<expr*>, const boost::fusion::vector<token<int_lit_s>, peg::sor, token<peg::chr<peg::chr_range_constraint<'(', '('> > >, token<op_s>, expr, expr, token<peg::chr<peg::chr_range_constraint<')', ')'> > >, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >]’ peg.hpp:228: instantiated from ‘bool peg::pi::parse_fun(Fun, T&, Input&, Input) [with Fun = void (expr::*)(int_lit, peg::sor, open_paren, op, expr&, const expr&, close_paren), T = expr, Input = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >]’ peg.hpp:240: instantiated from ‘bool peg::parser<T>::parse(T&, Input, Input) [with Input = __gnu_cxx::__normal_iterator<const char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, T = expr]’ sample-1.cpp:70: instantiated from here /home/kik/include/boost/fusion/functional/invocation/invoke.hpp:279: error: invalid initialization of reference of type ‘expr&’ from expression of type ‘const expr’ /home/kik/include/boost/fusion/functional/invocation/invoke.hpp:279: error: return-statement with a value, in function returning 'void'
かろうじて、最後から2行目を読めば何が悪いのか分かる