/* Copyright (c) 1992 by David Moore. All rights reserved. */ /* inst.c,v 2.8 1997/08/30 06:44:05 dmoore Exp */ #include "config.h" #include <string.h> #include "db.h" #include "code.h" #include "buffer.h" #include "typechk.h" #include "prim_offsets.h" #include "externs.h" /* #### support for primitives taking a list input is not working. */ /* The size on types below is needed because you can't initialize array's in structs, unless the array size is preknown in ansi c. */ struct primitive_info { const char *name; prim_func func; unsigned int wiz_only : 1; unsigned int num_args : 8; unsigned int num_rtn : 8; const int arg_types[5]; const int rtn_types[5]; }; static struct primitive_info prim_table[] = { #include "primtab.h" /* Generated by mkprimtab.h */ }; #define NUM_PRIM_ENTRIES (sizeof(prim_table)/sizeof(*prim_table)) const char *prim2name(const int primitive) { static Buffer buf; if (primitive == PRIM_PUSH) return "PUSH"; if ((primitive < 0) || (primitive >= NUM_PRIM_ENTRIES)) { Bufsprint(&buf, "Illegal primitive (%i).", primitive); return Buftext(&buf); } return prim_table[primitive].name; } /* Check for permissions to the given object. */ void check_perms(frame *fr, const dbref object, const int prim) { if (!permissions(fr, object)) interp_error(fr, prim, "Permission denied to #%d", object); } /* Check to see if this primitive can be run based only on stack space. */ void check_prim_space(const int primitive, frame *fr, data_stack *st) { int depth, num_args, num_rtn; if (primitive == PRIM_PUSH) { num_args = 0; num_rtn = 1; } else { num_args = prim_table[primitive].num_args; num_rtn = prim_table[primitive].num_rtn; } depth = depth_stack(st, DATA_STACK_SIZE); if (num_args > depth) { interp_error(fr, primitive, "Data stack underflow"); return; } /* Check that there will be enough room for the result. */ if (num_rtn + depth - num_args > DATA_STACK_SIZE) { interp_error(fr, primitive, "Data stack overflow"); } } void check_prim_types(const int primitive, frame *fr, data_stack *st) { typechk_stack(fr, st, primitive, prim_table[primitive].num_args, prim_table[primitive].arg_types); } /* Check the arguments to a primitive, and assign func to the proper C routine to handle this primitive. If the type checking fails then return an error string, otherwise NULL. */ prim_func prim_check(const int primitive, frame *fr, data_stack *st, data_stack *pop_stack) { inst *curr; int pop_cnt; pop_cnt = prim_table[primitive].num_args; /* Put everything that needs to be cleared onto the pop_stack, so after the primitive is done we can clear all the args. */ for (curr = st->top; pop_cnt; pop_cnt--, curr++) { if (dup_inst_p(curr)) push_stack(pop_stack, curr); } return prim_table[primitive].func; } /* This should use a hash table (probably) or a binary search once the shell script works. */ int lookup_primitive(const char *name) { int primitive; for (primitive = 0; primitive < NUM_PRIM_ENTRIES; primitive++) { if (!muck_stricmp(prim_table[primitive].name, name)) { /* The names match. */ return primitive; } } return -1; } int num_args_primitive(const int primitive) { return prim_table[primitive].num_args; } int num_rtn_primitive(const int primitive) { return prim_table[primitive].num_rtn; } /* is the return type of this primitive a list? */ int list_rtn_primitive(const int primitive) { int i, num_rtn; num_rtn = prim_table[primitive].num_rtn; for (i = 0; i < num_rtn; i++) { /* #### this isn't right if more than 1 list is returned */ if (prim_table[primitive].rtn_types[i] == INST_T_LIST) return 1; } return 0; } int wiz_primitive(const int primitive) { return prim_table[primitive].wiz_only; } #define DoNull(x) ((x)->un.string ? (x)->un.string->data : "") /* converts an instruction into a printable string, which is appended to the given buffer. */ void inst_bufcat(Buffer *buf, inst *what) { static Buffer buf2; switch (what->type) { case INST_STRING: Bufsprint(&buf2, "\"%s\"", DoNull(what)); break; case INST_INTEGER: Bufsprint(&buf2, "%i", what->un.integer); break; case INST_OBJECT: Bufsprint(&buf2, "#%d", what->un.object); break; case INST_CONNECTION: Bufsprint(&buf2, "C%i", what->un.connection); break; case INST_ADDRESS: Bufsprint(&buf2, "'#%d'%s", what->un.address->code->object, DoAnonymous(what->un.address->name)); break; case INST_VARIABLE: Bufsprint(&buf2, "V%i", what->un.variable); break; case INST_OFFSET: Bufsprint(&buf2, "JMP(%i)", what->un.offset); break; case INST_PRIMITIVE: Bufcpy(&buf2, prim2name(what->un.primitive)); break; case INST_IF: Bufsprint(&buf2, "IF(%i)", what->un.offset); break; case INST_NOT_IF: Bufsprint(&buf2, "NOT IF(%i)", what->un.offset); break; case INST_EXECUTE: Bufsprint(&buf2, "#%d'%s", what->un.address->code->object, DoAnonymous(what->un.address->name)); break; case INST_LINENO: Bufsprint(&buf2, "L%i", what->un.lineno); break; case INST_BADVAR: Bufsprint(&buf2, "XXX"); break; case INST_WIZCHECK: Bufsprint(&buf2, "WIZCHK(%s)", prim2name(what->un.primitive)); break; case INST_STKCHECK: Bufsprint(&buf2, "STKCHK(%s)", prim2name(what->un.primitive)); break; case INST_TYPECHECK: Bufsprint(&buf2, "TYPECHK(%s)", prim2name(what->un.primitive)); break; case INST_PICK: /* Note that 'x INST_PICK' is like 'x+1 PICK'. */ switch (what->un.integer) { case 0: Bufcpy(&buf2, "dup"); break; case 1: Bufcpy(&buf2, "over"); break; default: Bufsprint(&buf2, "PICK %i", what->un.integer + 1); break; } break; case INST_EXIT: Bufcpy(&buf2, "exit"); break; default: Bufsprint(&buf2, "???"); break; } Bufcat(buf, Buftext(&buf2)); } void debug_inst(frame *fr, data_stack *data_st, addr_stack *addr_st, inst *curr_inst) { int i, count; static Buffer buf; if (curr_inst) { Bufsprint(&buf, "D(#%d L%i) S(", JumpFunc(addr_st->top)->code->object, JumpLineno(addr_st->top)); } count = depth_stack(data_st, DATA_STACK_SIZE); if (count > 5) { Bufcat(&buf, "..., "); count = 5; } for (i = 0; i < count; i++) { inst_bufcat(&buf, data_st->top + (count - 1 - i)); if (i < count-1) Bufcat(&buf, ", "); } Bufcat(&buf, ") "); inst_bufcat(&buf, curr_inst); notify(fr->player, "%S", &buf); }