I posted this question to the Boost Spirit mailing list but there doesn't seem to be much traffic there. I'm hoping that the main mailing list also has a few Spirit users as well and can possible receive some help.
I'm wanting to add a semantic action for a complex rule. I'm not entirely sure this is the correct design. I need to parse the following EBNF grammar.
EBNF
value = (a-zA-Z_0-9)*
tag = (a-zA-Z_) value
tagValue = tag '=' value
list = "@list=" tag '=' tag ',' (tagValue ',')* "@end"
info = tag (',' (tagValue | list) )*
I thought if I defined the basic rules I could then created a custom instance of that rule with a semantic action. I did that for the first "tag" in the info definition and it seem to work well. I was also able to create this custom instance for the "tagValue" rule within the info definition. The problem is how to create the custom instance for list. The list result goes into a map of a map that I've created within my class. I'm not sure how to treat the tag=tag as the key and let the tagValue be the value.
Any help with the semantic action or changing the design would be appreciated. This is my first time using Spirit and the learning curve is proving to be difficult.
Ryan
#include <string>
#include <map>
#include <utility>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/std_pair.hpp>
class Bob {
typedef std::pair<std::string, std::string> infoPair;
typedef std::map<std::string, std::string> infoMap
typedef std::map<std::string, infoMap> infoMap2;
std::string m_Name;
infoMap m_Arguments;
infoMap2 m_ArgumentCollection;
public:
bool const parseMessage(std::string const& message) {
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
typedef std::string::const_iterator iter;
qi::rule<iter, std::string()> value = *qi::char_("a-zA-Z_0-9");
qi::rule<iter, std::string()> tag = qi::char_("a-zA-Z_") >> value;
qi::rule<iter, infoPair()> tagValue = tag >> '=' >> value;
qi::rule<iter, std::string()> name = tag[ phx::bind(&Bob::m_Name, this) = qi::_1 ];
qi::rule<iter, infoMap()> tagValueMap = tagValue[
[=](infoPair& p, qi::unused_type, qi::unused_type) {
m_Arguments[p.first] = p.second; } ];
//The compiler wants an infoPair. Not really sure that is what I need.
qi::rule<iter, infoPair()> list = "@list=" >> tag >> '=' >> tag >> ',' >> *(tagValue >> ',') >> "@end";
//How can I create a custom version of list (like I did for tag) to assign a semantic action.
//The action needs to allow tag=tag be the key to m_ArgumentCollection and place all
//the repeating tagValue items into its value.
auto first(message.begin()), last(message.end());
bool results = qi::parse(first, last, name >> (*(',' >> tagValueMap)));
//Something like this as the final form to the grammar.
//bool results = qi::parse(first, last, name >> (*(',' >> (tagValueMap | customList))));
if (!results || first != last)
return false;
return true;
}
};
int main(void) {
Bob bob;
bob.parseMessage("hello,this=great,@list=alice=here,wish=fish,@end,look=good");
return 0;
}