Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
566 views
in Technique[技术] by (71.8m points)

c++ - Factoring out common parts of Spirit rules

I have a lot of rules that have common prefix and suffix:

rule = begin_stuff >> some >> other >> stuff >> end_stuff.

(where begin_stuff and end_stuff are composed from literals)

I wanted to be able to say

 rule = wrapped(some >> other >> stuff);

I tried something along the lines of

  template<typename Rule> Rule wrapped(Rule inside) 
  {
    Rule result;
    result = begin_stuff >> inside >> end_stuff;
    return result;
  }

but all I get is lots of compile-time assertions from Qi.

How can I refactor Spirit rules in this fashion?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think you are looking for 'subrules' (that Spirit V1/classical used to have). These are obsolete now.

Have a look at

  • c++11 auto and BOOST_AUTO

    auto subexpression = int_ >> ',' >> double_;
    qi::rule<It> rule  = "A:" >> subexpression >> "Rest:" >> (subexpression % eol);
    

    There used to be issues with using auto on Spirit rules (notably with MSVC) (see Zero to 60 MPH in 2 seconds! and comments) but I have been informed this (soon) is no longer an issue:

    Yep. Anyway,FYI, it's fixed in Spirit-3. You can 
    use auto all you want. 
    
    Regards, 
    -- 
    Joel de Guzman
    
  • qi::lazy

  • inherited arguments - introduced in the Mini XML - ASTs tutorial

Here is a proof of concept that passes a common subrule to different 'compound' rules to allow for wrapping in (), [] or {}:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

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

typedef std::string::const_iterator It;

template <typename R>
    void test(const std::string& input, R const& rule)
{
    It f(input.begin()), l(input.end());
    bool ok = qi::phrase_parse(f,l,rule,qi::space);
    std::cout << "'" << input << "'parse " << (ok?"success":"failure") << "
";
}

int main()
{
    typedef qi::rule<It,                    qi::space_type> common_rule;
    typedef qi::rule<It, void(common_rule), qi::space_type> compound_rule;

    common_rule common = qi::int_;

    compound_rule 
        in_parens   = qi::lit('(') >> qi::_r1 >> ')',
        in_brackets = qi::lit('[') >> qi::_r1 >> ']',
        in_braces   = qi::lit('{') >> qi::_r1 >> '}';

    test("{ 231 }"  , in_braces  (phx::ref(common )) );
    test("{ hello }", in_braces  (phx::val("hello")) );

    test("( 231 )"  , in_parens  (phx::ref(common )) );
    test("( hello )", in_parens  (phx::val("hello")) );

    test("[ 231 ]"  , in_brackets(phx::ref(common )) );
    test("[ hello ]", in_brackets(phx::val("hello")) );
}

Output:

'{ 231 }'   parse success
'{ hello }' parse success
'( 231 )'   parse success
'( hello )' parse success
'[ 231 ]'   parse success
'[ hello ]' parse success

PS. Note the above is not a typical Spirit grammar. This way doesn't play too well when the 'common' rule would expose different attributes.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...