topnav

Series Info...Notes from the Dawn of Time #19:

The Binder

by Richard Bartle
May 29, 2002

In this series of articles about parsing, we’re now at the point where the input has been broken down into a nested list of atoms which is passed to the final phase of the parsing process, the binder. What is it, and why is it called “the binder”?

Well what it is is a collection of routines that make sense of commands in the context of the game world. As for why it’s called the binder, well, OK, a confession: that’s just what I call it. I’ve no idea what other people call things that do similar tasks for non-MUD applications, but I call it the binder as it binds atoms that represent classes to atoms that represent instances. Hey, if I can get the word “mobiles” into common currency among MUD players, “binder” is worth a shot!

Verbs

I’ll start with the easy stuff: verbs.

Consider the sentences GET THE SAND WITH THE BUCKET and GET THE SAND FROM THE BUCKET. In the first, there’s some sand lying around on the ground and you want to move it to the bucket; in the second, there’s some sand in the bucket and you want to move it to your hands. If you’re standing in a room where there’s sand on the floor and you’re holding a bucket half-full of sand, the parser had better be able to figure out which one you mean. Both commands use the same verb, though: GET.

You could avoid the problem by forcing players to use different words. SCOOP THE SAND WITH THE BUCKET and REMOVE THE SAND FROM THE BUCKET would be fine. Your players wouldn’t necessarily think so (especially newbies), but your parser would be happy.

Alternatively, you could use the fact that the pronouns are different to generate the appropriate verbs yourself. This is where the binder comes in. The binder takes verb modifiers and applies each one in turn to the verb to get a new verb.

To demonstrate, first, I’ll define the atoms:

adverb: *+ [ ?? ] +* //ADVERB is a subclass of root.
with: *+ [ adverb ] +* //WITH is a subclass of ADVERB.
from: *+ [ adverb ] +* //FROM is a subclass of ADVERB.

Now I’ll define the functions:

{ adverb ?? }: first //ADVERB applied to anything returns it
//unchanged
{ with get }: scoop //GET x WITH y => SCOOP x WITH y
{ from get }: remove //GET x FROM y => REMOVE x FROM y

The binder will take the verb and the list of modifiers and apply each in turn. For [get, [with]] it would call with(get) and find scoop. For [get, [from]] it would call from(get) and find remove. For other verbs and prepositions it would return the verb unaltered, as eg. both with(tickle) and to(get) would match only the pattern for { adverb ?? }.

A more complicated verb modification list such as [inside, very, quickly, secretively] would be handled the same way. Applying it to DROP, this particular list might first call inside(drop) to generate INSERT, then very(insert) would do nothing, then quickly(insert) which might convert it to INSERT_FAST. If you really wanted to be flash you could note that VERY is an adverb that modifies adverbs, and use it to change QUICKLY into VERY_FAST before applying very_fast(insert), but I wouldn’t bother; although the players may occasionally want to make this kind of fine distinction, the game itself is unlikely to have the necessary physics in place to handle it any differently.

Note that although I’ve said here that handling verbs is easy, it’s impossible if you can’t quantify over them (ie. can’t treat them as objects in their own right). This is precisely the case with most of the object-oriented MUDs out there. “Object over-oriented” might be a better way of describing them...

Nouns

Nouns are harder to bind than verbs, but not that much harder. I’ll start by explaining the theory.

If you were to issue the command PICK UP THE INGOTS in a room containing 3 ingots, how should the game handle it? First it would convert up(pick) into GET, which I’ve just described how to do. Then it would have to apply GET to the ingots. The naïve way to approach this is to pass the noun phrase as a parameter to GET, but whereas this might work if the most complicated thing a noun phrase can be is a single noun, it’s not going to work here. You might have said PICK UP 2 INGOTS, for example.

No, the way to do it is to find all possible referents for the noun phrase in the context of the verb, and apply the verb to each one in turn. In this manner, PICK UP THE INGOTS will convert into three separate function calls – one for each ingot. These would be, say: get(ingot1), get(ingot4), get(ingot7). Thus, by the time the code for GET is given control, there’s only ever one object to be got.

I said “in the context of the verb” there because different verbs will want to refer to different objects. If you were carrying an axe in a room containing an axe, GET THE AXE would pick up the axe from the floor whereas DROP THE AXE would drop the axe you were holding. When binding AXE to an object for GET, you look in the room before you look on the character; for DROP, you look on the character before you look in the room. Fortunately, most verbs follow similar search patterns when binding objects, so you can group them together as a class and write the necessary routines only once. GET and DROP are likely to be among the most complicated, and will probably need their own individual binding strategies, but the rest will tend to be one of the following:

  • Local command – bind noun to objects held, then objects in room. Most commands are of this kind, eg. OPEN, KISS, KILL, SMELL.
  • Global command – bind noun to objects wherever they are. Spells often tend to use these, eg. SUMMON, DEAFEN, GLOW.
  • No bind – the concept the noun describes is wanted, not the objects to which it refers. Useful for admin commands such as ones to print out parent/child relationships from the atom hierarchy, but also a good idea to bypass binding for commands you know don’t need it (eg. ones that take strings as parameters).
Note that commands can bind differently for each parameter. THROW DART AT PHOTO would want to bind DART to some dart you were holding and PHOTO to some photograph you weren’t!

Rebinding

The beauty of having the binder written in your game definition language is that the commands of the game can call the binder directly. If you’re really keen, you can implement an operator to call the parser on an arbitrary string, too. Thus, if you have some truly horrible command that you don’t know right up until execution time how to parse it, your game will still be OK.

The archetypal example of this is HELP, which must perforce be an enquoting string because people will type things like HELP ME, I DON’T KNOW WHAT TO DO that wouldn’t parse otherwise. However, people will also type things like HELP JACK – a command to assist someone else (it might take 2 people to open a door, for example). In binding terms, HELP would be a “no bind” command that always took a string as a parameter. When help(<string>) was called, it would have to check to see if <string> were parsable first; if so, it would do the necessary help-a-person stuff, and if not then it would invoke the general context-sensitive help system.

If binding individual verbs and nouns were all there was to it, I wouldn’t have to explain the binder further. You’d use adverbs and prepositions to modify the verb, then use the context of the verb to determines a search strategy for the noun. Then you’d go through all objects in the search space, recording those that were instances of the class that the noun represents (or, strictly speaking, that the atom representing the noun represents). This would give you a set of bindings for the noun, and you’d call the verb on each one in turn as a separate command invocation.

This isn’t all there is to it, though. The binder has to bind noun phrases, not just nouns. Next time, I’ll describe the principles involved in this.

Recent Discussions on Notes from the Dawn of Time:

jump new