Search code examples
c++c++11boostboost-spiritboost-spirit-x3

Why does this Boost.Spirit x3 rule parse correctly with angle brackets, but incorrectly with quotes?


The program below tries to parse C++ header include strings, such as "my/file.hpp" and <my/file.hpp>. For reasons I don't understand, my code fails to parse the " headers. Is this a bug in Spirit, or am I missing something obvious?

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
#include <cassert>

using namespace boost::spirit::x3;

int main() {

    auto header_name_brackets = '<' >> *(~char_('>')) >> '>';
    auto header_name_quotes   = '"' >> *(~char_('>')) >> '"'; 

    {
        auto s = std::string{"<my/file.hpp>"};
        std::string parsed;
        assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
    }

    {
        auto s = std::string{"\"my/file.hpp\""};
        std::string parsed;
        // this assert fails, but I don't know why.
        assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
    }
}

Solution

  • This works for me:

    #include <boost/spirit/home/x3.hpp>
    #include <iostream>
    #include <string>
    #include <cassert>
    
    using namespace boost::spirit::x3;
    
    int main() {
    
        auto header_name_brackets = '<' >> *(~char_('>')) >> '>';
        auto header_name_quotes   = '"' >> *(~char_('"')) >> '"'; 
    
        {
            auto s = std::string{"<my/file.hpp>"};
            std::string parsed;
            assert(phrase_parse(s.begin(), s.end(), header_name_brackets, space, parsed));
        }
    
        {
            auto s = std::string{"\"my/file.hpp\""};
            std::string parsed;
            // this assert fails, but I don't know why.
            assert(phrase_parse(s.begin(), s.end(), header_name_quotes, space, parsed));
        }
    }
    

    Note that you need to match all chars except " in the second case, just as you did with > in the first.