Boost::Spirit 2 Redux
Last dog watch, 8 bells (8:27 pm)

Well if you stopped by yesterday you may have read my post about Boost::Spirit 2 and the trouble I had converting to the new Spirit 2 library. Fortunately, Hartmut Kaiser, one of the Boost::Spirit authors must have a Google blog notification when Spirit is mentioned in a blog, because he left a comment with a suggestion for me earlier!

Unfortunately, I still can't seem to get qi::phrase_parse to work right. The problem is that I'm trying to match one of a set of increasingly complicated grammar structures (perhaps starting at the most complicated and working backwards would fix this issue…). So, here is my problem in gruesome detail:

I'm implementing a get command for a MUD, an online text-only game system. Since I'm writing it from scratch, I decided to use some of the most up-to-date tools I could find to do so, and Boost has some terrific libraries that make this possible. As far as I can discern, the get command can come in the following forms:

  1. get hammer
  2. get 20 nails
  3. get hammer 2 (the second hammer)
  4. get 20 nails 3 (20 of the 3rd type of nails visible)
  5. get hammer from toolbelt
  6. get 20 nails from bucket
  7. get hammer from toolbox 2 (the hammer from the second toolbox)
  8. get 20 nails from bucket 3 (you get the idea)
  9. get hammer 3 from toolbox 2
  10. get 20 nails 2 from bucket 3

The problem comes when using phrase_parse with an empty space skip-parser. Given the two rules:

bool res = qi::phrase_parse(first, str.end(),
				(
					+qi::alpha
				),
				' ',
				item
);

And

bool res = qi::phrase_parse(first, str.end(),
					(
						+qi::alpha
						>> "from"
						>> +qi::alpha
					),
					' ',
					item,
					container
);

If I check the phrase get hammer from bucket it matches rule one, because after you remove all the spaces from the string it's just one long word! This is an unexpected result, and even if I check rule two before rule one I only match rule one!

And now I'm really lost. I imagine there's a better way to do this, but I can't seem to figure it out. Also, since my allergies are going crazy, I've got to take the night off anyway. Anybody out there know of a solution?

3 Comments »
Boost::Spirit 2
Last dog watch, 1 bell (6:34 pm)

Last year I added Boost::Spirit to my MUD project. A few weeks ago I learned that all of the work I had done was deprecated in the new Spirit 2 library. I could still use "Spirit classic," but it is deprecated and may be removed at some point in the future. So I spent some time today figuring out how to convert my grammar rules.

For example, in Spirit classic, I had this rule to handle the most complex rule for my get command. In this case, it handles a command like get 20 items 2 from container 3:

rule6 = int_p[assign_a(mNumberToGet)] >> ' ' >>
			(+alpha_p)[assign_a(mItemToFind)] >> ' ' >>
			int_p[assign_a(mItemNumber)] >> ' ' >>
			str_p("from") >> ' ' >>
			(+alpha_p)[assign_a(mContainerToLookIn)] >> ' ' >>
			int_p[assign_a(mContainerNumber)];

which could be tested by the following code: if(parse(str.c_str(), rule6).full)

Here is the equivalent code in Spirit 2

	std::string::iterator first = str.begin();

	bool r = qi::parse(first, str.end(),
					(
						qi::int_ >> ' '
						>> +(~qi::char_(' ')) >> ' '
						>> qi::int_ 	>> ' '
						>> qi::lit("from") >> ' '
						>> +(~qi::char_(' ')) >> ' '
						>> qi::int_
					),
					mNumberToGet,
					mItemToFind,
					mItemNumber,
					mContainerToLookIn,
					mContainerNumber
	);

	if(r && first == command.end()) {
		return true;
	}

In many ways, the new Spirit 2 library is better, and purports to be much faster as well. The parse function has certainly been made somewhat more convenient. Overall, I'd rather not have had to spend time on this, but the only other option is to lock in with an old version of Boost that may hamper me in the future.

5 Comments »