toy_spirit.cpp
来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 668 行 · 第 1/2 页
CPP
668 行
this->in_skip_ = false; } } Skipper skip_; bool in_skip_; }; struct as_ichar_parser : proto::callable { typedef proto::function< ianychar_p , proto::terminal<char>::type , proto::terminal<char>::type >::type result_type; template<typename Expr> result_type operator()(Expr const &expr) const { char lo = std::tolower(proto::value(proto::child_c<1>(expr))); char hi = std::toupper(proto::value(proto::child_c<1>(expr))); result_type that = {ichar_, {lo}, {hi}}; return that; } }; struct as_ichar_range_parser : proto::callable { typedef proto::function< ianychar_range_p , proto::terminal<char>::type , proto::terminal<char>::type >::type result_type; template<typename Expr> result_type operator()(Expr const &expr) const { char lo = proto::value(proto::child_c<1>(expr)); char hi = proto::value(proto::child_c<2>(expr)); result_type that = {ichar_range_, {lo}, {hi}}; return that; } }; struct as_ichar_literal : proto::callable { typedef proto::function< ianychar_p , proto::terminal<char>::type , proto::terminal<char>::type >::type result_type; template<typename Expr> result_type operator()(Expr const &expr) const { char lo = std::tolower(proto::value(expr)); char hi = std::toupper(proto::value(expr)); result_type that = {ichar_, {lo}, {hi}}; return that; } }; struct as_intbs_literal : proto::callable { typedef proto::function< ianystr_p , proto::terminal<std::string>::type >::type result_type; template<typename Expr> result_type operator()(Expr const &expr) const { result_type that = {istr_, {utility::to_istr(proto::value(expr))}}; return that; } }; struct as_istdstring_literal : proto::callable { typedef proto::function< ianystr_p , proto::terminal<std::string>::type >::type result_type; template<typename Expr> result_type operator()(Expr const &expr) const { result_type that = {istr_, {utility::to_istr(proto::value(expr).c_str())}}; return that; } }; /////////////////////////////////////////////////////////////////////////// // Transforms /////////////////////////////////////////////////////////////////////////// struct skip_primitives : proto::transform<skip_primitives> { template<typename Expr, typename State, typename Data> struct impl : proto::transform_impl<Expr, State, Data> { typedef typename proto::shift_right< typename proto::dereference<State>::type , Expr >::type result_type; result_type operator ()( typename impl::expr_param expr , typename impl::state_param state , typename impl::data_param data ) const { result_type that = {{state}, expr}; return that; } }; }; /////////////////////////////////////////////////////////////////////////// // Grammar /////////////////////////////////////////////////////////////////////////// using proto::_; struct SpiritGrammar; struct SpiritCaseSensitivePrimitives : proto::or_< proto::when<CharParser, as_ichar_parser(_)> , proto::when<CharLiteral, as_ichar_literal(_)> , proto::when<NTBSLiteral, as_intbs_literal(_)> , proto::when<CharRangeParser, as_ichar_range_parser(_)> , proto::when<StdStringLiteral, as_istdstring_literal(_)> > {}; struct SpiritCaseInsensitivePrimitives : proto::or_< anychar_p , IStrParser , ICharParser , ICharRangeParser , proto::complement<SpiritPrimitives> > {}; struct SpiritPrimitives : proto::or_< SpiritCaseSensitivePrimitives , SpiritCaseInsensitivePrimitives > {}; template<typename Grammar> struct SpiritComposites : proto::or_< proto::bitwise_or< Grammar, Grammar > , proto::shift_right< Grammar, Grammar > , proto::minus< Grammar, Grammar > , proto::dereference< Grammar > , proto::unary_plus< Grammar > , proto::logical_not< Grammar > > {}; // Regular Spirit grammar, has no-case transforms struct SpiritGrammar : proto::or_< SpiritComposites<SpiritGrammar> , SpiritPrimitives > {}; // Spirit grammar with the skipper transform struct SkipperGrammar : proto::or_< SpiritComposites<SkipperGrammar> , proto::when<SpiritPrimitives, skip_primitives> > {}; /////////////////////////////////////////////////////////////////////////// // Directives /////////////////////////////////////////////////////////////////////////// struct no_case_directive { template<typename Expr> typename SpiritGrammar::result<void(Expr, mpl::void_, mpl::void_)>::type const operator [](Expr const &expr) const { mpl::void_ null; return SpiritGrammar()(expr, null, null); } }; // no_case no_case_directive const no_case = {}; template<typename Skipper> struct skip_directive { skip_directive(Skipper const &skip) : skip_(skip) {} template<typename Expr> typename boost::result_of<SkipperGrammar(Expr const &, Skipper const &, mpl::void_ &)>::type const operator [](Expr const &expr) const { mpl::void_ null; return SkipperGrammar()(expr, this->skip_, null); } private: Skipper skip_; }; // skip template<typename Skipper> skip_directive<Skipper> skip(Skipper const &skip) { return skip_directive<Skipper>(skip); } /////////////////////////////////////////////////////////////////////////// // parse /////////////////////////////////////////////////////////////////////////// template<typename FwdIter, typename Rule> bool parse(FwdIter begin, FwdIter end, Rule const &rule) { // make sure the rule corresponds to the Spirit grammar: BOOST_MPL_ASSERT((proto::matches<Rule, SpiritGrammar>)); spirit_context<FwdIter> ctx(begin, end); return proto::eval(rule, ctx); } // parse with a skip parser can be implemented in one of two ways: // Method 1) // The skip parser is passed to all the parsers which invoke it // before they invoke themselves. This is how Spirit-1 does it, // and it is the cause of the Scanner Business. However, it has // the advantage of not needing a parser transformation phase. // Method 2) // Transform the expression template to insert the skip parser // in between all sequenced parsers. That is, transform (A >> B) // to (*skip >> A >> *skip >> B). This has the advantage of making // it unnecessary to pass the scanner to all the parsers, which // means its type doesn't show up in function signatures, avoiding // the Scanner Business. // Recommendation: // Both methods should be supported. Method 1 should be preferred // when calling parse with parsers defined inline. Method 2 should // be preferred when a parser expression is assigned to a rule<>, // thereby making the type of the rule<> independent of the skip // parser used. I imagine a syntax like: // rule<> r = skip(space)[A >> B >> C] template<typename FwdIter, typename Rule, typename Skipper> bool parse(FwdIter begin, FwdIter end, Rule const &rule, Skipper const &skipper) { // make sure the rule corresponds to the Spirit grammar: BOOST_MPL_ASSERT((proto::matches<Rule, SpiritGrammar>)); //// Method 1: pass skip parser in the context structure. //spirit_context<FwdIter, Skipper> ctx(begin, end, skipper); //return proto::eval(rule, ctx); // Method 2: Embed skip parser via tree transformation. spirit_context<FwdIter> ctx(begin, end); return proto::eval(spirit2::skip(skipper)[rule], ctx); }}}using namespace boost;using namespace spirit2;void test_toy_spirit(){ std::string str("abcd"); // This will fail: BOOST_CHECK(!spirit2::parse(str.begin(), str.end() , char_ >> char_('a'))); // This will succeed: BOOST_CHECK(spirit2::parse(str.begin(), str.end() , char_ >> char_('b') >> char_ >> 'd')); // This will succeed: BOOST_CHECK(spirit2::parse(str.begin(), str.end() , 'a' >> ('c' >> char_ | 'b' >> char_('d') | 'b' >> char_('c')) >> 'd')); // This will succeed: BOOST_CHECK(spirit2::parse(str.begin(), str.end() , *(char_ - 'd'))); // This will succeed: BOOST_CHECK(spirit2::parse(str.begin(), str.end() , no_case[char_('A') >> 'B' >> "CD"])); // This will succeed: BOOST_CHECK(spirit2::parse(str.begin(), str.end() , no_case[*char_('A','Z')])); literal<char> a = lit('a'); literal<char const *> bcd = lit("bcd"); // This will succeed: BOOST_CHECK(spirit2::parse(str.begin(), str.end() , +~~a >> no_case[bcd])); // Scanner Business: R.I.P. :-) str = "a b cd"; BOOST_CHECK(spirit2::parse(str.begin(), str.end() , char_('a') >> 'b' >> 'c' >> 'd', space >> space));}using namespace boost::unit_test;///////////////////////////////////////////////////////////////////////////////// init_unit_test_suite//test_suite* init_unit_test_suite( int argc, char* argv[] ){ test_suite *test = BOOST_TEST_SUITE("test proto and and toy spirit-2"); test->add(BOOST_TEST_CASE(&test_toy_spirit)); return test;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?