Spirit Qi Syntax Issues

I have some problems writing a parser using Spirit :: Qi 2.4. I have a series of key-value pairs for parsing in the following format <key name>=<value> .

The key name can be [a-zA-Z0-9] , and it is always followed by the = sign without a space between the key name and the = sign. The key name must also always contain at least one space.

The value can be almost any C expression (spaces are also possible), with the exception of expressions containing = char and code blocks { } .

At the end of the sequence of key value pairs there is a { .

I am very struggling with writing a parser for this expression. Since the key name is always preceded by at least one space, and then = and does not contain spaces, I defined it as

  KeyName %= [+char_("a-zA-Z0-9_") >> lit("=")] ; 

The value can be almost anything, but it cannot contain the characters = and { , so I defined it as:

  Value %= +(char_ - char_("{=")) ; 

I was thinking about using look-ahead, like this, to catch the meaning:

 ValueExpression %= ( Value >> *space >> &(KeyName | lit("{")) ) ; 

But this will not work, for some reason (it seems that ValueExpression eagerly approaches the = sign and "does not know" what to do from there). I have limited knowledge of LL parsers, so I'm not quite sure what is cooking here. Is there any other way I could handle such a sequence?

Here is a sample series:

 EXP1=FunctionCall(A, B, C) TEST="Example String" \ AnotherArg=__FILENAME__ - 'BlahBlah' EXP2= a+ b+* { 

Additional information: since this is part of a much larger grammar, I cannot solve this problem other than using the Spirit.Qi parser (for example, splitting into '=' and doing some kind of custom parsing or something like that).

Edit:

I created a minimal working example here: http://ideone.com/kgYD8
(compiled in VS 2012 with an increase of 1.50, but it should be good on the old settings).

+2
source share
1 answer

I would advise you to take a look at the article Parsing a List of Key Pairs Using Spirit.Qi .

I greatly simplified your code, and

  • add attribute handling
  • phoenix semantic action removal
  • debugging rules

Here it is, without further ado:

 #define BOOST_SPIRIT_DEBUG #include <boost/fusion/adapted.hpp> #include <boost/spirit/include/qi.hpp> #include <map> namespace qi = boost::spirit::qi; namespace fusion = boost::fusion; typedef std::map<std::string, std::string> data_t; template <typename It, typename Skipper> struct grammar : qi::grammar<It, data_t(), Skipper> { grammar() : grammar::base_type(Sequence) { using namespace qi; KeyName = +char_("a-zA-Z0-9_") >> '='; Value = qi::no_skip [+(~char_("={") - KeyName)]; Sequence = +(KeyName > Value); BOOST_SPIRIT_DEBUG_NODE(KeyName); BOOST_SPIRIT_DEBUG_NODE(Value); BOOST_SPIRIT_DEBUG_NODE(Sequence); } private: qi::rule<It, data_t(), Skipper> Sequence; qi::rule<It, std::string()> KeyName; // no skipper, removes need for qi::lexeme qi::rule<It, std::string(), Skipper> Value; }; template <typename Iterator> data_t parse (Iterator begin, Iterator end) { grammar<Iterator, qi::space_type> p; data_t data; if (qi::phrase_parse(begin, end, p, qi::space, data)) { std::cout << "parse ok\n"; if (begin!=end) { std::cout << "remaining: " << std::string(begin,end) << '\n'; } } else { std::cout << "failed: " << std::string(begin,end) << '\n'; } return data; } int main () { std::string test(" ARG=Test still in first ARG ARG2=Zombie cat EXP2=FunctionCall(A, BC) {" ); auto data = parse(test.begin(), test.end()); for (auto& e : data) std::cout << e.first << "=" << e.second << '\n'; } 

The output will be:

 parse ok remaining: { ARG=Test still in first ARG ARG2=Zombie cat EXP2=FunctionCall(A, BC) 

If you really want '{' to be part of the last value, change this line:

 Value = qi::no_skip [+(char_ - KeyName)]; 
+3
source

All Articles