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

Parsing quoted string only works in some cases


I've encountered something weird when trying to parse simple quoted strings. So I've written this simple parser that successfully parses quoted strings like "string" or "".

#include <iostream>
#include "boost/spirit/include/qi.hpp"

namespace qi      = boost::spirit::qi;
namespace iso8859 = boost::spirit::iso8859_1;


int main( int argc, char* argv[] )
{
    using namespace qi;

    std::string input = "\"\"";

    std::string::const_iterator front = input.cbegin();
    std::string::const_iterator end   = input.cend();
    bool parseSuccess = phrase_parse( front, end,
                                      '\"' >> *~char_('\"') >> '\"',
                                      iso8859::space );

    if ( front != end )
    {
        std::string trail( front, end );
        std::cout << "String parsing trail: " << trail << std::endl;
    }

    if ( !parseSuccess )
        std::cout << "Error parsing input string" << std::endl;

    std::cout << "Press enter to exit" << std::endl;
    std::cin.get();
    return 0;
}

This all works perfectly fine, but when I extend the parsing rules to also parse things before the quoted string, it suddenly breaks..

So, of example, this parses successfully:

std::string input = "normalString 10.0 1.5 1.0 1.0 1.0 1.0" With parsing rule:

*char_ >> *double_

And now if I combine this rule with the quoted string rule:

std::string input = "normalString 10.0 1.5 1.0 1.0 1.0 1.0 \"quotedString\""

With parsing rule:

*char_ >> *double_ >> '\"' >> *~char_('\"') >> '\"'

It suddenly doesn't work anymore and parsing fails. I have no idea why. Can anyone explain this?

EDIT: Just in case it matters, I'm using Boost 1.53


Solution

  • As cv_and_he stated earlier - your *char_ eats everything and from the "updated" parser sequence you can guess why it did not work :-)

    #include <iostream>
    #include "boost/spirit/include/qi.hpp"
    
    namespace qi      = boost::spirit::qi;
    namespace iso8859 = boost::spirit::iso8859_1;
    
    int main( int argc, char* argv[] )
    {
        using namespace qi;
    
        std::vector< std::string > inputVec{
            "normalString 10.0 1.5 1.0 1.0 1.0 1.0 \"quotedString\"",
            "normalString \"quotedString\"",
            "10.0 1.5 1.0 1.0 1.0 1.0 \"quotedString\"",
            "10.0 1.5 1.0 1.0 1.0 1.0 \"\"",
            "\"\""};
    
        for( const auto &input : inputVec )
        {
            std::string::const_iterator front = input.cbegin();
            std::string::const_iterator end   = input.cend();
            bool parseSuccess = phrase_parse( front, end,
                no_skip [ *(char_ - space - double_ - '\"') ] 
                >> *double_ >> '\"' >> *~char_('\"') >> '\"',
              iso8859::space );    
            if ( parseSuccess && front == end)
                std::cout << "success:";
            else
                std::cout << "failure:";
             std::cout << "`" << input << "`" << std::endl;
        }
        return 0;
    }