/* Copyright (c) 1993 Stephen F. White */

#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>
#include <sys/time.h>

#include "config.h"
#include "cool.h"
#include "proto.h"
#include "sys_proto.h"
#include "execute.h"
#include "x.tab.h"

Op_entry  opcode_info[] = {
    { IF,	"IF",		op_if,		2, { NUM_ARG, NUM_ARG } },
    { ELSEIF, "ELSEIF",		op_elseif,	1, { NUM_ARG } },
    { ELSE, "ELSE",		op_null,	0, 0 },
    { FOR, "FOR",		op_for,		2, { VARNO_ARG, NUM_ARG } },
    { FORRNG, "FORRNG",		op_forrng,	2, { VARNO_ARG, NUM_ARG } },
    { WHILE, "WHILE",		op_while,	1, { NUM_ARG } },
    { DO, "DO",			op_do,		1, { NUM_ARG } },
    { DOWHILE, "DOWHILE",	op_dowhile,	2, { NUM_ARG, NUM_ARG } },
    { AT, "AT",			op_at,		1, { NUM_ARG } },
    { PUSHPC, "PUSHPC",		op_pushpc,	0, 0 },
    { SLEEP, "SLEEP",		op_sleep,	1, { NUM_ARG } },
    { NUMPUSH, "NUMPUSH",	op_numpush,	1, { NUM_ARG } },
    { STRPUSH, "STRPUSH",	op_strpush,	1, { STR_ARG } },
    { OBJPUSH, "OBJPUSH",	op_objpush,	2, { NUM_ARG, NUM_ARG } },
    { LISTPUSH, "LISTPUSH",	op_listpush,	1, { NUM_ARG } },
    { ERRPUSH, "ERRPUSH",	op_errpush,	1, { NUM_ARG } },
    { GETLVAR, "GETLVAR",	op_getlvar,	1, { VARNO_ARG } },
    { GETGVAR, "GETGVAR",	op_getgvar,	1, { ID_ARG } },
    { GETGVAREXPR, "GETGVAREXPR", op_getgvarexpr, 1, { NUM_ARG } },
    { ASGNLVAR, "ASGNLVAR",	op_asgnlvar,	1, { VARNO_ARG } },
    { ASGNGVAR, "ASGNGVAR",	op_asgngvar,	1, { ID_ARG } },
    { ASGNGVAREXPR, "ASGNGVAREXPR", op_asgngvarexpr, 1, { NUM_ARG } },
    { PARENTS, "PARENTS",	op_parents,	0, 0 },
    { THIS, "THIS",		op_this,	0, 0 },
    { PLAYER, "PLAYER",		op_player,	0, 0 },
    { CALLER, "CALLER",		op_caller,	0, 0 },
    { ARGS, "ARGS",		op_args,	0, 0 },
    { SETPLAYER, "SETPLAYER",	op_setplayer,	0, 0 },
    { ADD, "ADD",		op_add,		0, 0 },
    { SUB, "SUB",		op_sub,		0, 0 },
    { MUL, "MUL",		op_mul,		0, 0 },
    { DIV, "DIV",		op_div,		0, 0 },
    { MOD, "MOD",		op_mod,		0, 0 },
    { NEGATE, "NEGATE",		op_negate,	0, 0 },
    { AND, "AND",		op_and,		1, { NUM_ARG } },
    { OR, "OR",			op_or,		1, { NUM_ARG } },
    { ENDAND, "ENDAND",		op_null,	0, 0 },
    { ENDOR, "ENDOR",		op_null,	0, 0 },
    { NOT, "NOT",		op_not,		0, 0 },
    { EQ, "EQ",			op_eq,		0, 0 },
    { NE, "NE",			op_ne,		0, 0 },
    { GT, "GT",			op_gt,		0, 0 },
    { GE, "GE",			op_ge,		0, 0 },
    { LT, "LT",			op_lt,		0, 0 },
    { LE, "LE",			op_le,		0, 0 },
    { MESSAGE, "MESSAGE",	op_message,	2, { NUM_ARG, STR_ARG } },
    { MESSAGE_EXPR, "MESSAGE_EXPR", op_message_expr, 1, { NUM_ARG } },
    { INDEX, "INDEX",		op_index,	0, 0 },
    { IN, "IN",			op_in,		0, 0 },
    { SUBSET, "SUBSET",		op_subset,	0, 0 },
    { LSUBSET, "LSUBSET",	op_lsubset,	0, 0 },
    { RSUBSET, "RSUBSET",	op_rsubset,	0, 0 },
    { LENGTHOF, "LENGTHOF",	op_lengthof,	1, { NUM_ARG } },
    { SETADD, "SETADD",		op_setadd,	1, { NUM_ARG } },
    { SETREMOVE, "SETREMOVE",	op_setremove,	1, { NUM_ARG } },
    { LISTINSERT, "LISTINSERT",	op_listinsert,	1, { NUM_ARG } },
    { LISTAPPEND, "LISTAPPEND",	op_listappend,	1, { NUM_ARG } },
    { LISTDELETE, "LISTDELETE",	op_listdelete,	1, { NUM_ARG } },
    { LISTASSIGN, "LISTASSIGN",	op_listassign,	1, { NUM_ARG } },
    { EXPLODE, "EXPLODE",	op_explode,	1, { NUM_ARG } },
    { STRSUB, "STRSUB",		op_strsub,	1, { NUM_ARG } },
    { PAD, "PAD",		op_pad,		1, { NUM_ARG } },
    { PSUB, "PSUB",		op_psub,	1, { NUM_ARG } },
    { RANDOM, "RANDOM",		op_random,	1, { NUM_ARG } },
    { TOSTR, "TOSTR",		op_tostr,	1, { NUM_ARG } },
    { TONUM, "TONUM",		op_tonum,	1, { NUM_ARG } },
    { TOOBJ, "TOOBJ",		op_toobj,	1, { NUM_ARG } },
    { TOERR, "TOERR",		op_toerr,	1, { NUM_ARG } },
    { TYPEOF, "TYPEOF",		op_typeof,	1, { NUM_ARG } },
    { SERVEROF, "SERVEROF",	op_serverof,	1, { NUM_ARG } },
    { SERVERNAME, "SERVERNAME",	op_servername,	1, { NUM_ARG } },
    { SERVERS, "SERVERS",	op_servers,	1, { NUM_ARG } },
    { STOP, "STOP",		op_stop,	0, 0 },
    { T_RAISE, "RAISE",		op_raise,	0, 0 },
    { T_RETURN, "RETURN",	op_return,	0, 0 },
    { BREAK, "BREAK",		op_break,	1, { NUM_ARG } },
    { CONTINUE, "CONTINUE",	op_continue,	1, { NUM_ARG } },
    { ECHO, "ECHO",		op_echo,	1, { NUM_ARG } },
    { ECHO_FILE, "ECHO_FILE",	op_echo_file,	1, { NUM_ARG } },
    { TIME, "TIME",		op_time,	1, { NUM_ARG } },
    { CTIME, "CTIME",		op_ctime,	1, { NUM_ARG } },
    { CLONE, "CLONE",		op_clone,	1, { NUM_ARG } },
    { DESTROY, "DESTROY",	op_destroy,	1, { NUM_ARG } },
    { CHPARENTS, "CHPARENTS",	op_chparents,	1, { NUM_ARG } },
    { FIND_METHOD, "FIND_METHOD", op_find_method, 1, { NUM_ARG } },
    { SPEW_METHOD, "SPEW_METHOD", op_spew_method, 1, { NUM_ARG } },
    { LIST_METHOD, "LIST_METHOD", op_list_method, 1, { NUM_ARG } },
    { DECOMPILE, "DECOMPILE",	op_decompile,	1, { NUM_ARG } },
    { POP, "POP",		op_pop,		0, 0 },
    { CRYPT, "CRYPT",		op_crypt,	1, { NUM_ARG } },
    { CHECKMEM, "CHECKMEM",	op_checkmem,	1, { NUM_ARG } },
    { CACHE_STATS, "CACHE_STATS", op_cache_stats, 1, { NUM_ARG } },
    { LOCK, "LOCK",		op_lock,	1, { NUM_ARG } },
    { UNLOCK, "UNLOCK",		op_unlock,	1, { NUM_ARG } },
    { HASPARENT, "HASPARENT",	op_hasparent,	1, { NUM_ARG } },
    { OBJSIZE, "OBJSIZE",	op_objsize,	1, { NUM_ARG } },
    { VARS, "VARS",		op_vars,	1, { NUM_ARG } },
    { VERBS, "VERBS",		op_verbs,	1, { NUM_ARG } },
    { METHODS, "METHODS",	op_methods,	1, { NUM_ARG } },
    { VERB, "VERB",		op_verb,	1, { NUM_ARG } },
    { RMVERB, "RMVERB",		op_rmverb,	1, { NUM_ARG } },
    { RMMETHOD, "RMMETHOD",	op_rmmethod,	1, { NUM_ARG } },
    { RMVAR, "RMVAR",		op_rmvar,	1, { NUM_ARG } },
    { PROGRAM, "PROGRAM",	op_program,	1, { NUM_ARG } },
    { COMPILE, "COMPILE",	op_compile,	1, { NUM_ARG } },
    { MATCH, "MATCH",		op_match,	1, { NUM_ARG } },
    { MATCH_FULL, "MATCH_FULL",	op_match_full,	1, { NUM_ARG } },
    { SHUTDOWN, "SHUTDOWN",	op_shutdown,	1, { NUM_ARG } },
    { DUMP, "DUMP",		op_dump,	1, { NUM_ARG } },
    { WRITELOG, "WRITELOG",	op_writelog,	1, { NUM_ARG } },
    { QUIT, "QUIT",		op_boot,	1, { NUM_ARG } },
    { KILL, "KILL",		op_kill,	1, { NUM_ARG } },
    { PS, "PS",			op_ps,		1, { NUM_ARG } },
    { PASS, "PASS",		op_pass,	2, { NUM_ARG, NUM_ARG } },
};

Op_entry	*opcodes[LAST_TOKEN];

void
opcode_init(void)
{
    int		i;

    for (i = 0; i < LAST_TOKEN; i++) {
	opcodes[i] = 0;
    }
    for (i = 0; i < Arraysize(opcode_info); i++) {
	opcodes[opcode_info[i].opcode] = &opcode_info[i];
    }
}

void
opcode_free_symbols(Object *o, Method *m)
{
    int		pc = 0, arg;
    Op_entry   *entry;

    while (pc < m->ninst) {
	if (!(entry = opcodes[m->code[pc++]])) {
	    return;
	}
	for (arg = 0; arg < entry->nargs; arg++, pc++) {
	    if (entry->arg_type[arg] == STR_ARG
	     || entry->arg_type[arg] == ID_ARG) {
		sym_free(o, m->code[pc]);
	    }
	}
    }
}