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