#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;
}