A Complete Exampleby Richard Bartle Heres an example of the complete parsing process (as described in my previous 13 articles) in action. Phase 1 - Command Line InputThe user types a sequence of characters. Lets go with something that players might actually type, rather than something that illustrates the finer points of parsing: Phase 2 Pre-processingThe input line is normalised. White space is removed, control characters are processed and letters are converted to same-case. Phase 3 TokenisationThe pre-processed line is split into words, which are looked up in the vocabulary. If a word doesnt have a vocabulary entry, this is reported and the parsing process stops.
the tokenisation that results would be:
Phase 4 ParsingTheres an ambiguity in the input sentence, depending on how its prepositions are read. It could mean:
How this is resolved is, in theory, entirely up to the parser so long as it does whatever it does consistently. However, the first alternative is bad because it means DROP cant ever take 2 parameters, and the second is bad because players almost invariably prefer to specify the subject (ie. first parameter) rather than the object (ie. second parameter). Trust me: even if you have to hack your parser to get the third possibility, do so! In MUD2, I implement it by having two types of preposition: those that connect noun phrases and those that connect noun groups. IN is one of the former and X is one of the latter, which together enforce the third reading of the command. This is how its done in the following trace: current: DR + parse([r_input]) | + parse([r_sentence, r_inpa]) | | + parse([r_command, r_snta, r_inpa]) | | | + parse([r_command1, r_snta, r_inpa]) | | | | + parse([r_cmd1a, r_snta, r_inpa]) | | | | | + current(verb) | | | | | - current(verb) =true T | | | | | + parse([r_noun_phrase, r_cmd1b, r_snta, r_inpa]) | | | | | | + parse([r_noun_group, r_npa, r_cmd1b, ... ]) | | | | | | | + current(article) | | | | | | | - current(article) =false | | | | | | | + parse([r_nga, r_npa, r_cmd1b, ...]) | | | | | | | | + current(integer) | | | | | | | | - current(integer) =false | | | | | | | | + parse([r_ngb, r_npa, r_cmd1b, ...]) | | | | | | | | | + current(adjective) | | | | | | | | | - current(adjective) =false | | | | | | | | | + parse([r_ngc, r_npa, r_cmd1b, ...]) | | | | | | | | | | + current(noun) | | | | | | | | | | - current(noun) =true X | | | | | | | | | | + parse([r_npa, r_cmd1b, ...]) | | | | | | | | | | | + current(ng_prep) | | | | | | | | | | | - current(ng_prep) =true DIAMONDS | | | | | | | | | | | + parse([r_noun_group, r_npa, r_cmd1b, ... ]) ... | | | | | | | | | | | | + current(noun) | | | | | | | | | | | | - current(noun) =true IN | | | | | | | | | | | | + parse([r_npa, r_cmd1c, ...]) | | | | | | | | | | | | | + current(ng_prep) | | | | | | | | | | | | | - current(ng_prep) =false | | | | | | | | | | | | | + parse([r_cmd1d, ...]) | | | | | | | | | | | | | | + parse([r_cmd1e, ...]) | | | | | | | | | | | | | | | + current(np_prep) | | | | | | | | | | | | | | | - current(np_prep) =true BOX | | | | | | | | | | | | | | | + parse([r_noun_phrase, r_cmd1f, ...]) ... EOL | | | | | | | | | | | | | | -parse([r_cmd1e, ...]) | | | | | | | | | | | | | - parse([r_cmd1d, ...]) | | | | | | | | | | | | - parse([r_npa, r_cmd1c, ...]) ... | | | - parse([r_command1, r_snta, r_inpa]) =true | | - parse([r_command, r_snta, r_inpa]) =true | - parse([r_sentence, r_inpa]) =true - parse([r_input]) =true Phase 5 BindingFrom the parse phase, we get [drop, [in], [ [treasure_plural, [but, [diamond_plural]] ], [box, []] ] ] First, the binder identifies the verb by applying each verb modifier to it. If weve defined
then the verb becomes INSERT.
This set has to be modified by the BUT clause. That clause requires that DIAMOND_PLURAL be bound in the context of INSERT, which gives
We can now apply
to get [ruby1, ruby2, ring7] for the set of objects that satisfy the first noun phrase. For the second noun phrase, we have to bind BOX in the context of being the second parameter to DROP. Lets say it finds [box2, box5].
Phase 6 ExecutionEach execution inserts one object into box2 and generates the appropriate messages. The player reads the messages and decides what to do next. The whole process can then begin again. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||