Subject: RE: [DGD]parse_string
From: "Jason Cone"
To: DGD Mailing List
Date: Mon, 5 Apr 1999 11:05:58 -0500

> -----Original Message-----
> From: Erlend Simonsen
> Sent: Saturday, April 03, 1999 5:36 PM
> To: DGD Mailing List
> Subject: [DGD]parse_string
>
>
> I've been spending some time this easter trying to get my MudOS-like
> parser using parse_string() up and running. And I'm ALMOST happy with
> it. I've run into two problems, which I thought I'd see if any of you
> had an answer to.
>
> 1.
> When trying to get an object from a container I have the problem that
> when my find_object() function is called, I have no idea which
> environment to look for the object in. And I can't just scan all
> containers in the environment looking for the object, since I might
> end up with the wrong object if several instances of it is present.

With MudOS, every object is required to register itself with the driver as
an object that can be targeted by the parser.  Thus, you can effectively
eliminate certain objects that shouldn't be directly interacted with in the
game.  In the event that multiple (registered) objects of the same class
exist and are being targeted via a certain parsed sentence, it's up to the
parser (not the actual grammar, but the functionality surrounding the
grammar) to determine which object is flagged as the "found" object.  DGD &
parse_string() benefit heavily in this area as you can define this behavior
based on what you want to accomplish.  For example, in a 3D space, you could
return the object that is "closest" to the person issuing the command or if
the object exists in the person's inventory, you could return the object
that was last used, etc. etc.  This isn't possible with the MudOS parser;
order of precedence is defined for you.  All that to say, your find_object()
function is going to have to take care of that for you.

> 2.  I want to call can_get_obj_from_obj() and the like. The problem I
> am having here is that I know nothing about the rule that is matched,
> so I build the function name by checking the type of each element in
> the result from parse_string(). Which basically breaks all STR
> (string) parts of the rules.
>
> What I tried doing when building the function to call, is to treat all
> strings as 'str', but that gives me function names like
> can_buy_str_str_liv(), and that doesn't look too nice. I would rather
> have it look like is can_buy_str_from_liv(). Anyone have solved this
> problem and would like to share with me how they did it?

The following description is how CornerStone's verb system works (I'm
returning to its development after a hiatus of sorts).

Each verb exists as its own file ("look" == "/bin/verbs/_look.c").
/bin/verbs/_look.c inherits /std/inherit/verb.c which contains all the
functions to set error messages, verb rules (described in a minute), and
perform the actual verb-related actions.  All verbs are handled by a verb
daemon that also keeps track of the verbs' grammar objects (described
later).  Each verb is responsible for registering the rules that will be
used for parsing out the input.  For example, the "look" verb would register
its rules via

  add_rules(({
    "", "OBJ", "DIR",
  }));

The token values will be described in a minute, but the above is called when
the object is created.

When a player issues a command and the first word of the command line is
equal to a registered verb, the daemon will do the following:

* Take each rule for the verb ("", "OBJ", "DIR") and query a rule daemon for
an object that contains the actual grammar for that rule.  This way,
multiple verbs can use the same rule objects to take advantage of the
processed parse_string() grammars.

* The rule object will parse the input string (minus the first word) and
call the necessary functions in the verb object.  Take the "OBJ" rule, for
example.  If the input matches that rule, then it will call can_look_obj in
the verb object.  If that function returns 1, it will call do_look_obj in
the verb object to perform the action.  If either the can_ or the do_
functions returns 0, then the verb rule will fail and the verb daemon will
proceed to the next verb rule for that verb.

It was a real pain to design the verb system this way, but it's really
turned out to be a blessing for (mainly) 2 reasons.  1) It's easier to
maintain the code for the overall system by breaking delegating
functionality to different subsystems.  I also use the rule daemon for a
trigger system (an add_action-like system that can optionally use verb-like
rules).  2) You can dynamically add/remove rules from particular verbs
without having to rebuild grammars.  Some may say using multiple grammars
instead of one huge grammar for every possible verb is inefficient, but I
feel the maintainability and administration value of having it broken up
outweighs that consideration.

Ok, anyway, after that long diatribe, let's see if I can actually answer
your question.  Here are the tokens that I use in my system:

OBJ
  Evaluates to:
    Object found in immediate inventory OR immediate environment

  Return value:
    Object

LIV
  Evaluates to:
    Living object (NPC or other player) in immediate environment

  Return value:
    Object

OBJI
  Evaluates to:
    Object in the caller's inventory

  Return value:
    Object

OBJE
  Evaluates to:
    Object that is contained somewhere in the caller's immediate environment

  Return value:
    Object

OBJA
  Evaluates to:
    A hypothetical object in the player's immediate inventory or
    immediate environment

  Return value:
    Ambiguous object packet
      ({ ({ Adjectives }), Noun, Object Index })

DIR
  Evaluates to:
    A legitimate direction according to the verb.

  Return value:
    String

The only token I'm compelled to really describe in detail is the OBJA token.
This token allows you to extract a noun (object) from the input
command/sentence without it actually existing as a loaded object.  Thus, if
I type "look at the blue piece of paper", the piece of paper doesn't need to
be an actual object that DGD is aware of whereas all of the OBJ* tokens
evaluate to actually loaded objects.

Dworkin answered your question pretty well with the "buy STR from LIV".
Though, I would highly recommend separating the verb from the rules; "buy
STR from LIV" should be "STR from LIV" and be associated with the "buy verb.
This would allow rule reuse (I'm an OO freak, I guess).

The one challenge I'm facing is how to handle chained tokens.  For example,
what would a rule look like that could evaluate something like "look at the
first note on the board"?  The obvious solution would be to have a rule that
looked like "OBJ on OBJ".  But what happens when the depth is really
unknown?  Could it be possible to have an OBJS token that could handle any
number of objects that appear in relation to each other?  Food for
thought... I would love to hear ideas if any exist.

Anyway, I think I've rambled entirely too long and probably haven't answered
anything directly.

JC