/* $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 <ctype.h> #include <string.h> /* some of you might have to use strings.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; }