Search code examples
c++parsingboost-spiritboost-spirit-x3

Parsing a comma separated 0 or more list using boost spirit x3


I often need to parse a comma separated 0 or more list in boost spirit x3. I know the %-operator which parses a 1 or more list into an std::vector. When I need a 0 or more list I currently do it like this -(element_parser % separator), which does what I want, but parses into a boost::optional<std::vector>, which is not quite the thing I am after. So how can I make a parser, which parses a comma separated 0 or more list into a plain std::vector using boost spirit x3.


Solution

  • Perhaps I'm missing something, but using - works as expected for me:

    #include <iostream>
    #include <stdexcept>
    #include <string>
    #include <vector>
    
    #include <boost/spirit/home/x3.hpp>
    
    namespace x3 = boost::spirit::x3;
    
    const x3::rule<class number_list_tag, std::vector<int>> integer_list = "integer_list";
    const auto integer_list_def = -(x3::int_ % ',');
    BOOST_SPIRIT_DEFINE(integer_list);
    
    template <typename T>
    std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec)
    {
        bool first = true;
        os << '[';
        for (const T& x : vec)
        {
            if (first)
                first = false;
            else
                os << ", ";
    
            os << x;
        }
        os << ']';
        return os;
    }
    
    std::vector<int> parse(const std::string& src)
    {
        std::vector<int> result;
        auto iter = src.begin();
        bool success = x3::phrase_parse(iter, src.end(), integer_list, x3::space, result);
        if (!success || iter != src.end())
            throw std::runtime_error("Failed to parse");
        else
            return result;
    }
    
    int main()
    {
        std::cout << "\"\":\t" << parse("") << std::endl;
        std::cout << "\"5\":\t" << parse("5") << std::endl;
        std::cout << "\"1, 2, 3\":\t" << parse("1, 2, 3") << std::endl;
    }
    

    Output is:

    "":     []
    "5":    [5]
    "1, 2, 3":      [1, 2, 3]