#include "Process.h" #include "main.h" #include "parser.h" #include <fstream.h> extern "C"{ #include <stdio.h> } #pragma implementation Value* lvarstack::assign (String* s, Value* v){ struct svl_rep* temp; for (temp=pair_list ; temp && temp->next ; temp=temp->next) if (*s == *(temp->symbol)) {temp->val->release(); temp->val = v->grab(); return v;} return NULL; } /************************************************************************** ************************* Frame methods *********************************** ***************************************************************************/ static Value anon (new String ("an anonymous method")); #define PUSH_EXPR_SCOPE {expression_stack.push_scope (); \ data_stack.push_scope ();} Frame::Frame (int obj_on , Value* mthd_nm , Val_List* actuals , Process* process_ptr , Frame* prev , Value* active_method){ Value* tempval; String* tempstring; Val_List* actraverse; if (! active_method) if (!(active_method = db->lookup_var (obj_on , mthd_nm->sym))) {process_ptr->last_error = new Value (E_VAR_NOT_FOUND , ERR); process_ptr->last_error_msg = "Could not find method "; process_ptr->last_error_msg += *(mthd_nm->sym); process_ptr->last_error_msg += "\n"; return;} method_on.push (var_found_on); if (active_method->type != MTHD) {cout << "Non-Method " << *(mthd_nm->sym) << " called as method.\n"; exit (1);} data_stack.push_scope(); data_stack.push_val (active_method); for (actraverse=actuals ; actraverse ; actraverse=actraverse->next) data_stack.push_val (actraverse->elem); delete actuals; previous = prev; this_obj = obj_on; proc = process_ptr; tempval = new Value (obj_on, OBJ); tempstring = new String ("THIS"); local_vars.push (tempstring, tempval); delete tempstring; tempval->release(); tempval = new Value (proc->player_obj, OBJ); tempstring = new String ("PLAYER"); local_vars.push (tempstring, tempval); delete tempstring; tempval->release(); push_method (mthd_nm); } Frame::~Frame (){ proc->active_frame = previous; } int Frame::exprpop(){ Value* temp; if (expression_stack.depth) {temp = expression_stack.peek();} expression_stack.pop_scope(); data_stack.pop_scope(); if (!expression_stack.depth) return 0; if (expression_stack.peek()->type == MTHD) {pop_method(); return 1;} return 0; } void Frame::push_method (Value* mthd_nm){ Value** val_stack_ptr; Value* tempval; Val_List* formals; String* tempstring; int argc; argc = data_stack.scope_depth; if (!argc) {cout << "stack scope was empty in push_method\n"; exit(1);} val_stack_ptr = data_stack.pointer_scope_bottom(); method_names.push_val (mthd_nm); // cerr << "Starting method: " << *(mthd_nm->sym) << "\n"; formals = (*val_stack_ptr)->mthd->symlist; expression_stack.push_val (*(val_stack_ptr++)); argc--; if (formals->length() != argc) {proc->last_error = new Value (E_INVALID_FUNCTION , ERR); proc->last_error_msg = "Incorrect number of parameters passed to "; proc->last_error_msg += *(mthd_nm->sym); proc->last_error_msg += "\n"; return;} tempstring = new String ("CALLER"); if (!(local_vars.lookup(tempstring)) && previous) tempval = new Value (previous->this_obj , OBJ); else tempval = new Value (this_obj , OBJ); local_vars.push (tempstring , tempval); delete tempstring; tempval->release(); for (; formals ; formals=formals->next , val_stack_ptr++) local_vars.push (formals->elem->str, (*val_stack_ptr)); PUSH_EXPR_SCOPE; expression_stack.push_val (expression_stack.peek()->mthd->expr); } void Frame::pop_method (){ String* tempstr; while (tempstr = local_vars.peek_symbol()) {if (*tempstr == "CALLER") break; local_vars.pop();} local_vars.pop(); /** this one picks up caller **/ method_names.pop_val()->release(); exprpop(); method_on.pop(); } void Frame::returned_val (Value* val){ exprpop(); data_stack.push_val (val); } Value* Frame::lookup (Value* symname){ String* temp; Value* retval; temp = symname->sym; // cout << "Looking up symbol: " << *temp << "\n"; if (retval = local_vars.lookup (temp)) {var_found_on = this_obj;} else retval = db->lookup_var (this_obj, temp); // if (retval) // cout << "found a value.\n"; return retval; } int Frame::check_error_raise (Value* errnum, String* msg){ static char numstr [20]; String last_mthd; Value* tempval; if ((errnum->type == ERR) && (! ignore_list.check_is_inlist (errnum->err))) {proc->last_error = errnum->grab(); proc->last_error_msg = "Error code "; sprintf (numstr , "%d" , errnum->err); proc->last_error_msg += numstr; if (msg) {proc->last_error_msg += ": "; proc->last_error_msg += *msg; proc->last_error_msg += "\n"; delete msg;} else proc->last_error_msg += " "; proc->last_error_msg += "raised on object "; sprintf (numstr , "%d" , this_obj); proc->last_error_msg += numstr; proc->last_error_msg += " in method "; while (method_names.depth) {tempval = method_names.pop_val(); if (! last_mthd.length()) {last_mthd = *(tempval->sym); proc->last_error_msg += last_mthd;} else {if ((last_mthd) != *(tempval->sym)) {proc->last_error_msg += " called from "; last_mthd = *(tempval->sym); proc->last_error_msg += last_mthd;}} tempval->release();} return 1;} delete msg; return 0; } int Frame::transfer_to_data(){ Value* temp, *expanded; String* tempstring; temp = expression_stack.pop_val(); exprpop(); if (data_stack.scope_depth || !data_stack.depth) {if (temp->type == SYM) {if (!(expanded = lookup (temp))) {tempstring = new String ("Symbol "); *tempstring += *(temp->sym); *tempstring += " not bound here"; check_error_raise ((expanded = new Value (E_VAR_NOT_FOUND , ERR)), tempstring);} else expanded->grab(); temp->release(); temp = expanded;} data_stack.push_val (temp); temp->release(); return 1;} else {while (temp->type == SYM) {if (!(expanded = lookup (temp))) {tempstring = new String ("Method "); *tempstring += *(temp->sym); *tempstring += " not defined here"; check_error_raise ((expanded = new Value (E_VAR_NOT_FOUND , ERR)), tempstring); temp->release(); exprpop(); data_stack.push_val (expanded); expanded->release(); return 1;} else {if (expanded->type == MTHD) break; else expanded->grab();} temp->release(); temp = expanded;} switch (temp->type) {case SYM: case RESERVED: case MTHD: data_stack.push_val (temp); break; default: exprpop(); tempstring = new String ("function at start of expression must be a METHOD or BUILT-IN"); check_error_raise (expanded = new Value (E_INVALID_FUNCTION , ERR), tempstring); data_stack.push_val (expanded); expanded->release();}} temp->release(); return 1; } int Frame::do_operation (){ Value* temp; int retval; // dump_state(); if (! expression_stack.depth) {temp = data_stack.pop_val(); // cout << "RETURNING VALUE: "; // temp->copy()->print_val(); // cout << "\n"; proc->active_frame = previous; if (previous) previous->returned_val (temp); temp->release(); delete this; return 0;} temp = expression_stack.peek(); if (temp->type != EXPR) {return transfer_to_data();} if (retval = try_operation()) {// cout << print_mem_usage() << "\n"; return retval;} temp = expression_stack.peek(); temp = temp -> nth (data_stack.scope_depth + 1); PUSH_EXPR_SCOPE; expression_stack.push_val(temp); return 1; } int Frame::try_operation(){ Value* bot, *temp2; String* tempstring; if (!(bot = data_stack.peek_scope_bottom())) return 0; if (expression_stack.peek()->expr->length() > data_stack.scope_depth) if (bot->type == RESERVED) if (data_stack.scope_depth <= tokentable[bot->reserved].check_after) return 0; switch (bot->get_type()) {case RESERVED: return handle_reserved(); case MTHD: if (data_stack.scope_depth < expression_stack.peek()->expr->length()) return 0; push_method (&anon); method_on.push(method_on.peek()); return 1; case SYM: if (expression_stack.peek()->expr->length() > data_stack.scope_depth) return 0; if (!(temp2 = lookup (bot)) || temp2->type != MTHD) {/** someone reassigned that variable. **/ tempstring = new String ("symbol "); *tempstring += *(bot->sym); *tempstring += " is not bound to a METHOD"; check_error_raise (temp2 = new Value (E_INVALID_FUNCTION , ERR), tempstring); exprpop(); data_stack.push_val (temp2); temp2->release(); return 5;} method_on.push (var_found_on); *(data_stack.pointer_scope_bottom()) = temp2->grab(); push_method (bot); bot->release(); return 6; default: break;} tempstring = new String ("expression must start with a SYMBOL, METHOD, or RESERVED function, "); *tempstring += type_strings[bot->type]; *tempstring += " found instead"; exprpop(); check_error_raise (temp2 = new Value (E_INVALID_FUNCTION , ERR), tempstring); temp2->release(); return 1; } int Frame::assert_type (Value* val, Value_Type intype){ Value* vtemp; String* tempstring; if (val->type == intype) return 1; vtemp = data_stack.peek_scope_bottom(); tempstring = new String (tokentable [vtemp->reserved].symbol); *tempstring += " expects type "; *tempstring += type_strings[intype]; *tempstring += ", received type "; *tempstring += type_strings[(val)->type]; vtemp = new Value (E_TYPE, ERR); exprpop(); data_stack . push_val (vtemp); check_error_raise (vtemp, tempstring); val->release(); vtemp->release(); return 0; } #define ASSERT_TYPE(v,t) \ if (! assert_type (v, t)) \ return 1; #define ASSERT2(v,t,v2,t2) \ if (! assert_type (v,t)) \ {v2->release(); \ return 1;} \ if (! assert_type (v2, t2)) \ {v->release(); \ return 1;} int Frame::handle_reserved(){ Value* temp; String* tempstring; int i, j; temp = data_stack.peek_scope_bottom(); i = (expression_stack.peek()->expr->length() - 1); if (tokentable [temp->reserved].max_args < i) {tempstring = new String (tokentable[temp->reserved].symbol); *tempstring += " allows "; concat_num (*tempstring, tokentable[temp->reserved].max_args); *tempstring += " arguments, received "; concat_num (*tempstring, i); check_error_raise ((temp = new Value (E_TOO_MANY_ARGUMENTS , ERR)), tempstring); exprpop(); data_stack.push_val (temp); temp->release(); return 2;} if (tokentable [temp->reserved].min_args > i) {tempstring = new String (tokentable[temp->reserved].symbol); *tempstring += " requires "; concat_num (*tempstring, tokentable[temp->reserved].max_args); *tempstring += " arguments, received "; concat_num (*tempstring, i); check_error_raise ((temp = new Value (E_TOO_FEW_ARGUMENTS , ERR)), tempstring); exprpop(); data_stack.push_val (temp); temp->release(); return 2;} // print_mem_usage(); // cout<<tokentable[data_stack.peek_scope_bottom()->reserved].symbol<<"\n"; tempstring = NULL; switch (data_stack.peek_scope_bottom()->reserved) {case EQ: return op_EQ(); case LT: return op_LT(); case GT: return op_GT(); case LTE: return op_LTE(); case GTE: return op_GTE(); case MOD: return op_MOD(); case DIV: return op_DIV(); case SUB: return op_SUB(); case ADD: return op_ADD(); case MUL: return op_MUL(); case SETS: return op_SETS(); case SET: return op_SET(); case NOT: return op_NOT(); case OR: return op_OR(); case AND: return op_AND(); case INDEX: return op_INDEX(); case RANGE: return op_RANGE(); case TONUM: return op_TONUM(); case TOREAL: return op_TOREAL(); case TOSTR: return op_TOSTR(); case FORMAT: return op_FORMAT(); case TOOBJ: return op_TOOBJ(); case TIME: return op_TIME(); case RANDOM: return op_RANDOM(); case LENGTH: return op_LENGTH(); case INSERT: return op_INSERT(); case CRYPT: return op_CRYPT(); case IF: return op_IF(); case DOTIMES: return op_DOTIMES(); case FOREACH: return op_FOREACH(); case WHILE: return op_WHILE(); case PASS: return op_PASS(); case PASS_TO: return op_PASS_TO(); case SLEEP: return op_SLEEP(); case FORK: return op_FORK(); case KILL: return op_KILL(); case ECHO_CMD: return op_ECHO_CMD(); case SETPARENTS: return op_SETPARENTS(); case VAR: return op_VAR(); case RMVAR: return op_RMVAR(); case ADDCMD: return op_ADDCMD(); case RMCMD: return op_RMCMD(); case MATCHCMD: return op_MATCHCMD(); case CALL: return op_CALL(); case METHOD: cout << "MAJOR PROBLEM: 'METHOD' REACHED AS EXPRESSION\n"; cerr << "MAJOR PROBLEM: 'METHOD' REACHED AS EXPRESSION\n"; exit(1); case COMMANDS: return op_COMMANDS(); case VARS: return op_VARS(); case CLONE: return op_CLONE(); case DISCONNECT: return op_DISCONNECT(); case RECONNECT: return op_RECONNECT(); case SHUTDOWN: return op_SHUTDOWN(); case RETURN: return op_RETURN(); case BEGIN_CMD: return op_BEGIN_CMD(); case TOERROR: return op_TOERROR(); case TOLIST: return op_TOLIST(); case IGNORE: return op_IGNORE(); case COMPILE: return op_COMPILE(); case SEARCH: return op_SEARCH(); case PARENTS: return op_PARENTS(); case EXPLODE: return op_EXPLODE(); case IMPLODE: return op_IMPLODE(); case PURGECMDS: return op_PURGECMDS(); case CAR: return op_CAR(); case CDR: return op_CDR(); case CONS: return op_CONS(); case TOSYM: return op_TOSYM(); case AFTER: return op_AFTER(); case BEFORE: return op_BEFORE(); case QUOTE: return op_QUOTE(); case EVAL: return op_EVAL(); case TYPEOF: return op_TYPEOF(); case FILETEXT: return op_FILETEXT(); case RUNSCRIPT: return op_RUNSCRIPT(); case CLASS: return op_CLASS(); case SQRT: return op_SQRT(); case REGSPLIT: return op_REGSPLIT(); case CONNOUT: return op_CONNOUT(); case HANDLE: return op_HANDLE(); case SEMAPHORE: return op_SEMAPHORE(); case ADDRESS: return op_ADDRESS(); case NUM2CHAR: return op_NUM2CHAR(); case CHAR2NUM: return op_CHAR2NUM(); case COLLECT: return op_COLLECT(); case MATCHONE: return op_MATCHONE(); case LOG: return op_LOG(); default: break;} return 1; } /******************************************** ******** the operators ... ***************** ********************************************/ Frame::op_EQ(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); temp->equal (temp2 = data_stack.pop_val(), &tempstring); temp2->release(); check_error_raise (temp, tempstring); exprpop(); data_stack.push_val(temp); temp->release(); return 2; } Frame::op_LT(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp2 = data_stack.pop_val(); temp = data_stack.pop_val()->ensure_clean(); temp->less_than (temp2, &tempstring); temp2->release(); exprpop(); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); return 2; } Frame::op_GT(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp2 = data_stack.pop_val(); temp = data_stack.pop_val()->ensure_clean(); temp->greater_than (temp2, &tempstring); temp2->release(); exprpop(); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); return 2; } Frame::op_MOD(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); while (data_stack.scope_depth > 2) {temp->mul (temp2 = data_stack.pop_val(), &tempstring); temp2->release();} temp2 = data_stack.pop_val()->ensure_clean(); temp2->mod (temp); exprpop(); data_stack.push_val(temp2); check_error_raise (temp2, tempstring); temp->release(); temp2->release(); return 2; } Frame::op_DIV(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); while (data_stack.scope_depth > 2) {temp->mul (temp2 = data_stack.pop_val(), &tempstring); temp2->release();} temp2 = data_stack.pop_val()->ensure_clean(); temp2->div (temp); exprpop(); data_stack.push_val(temp2); check_error_raise (temp2, tempstring); temp->release(); temp2->release(); return 2; } Frame::op_SUB(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); while (data_stack.scope_depth > 2) {temp->add (temp2 = data_stack.pop_val()); temp2->release();} temp2 = data_stack.pop_val()->ensure_clean(); temp2->subtract (temp, &tempstring); exprpop(); data_stack.push_val(temp2); check_error_raise (temp2, tempstring); temp->release(); temp2->release(); return 2; } Frame::op_ADD(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); while (data_stack.scope_depth > 1) {temp->add (temp2 = data_stack.pop_val(), &tempstring); temp2->release();} exprpop(); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); return 2; } Frame::op_MUL(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); while (data_stack.scope_depth > 1) {temp->mul (temp2 = data_stack.pop_val(), &tempstring); temp2->release();} exprpop(); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); return 2; } Frame::op_SET(){ Value* temp; Value* temp2; Value* temp3; Value** vsptr; String* tempstring = NULL;; switch (data_stack.scope_depth) {case 1: if ((expression_stack.peek()->expr->length()) < 3) {exprpop(); temp = new Value (E_TOO_FEW_ARGUMENTS, ERR); check_error_raise (temp); data_stack.push_val (temp); temp->release(); return 1;} if (expression_stack.peek()->nth(2)->type == SYM) data_stack.push_val (expression_stack.peek()->nth(2)); return 0; case 3: temp3 = data_stack.pop_val(); // value temp2 = data_stack.pop_val(); // symbol ASSERT2 (temp2, SYM, temp3, temp3->type); if (! local_vars.assign (temp2->sym , temp3)) {if ((temp2->sym->index ("~") == 0) && (db->pass_vlookup (this_obj, temp2->sym))) {temp = new Value (E_OVERRIDE, ERR); check_error_raise (temp); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2;} else db->addvar (this_obj , temp2->sym , temp3);} data_stack.push_val (temp2); temp2->release(); data_stack.push_val(temp3); temp3->release();} if (data_stack.scope_depth == expression_stack.peek()->expr->length()) {temp = data_stack.pop_val(); exprpop(); data_stack.push_val(temp); temp->release(); return 2;} return 0; } Frame::op_NOT(){ Value* temp; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); temp->not(&tempstring); exprpop(); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); return 1; } Frame::op_OR(){ Value* temp; if (expression_stack.peek()->expr->length() == data_stack.scope_depth || data_stack.peek()->boolean_val()) {temp = data_stack.pop_val(); exprpop(); data_stack.push_val(temp); check_error_raise (temp); temp->release(); return 3;} return 0; } Frame::op_AND(){ Value* temp; String* tempstring = NULL;; if (expression_stack.peek()->expr->length() == data_stack.scope_depth || !data_stack.peek()->boolean_val()) {temp = data_stack.pop_val(); exprpop(); data_stack.push_val(temp); check_error_raise (temp); temp->release(); return 3;} return 0; } Frame::op_INDEX(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp2 = data_stack.pop_val(); temp = temp2->index (data_stack.peek(), &tempstring); exprpop(); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); temp2->release(); return 3; } Frame::op_RANGE(){ Value* temp; Value* temp2; Value* temp3; Val_List* templist, **listptr; String* tempstring = NULL;; int i; temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); temp = data_stack.pop_val(); if (! (temp->type == NUM && temp2->type == NUM)) {temp->release(); temp2->release(); temp3->release(); check_error_raise (temp = new Value (E_TYPE , ERR)); exprpop(); data_stack.push_val (temp); temp->release(); return 1;} i = temp->num; temp->release(); temp = new Value (temp3 , i , temp2->num); if (temp->type == ERR) check_error_raise (temp , new String("invalid arguments to 'range'")); else check_error_raise (temp); temp3->release(); temp2->release(); exprpop(); data_stack.push_val(temp); temp->release(); return 2; } Frame::op_TONUM(){ Value* temp; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); temp->tonum(&tempstring); exprpop(); data_stack.push_val(temp); check_error_raise(temp, tempstring); temp->release(); return 2; } Frame::op_TOREAL(){ Value* temp; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); temp->toreal(&tempstring); exprpop(); data_stack.push_val(temp); check_error_raise(temp, tempstring); temp->release(); return 2; } Frame::op_TOSTR(){ Value* temp; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); temp->tostr(&tempstring); exprpop(); data_stack.push_val(temp); check_error_raise(temp, tempstring); temp->release(); return 4; } Frame::op_TOOBJ(){ Value* temp; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); temp->toobj(&tempstring); exprpop(); data_stack.push_val(temp); check_error_raise(temp, tempstring); temp->release(); return 2; } Frame::op_TIME(){ Value* temp; exprpop(); temp = get_time(); data_stack.push_val(temp); temp->release(); return 2; } Frame::op_RANDOM(){ Value* temp; exprpop(); temp = get_random(); data_stack.push_val(temp); temp->release(); return 2; } Frame:: op_LENGTH(){ Value* temp; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); temp->tolength(&tempstring); exprpop(); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); return 3; } Frame::op_INSERT(){ Value* temp; Value* temp2; Value* temp3; String* tempstring = NULL;; temp3 = data_stack.pop_val(); ASSERT_TYPE (temp3, NUM); temp2 = data_stack.pop_val()->ensure_clean(); temp = data_stack.pop_val(); temp2->insert (temp, temp3->num, &tempstring); temp3->release(); temp->release(); exprpop(); check_error_raise (temp2, tempstring); data_stack.push_val (temp2); temp2->release(); return 4; } Frame::op_CRYPT(){ Value* temp; String* tempstring = NULL;; temp = (data_stack.pop_val())->ensure_clean(); exprpop(); temp->encryption(&tempstring); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); return 5; } Frame::op_IF(){ Value* temp; Value* temp2; if (data_stack.scope_depth == 2) {if (!data_stack.peek()->boolean_val()) {if (expression_stack.peek()->expr->length() == 3) {exprpop(); temp = new Value ((Val_List*)NULL); data_stack.push_val (temp); temp->release(); return 2;} else {temp = new Value (E_BUG_IN_PROCESS_IF , ERR); data_stack.push_val (temp); temp->release(); return 0;}} else return 0;} temp = data_stack.pop_val(); exprpop(); data_stack.push_val (temp); temp->release(); return 3; } Frame::op_DOTIMES(){ Value* temp; Value* temp2; Value* temp3; Value** vsptr; Val_List* templist, **listptr; String* tempstring = NULL;; int i; if (data_stack.scope_depth == 2) {temp2 = data_stack.pop_val(); if (temp2->type != NUM) {exprpop(); check_error_raise (temp = new Value (E_TYPE , ERR)); data_stack.push_val (temp); temp->release(); temp2->release(); return 1;} if (temp2->num < 1) {exprpop(); data_stack.push_val (temp2); temp2->release(); return 1;} local_vars.push (expression_stack.peek()->expr->nth(2)->nth(1)->sym, temp = new Value (1)); data_stack.push_val (temp); temp->release(); tempstring = new String ((*expression_stack.peek()->expr->nth(2)->nth(1)->sym) + "_MaX"); local_vars.push (tempstring, temp2); delete tempstring; temp2->release(); return 0;} if (data_stack.scope_depth == 1) {temp2 = expression_stack.peek(); if (temp2->expr->length() != 3 || (temp3 = temp2->nth (2))->type != EXPR || temp3->expr->length() != 2 || temp3->nth (1)->type != SYM || (temp3->nth (2)->type != NUM && temp3->nth (2)->type != EXPR)) {exprpop(); temp = new Value (E_INVALID_PAIR , ERR); check_error_raise(temp); data_stack.push_val (temp); temp->release(); return 1;} else {PUSH_EXPR_SCOPE; expression_stack.push_val (temp3->nth(2)); return 1;}} temp2 = data_stack.pop_val(); temp = data_stack.peek(); temp->increment(); if (temp->compare (local_vars.peek()) > 0) {exprpop(); data_stack.push_val (temp2); local_vars.pop(); local_vars.pop();} else {local_vars.assign (expression_stack.peek()->nth(2)->nth(1)->sym, temp); temp2->release(); return 0;} temp2->release(); return 1; } Frame::op_FOREACH(){ Value* temp; Value* temp2; Value* temp3; Value** vsptr; Val_List* templist, **listptr; String* tempstring = NULL;; int i; if (data_stack.scope_depth == 2) {temp2 = data_stack.pop_val(); if (temp2->type != LIST && temp2->type != SUBR) {exprpop(); check_error_raise (temp = new Value (E_TYPE , ERR)); data_stack.push_val (temp); temp->release(); temp2->release(); return 1;} if ((temp2->type == SUBR && (! temp2->sub->get_length())) || (! temp2->list)) {exprpop(); data_stack.push_val (temp = new Value ((Val_List*)NULL)); temp->release(); temp2->release(); return 1;} temp = temp2->nth (1); local_vars.push (expression_stack.peek()->expr->nth(2)->nth(1)->sym, temp); data_stack.push_val (temp = new Value (1)); temp->release(); tempstring = new String ((*expression_stack.peek()->expr->nth(2)->nth(1)->sym) + "_LiSt"); local_vars.push (tempstring, temp2); delete tempstring; temp2->release(); return 0;} if (data_stack.scope_depth == 1) {temp2 = expression_stack.peek(); if (temp2->expr->length() != 3 || (temp3 = temp2->nth (2))->type != EXPR || temp3->expr->length() != 2 || temp3->nth (1)->type != SYM || (temp3->nth (2)->type != LIST && temp3->nth (2)->type != EXPR && temp3->nth (2)->type != SYM && temp3->nth (2)->type != SUBR)) {exprpop(); temp = new Value (E_INVALID_PAIR , ERR); check_error_raise(temp); data_stack.push_val (temp); temp->release(); return 1;} else {PUSH_EXPR_SCOPE; expression_stack.push_val (temp3->nth(2)); return 1;}} temp2 = data_stack.pop_val(); temp = data_stack.peek(); temp->increment(); temp3 = local_vars.peek(); if ((temp3->type == SUBR && temp->num > temp3->sub->get_length()) || (temp3->type == LIST && (temp->num > local_vars.peek()->list->length()))) {exprpop(); data_stack.push_val (temp2); local_vars.pop(); local_vars.pop();} else {temp3 = ((temp3->type == SUBR) ? temp3->sub->nth(temp->num) : temp3->list->nth(temp->num)); local_vars.assign (expression_stack.peek()->nth(2)->nth(1)->sym, temp3); temp2->release(); return 0;} temp2->release(); return 1; } Frame::op_WHILE(){ Value* temp; if (data_stack.scope_depth == 2) {if (data_stack.peek()->boolean_val()) return 0; exprpop(); data_stack.push_val (temp = new Value (0)); temp->release(); return 1;} data_stack.pop_val()->release(); data_stack.pop_val()->release(); return 0; } Frame::op_PASS(){ Value* temp; Value* temp2; Value** vsptr; String* tempstring = NULL;; temp = method_names.highest_not_anon (&anon) -> grab(); temp2 = db->pass_vlookup (this_obj , temp->str); temp2 = db->pass_vlookup (method_on.peek(), temp->str); if (! temp2) {tempstring = new String ("Method "); *tempstring += *(temp->str); *tempstring += " not defined on any parents"; exprpop(); check_error_raise (temp2 = new Value (E_CANNOT_PASS , ERR), tempstring); data_stack.push_val (temp2); temp->release(); return 3;} method_on.push(var_found_on); vsptr = data_stack.pointer_scope_bottom(); (*vsptr)->release(); *vsptr = temp2->grab(); push_method (temp); temp->release(); return 4; } Frame::op_PASS_TO(){ Value* temp; Value* temp2; Value* temp3; Value** vsptr; Val_List* templist, **listptr; String* tempstring = NULL;; int i; temp3 = data_stack.pop_val(); if (temp3->type != OBJ) {exprpop(); check_error_raise (temp2 = new Value (E_TYPE , ERR), new String ("pass-to requires an object as the last argument")); data_stack.push_val (temp2); temp3->release(); temp2->release(); return 3;} temp = method_names.highest_not_anon (&anon); if (! db->inparents (method_on.list[depth_found_at] , temp3->obj)) {exprpop(); check_error_raise (temp2 = new Value (E_INVALID_OBJECT , ERR), new String ("methods can only pass to one of their parents")); data_stack.push_val (temp2); temp2->release(); temp3->release(); return 3;} temp->grab(); temp2 = db->lookup_var (temp3->obj , temp->str); temp3->release(); if (! temp2) {tempstring = new String ("Method "); *tempstring += *(temp->str); *tempstring += " not defined on any parents"; exprpop(); check_error_raise (temp2 = new Value (E_CANNOT_PASS , ERR), tempstring); data_stack.push_val (temp2); temp->release(); return 3;} method_on.push (var_found_on); vsptr = data_stack.pointer_scope_bottom(); (*vsptr)->release(); *vsptr = temp2->grab(); push_method (temp); temp->release(); return 4; } Frame::op_SLEEP(){ Value* temp; temp = data_stack.pop_val(); ASSERT_TYPE (temp, NUM); if (temp->num > 0) proc->add_sleeping(temp->num); exprpop(); data_stack.push_val (temp); temp->release(); return 1; } Frame::op_FORK(){ Value* temp; Value* temp2; Value* temp3; Value** vsptr; Val_List* templist, **listptr; String* tempstring = NULL;; int i; if (data_stack.scope_depth == 1) {if (expression_stack.peek()->expr->length() < 2) {exprpop(); check_error_raise (temp = new Value (E_TOO_FEW_ARGUMENTS, ERR), new String ("fork requires an argument")); data_stack.push_val (temp); temp->release(); return 1;} if ((temp = expression_stack.peek()->expr->nth(2))->type == SYM) data_stack.push_val (temp); else return 0;} if (data_stack.scope_depth > 1 && data_stack.scope_depth < expression_stack.peek()->expr->length()) return 0; for (templist = NULL ; data_stack.scope_depth > 2 ;) templist = new Val_List (data_stack.pop_val() , templist); temp2 = data_stack.peek(); if (temp2->type != SYM || !lookup (temp2)) {delete templist; exprpop(); check_error_raise (temp = new Value (E_INVALID_FUNCTION , ERR), new String ("fork requires a symbol as the first argument")); data_stack.push_val (temp); temp->release(); return 1;} i = all_processes.add_process (proc->player_obj , temp2 , templist , proc->ticks_left / 2); proc->ticks_left /= 2; exprpop(); temp = new Value (i); data_stack.push_val (temp); temp->release(); return 4; } Frame::op_KILL(){ Value* temp; /** okay ... this is sort of a hack ... but it was the *** easiest way to do the job. */ check_error_raise (temp = new Value (E_NOT_CONNECTED , ERR)); temp->release(); return 1; } Frame::op_ECHO_CMD(){ Value* temp; Value* temp2; int i; temp2 = data_stack.pop_val(); ASSERT_TYPE (temp2 , STR); if (i = all_sockets.send_line (this_obj , temp2->str)) {if (i < 0) {temp = new Value (new String ("quit"), SYM); all_processes.add_process (this_obj , temp , NULL); temp->release(); temp = new Value (E_NOT_CONNECTED , ERR);} else temp = temp2->grab();} else {temp = new Value (E_INVALID_OBJECT , ERR);} exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); return 2; } Frame::op_SETPARENTS(){ Value* temp; Value* temp2; Value* temp3; temp2 = data_stack.pop_val(); if (temp2->type == SUBR) temp2->subr_to_list(); temp3 = data_stack.pop_val(); ASSERT2 (temp3 , OBJ , temp2 , LIST); if (!this_obj) {temp = new Value (db->chparents (temp3->obj , temp2->list)); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 5;} exprpop(); check_error_raise (temp = new Value (E_SYSTEM_ONLY, ERR), new String ("setparents can only be evaluated by object #0")); data_stack . push_val (temp); temp->release(); return 1; } Frame::op_VAR(){ Value* temp; Value* temp2; Value* temp3; int i; if (data_stack.scope_depth == 1) {if ((i = expression_stack.peek()->expr->length()) < 3) {exprpop(); temp = new Value (E_TOO_FEW_ARGUMENTS , ERR); check_error_raise (temp, new String ("'var' requires at least two arguments")); data_stack.push_val (temp); temp->release(); return 1;} temp2 = expression_stack.peek()->nth(2); if (temp2->type != SYM) {exprpop(); check_error_raise (temp = new Value (E_TYPE , ERR), new String ("var requires a symbol for the first argument")); data_stack.push_val (temp); temp->release(); return 1;} temp3 = new Value (E_UNINITIALIZED , ERR); local_vars.push (temp2->sym , temp3); temp3->release(); data_stack.push_val (temp2); return 0;} if (data_stack.scope_depth < expression_stack.peek()->expr->length()) return 0; temp3 = data_stack.pop_val(); /* value */ local_vars.pop(); exprpop(); data_stack.push_val (temp3); temp3->release(); return 2; } Frame::op_RMVAR(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp2 = data_stack.pop_val(); if (temp2->type == STR) {temp2 = temp2->ensure_clean(); temp2->type = SYM;} ASSERT_TYPE (temp2, SYM); if (db->rmvar (this_obj, temp2->sym)) {temp = temp2->grab();} else {temp = new Value (E_VAR_NOT_FOUND, ERR); tempstring = new String ("Variable "); *tempstring += *temp2->sym; *tempstring += " is not bound here";} exprpop(); data_stack . push_val (temp); check_error_raise (temp, tempstring); temp->release(); temp2->release(); return 3; } Frame::op_ADDCMD(){ Value* temp; Value* temp2; Value* temp3; Val_List* templist; String* tempstring = NULL;; int i; temp2 = data_stack.pop_val(); temp3 = data_stack.pop_val(); if (temp2->type == STR) {temp2 = temp2->ensure_clean(); temp2->type = SYM;} ASSERT2 (temp3, LIST , temp2, SYM); templist = temp3->list->copy(); i = db->addcmd (this_obj, templist , new String (*(temp2->str))); exprpop(); if (i) data_stack.push_val (temp3); else {delete templist; data_stack.push_val (temp = new Value (E_CMD_NOT_FOUND, ERR)); check_error_raise (temp, new String ("invalid command sentence passed to addcmd")); temp->release();} temp2->release(); temp3->release(); return 3; } Frame::op_RMCMD(){ Value* temp; Value* temp2; String* tempstring = NULL;; int i; temp2 = data_stack.pop_val(); ASSERT_TYPE (temp2, STR); if (! db->rmcmd (this_obj , temp2->str)) {tempstring = new String ("rmcmd could not find command "); *tempstring += *(temp2->str); *tempstring += " on this object"; exprpop(); check_error_raise (temp = new Value (E_CMD_NOT_FOUND , ERR), tempstring); data_stack.push_val (temp); temp->release(); return 1;} exprpop(); data_stack . push_val (temp2); temp2->release(); return 3; } Frame::op_MATCHCMD(){ Value* temp; Value* temp2; temp2 = data_stack.pop_val(); ASSERT_TYPE (temp2, STR); temp = db->listmatches (this_obj, temp2->str); exprpop(); data_stack . push_val (temp); temp->release(); temp2->release(); return 5; } Frame::op_CALL(){ Value* temp, *temp2, *temp3; Value** vsptr; Val_List* templist, **listptr; String* tempstring = NULL;; int i; int j; if (data_stack.scope_depth == 2 && expression_stack.peek()->expr->length() > 2 && expression_stack.peek()->expr->nth(3)->type == SYM) {data_stack.push_val (expression_stack.peek()->nth(3)); return 1;} if (data_stack.scope_depth < expression_stack.peek()->expr->length()) return 0; templist = NULL; while (data_stack.scope_depth > 3) templist = new Val_List (data_stack.pop_val() , templist); temp2 = data_stack.pop_val(); temp3 = data_stack.pop_val(); if (temp3->get_type() == USER) {templist = new Val_List (temp3->user->get_val()->grab(), templist); temp = new Value (temp3->user->get_type(), OBJ); temp3->release(); temp3 = temp;} if (temp2->type != SYM || temp3->type != OBJ) {exprpop(); check_error_raise (temp = new Value (E_TYPE , ERR), new String ("call requires a symbol and an object as arguments")); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); delete templist; return 1;} if (! db->obj_exists (temp3->obj)) {exprpop(); check_error_raise (temp = new Value (E_INVALID_OBJECT , ERR), new String ("Attempting to 'call' a method on an invalid object")); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); delete templist; return 1;} if (! (temp = db->lookup_var (temp3->obj , temp2->sym))) {tempstring = new String ("default"); if ((temp = db->lookup_var (temp3->obj , tempstring)) && temp->type == MTHD) {templist = new Val_List (temp2, new Val_List (new Value (templist))); temp2 = new Value (tempstring, SYM);} else {delete tempstring; tempstring = new String ("Object "); concat_num (*tempstring, temp3->obj); *tempstring += " does not define method "; *tempstring += *(temp2->sym); exprpop(); check_error_raise (temp = new Value (E_VAR_NOT_FOUND , ERR), tempstring); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); delete templist; return 1;}} if (temp->type != MTHD) {tempstring = new String ("Attempting to call non-METHOD variable "); *tempstring += *(temp2->sym); exprpop(); check_error_raise (temp = new Value (E_INVALID_FUNCTION , ERR), tempstring); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); delete templist; return 1;} // cerr <<"Calling method " <<*(temp2->sym) <<" on " <<(temp3->obj) <<"\n"; proc->active_frame = new Frame (temp3->obj , temp2 , templist , proc , this , temp); temp2->release(); temp3->release(); return 1; } Frame::op_COMMANDS(){ Value* temp; temp = db->listcmds (this_obj); exprpop(); data_stack . push_val (temp); temp->release(); return 2; } Frame::op_VARS(){ Value* temp; temp = db->listvars (this_obj); exprpop(); data_stack . push_val (temp); temp->release(); return 2; } Frame::op_CLONE(){ Value* temp; temp = new Value (db->clone_obj (this_obj) , OBJ); exprpop(); data_stack . push_val (temp); temp->release(); return 2; } Frame::op_DISCONNECT(){ Value* temp; int i; exprpop(); if (i = all_sockets.break_connection (this_obj)) temp = new Value (this_obj , OBJ); else temp = new Value (0, NUM); check_error_raise(temp); data_stack.push_val (temp); temp->release(); return 2; } Frame::op_RECONNECT(){ Value* temp; Value* temp2; Value* temp3; String* tempstring = NULL;; int i; temp2 = data_stack.pop_val(); temp3 = data_stack.pop_val(); ASSERT2 (temp3 , OBJ , temp2 , OBJ); if (! db->obj_exists (temp3->obj)) {temp2->release(); temp3->release(); exprpop(); temp = new Value (E_INVALID_OBJECT , ERR); data_stack . push_val (temp); check_error_raise (temp); temp->release();} if (!this_obj) {// cerr << "Moving connection to " << temp2->obj << "\n"; all_sockets.break_connection (temp2->obj); i = all_sockets.move_connection (temp3->obj , temp2->obj); if (i) {temp = new Value (temp2->obj , OBJ); if (proc->player_obj == temp3->obj) proc->player_obj = temp2->obj;} else {temp = new Value (E_INVALID_OBJECT , ERR);}} else {temp = new Value (E_SYSTEM_ONLY , ERR);} temp2->release(); temp3->release(); exprpop(); data_stack . push_val (temp); check_error_raise (temp); temp->release(); return 1; } Frame::op_SHUTDOWN(){ Value* temp; if (!this_obj) {cout << "Shutdown initiated by object " << proc->player_obj << "\n"; delete db; exit (1);} exprpop(); check_error_raise (temp = new Value (E_SYSTEM_ONLY, ERR)); data_stack . push_val (temp); temp->release(); return 1; } Frame::op_RETURN(){ Value* temp; temp = data_stack.pop_val(); while (expression_stack.scope_depth && !exprpop()); data_stack.push_val(temp); temp->release(); return 2; } Frame::op_BEGIN_CMD(){ Value* temp; temp = data_stack.pop_val(); exprpop(); data_stack.push_val (temp); temp->release(); return 1; } Frame::op_TOERROR(){ Value* temp; Value* temp2; String* tempstring = NULL;; if (data_stack.scope_depth > 2) {temp2 = data_stack.pop_val(); temp = data_stack.pop_val()->ensure_clean(); ASSERT2(temp, NUM, temp2, STR); tempstring = new String (*(temp2->str)); temp2->release();} else {temp = data_stack.pop_val()->ensure_clean(); ASSERT_TYPE (temp, NUM);} temp->toerr(); exprpop(); data_stack.push_val (temp); check_error_raise (temp, tempstring); temp->release(); return 1; } Frame::op_TOLIST(){ Value* temp; Val_List* templist; templist = NULL; while (data_stack.scope_depth > 1) templist = new Val_List (data_stack.pop_val() , templist); temp = new Value (templist); exprpop(); data_stack.push_val (temp); temp->release(); return 4; } Frame::op_IGNORE(){ Value* temp; if (data_stack.scope_depth == 2) {temp = data_stack.pop_val(); if (temp->type == ERR) temp->type = NUM; ASSERT_TYPE (temp , NUM); ignore_list.push (temp->num); data_stack.push_val (temp); temp->release(); return 0;} ignore_list.pop (); check_error_raise (temp = data_stack.pop_val()); exprpop(); data_stack.push_val (temp); temp->release(); return 1; } Frame::op_COMPILE(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp2 = data_stack.pop_val(); ASSERT_TYPE (temp2 , STR); tempstring = NULL; if (! (temp = parse_string (temp2->str))) {temp = new Value (E_PARSE_ERROR, ERR); tempstring = new String (parse_fail_msg);} exprpop(); check_error_raise (temp, tempstring); data_stack.push_val (temp); temp->release(); temp2->release(); return 12; } Frame::op_SEARCH(){ Value* temp; Value* temp2; Value* temp3; Val_List* templist, **listptr; String* tempstring = NULL;; int i; temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); switch (temp3->type) {case STR: if (temp3->type != STR) temp = new Value (E_TYPE , ERR); else {i = temp3->str->index (*temp2->str) + 1; temp = new Value (i);} break; case SUBR: for (temp = NULL , i=1 , templist = temp3->sub->sublist ; i <= temp3->sub->get_length() ; i++ , templist = templist->next) if (! temp2->compare (templist->elem)) {temp = new Value (i); break;} if (!temp) temp = new Value (0); break; case LIST: for (temp = NULL , i=1 , templist = temp3->list ; templist ; i++ , templist = templist->next) if (! temp2->compare (templist->elem)) {temp = new Value (i); break;} if (!temp) temp = new Value (0); break; default: temp = new Value (E_TYPE , ERR);} exprpop(); temp2->release(); temp3->release(); check_error_raise (temp); data_stack.push_val (temp); temp->release(); return 4; } Frame::op_PARENTS(){ exprpop(); data_stack.push_val (db->listparents(this_obj)); data_stack.peek()->release(); return 2; } Frame::op_EXPLODE(){ Value* temp; Value* temp2; Value* temp3; Val_List* templist, **listptr; String* tempstring = NULL;; int i; temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); ASSERT2 (temp2 , STR , temp3 , STR); if (!temp2->str->length()) check_error_raise (temp = new Value (E_BAD_SEPERATOR , ERR), new String ("explode requires a non-empty separator")); else {tempstring = new String (*temp3->str); templist = NULL; for (listptr = &templist ; (i = tempstring->index (*temp2->str , 0)) >= 0 ;) {temp = new Value (new String (tempstring->before (*temp2->str, i))); *listptr = new Val_List (temp); listptr = & (*listptr)->next; *tempstring = tempstring->after (*temp2->str , i);} *listptr = new Val_List (new Value (tempstring)); temp = new Value (templist);} exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 5; } Frame::op_PURGECMDS(){ Value* temp; exprpop(); data_stack.push_val (temp = new Value (db->purgecmds (this_obj))); temp->release(); return 4; } Frame::op_CAR(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp = data_stack.pop_val(); temp2 = temp->car(&tempstring); check_error_raise (temp2, tempstring); temp->release(); exprpop(); data_stack.push_val (temp2); temp2->release(); return 1; } Frame::op_CDR(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp = data_stack.pop_val(); switch (temp->type) {case LIST: case EXPR: if (temp->list->length() == 1) temp2 = new Value ((Val_List*)NULL); else temp2 = new Value (temp , 2 , temp->list->length()); break; case SUBR: if (temp->sub->get_length() == 1) temp2 = new Value ((Val_List*)NULL); else temp2 = new Value (temp , 2 , temp->sub->get_length()); break; default: temp2 = new Value (E_TYPE , ERR); tempstring = new String ("cdr requires a LIST argument");} exprpop(); check_error_raise (temp2, tempstring); data_stack.push_val (temp2); temp->release(); temp2->release(); return 1; } Frame::op_CONS(){ Value* temp; Value* temp2; temp = data_stack.pop_val(); if (temp->type == SUBR) {temp = temp->ensure_clean(); temp->subr_to_list();} ASSERT_TYPE (temp , LIST); temp2 = data_stack.pop_val(); temp = temp->ensure_clean(); temp->list = new Val_List (temp2, temp->list); exprpop(); data_stack.push_val (temp); temp->release(); return 1; } Frame::op_TOSYM(){ Value* temp; temp = data_stack.pop_val(); ASSERT_TYPE (temp , STR); temp = temp->ensure_clean(); *(temp->sym) = upcase (*(temp->sym)); temp->type = SYM; exprpop(); data_stack.push_val (temp); temp->release(); return 1; } Frame::op_AFTER(){ Value* temp; Value* temp2; Value* temp3; Val_List* templist, **listptr; String* tempstring = NULL;; int i; temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); switch (temp3->type) {case LIST: case EXPR: case SUBR: if (temp2->type != NUM) {exprpop(); check_error_raise (temp = new Value (E_TYPE , ERR), new String ("after requires a NUMBER with a LIST")); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 1;} if (temp3->get_length() < temp2->num || temp2->num < 1) {exprpop(); check_error_raise (temp = new Value (E_RANGE , ERR), new String ("out of range for 'after'")); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 1;} exprpop(); if (temp3->get_length() == temp2->num) temp = new Value ((Val_List*) NULL); else temp = new Value (temp3, (temp2->num + 1), temp3->get_length()); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2; case STR: switch (temp2->type) {case NUM: if (temp3->get_length() < temp2->num || temp2->num < 1) {exprpop(); check_error_raise (temp = new Value (E_RANGE , ERR), new String ("out of range for 'after'")); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2;} temp = new Value (new String (temp3->str->after (temp2->num - 1))); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2; case STR: if (! temp3->str->contains (*(temp2->str))) {exprpop(); check_error_raise (temp = new Value (E_RANGE , ERR), new String ("string 2 doesn't contain string 1 in 'after'")); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 3;} temp= new Value (new String (temp3->str->after (*(temp2->str)))); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2; default: exprpop(); check_error_raise (temp = new Value (E_TYPE , ERR), new String ("'after' requires a string or a list")); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release();}} return 1; } Frame::op_BEFORE(){ Value* temp; Value* temp2; Value* temp3; temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); switch (temp3->type) {case LIST: case EXPR: case SUBR: if (temp2->type != NUM) {exprpop(); check_error_raise (temp = new Value (E_TYPE , ERR)); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 1;} if (temp3->get_length() < temp2->num || temp2->num < 1) {check_error_raise (temp = new Value (E_RANGE , ERR), new String ("'before' requires a NUMBER with a LIST")); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 1;} exprpop(); if (temp2->num == 1) temp = new Value ((Val_List*) NULL); else temp = new Value (temp3, 1 , temp2->num - 1); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2; case STR: switch (temp2->type) {case NUM: if (temp3->get_length() < temp2->num || temp2->num < 1) {exprpop(); check_error_raise (temp = new Value (E_RANGE , ERR)); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2;} temp = new Value (new String (temp3->str->before (temp2->num - 1))); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2; case STR: if (! temp3->str->contains (*(temp2->str))) {check_error_raise (temp = new Value (E_RANGE , ERR), new String("string 2 doesn't contain string 1 in 'before'")); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 3;} temp= new Value (new String (temp3->str->before(*(temp2->str)))); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2; default: exprpop(); check_error_raise (temp = new Value (E_TYPE , ERR)); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release();}} return 1; } Frame::op_QUOTE(){ Value* temp; if (expression_stack.peek()->get_length() > 1) temp = expression_stack.peek()->nth(2)->grab(); else check_error_raise (temp = new Value (E_TOO_FEW_ARGUMENTS , ERR), new String ("quote requires an argument")); exprpop(); if (temp->get_type() == EXPR) {temp = temp->ensure_clean(); temp->type = LIST;} data_stack.push_val (temp); temp->release(); return 1; } Frame::op_EVAL(){ Value* temp; if (data_stack.scope_depth < 3) {temp = data_stack.peek(); PUSH_EXPR_SCOPE; if (temp->get_type() == LIST) {temp = temp->copy(); temp->type = EXPR; expression_stack.push_val (temp); temp->release();} else expression_stack.push_val (temp); return 1;} temp = data_stack.pop_val(); exprpop(); data_stack.push_val (temp); return 1; } Frame::op_TYPEOF(){ Value* temp; Value* temp2; temp2 = data_stack.peek(); switch (temp2->type) {case USER: temp = new Value (temp2->user->get_type(), OBJ); break; case SUBR: temp = new Value (type_strings[LIST], SYM); break; default: temp = new Value (type_strings[temp2->type], SYM); break;} exprpop(); data_stack.push_val (temp); temp->release(); return 1; } Frame::op_FILETEXT(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp2 = data_stack.pop_val(); ASSERT_TYPE (temp2, STR); if (temp2->str->length() && temp2->str->contains ("..")) {temp2->release(); check_error_raise (temp = new Value (E_BAD_FILE , ERR), new String ("attempting to get filetext of invalid file")); exprpop(); data_stack.push_val (temp); return 4;} tempstring = new String ("text/"); *tempstring += *(temp2->str); temp = new Value (new ifstream (tempstring->chars())); exprpop(); check_error_raise (temp); data_stack.push_val (temp); delete tempstring; temp2->release(); temp->release(); return 10; } Frame::op_RUNSCRIPT(){ Value* temp; Value* temp2; Value* temp3; String* tempstring = NULL;; if (this_obj) {exprpop(); check_error_raise (temp = new Value (E_SYSTEM_ONLY, ERR), new String ("only the system object can use run-script")); data_stack . push_val (temp); temp->release(); return 1;} if (data_stack.scope_depth == 3) temp3 = data_stack.pop_val(); else temp3 = NULL; temp2 = data_stack.pop_val(); ASSERT2 (temp2, STR, temp3, STR); if (temp2->str->length() && (temp2->str->contains ("..") || temp2->str->contains (" "))) {temp2->release(); check_error_raise (temp = new Value (E_BAD_FILE , ERR), new String ("attempting to run-script on invalid file")); exprpop(); data_stack.push_val (temp); return 4;} tempstring = new String ("script/"); *tempstring += *(temp2->str); exprpop(); check_error_raise (temp = new Value (popen (tempstring->chars() , "r"))); data_stack.push_val(temp); delete tempstring; temp3->release(); temp2->release(); temp->release(); return 1; // run by the system object ... ticks do not matter. } Frame::op_CLASS(){ Value* temp; Value* temp2; Value* temp3; temp = data_stack.pop_val(); temp3 = data_stack.pop_val(); ASSERT2 (temp3 , OBJ , temp , temp->get_type()); temp2 = new Value (temp3, temp); check_error_raise (temp2); exprpop(); data_stack.push_val (temp2); temp2->release(); temp3->release(); temp->release(); return 3; } Frame::op_SQRT(){ Value* temp; String* tempstring = NULL;; temp = data_stack.pop_val()->ensure_clean(); temp->square_root(&tempstring); check_error_raise (temp, tempstring); exprpop(); data_stack.push_val(temp); temp->release(); return 1; } Frame::op_REGSPLIT(){ Value* temp; Value* temp2; Value* temp3; temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); ASSERT2 (temp2, STR, temp3, STR); check_error_raise(temp = reg_split(temp2, temp3)); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 5; } Frame::op_CONNOUT(){ Value* temp; Value* temp2; Value* temp3; String* tempstring = NULL;; int i; if (this_obj) {exprpop(); check_error_raise (temp = new Value (E_SYSTEM_ONLY, ERR), new String ("only the system object can use connect-out")); data_stack . push_val (temp); temp->release(); return 1;} temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); ASSERT2 (temp2, OBJ, temp3, STR); if (! (db->obj_exists (temp2->obj))) {exprpop(); check_error_raise (temp = new Value (E_INVALID_OBJECT, ERR), new String ("invalid object passed to connect-out")); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 3;} all_sockets.break_connection (temp2->obj); if (!(all_sockets.add_connection (temp3->str, temp2->obj))) {temp2->release(); temp2 = new Value (E_NOT_CONNECTED , ERR);} check_error_raise (temp2); exprpop(); data_stack.push_val (temp2); temp2->release(); temp3->release(); return 10; } Frame::op_HANDLE(){ Value* temp; temp = data_stack.pop_val(); exprpop(); data_stack.push_val (temp); temp->release(); return 1; } Frame::op_SEMAPHORE(){ Value* temp; Value* temp2; Value* temp3; String* tempstring = NULL;; switch (data_stack.scope_depth) {case 1: if ((expression_stack.peek()->expr->length()) < 3) {exprpop(); temp = new Value (E_TOO_FEW_ARGUMENTS, ERR); check_error_raise (temp); data_stack.push_val (temp); temp->release(); return 1;} if (expression_stack.peek()->nth(2)->type == SYM) data_stack.push_val (expression_stack.peek()->nth(2)); return 0; case 3: temp3 = data_stack.pop_val(); // value temp2 = data_stack.pop_val(); // symbol ASSERT2 (temp2, SYM, temp3, temp3->type); if (! local_vars.assign (temp2->sym , temp3)) {if ((temp2->sym->index ("~") == 0) && (db->pass_vlookup (this_obj, temp2->sym))) {temp = new Value (E_OVERRIDE, ERR); check_error_raise (temp); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2;} else {temp = db->lookup_var (this_obj , temp2->sym); if (!temp || temp->compare (temp3)) db->addvar (this_obj , temp2->sym , temp3); else {exprpop(); tempstring = new String ("semaphore variable "); *tempstring += *(temp2->sym); *tempstring += " already set to that value"; temp = new Value (E_SEMAPHORE, ERR); check_error_raise (temp , tempstring); temp->release(); temp2->release(); temp3->release(); return 2;}}} data_stack.push_val (temp2); temp2->release(); data_stack.push_val(temp3); temp3->release();} if (data_stack.scope_depth == expression_stack.peek()->expr->length()) {temp = data_stack.pop_val(); exprpop(); data_stack.push_val(temp); temp->release(); return 2;} return 0; } Frame::op_ADDRESS(){ Value* temp; String* tempstring = NULL;; exprpop(); if (tempstring = all_sockets.get_destination (this_obj)) temp = new Value (tempstring); else temp = new Value (E_NOT_CONNECTED, ERR); check_error_raise (temp, new String ("unconnected object has no 'address'")); data_stack.push_val (temp); return 5; } Frame::op_GTE(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp2 = data_stack.pop_val(); temp = data_stack.pop_val()->ensure_clean(); temp->greater_than_equal (temp2, &tempstring); temp2->release(); exprpop(); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); return 2; } Frame::op_LTE(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp2 = data_stack.pop_val(); temp = data_stack.pop_val()->ensure_clean(); temp->less_than_equal (temp2, &tempstring); temp2->release(); exprpop(); data_stack.push_val(temp); check_error_raise (temp, tempstring); temp->release(); return 2; } Frame::op_FORMAT(){ Value* temp; Value* temp2; String* tempstring = NULL;; temp2 = data_stack.pop_val(); ASSERT_TYPE (temp2, NUM); temp = (data_stack.pop_val())->ensure_clean(); if (temp2->num > 10) temp->format(0, temp2->num); else temp->format(0, 79); exprpop(); data_stack.push_val(temp); check_error_raise(temp, tempstring); temp->release(); temp2->release(); return 4; } Frame::op_IMPLODE(){ Value* temp; Value* temp2; Value* temp3; String* tempstring = NULL;; temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); ASSERT2 (temp2 , STR , temp3 , LIST); temp = temp3->implode (temp2, &tempstring); check_error_raise (temp, tempstring); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 4; } Frame::op_SETS(){ Value* temp; Value* temp2; Value* temp3; String* tempstring = NULL;; if (data_stack.scope_depth == 3) {temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); ASSERT2 (temp2, SYM, temp3, temp3->type); if (! local_vars.assign (temp2->sym , temp3)) {if ((temp2->sym->index ("~") == 0) && (db->pass_vlookup (this_obj, temp2->sym))) {temp = new Value (E_OVERRIDE, ERR); check_error_raise (temp); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 2;} else db->addvar (this_obj , temp2->sym , temp3);} data_stack.push_val (temp2); temp2->release(); data_stack.push_val(temp3); temp3->release();} if (data_stack.scope_depth == expression_stack.peek()->expr->length()) {temp = data_stack.pop_val(); exprpop(); data_stack.push_val(temp); temp->release(); return 2;} return 0; } Frame::op_NUM2CHAR(){ Value* temp; String* tempstring; temp = data_stack.pop_val(); ASSERT_TYPE (temp, NUM); tempstring = new String ((char)temp->num); temp->release(); temp = new Value (tempstring); exprpop(); data_stack.push_val (temp); temp->release(); return 1; } Frame::op_CHAR2NUM(){ Value* temp; int i=0; temp = data_stack.pop_val(); ASSERT_TYPE (temp, STR); if (temp->str->length()) i = temp->str->elem(0); temp->release(); temp = new Value (i); exprpop(); data_stack.push_val (temp); temp->release(); return 1; } Frame::op_COLLECT(){ Value* temp; Val_List* templist; temp = data_stack.pop_val(); ASSERT_TYPE (temp, SYM); templist = db->collect_var (this_obj , temp->sym); exprpop(); data_stack.push_val (new Value (templist)); temp->release(); return 5; } Frame::op_MATCHONE(){ Value* temp, *temp2, *temp3; String* tempstring = NULL;; temp3 = data_stack.pop_val(); temp2 = data_stack.pop_val(); ASSERT2 (temp2 , LIST , temp3 , STR); temp = list_lookup (temp2->list, temp3->str, &tempstring); check_error_raise (temp, tempstring); exprpop(); data_stack.push_val (temp); temp->release(); temp2->release(); temp3->release(); return 3; } Frame::op_LOG(){ Value *temp; if (this_obj) {exprpop(); check_error_raise (temp = new Value (E_SYSTEM_ONLY, ERR), new String ("only the system object can use 'log'")); data_stack . push_val (temp); temp->release(); return 1;} temp = data_stack.pop_val(); ASSERT_TYPE (temp , STR); cout << "LOG FROM #" << proc->player_obj << ": " << *(temp->str) << "\n"; exprpop(); data_stack.push_val (temp); temp->release(); return 1; } /** for debugging only **/ void Frame::dump_state(){ Value* temp; cout << "data_stack: depth = " << data_stack.depth << " scope depth = "; cout << data_stack.scope_depth; if (data_stack.depth) {temp = data_stack.peek()->copy(); cout << " top: "; temp->print_val(); temp->release(); temp = data_stack.peek(); cout << " use_count: " << temp->use_count;} cout << "\n "; cout << "expr stack: depth = " << expression_stack.depth; cout << " scope depth = " << expression_stack.scope_depth; if (expression_stack.depth) {temp = expression_stack.peek()->copy(); cout << " top: "; temp->print_val(); temp->release(); temp = expression_stack.peek(); cout << " use_count: " << temp->use_count;} cout << "\n"; } void Frame::dump_local_vars(){ struct svl_rep* rptr; for (rptr = local_vars.pair_list ; rptr ; rptr = rptr->next) cout << *(rptr->symbol) << " "; cout << "\n"; } int Frame::is_handling_error(int err, Value* msg){ Value* tempval, *temperr; data_stack.pop_val()->release(); while (data_stack.depth) {if ((data_stack.scope_depth == 3) && (tempval = data_stack.peek_scope_bottom())) {if (tempval->type == RESERVED && tempval->reserved == HANDLE) {tempval = data_stack.pop_val(); if ((temperr = data_stack.peek())->type == NUM && temperr->num == err && tempval->type == MTHD) {temperr->grab(); exprpop(); PUSH_EXPR_SCOPE; data_stack.push_val(tempval); data_stack.push_val(temperr); data_stack.push_val(msg); temperr->release(); tempval->release(); msg->release(); tempval = new Value ("an error handler"); push_method (tempval); tempval->release(); method_on.push (method_on.peek()); return 1;} else tempval->release();}} exprpop();} return 0; } /************************************************************************ ************************* Process methods ******************************* *************************************************************************/ Process::Process (int obj_on , int pid , Value* mthd_nm , int ticks , Val_List* actuals){ ticks_left = ticks; process_id = pid; sleeping_til = 0; player_obj = obj_on; last_error = NULL; active_frame = new Frame (obj_on , mthd_nm , actuals , this); } Process::~Process (){ while (active_frame) delete active_frame; delete last_error; } void Process::add_sleeping (int seconds){ sleeping_til = (time ((time_t*)0)) + seconds; } int Process::give_ticks (int tick_slice){ int i, slice_left; Value* returned; if (!active_frame) return 0; // cout << "Ticks left: " << ticks_left << "\n"; if (ticks_left <= 0) {last_error = new Value (new String ("Killing Process -- Timed Out")); *last_error->str += " "; *last_error->str += last_error_msg; *last_error->str += "\n"; returned = new Value (new String ("tell"), SYM); all_processes.add_process (player_obj , returned , new Val_List (last_error)); returned->release(); last_error->release(); last_error = NULL; return 0;} // cout << "Expression depth: " << active_frame->expression_depth() << "\n"; if (active_frame->expression_depth() > MAX_DEPTH) {last_error = new Value(new String("Killing Process - Max Depth Reached")); *last_error->str += " "; *last_error->str += last_error_msg; *last_error->str += "\n"; returned = new Value (new String ("tell"), SYM); all_processes.add_process (player_obj , returned , new Val_List (last_error)); returned->release(); last_error->release(); last_error = NULL; return 0;} if (sleeping_til) {if (sleeping_til > time ((time_t*)0)) return -1; else {sleeping_til = 0;}} if (active_frame->this_obj) ticks_left -= tick_slice; else if ((active_frame->previous) && (! active_frame->previous->this_obj)) ticks_left = default_max_ticks; for (last_error = NULL, slice_left = tick_slice; !sleeping_til && slice_left >=0 ; slice_left -= i) {i = active_frame->do_operation(); if (! active_frame) break; if (last_error) {i = last_error->err; last_error->release(); last_error = new Value (new String (last_error_msg)); *last_error->str += "\n"; while (active_frame) {if (active_frame->is_handling_error (i, last_error)) {last_error->release(); last_error = NULL; return 1;} delete active_frame;} returned = new Value (new String ("handler"), SYM); if (db->lookup_var (player_obj , returned->str)) {all_processes.add_process (player_obj , returned , new Val_List (new Value(i), new Val_List (last_error))); returned->release(); last_error = NULL; return 0;} else {returned->release(); returned = new Value (new String ("tell"), SYM); all_processes.add_process (player_obj , returned , new Val_List (last_error)); returned->release(); last_error = NULL; return 0;}}} if (slice_left > 0) ticks_left += slice_left + sleep_return * tick_slice; return 1; }