sima/autoconf/
sima/hosts/i386/
sima/mudlib/
sima/mudlib/kernel/
sima/mudlib/obj/
sima/mudlib/sys/
sima/synhash/mips/
/* Stuff needed to interpret programs and closures */
#ifndef INTERPRET_H
#define INTERPRET_H

#include "alloc.h"

struct control_ret {
    struct frame *fp;
    union svalue *sp;
};

union control_virtual {
	uint16 *variable; uint8 *function_8; uint16 *function_16;
};

typedef struct control_ret (*inter_callback)(svalue result, struct frame *fp);

struct frame {
    union svalue arguments[1];	/* last argument */
    union svalue *shared;
    union svalue *variable;
    union control_virtual virtual;
    union svalue object;
    struct program *program;
    union {
	p_int i;
	inter_callback fun;
    } return_mode;
    unsigned char *funstart;
    uint8 *pc;
    struct frame *previous;
    union svalue locals[0];
#define CONTROL_LOCALS(fp)  ((fp)[1].arguments)
};

#define IR_LOCAL	0
#define IR_LOCAL_XF	1 /* frame in external stack */
#define IR_EXTERN	2
#define IR_EXTERN_XF	3
#define IR_CATCH	4 /* must be largest for correct error handling */

/*
 * Most frames are allocated on the general stack, and are above arguments,
 * but below local variables. Alas, to make efun closures work that eat
 * up their arguments and might call functions, call_lambda() uses the
 * external part, which is above everything in the general stack and thus
 * avoids extra popping.
 * Moreover, it is used for calls to ALIEN_EFUN closures to store the
 * outer frame, so that the arguments are just one frame off the locals.
 */

extern struct inter_stack {
    union svalue general[1024];
    struct frame external[256];
} inter_stack;

/*
 * Usually, sp and fp are passed up and down as function arguments /
 * return values; only the interpreter itself needs to know pc. Error
 * handling goes via the return chain, sometimes with modifying the
 * return_mode first. Loading objects is a special case: while the
 * compiler is active, it can't return, thus it defines a new bottom
 * of possible return and suspend depth.
 * Since it would be very hard and pretty pointless to pass sp and fp
 * of the interpreter up and down in the compiler, these values are
 * stored in inter_sp and inter_fp, respectively, while compiling is done.
 * A number of driver hooks will also define a new return/suspend bottom
 * for modularity reasons.
 */

extern union svalue *inter_sp, *inter_general_stack_bottom;
extern struct frame *inter_fp, *inter_ex_fp, *inter_external_stack_bottom;

/*
 * funstart could be saved by making error tracebacks search the program for
 * the function enclosing pc; but having it makes function setup & iteration
 * easier too.
 */

extern struct frame control_stack[];

#define PUSH_NUMBER(n) ((void)((++inter_sp)->i = (n) << 1))
#define PUSH_REFERENCED_SVALUE(sv) (*++inter_sp = (sv))

extern int inter_errno;
extern enum eval_state { off = 0x00, on = 0xff } eval_switch;
extern int32 eval_cost, last_eval_cost;

#define ASSIGN_EVAL_COST(ob) ((void)(\
  (ob)->x.uid->self->total_eval_cost += eval_cost - last_eval_cost,\
  last_eval_cost = eval_cost \
))

/* types are sorted by number of indizes - the code relies on this. */
#define LVALUE_SIMPLE		0
#define LVALUE_PROTECTED	1
#define LVALUE_CHAR		2
#define LVALUE_CBR_CHAR		3
#define LVALUE_NN_INDEXED	4
#define LVALUE_NR_INDEXED	5
#define LVALUE_RN_INDEXED	6
#define LVALUE_RR_INDEXED	7

#define LVALUE_CATCH		8	/* not actually an lvalue */

struct call_cache_entry {
    union svalue name;	/* shared string function name */
    p_int cache_id;
    struct program *program;
    uint8 *funstart;
    uint16 cache_virtual_index_offset;
    uint16 cache_variable_index_offset;
};
/* This structure should have a size of 20 bytes, this makes indexing
 * only take some shifts and one addition if no fast integer multiply is
 * available.
 */

struct call_cache_cell {
    uint8 last_written;
    uint8 unstatic[3]; /* protected is marked like undefined */
    /* 0x80 : freely callable  0: static  1: undefined/protected */
    struct call_cache_entry entry[3];
};

struct leaf_inherit_cache_tag {
    union svalue name;	/* shared string function name */
    p_int cache_id;
};

struct leaf_inherit_cache_cell {
    struct leaf_inherit_cache_tag tag[3];
    uint16 index[3];
    uint8 last_written;
};

struct cache_call_ret {
  union { svalue ob; char unstatic; } u;
  struct call_cache_entry *entry;
} ALIGN8 cache_call(svalue ob, union svalue name, struct frame *fp);

struct control_ret make_frame(union svalue *, int, uint8 *);
struct control_ret closure_frame
  (svalue, svalue *, struct frame *, int, uint8*, p_int);
svalue interpreter(struct frame *fp, svalue *sp);

union svalue *(*efun_table[])(union svalue *);

extern svalue *f_text_message(svalue *, struct frame *);
extern svalue *f_shadow(svalue *, struct frame *);
extern svalue *f_set_interactive_hook(svalue *, struct frame *);
extern svalue *f_get_dir(svalue *, struct frame *);
extern svalue *f_write_file(svalue *, struct frame *);
extern svalue *f_sprintf(svalue *, int);
extern svalue *f_range(svalue *, struct frame *, svalue, int);
extern svalue *f_member(svalue *);

#endif /* INTERPRET_H */