2

I am new to spirit and currently trying to parse an ini like file into a struct. Creating the grammar is ok, but the mapping generation is still some kind of magic to me. The file looks like this:

[fine]
@cmp1
@cmp2
muh=b

[fail]
@cmp1
a=b
@cmp2

it works as long as i have the requirements and properties ordered (section "fine") but I can't get it to work if the requirements and properties are interleaved (section "fail"). My struct definition looks like this:

typedef std::map<std::string, std::string> Pairs;
struct Section
{
    std::string name;
    std::vector<std::string> requirements;
    Pairs properties;
};
BOOST_FUSION_ADAPT_STRUCT(
    Section, 
    (std::string, name)
    (std::vector<std::string>, requirements)
    (Pairs, properties)
)

My current grammar looks like this:

template <typename Iterator, typename Skipper>
struct SectionParser : qi::grammar<Iterator, Section(), Skipper>
{
    qi::rule<Iterator, Section(), Skipper> section;
    qi::rule<Iterator, std::pair<std::string, std::string>(), Skipper> pair;
    qi::rule<Iterator, std::vector<std::string>()> requirements;
    qi::rule<Iterator, std::string()> key, value, sectionIdent, name, component;

    SectionParser() 
        : SectionParser::base_type(section, "entity grammar")
    {
        using namespace qi;

        sectionIdent = *(qi::char_ - (qi::lit('[') | qi::lit(']') | qi::eol));
        name = *qi::eol > qi::lit('[') > sectionIdent > qi::lit(']') > (qi::eol | qi::eoi);         

        component = qi::char_('@') > *(qi::char_ - (qi::eol)) > (qi::eol | qi::eoi);

        value = *(qi::char_ - (qi::eol | qi::eoi));
        key = qi::char_("a-zA-Z_") > *qi::char_("a-zA-Z_0-9");
        pair = key > qi::lit('=') > value > (qi::eol | qi::eoi);

        section = name >> *component >> *pair;
    }
};

Thats how I run the parser:

std::vector<Section> sections;
bool ok = phrase_parse(first, last, (sectionParser % +qi::eol) >> *qi::eol > qi::eoi, qi::blank, sections);

I also have the feeling that i made the line ending handling more complicated than it should be...

Jakob
  • 31
  • 2

1 Answers1

1

After reading parsing into several vector members i found a solution using only semantic actions.

The struct definition stays the same:

struct Section
{
    std::string name;
    std::vector<std::string> requirements;
    Pairs properties;
};

dont use adapt struct anymore.

The grammar changes to:

template <typename Iterator, typename Skipper>
struct SectionParser : qi::grammar<Iterator, Section(), Skipper>
{
    qi::rule<Iterator, Section(), Skipper> start;
    qi::rule<Iterator, std::string()> value, ident, name, component;
    qi::rule<Iterator, std::pair<std::string, std::string>()> pair;

    SectionParser() 
        : SectionParser::base_type(start, "section grammar")
    {
        auto add_component = phx::push_back(phx::bind(&Section::requirements, qi::_val), qi::_1);
        auto add_pair = phx::insert(phx::bind(&Section::properties, qi::_val), qi::_1);
        auto set_name = phx::assign(phx::bind(&Section::name, qi::_val), qi::_1);

        ident = +qi::char_("a-zA-Z0-9_");
        component = qi::char_('@') > ident >> (qi::eol | qi::eoi);
        value = *(qi::char_ - (qi::eol | qi::eoi));
        pair = ident > qi::lit('=') > value >> (qi::eol | qi::eoi);
        name = qi::lit('[') > ident > qi::lit(']') >> (qi::eol | qi::eoi);
        start = name[set_name] >> *(component[add_component] | pair[add_pair]);
    }
};
Community
  • 1
  • 1
Jakob
  • 31
  • 2