/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/boolexp.c,v 1.8 90/09/16 04:40:58 rearl Exp $ */
/*
* $Log: boolexp.c,v $
* Revision 1.8 90/09/16 04:40:58 rearl
* Preparation code added for disk-based MUCK.
*
* Revision 1.7 90/09/10 02:19:08 rearl
* Introduced string compression of properties, for the
* COMPRESS compiler option.
*
* Revision 1.6 90/08/27 03:19:28 rearl
* Added match_here to key match routines.
*
* Revision 1.5 90/08/11 03:49:51 rearl
* *** empty log message ***
*
* Revision 1.4 90/08/05 03:18:56 rearl
* Redid matching routines.
*
* Revision 1.3 90/08/02 18:49:20 rearl
* Fixed some calls to logging functions.
*
* Revision 1.2 90/07/29 17:30:37 rearl
* Added support for ROOM locks to programs.
*
* Revision 1.1 90/07/19 23:01:56 casie
* Initial revision
*
*
*/
#include "copyright.h"
#include "config.h"
#include <ctype.h>
#include "strings.h"
#include "db.h"
#include "match.h"
#include "externs.h"
#include "params.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, dbref thing )
{
int result;
if(b == TRUE_BOOLEXP) {
return 1;
} else {
switch(b->type) {
case BOOLEXP_AND:
return (eval_boolexp(player, b->sub1, thing)
&& eval_boolexp(player, b->sub2, thing));
case BOOLEXP_OR:
return (eval_boolexp(player, b->sub1, thing)
|| eval_boolexp(player, b->sub2, thing));
case BOOLEXP_NOT:
return !eval_boolexp(player, b->sub1, thing);
case BOOLEXP_CONST:
if (Typeof(b -> thing) == TYPE_PROGRAM)
{
if (DBFETCH(player)->run) return 0;
result = interp(player, b -> thing, thing);
if (!(DBFETCH(player)->run -> pc))
{
free((void *) DBFETCH(player)->run);
DBFETCH(player)->run = 0;
}
return result;
}
return (b->thing == player
|| member(b->thing, DBFETCH(player)->contents)
|| b->thing == DBFETCH(player)->location);
case BOOLEXP_PROP:
return( has_property(player, b -> prop_check -> type,
b -> prop_check -> class));
default:
abort(); /* bad type */
return 0;
}
}
}
struct boolexp *
copy_bool(struct boolexp *old)
{
struct boolexp *o = (struct boolexp *)malloc(sizeof(struct boolexp));
if (!old || !o)
return 0;
o -> type = old -> type;
switch ( old -> type )
{
case BOOLEXP_AND:
case BOOLEXP_OR:
o -> sub1 = copy_bool(old -> sub1);
o -> sub2 = copy_bool(old -> sub2);
break;
case BOOLEXP_NOT:
o -> sub1 = copy_bool(old -> sub1);
break;
case BOOLEXP_CONST:
o -> thing = old -> thing;
break;
case BOOLEXP_PROP:
if (!old -> prop_check)
{
free((void *) o);
return 0;
}
o -> prop_check = new_prop();
o -> prop_check -> class = alloc_string(old -> prop_check -> class);
o -> prop_check -> type = alloc_string(old -> prop_check -> type);
break;
default:
log_status("PANIC: copy_boolexp: Error in boolexp!\n");
abort();
}
return o;
}
/* 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;
struct match_data md;
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, &md);
match_neighbor(&md);
match_possession(&md);
match_me(&md);
match_here(&md);
match_absolute(&md);
match_player(&md);
b->thing = match_result(&md);
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 = alloc_string(buf);
char *class = (char *)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 --)
;
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++)
;
*temp = '\0';
p -> type = alloc_string(type);
p -> class = alloc_string(class);
free((void *) x);
return b;
}