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

#include "cool.h"
#include "proto.h"
#include "execute.h"
#include "y.tab.h"

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

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++) {
	opcode_info[i].builtin = bf_id2entry(opcode_info[i].opcode);
    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]);
      }
    }
  }
}