/* interp.c */
#include "config.h"
#include "object.h"
#include "construct.h"
#include "interp.h"
#include "instr.h"
#include "operproto.h"
#include "globals.h"
#include "cache.h"
int (*oper_array[NUM_OPERS+NUM_SCALLS])(struct object *caller, struct object
*obj, struct object *player, struct
var_stack **rts)={
comma_oper,eq_oper,pleq_oper,mieq_oper,mueq_oper,dieq_oper,moeq_oper,
aneq_oper,exeq_oper,oreq_oper,lseq_oper,rseq_oper,cond_oper,or_oper,
and_oper,bitor_oper,exor_oper,bitand_oper,condeq_oper,noteq_oper,less_oper,
lesseq_oper,great_oper,greateq_oper,ls_oper,rs_oper,add_oper,min_oper,
mul_oper,div_oper,mod_oper,not_oper,bitnot_oper,postadd_oper,preadd_oper,
postmin_oper,premin_oper,umin_oper,s_add_verb,s_add_xverb,s_call_other,
s_alarm,s_remove_alarm,s_caller_object,s_clone_object,s_destruct,
s_contents,s_next_object,s_location,s_next_child,s_parent,s_next_proto,
s_move_object,s_this_object,s_this_player,s_set_interactive,
s_interactive,s_set_priv,s_priv,s_in_editor,s_connected,s_get_devconn,
s_send_device,s_reconnect_device,s_disconnect_device,s_random,s_time,
s_mktime,s_typeof,s_command,s_compile_object,s_edit,s_cat,s_ls,s_rm,s_cp,
s_mv,s_mkdir,s_rmdir,s_hide,s_unhide,s_chown,s_syslog,s_sscanf,s_sprintf,
s_midstr,s_strlen,s_leftstr,s_rightstr,s_subst,s_instr,s_otoa,s_itoa,
s_atoi,s_atoo,s_upcase,s_downcase,s_is_legal,s_otoi,s_itoo,s_chmod,
s_fread,s_fwrite,s_remove_verb,s_ferase,s_chr,s_asc,s_sysctl,
s_prototype,s_iterate,s_next_who };
void interp_error(char *msg, struct object *player, struct object *obj,
struct fns *func, unsigned long line) {
char *buf;
buf=MALLOC(strlen(obj->parent->pathname)+strlen(msg)+(2*ITOA_BUFSIZ)+20);
sprintf(buf," interp: %s#%ld line #%ld: %s",obj->parent->pathname,
(long) obj->refno,(long) line,msg);
log_sysmsg(buf);
if (player) {
send_device(player,buf+1);
send_device(player,"\n");
}
FREE(buf);
}
void clear_locals() {
int loop;
if (!num_locals) return;
loop=0;
while (loop<num_locals) {
clear_var(&(locals[loop]));
loop++;
}
FREE(locals);
}
struct fns *find_fns(char *name, struct object *obj) {
struct fns *next;
next=obj->parent->funcs->func_list;
while (next) {
if (!strcmp(next->funcname,name))
return next;
next=next->next;
}
return NULL;
}
int interp(struct object *caller, struct object *obj, struct object *player,
struct var_stack **arg_stack, struct fns *func) {
struct var_stack *rts,*stack1;
struct var tmp,tmp2;
struct fns *temp_fns;
unsigned long arg_count,loop,line;
unsigned int old_num_locals,error_occurred;
struct var *old_locals;
int retstatus;
load_data(obj);
rts=NULL;
stack1=NULL;
line=0;
num_locals=func->num_locals;
loop=0;
if (num_locals)
locals=(struct var *) MALLOC(sizeof(struct var)*num_locals);
else
locals=NULL;
while (loop<num_locals) {
locals[loop].type=INTEGER;
locals[loop].value.integer=0;
loop++;
}
if (pop(&tmp,arg_stack,caller)) {
interp_error("malformed argument stack",player,obj,func,0);
free_stack(arg_stack);
return 1;
}
if (tmp.type!=NUM_ARGS) {
interp_error("malformed argument stack",player,obj,func,0);
free_stack(arg_stack);
return 1;
}
if (tmp.value.num>num_locals) {
interp_error("too many arguments",player,obj,func,0);
return 1;
}
loop=tmp.value.num;
while (loop>0) {
if (pop(&tmp,arg_stack,caller)) {
interp_error("malformed argument stack",player,obj,func,0);
free_stack(arg_stack);
clear_locals();
return 1;
}
--loop;
copy_var(&(locals[loop]),&tmp);
clear_var(&tmp);
}
loop=0;
while (1) {
#ifdef CYCLE_HARD_MAX
if (hard_cycles++>CYCLE_HARD_MAX) {
tmp.type=INTEGER;
tmp.value.integer=0;
interp_error("cycle hard maximum exceeded",player,obj,func,line);
pushnocopy(&tmp,arg_stack);
clear_locals();
return 0;
}
#endif /* CYCLE_HARD_MAX */
#ifdef CYCLE_SOFT_MAX
if (soft_cycles++>CYCLE_SOFT_MAX) {
tmp.type=INTEGER;
tmp.value.integer=0;
interp_error("cycle soft maximum exceeded",player,obj,func,line);
pushnocopy(&tmp,arg_stack);
clear_locals();
return 0;
}
#endif /* CYCLE_SOFT_MAX */
switch (func->code[loop].type) {
case INTEGER:
case STRING:
case OBJECT:
case GLOBAL_L_VALUE:
case LOCAL_L_VALUE:
case NUM_ARGS:
case ARRAY_SIZE:
push(&(func->code[loop]),&rts);
loop++;
break;
case LOCAL_REF:
case GLOBAL_REF:
if (popint(&tmp,&rts,obj)) {
interp_error("failed array reference",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
tmp2.value.l_value.size=tmp.value.integer;
if (popint(&tmp,&rts,obj)) {
interp_error("failed array reference",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
tmp2.value.l_value.ref=tmp.value.integer;
if (func->code[loop].type==LOCAL_REF) {
if (tmp2.value.l_value.ref>=num_locals) {
interp_error("array reference out of bound",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
} else
if (tmp2.value.l_value.ref>=obj->parent->funcs->num_globals) {
interp_error("array reference out of bound",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
if (tmp2.value.l_value.size!=1) {
interp_error("illegal array reference",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
if (func->code[loop].type==LOCAL_REF)
tmp2.type=LOCAL_L_VALUE;
else
tmp2.type=GLOBAL_L_VALUE;
push(&tmp2,&rts);
loop++;
break;
case ASM_INSTR:
if (func->code[loop].value.instruction<NUM_OPERS) {
retstatus=((*oper_array[func->code[loop].value.instruction])
(caller,obj,player,&rts));
if (retstatus) {
interp_error("arithmetic operation failed",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
} else {
old_locals=locals;
old_num_locals=num_locals;
if (func->code[loop].value.instruction==S_SSCANF ||
func->code[loop].value.instruction==S_SPRINTF ||
func->code[loop].value.instruction==S_FREAD)
stack1=gen_stack_noresolve(&rts,obj);
else
stack1=gen_stack(&rts,obj);
retstatus=((*oper_array[func->code[loop].value.instruction])
(caller,obj,player,&stack1));
locals=old_locals;
num_locals=old_num_locals;
if (retstatus) {
interp_error("system call failed",player,obj,func,line);
free_stack(&rts);
free_stack(&stack1);
clear_locals();
return 1;
}
if (pop(&tmp,&stack1,obj)) {
interp_error("system call returned malformed stack",player,obj,
func,line);
free_stack(&rts);
free_stack(&stack1);
clear_locals();
return 1;
}
pushnocopy(&tmp,&rts);
free_stack(&stack1);
}
loop++;
break;
case FUNC_CALL:
stack1=gen_stack(&rts,obj);
old_locals=locals;
old_num_locals=num_locals;
if (interp(obj,obj,player,&stack1,func->code[loop].value.func_call)) {
locals=old_locals;
num_locals=old_num_locals;
free_stack(&stack1);
free_stack(&rts);
clear_locals();
return 1;
}
locals=old_locals;
num_locals=old_num_locals;
if (pop(&tmp,&stack1,obj)) {
interp_error("function returned malformed stack",player,obj,func,
line);
free_stack(&rts);
free_stack(&stack1);
clear_locals();
return 1;
}
pushnocopy(&tmp,&rts);
free_stack(&stack1);
loop++;
break;
case FUNC_NAME:
temp_fns=find_fns(func->code[loop].value.string,obj);
if (!temp_fns) {
interp_error("unknown function",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
clear_var(&(func->code[loop]));
func->code[loop].type=FUNC_CALL;
func->code[loop].value.func_call=temp_fns;
break;
case JUMP:
loop=func->code[loop].value.num;
break;
case BRANCH:
if (pop(&tmp,&rts,obj)) {
interp_error("failed branch instruction",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
if (resolve_var(&tmp,obj)) {
interp_error("failed variable resolution",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
if (tmp.type==INTEGER && tmp.value.integer==0) {
loop=func->code[loop].value.num;
} else {
clear_var(&tmp);
loop++;
}
break;
case NEW_LINE:
free_stack(&rts);
line=func->code[loop].value.num;
loop++;
break;
case RETURN:
if (pop(&tmp,&rts,obj)) {
interp_error("stack malformed on return",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
if (resolve_var(&tmp,obj)) {
interp_error("stack malformed on return",player,obj,func,line);
free_stack(&rts);
clear_locals();
return 1;
}
pushnocopy(&tmp,arg_stack);
free_stack(&rts);
clear_locals();
return 0;
break;
}
}
}