Search code examples
c++boostboost-spiritboost-spirit-qi

boost::spirit permutations


I have to parse the following piece of text

Camera {
    position 0 0 0
    direction 0 -1 0
    up 0 1 0
    FOVy 45
}

My choice went on boost:spirit since I had not to deal with flex or bison.

I finally had this grammar

struct camera_grammar :  qi::grammar<Iterator, camera(), ascii::space_type>
{
    qi::rule<Iterator, camera(), ascii::space_type> start;

    camera_grammar() : camera_grammar::base_type(start)
    {
        start %=
        lit("Camera")
        >> '{'
        >> (lit("position") >> float_ >> float_ >> float_) 
        >> (lit("direction") >> float_ >> float_ >> float_)
        >> (lit("up") >> float_ >> float_ >> float_)
        >> (lit("FOVy") >> int_)
        >> '}'
        ;
    }
};

The problem is that the parts inside the curly braces could even be swapped; I have read about the permutation operator ^ but I read that matches when at least one of the operands is matched in any order. I need my grammar to match only when there are all of them in any order and once only.

Can somebody help me?


Solution

  • Hartmut Kaiser explains how to do this in this article.

    You'll want to define the no_empties_impl class as described in the article, and then declare a function

    phoenix::function<no_empties_impl> const no_empties = no_empties_impl();
    

    Then, in your grammar, you'll want to define rules for each of position, direction, up, and FOVy. Then your start grammar will look like (untested):

    start %=
    lit("Camera")
    >> '{'
    >> position ^ direction ^ up ^ FOVy
    >> '}'
        [qi::_pass = no_empties(qi::_0)]
    ;