
object
Ieval(form)
object form;
{
	object endp_temp;
       DEBUG_AVMA
	object fun, x;
	object *top;
	object *base;
	object orig_form;

	cs_check(form);

EVAL:

	vs_check;

	if (Vevalhook->s.s_dbind != Cnil && eval1 == 0)
	{
		bds_ptr old_bds_top = bds_top;
		object hookfun = symbol_value(Vevalhook);
		/*  check if Vevalhook is unbound  */

		bds_bind(Vevalhook, Cnil);
		form = Ifuncall_n(hookfun,2,form,list(3,lex_env[0],lex_env[1],lex_env[2]));
		bds_unwind(old_bds_top);
		return form;
	} else
		eval1 = 0;

	if (type_of(form) == t_cons)
		goto APPLICATION;

	if (type_of(form) != t_symbol)  RETURN1(form);

SYMBOL:
	switch (form->s.s_stype) {
	case stp_constant:
	  RETURN1((form->s.s_dbind));

	case stp_special:
		if(form->s.s_dbind == OBJNULL)
			FEunbound_variable(form);
	  RETURN1((form->s.s_dbind));

	default:
		/*  x = lex_var_sch(form);  */
		for (x = lex_env[0];  type_of(x) == t_cons;  x = x->c.c_cdr)
			if (x->c.c_car->c.c_car == form) {
				x = x->c.c_car->c.c_cdr;
				if (endp(x))
					break;
				RETURN1((x->c.c_car));
			}
		if(form->s.s_dbind == OBJNULL)
			FEunbound_variable(form);
	  RETURN1((form->s.s_dbind));
	}

APPLICATION:
	/* Hook for possibly stopping at forms in the break point
	   list.  Also for stepping.  We only want to check
	   one form each time round, so we do *breakpoints*
	   */
	if (sSAbreak_pointsA->s.s_dbind != Cnil)
	  { if (sSAbreak_stepA->s.s_dbind == Cnil ||
		ifuncall2(sSAbreak_stepA->s.s_dbind,form,
			  list(3,lex_env[0],lex_env[1],lex_env[2])) == Cnil)
	      {object* bpts = sSAbreak_pointsA->s.s_dbind->v.v_self;
	       int i = sSAbreak_pointsA->s.s_dbind->v.v_fillp;
	       while (--i >= 0)
		 { if((*bpts)->c.c_car == form)
		     {ifuncall2(sSAbreak_pointsA->s.s_gfdef,form,
				list(3,lex_env[0],lex_env[1],lex_env[2]));

		      break;}
		   bpts++;}
	     }}
	
	fun = MMcar(form);
	if (type_of(fun) != t_symbol)
		goto LAMBDA;
	if (fun->s.s_sfdef != NOT_SPECIAL) {
		ihs_check;
		ihs_push(form);
		ihs_top->ihs_base = lex_env;
		(*fun->s.s_sfdef)(MMcdr(form));
		CHECK_AVMA;
		ihs_pop();
		return Ivs_values();
	}
	/*  x = lex_fd_sch(fun);  */
	for (x = lex_env[1];  type_of(x) == t_cons;  x = x->c.c_cdr)
		if (x->c.c_car->c.c_car == fun) {
			x = x->c.c_car;
			if (MMcadr(x) == sLmacro) {
				x = MMcaddr(x);
				goto EVAL_MACRO;
			}
			x = MMcaddr(x);
			goto EVAL_ARGS;
		}

GFDEF:
	if ((x = fun->s.s_gfdef) == OBJNULL)
		FEundefined_function(fun);

	if (fun->s.s_mflag) {
	EVAL_MACRO:

		form = Imacro_expand1(x, form);
		goto EVAL;
	}

	  
	
EVAL_ARGS:
	{ int n ;
	ihs_check;
	ihs_push(form);
	ihs_top->ihs_base = lex_env;
	form = form->c.c_cdr;
  	base = vs_top;
	top = base ;
	while(!endp(form)) {
	  object ans = Ieval(MMcar(form));
	  top[0] = ans;
	  vs_top = ++top;
	  form = MMcdr(form);}
	  n =top - base; /* number of args */
	if (Vapplyhook->s.s_dbind != Cnil) {
	  base[0]= (object)n;
	  base[0] = c_apply_n(list,n+1,base);
	  x = Ifuncall_n(Vapplyhook->s.s_dbind,3,
			 x, /* the function */
			 base[0], /* the arg list */
			 list(3,lex_env[0],lex_env[1],lex_env[2]));
	  vs_top = base; return x;
	}
	ihs_top->ihs_function = x;
	ihs_top->ihs_base = vs_base;
	x=IapplyVector(x,n,base+1);
	CHECK_AVMA;
	ihs_pop();
	vs_top = base;  
	return x;
		 }

LAMBDA:
	if (type_of(fun) == t_cons && MMcar(fun) == sLlambda) {
	  x = listA(4,sLlambda_closure,lex_env[0],lex_env[1],lex_env[2],Mcdr(fun));
	  goto EVAL_ARGS;
	}
	FEinvalid_function(fun);
}	
