I've been working on implementing boost::spirit in my MUD to parse complicated grammar. Once I figured out how the library worked, it wasn't difficult to add to my existing codebase. The complicated part comes from actually using the results of the grammar. Take the get command, for instance. Now that I have an easy-to-use grammar system, I can make it as complicated as I want. I currently support the following types of get commands:
- get book
- get book 2
- get 30 coins
- get book from shelf
- get book 3 from shelf
- get book from shelf 2
- get book 2 from shelf 3
- get 30 coins from bag 2
- get 5 arrows 2 from quiver 3
I had to define a search order, too. If a player is carrying a container, and a similarly-named container also exists in the player's current room, the player can only manipulate the one in their inventory, and would have to first pick up container, then take items from it. I could work out a way to combine the inventories of the player and their location, but I'm not sure I want to go that far. Honestly, the way I've coded things it's not too difficult, but I'm more worried about perception of items and the confusion combining them all could potentially cause.
In any case, the get
command is growing in complexity by orders of magnitude right now, and it's almost too much to keep in my head. I'm going to have to go through and refactor it before I've even finished writing it.
Here's a code example of one of my rules:
// 'get 20 items from container 2' grammar rule5a = boost::spirit::int_p[boost::spirit::assign_a(mNumberToGet)] >> ' ' >> (+boost::spirit::alpha_p)[boost::spirit::assign_a(mItemToFind)] >> ' ' >> boost::spirit::str_p("from") >> ' ' >> (+boost::spirit::alpha_p)[boost::spirit::assign_a(mContainerToLookIn)] >> ' ' >> boost::spirit::int_p[boost::spirit::assign_a(mContainerNumber)];
Which reminds me, since this class (the get
command) is a shared pointer, I have to lock up the volatile bits in a mutex so multiple threads play nice together.