I really am not crazy about using a compilers syntax to implement a DSL--Sorry, I know some people like it and I readily admit that it's a cute trick, but it's so easy to write your own parser, why not do it? Then you don't have random commas and underscores scattered throughout your text.
Here's an easy trick I've used to implement a simple syntax like the one you describe:
First of all, look at your commands--note that most are in the format of "verb noun params"
This maps really well to methodName, objectName, params
So a nice procedure would be:
split sentence into string array s
for a line with a single word (if s.length == 1):
instantiate an object with that name
call a default method on that object
done
for a line with more than one word
instantiate the object s[1]
call method s[0] with s[2...] as parameters
done
This simple 5-10 or so line parser will solve many of your DSL type problems. Beyond that you can add features pretty easily:
If the parameters (2...) are in the form "name=value", scan for a parameter named "name" and pass "value" for that specific parameter. This probably wouldn't work in this specific case, but can be good for other uses.
If your single-word commands require parameters, then attempt to instantiate s[0] as a class even if there are multiple words. If this fails, revert to the multi-word algorithm above.
I had one case where I needed to keep objects around after they were instantiated. I used the syntax:
find person:ana
(the syntax could be fixed back to your original syntax by keeping a table mapping ana to person and checking this table along with trying to instantiate objects)
and from then on, ana was an instance of the person class (in other words, after instantiating "person" and calling the method "find" on it, I stored the person object in a hash under the name "ana", the next time they used a command like:
talk ana
It would search the hash first, grab the object stored in there and call "talk" on that existing object (at which point it might check to see if ana had a "found" flag set, if not it might return a different message). In this way, you could have multiple friends, each with all their own state information.
This system has some limitations, but is still much more flexible than a Ruby style DSL and really isn't at all difficult to implement.