/* $Header: boolexp.c,v 1.2 90/04/21 17:20:32 lachesis Exp $
* $Log: boolexp.c,v $
* Revision 1.2 90/04/21 17:20:32 lachesis
* Added property lists.
*
* Revision 1.1 90/04/14 14:56:38 lachesis
* Initial revision
*
*/
#include "copyright.h"
#include "os.h"
#include "db.h"
#include "match.h"
#include "externs.h"
#include "config.h"
#include "interface.h"
/* Lachesis note on the routines in this package:
eval_booexp does just evaluation.
parse_boolexp makes potentially recursive calls to several different
subroutines ---
parse_boolexp_F
This routine does the leaf level parsing and the NOT.
parse_boolexp_E
This routine does the ORs.
pasre_boolexp_T
This routine does the ANDs.
Because property expressions are leaf level expressions, I have only
touched eval_boolexp_F, asking it to call my additional parse_boolprop()
routine. */
int eval_boolexp (dbref player, struct boolexp *b)
{
if (b == TRUE_BOOLEXP) {
return 1;
} else {
switch (b->type) {
case BOOLEXP_AND:
return (eval_boolexp (player, b->sub1)
&& eval_boolexp (player, b->sub2));
case BOOLEXP_OR:
return (eval_boolexp (player, b->sub1)
|| eval_boolexp (player, b->sub2));
case BOOLEXP_NOT:
return !eval_boolexp (player, b->sub1);
case BOOLEXP_CONST:
return (b->thing == player || member (b->thing, db[player].contents)
|| b->thing == db[player].location);
case BOOLEXP_PROP:
return (has_property (player, b->prop_check->type, b->prop_check->class,
#ifdef NUMBER_PROPS
b->prop_check->value
#else
0
#endif
));
default:
abort (); /* bad type */
return 0;
}
}
}
/* If the parser returns TRUE_BOOLEXP, you lose */
/* TRUE_BOOLEXP cannot be typed in by the user; use @unlock instead */
static const char *parsebuf;
static dbref parse_player;
static void skip_whitespace (void)
{
while (*parsebuf && isspace (*parsebuf))
parsebuf++;
}
static struct boolexp *parse_boolexp_E (void); /* defined below */
static struct boolexp *parse_boolprop (char *buf); /* defined below */
/* F -> (E); F -> !F; F -> object identifier */
static struct boolexp *parse_boolexp_F (void)
{
struct boolexp *b;
char *p;
char buf[BUFFER_LEN];
char msg[BUFFER_LEN];
skip_whitespace ();
switch (*parsebuf) {
case '(':
parsebuf++;
b = parse_boolexp_E ();
skip_whitespace ();
if (b == TRUE_BOOLEXP || *parsebuf++ != ')') {
free_boolexp (b);
return TRUE_BOOLEXP;
} else {
return b;
}
/* break; */
case NOT_TOKEN:
parsebuf++;
b = (struct boolexp *) malloc (sizeof (struct boolexp));
b->type = BOOLEXP_NOT;
b->sub1 = parse_boolexp_F ();
if (b->sub1 == TRUE_BOOLEXP) {
free ((void *) b);
return TRUE_BOOLEXP;
} else {
return b;
}
/* break */
default:
/* must have hit an object ref */
/* load the name into our buffer */
p = buf;
while (*parsebuf
&& *parsebuf != AND_TOKEN
&& *parsebuf != OR_TOKEN && *parsebuf != ')') {
*p++ = *parsebuf++;
}
/* strip trailing whitespace */
*p-- = '\0';
while (isspace (*p))
*p-- = '\0';
/* check to see if this is a property expression */
if (index (buf, PROP_DELIMITER)) {
return parse_boolprop (buf);
}
b = (struct boolexp *) malloc (sizeof (struct boolexp));
b->type = BOOLEXP_CONST;
/* do the match */
init_match (parse_player, buf, TYPE_THING);
match_neighbor ();
match_possession ();
match_me ();
match_absolute ();
match_player ();
b->thing = match_result ();
if (b->thing == NOTHING) {
sprintf (msg, "I don't see %s here.", buf);
notify (parse_player, msg);
free ((void *) b);
return TRUE_BOOLEXP;
} else if (b->thing == AMBIGUOUS) {
sprintf (msg, "I don't know which %s you mean!", buf);
notify (parse_player, msg);
free ((void *) b);
return TRUE_BOOLEXP;
} else {
return b;
}
/* break */
}
}
/* T -> F; T -> F & T */
static struct boolexp *parse_boolexp_T (void)
{
struct boolexp *b;
struct boolexp *b2;
if ((b = parse_boolexp_F ()) == TRUE_BOOLEXP) {
return b;
} else {
skip_whitespace ();
if (*parsebuf == AND_TOKEN) {
parsebuf++;
b2 = (struct boolexp *) malloc (sizeof (struct boolexp));
b2->type = BOOLEXP_AND;
b2->sub1 = b;
if ((b2->sub2 = parse_boolexp_T ()) == TRUE_BOOLEXP) {
free_boolexp (b2);
return TRUE_BOOLEXP;
} else {
return b2;
}
} else {
return b;
}
}
}
/* E -> T; E -> T | E */
static struct boolexp *parse_boolexp_E (void)
{
struct boolexp *b;
struct boolexp *b2;
if ((b = parse_boolexp_T ()) == TRUE_BOOLEXP) {
return b;
} else {
skip_whitespace ();
if (*parsebuf == OR_TOKEN) {
parsebuf++;
b2 = (struct boolexp *) malloc (sizeof (struct boolexp));
b2->type = BOOLEXP_OR;
b2->sub1 = b;
if ((b2->sub2 = parse_boolexp_E ()) == TRUE_BOOLEXP) {
free_boolexp (b2);
return TRUE_BOOLEXP;
} else {
return b2;
}
} else {
return b;
}
}
}
struct boolexp *parse_boolexp (dbref player, const char *buf)
{
parsebuf = buf;
parse_player = player;
return parse_boolexp_E ();
}
/* parse a property expression
If this gets changed, please also remember to modify set.c */
static struct boolexp *parse_boolprop (char *buf)
{
char *type = get_string (buf);
char *class = index (type, PROP_DELIMITER);
char *x;
struct boolexp *b;
struct plist *p;
char *temp;
x = type;
b = (struct boolexp *) malloc (sizeof (struct boolexp));
p = new_prop ();
b->type = BOOLEXP_PROP;
b->sub1 = b->sub2 = 0;
b->thing = NOTHING;
b->prop_check = p;
while (isspace (*type) && (*type != PROP_DELIMITER))
type++;
if (*type == PROP_DELIMITER) {
/* Oops! Clean up and return a TRUE */
free ((void *) x);
free ((void *) b);
free ((void *) p);
return TRUE_BOOLEXP;
}
/* get rid of trailing spaces */
for (temp = class - 1; isspace (*temp); temp--)
/*EMPTY*/;
temp++;
*temp = '\0';
class++;
while (isspace (*class) && *class)
class++;
if (!*class) {
/* Oops! CLEAN UP AND RETURN A TRUE */
free ((void *) x);
free ((void *) b);
free ((void *) p);
return TRUE_BOOLEXP;
}
/* get rid of trailing spaces */
for (temp = class; !isspace (*temp) && *temp; temp++)
/*EMPTY*/;
*temp = '\0';
p->type = alloc_string (type);
p->class = alloc_string (class);
free ((void *) x);
return b;
}