Search code examples
c++boostboost-spirit-qi

Boost Spirit nested components


I am trying to parse the following messages with Spirit Qi:

"A/B AND C/D", "A/B", "A/B AND C/D AND E/F"

I am able to parse "A/B" but cannot get the correct results for the other strings.

I tried to following code:

qi::rule<It, AstNodeVector()> entries;
qi::rule<It, AstNodeVector()> lists;
qi::rule<It, std::string()> element;

this->entries= *(this->lists % " AND ");
this->lists= this->element >> '/' >> this->element;
this->element = qi::char_("A-Z");

What is wrong with my grammar?


Solution

  • It seems you're not skipping whitespace. Maybe that's a conceptual problem (see Boost spirit skipper issues).

    Regardless, it does parse:

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    #include <iomanip>
    namespace qi = boost::spirit::qi;
    
    using AstNodeVector = std::vector<std::string>;
    
    template <typename It>
    struct P : qi::grammar<It, AstNodeVector()> {
        P() : P::base_type(entries) {
            entries = *(lists % " AND ");
            lists   = element >> '/' >> element;
            element = qi::char_("A-Z");
        }
      private:
        qi::rule<It, AstNodeVector()> entries;
        qi::rule<It, AstNodeVector()> lists;
        qi::rule<It, std::string()> element;
    };
    
    int main() {
        using It = std::string::const_iterator;
        P<It> const p {};
    
        for (std::string const input: {
            "A/B AND C/D",
            "A/B",
            "A/B AND C/D AND E/F",
            })
        {
            It f = begin(input), l = end(input);
            AstNodeVector results;
            if (phrase_parse(f, l, p, qi::space, results)) {
                std::cout << "Success: " << std::quoted(input) << "\n";
                for (auto& el : results) {
                    std::cout << " -- " << std::quoted(el) << "\n";
                }
            } else {
                std::cout << "FAIL: " << std::quoted(input) << "\n";
            }
    
            if (f != l) {
                std::cout << "Remaining input: " << std::quoted(std::string(f,l)) << "\n";
            }
        }
    }
    

    Prints

    Success: "A/B AND C/D"
     -- "A"
     -- "B"
     -- "C"
     -- "D"
    Success: "A/B"
     -- "A"
     -- "B"
    Success: "A/B AND C/D AND E/F"
     -- "A"
     -- "B"
     -- "C"
     -- "D"
     -- "E"
     -- "F"
    

    Perhaps you should have included self-contained code, or elaborate on what exactly is the problem.