Search code examples
c++parsingboost-spirit-qi

Boost spirit qi - parse string into boolean


I need to parse a string into a boolean value; in particular

  • if the string is ack I want the parser sets a boolean variable with true;
  • if the string is noack I want the parser sets a boolean variable with false;

Note that I do not want to use the return value of the function qi::parse; I want the qi::parse function sets a boolean variable given as argument. Something like the following (not compiling) code:

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

using namespace boost::spirit;

int main() {
    bool b;
    std::string s("ack");
    auto it = s.begin();
    if (qi::parse(it, s.end(), < need a rule here... >, b))
        std::cout << "Value: " << std::boolalpha << b << std::endl;
    return 0;
}

Solution

  • The simplest approach that comes to mind is "noack" >> qi::attr(false) and its complement. Add an eoi to ensure full input is parsed:

    Live On Coliru

    #define BOOST_SPIRIT_DEBUG
    #include <boost/spirit/include/qi.hpp>
    #include <iostream>
    #include <string>
    
    namespace qi = boost::spirit::qi;
    
    int main() {
        for (std::string const s : {"ack","noack","oops","ack 2",""}) {
            bool b;
            if (qi::parse(s.begin(), s.end(), ("ack" >> qi::attr(true) | "noack" >> qi::attr(false)) >> qi::eoi, b))
                std::cout << "'" << s << "' -> " << std::boolalpha << b << std::endl;
            else
                std::cout << "'" << s << "' -> FAIL\n";
        }
    }
    

    Prints

    'ack' -> true
    'noack' -> false
    'oops' -> FAIL
    'ack 2' -> FAIL
    '' -> FAIL
    

    BONUS:

    Use symbol for more elegance:

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    #include <iostream>
    #include <string>
    
    namespace qi = boost::spirit::qi;
    
    struct acknoack_type : qi::symbols<char, bool> {
        acknoack_type() { this->add("ack", true)("noack", false); }
    } static const acknoack;
    
    int main() {
        for (std::string const s : {"ack","noack","oops","ack 2",""}) {
            bool b;
            if (qi::parse(s.begin(), s.end(), acknoack >> qi::eoi, b))
                std::cout << "'" << s << "' -> " << std::boolalpha << b << std::endl;
            else
                std::cout << "'" << s << "' -> FAIL\n";
        }
    }