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

How to ensure that this qi parser disallows spaces between the dot operators?


I have a snippet of boost::spirit::qi code which can match "M7. x . y . z" or "M7.x.y.z", but I want a parser which fails on the former input.

I think I need to insert qi::lexeme[] or qi::no_skip[] in there, but I'm having no luck getting it to compile properly.

EDIT simplified rule for variable

Code

#define BOOST_SPIRIT_DEBUG

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>

#include <string>
namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    template <typename Iterator>
    struct my_parser : qi::grammar<Iterator, std::vector<std::string>(), 
        ascii::space_type>
    {
      my_parser() : 
            my_parser::base_type( variable )
        {
            using qi::int_;
            using qi::lit;
            using qi::double_;
            using qi::lexeme;
            using ascii::char_;

            identifier %= 
                char_( "[a-z_]" )
                >> *char_( "*[a-zA-Z0-9_]" )
            ;

            variable %= simple_var % '.'   // <----- need fix here
            ;

            simple_var %= qi::string("M7") | identifier;

            BOOST_SPIRIT_DEBUG_NODE( variable );
            BOOST_SPIRIT_DEBUG_NODE( identifier );
        }

        qi::rule<Iterator, std::string(), ascii::space_type> 
            identifier, simple_var;

        qi::rule<Iterator, std::vector<std::string>(), ascii::space_type> 
            variable;
    };
}

int main( int argc, char* argv[] )
{
    using boost::spirit::ascii::space;

    typedef std::string::const_iterator iterator_type;
    typedef client::my_parser<iterator_type> my_parser;

    my_parser       g; 

    std::vector< std::string >    result;
    std::string input( "M7. x . y . z" );  // want this to FAIL!!!

    std::string::const_iterator iter = input.begin();
    std::string::const_iterator end  = input.end();

    if (phrase_parse( iter, end, g, space, result ) && iter == end)
        std::cout << "Parsing succeeded\n";
    else
        std::cout << "Parsing failed\n";
}

Solution

  • qi::lexeme[] accets only no-skipper rules.

    You can declare identifier and simple_var as:

    qi::rule<Iterator, std::string()> identifier,simple_var;
    

    Now you can use lexeme in variable

    variable %= lexeme[simple_var % '.'];