/* $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; }