/* Copyright (c) 1993 Stephen F. White */
#include <stdio.h>
#ifdef SYSV
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>
#include <math.h>
#include <sys/time.h>
#include "config.h"
#include "cool.h"
#include "proto.h"
#include "sys_proto.h"
#include "x.tab.h"
#include "execute.h"
extern void writelog(void);
static String *decode_arg(String *s, Object *o, Method *m,
enum arg_type type, int arg);
static int expr_prec(int opcode);
static void tpush(Inst *i);
static Inst *tpop(void);
/*
* decode_method()
*
* Takes a list of tokens and turns it into readable code.
*
* level: 0 - integers (least readable)
* 1 - tokens and integers (./compile -n produces this)
* 2 - symbol table lookups are performed (most readable)
*
* Returned as a 1-line string
*/
String *
decode_method(Object *o, Method *m, int level)
{
int i, arg;
String *s = string_new(0);
Op_entry *op;
for (i = 0; i < m->ninst; ) {
if (level == 0) { /* level zero, numeric tokens only */
s = string_catnum(s, m->code[i++]);
s = string_cat(s, " ");
} else {
op = opcodes[m->code[i]];
if (!op) {
writelog();
fprintf(stderr,
"decode_method(): Unknown opcode %d in method %s on #%d\n",
m->code[i++], sym_get(o, m->name)->str, o->id.id);
return s;
} else {
s = string_cat(s, op->name);
s = string_cat(s, " ");
i++;
for (arg = 0; arg < op->nargs; arg++) {
if (level == 2) {
s = decode_arg(s, o, m, op->arg_type[arg],
m->code[i++]);
s = string_cat(s, " ");
} else { /* level 1 */
s = string_catnum(s, m->code[i++]);
s = string_cat(s, " ");
}
}
}
}
}
return s;
}
static String *
decode_arg(String *s, Object *o, Method *m, enum arg_type type, int arg)
{
int n;
switch (type) {
case NUM_ARG:
s = string_catnum(s, arg);
break;
case ID_ARG:
s = string_cat(s, sym_get(o, arg)->str);
break;
case STR_ARG:
s = string_cat(s, "\"");
s = string_cat(s, sym_get(o, arg)->str);
s = string_cat(s, "\"");
break;
case VARNO_ARG:
n = var_find_local(m, arg)->name;
s = string_cat(s, sym_get(o, n)->str);
break;
case none:
break; /* must be a mistake in token table */
}
return s;
}
#define MAX_TSTACK 100
static Inst *tstack[MAX_TSTACK]; /* stack for unparsing exprs */
static int tsp;
#define MAX_TREE 200
static Inst tree[MAX_TREE]; /* parse tree memory */
static int tptr;
static int indent; /* current indentation value */
static int indent_by; /* how much to indent by (shiftwid) */
static int full_bracketing; /* full bracketing flag */
static int lineno; /* current line # */
static int find_pc; /* what PC to search line # for */
static int found_lineno; /* found line # (corresponding to pc) */
static int number_lines; /* flag: number lines? */
static String *decompile_local_vars(String *s, Object *o, Method *m);
static String *decompile_ehandler(String *s, Object *o, Method *m);
static String *decompile_stmts(String *s, Object *o, Method *m, int i);
static String *decompile_expr(String *s, Object *o, Method *m, Inst *t,
int prec);
static String *decompile_args(String *s, Object *o, Method *m, Inst in);
static void tree_list(Method *m, int i);
static void tree_args(int len);
static void tree_message(Method *m, int i);
static void tree_message_expr(Method *m, int i);
static void tree_pass(Method *m, int i);
static void tree_ternop(Method *m, int i);
static void tree_binop(Method *m, int i);
static void tree_unop(Method *m, int i);
static void tree_func(Method *m, int i);
static String *line_start(String *str, int ind, const char *s);
static String *decompile_parents(String *s, Object *o);
static String *decompile_global_vars(String *s, Object *o);
static String *decompile_verbs(String *s, Object *o);
static String *decompile_methods(String *s, Object *o);
struct prec_entry {
int op;
int prec;
} prec_table[] = {
{ ASGNLVAR, 1 },
{ ASGNGVAR, 1 },
{ UPTO, 2 },
{ ENDOR, 3 },
{ ENDAND, 4 },
{ IN, 5 },
{ EQ, 6 },
{ NE, 6 },
{ LT, 7 },
{ LE, 7 },
{ GT, 7 },
{ GE, 7 },
{ ADD, 8 },
{ SUB, 8 },
{ MUL, 9 },
{ DIV, 9 },
{ MOD, 9 },
{ NOT, 10 },
};
static int
expr_prec(int opcode)
{
int i;
for (i = 0; i < Arraysize(prec_table); i++) {
if (prec_table[i].op == opcode) {
return prec_table[i].prec;
}
}
return 0; /* default to low precedence */
}
String *
decompile_method(String *s, Object *o, Method *m, int opt_lineno,
int opt_brackets, int opt_indent, int indent_from,
int opt_find_pc, int *pfound_lineno)
{
tptr = 0; tsp = 0;
number_lines = opt_lineno;
indent_by = opt_indent;
full_bracketing = opt_brackets;
lineno = found_lineno = 1; find_pc = opt_find_pc;
indent = indent_from;
s = decompile_local_vars(s, o, m);
s = decompile_ehandler(s, o, m);
s = decompile_stmts(s, o, m, 0);
if (s) {
s->len -= 2;
s->str[s->len] = '\0'; /* nuke last CRLF */
}
if (pfound_lineno) {
*pfound_lineno = found_lineno;
}
return s;
}
static String *
decompile_local_vars(String *s, Object *o, Method *m)
{
Vardef *v;
if (!m->vars) {
return s;
}
s = string_indent_cat(s, indent + (number_lines ? 6 : 0), "var ");
for (v = m->vars; v; v = v->next) {
s = string_cat(s, sym_get(o, v->name)->str);
if (v->next) {
s = string_cat(s, ", ");
}
}
s = string_cat(s, ";\r\n");
return s;
}
static String *
decompile_ehandler(String *s, Object *o, Method *m)
{
int i, started = 0;
for (i = 0; i < NERRS; i++) {
if (m->ehandler[i] == EH_IGNORE) {
if (!started) {
s = string_indent_cat(s, indent + (number_lines ? 6 : 0),
"ignore ");
started = 1;
} else {
s = string_cat(s, ", ");
}
s = string_cat(s, err_id2name(i));
}
}
if (started) {
s = string_cat(s, ";\r\n");
}
return s;
}
static void
tpush(Inst *i)
{
if (tsp >= MAX_TSTACK) {
tsp++; /* stack full; fake it */
} else {
tstack[tsp++] = i;
}
}
static Inst *
tpop(void)
{
if (!tsp) {
return 0;
} else if(tsp >= MAX_TSTACK) {
--tsp; /* fake it again */
return 0;
} else {
return tstack[--tsp];
}
}
#define UNPARSE_BINOP(STR) \
s = decompile_expr(s, o, m, (Inst *) t[2], tprec - 1); \
s = string_cat(s, (STR)); \
s = decompile_expr(s, o, m, (Inst *) t[1], tprec);
static String *
decompile_stmts(String *s, Object *o, Method *m, int i)
{
int n, stopped = 0;
Inst *upper;
while (!stopped) {
if (find_pc >= 0 && i >= find_pc) {
found_lineno = lineno;
find_pc = -1;
}
switch (m->code[i]) {
case IF:
s = line_start(s, indent, "if (");
s = decompile_expr(s, o, m, tpop(), 0);
tptr = 0;
s = string_cat(s, ")\r\n");
lineno++;
indent += indent_by;
s = decompile_stmts(s, o, m, i + 3);
if (m->code[m->code[i + 1]] != STOP) {
s = decompile_stmts(s, o, m, m->code[i + 1]);
}
indent -= indent_by;
s = line_start(s, indent, "endif\r\n");
lineno++;
i = m->code[i + 2];
break;
case ELSEIF:
s = line_start(s, indent - indent_by, "elseif (");
s = decompile_expr(s, o, m, tpop(), 0);
tptr = 0;
s = string_cat(s, ")\r\n");
lineno++;
s = decompile_stmts(s, o, m, i + 2);
i = m->code[i + 1];
break;
case ELSE:
s = line_start(s, indent - indent_by, "else\r\n");
lineno++;
i++;
break;
case FOR:
(void) tpop(); /* skip NUMPUSH */
s = line_start(s, indent, "for ");
n = var_find_local(m, m->code[i+1])->name;
s = string_cat(s, sym_get(o, n)->str);
s = string_cat(s, " in (");
s = decompile_expr(s, o, m, tpop(), 0);
tptr = 0;
s = string_cat(s, ")\r\n");
lineno++;
indent += indent_by;
s = decompile_stmts(s, o, m, i + 3);
indent -= indent_by;
s = line_start(s, indent, "endfor\r\n");
lineno++;
i = m->code[i + 2];
break;
case FORRNG:
s = line_start(s, indent, "for ");
n = var_find_local(m, m->code[i+1])->name;
s = string_cat(s, sym_get(o, n)->str);
s = string_cat(s, " in [");
upper = tpop();
s = decompile_expr(s, o, m, tpop(), 0);
s = string_cat(s, "..");
s = decompile_expr(s, o, m, upper, 0);
tptr = 0;
s = string_cat(s, "]\r\n");
lineno++;
indent += indent_by;
s = decompile_stmts(s, o, m, i + 3);
indent -= indent_by;
s = line_start(s, indent, "endfor\r\n");
lineno++;
i = m->code[i + 2];
break;
case WHILE:
s = line_start(s, indent, "while (");
s = decompile_expr(s, o, m, tpop(), 0);
tptr = 0;
s = string_cat(s, ")\r\n");
lineno++;
indent += indent_by;
s = decompile_stmts(s, o, m, i + 2);
indent -= indent_by;
s = line_start(s, indent, "endwhile\r\n");
lineno++;
i = m->code[i + 1];
break;
case DO:
s = line_start(s, indent, "do\r\n");
lineno++;
indent += indent_by;
i += 2;
break;
case DOWHILE:
indent -= indent_by;
s = line_start(s, indent, "while (");
s = decompile_expr(s, o, m, tpop(), 0);
s = string_cat(s, ");\r\n");
tptr = 0;
lineno++;
i += 3;
break;
case AT:
s = line_start(s, indent, "at (");
s = decompile_expr(s, o, m, tpop(), 0);
tptr = 0;
s = string_cat(s, ")\r\n");
lineno++;
indent += indent_by;
s = decompile_stmts(s, o, m, i + 2);
indent -= indent_by;
s = line_start(s, indent, "endat\r\n");
lineno++;
i = m->code[i + 1];
break;
case POP: /* expr; */
s = line_start(s, indent, "");
s = decompile_expr(s, o, m, tpop(), 0);
tptr = 0;
s = string_cat(s, ";\r\n");
lineno++;
i++;
break;
case ASGNGVAR:
s = line_start(s, indent, sym_get(o, m->code[i + 1])->str);
s = string_cat(s, " = ");
s = decompile_expr(s, o, m, tpop(), 0);
s = string_cat(s, ";\r\n");
lineno++;
tptr = 0;
i += 2;
break;
case ASGNLVAR:
n = var_find_local(m, m->code[i + 1])->name;
s = line_start(s, indent, sym_get(o, n)->str);
s = string_cat(s, " = ");
s = decompile_expr(s, o, m, tpop(), 0);
s = string_cat(s, ";\r\n");
lineno++;
tptr = 0;
i += 2;
break;
case SETPLAYER:
s = line_start(s, indent, "player = ");
s = decompile_expr(s, o, m, tpop(), 0);
s = string_cat(s, ";\r\n");
lineno++;
tptr = 0;
i++;
break;
case T_RETURN:
s = line_start(s, indent, "return ");
s = decompile_expr(s, o, m, tpop(), 0);
s = string_cat(s, ";\r\n");
lineno++;
tptr = 0;
i++;
break;
case T_RAISE:
s = line_start(s, indent, "raise ");
s = decompile_expr(s, o, m, tpop(), 0);
s = string_cat(s, ";\r\n");
lineno++;
tptr = 0;
i++;
break;
case CONTINUE:
if (m->code[i + 1] > 1) {
s = line_start(s, indent, "continue ");
s = string_catnum(s, m->code[i + 1]);
s = string_cat(s, ";\r\n");
} else {
s = line_start(s, indent, "continue;\r\n");
}
lineno++;
i += 2;
break;
case BREAK:
if (m->code[i + 1] > 1) {
s = line_start(s, indent, "break ");
s = string_catnum(s, m->code[i + 1]);
s = string_cat(s, ";\r\n");
} else {
s = line_start(s, indent, "break;\r\n");
}
lineno++;
i += 2;
break;
/*
* everything below here is an expr, and pushed onto the stack
*/
/*
* leaf nodes - these op's don't have any descendants, so we
* can push the address of the method's actual code
*/
case PARENTS: case ARGS: case THIS: case PLAYER: case CALLER:
tpush(m->code + i);
i++;
break;
case NUMPUSH: case STRPUSH: case ERRPUSH:
case GETLVAR: case GETGVAR:
tpush(m->code + i);
i += 2;
break;
case OBJPUSH:
tpush(m->code + i);
i += 3;
break;
case LISTPUSH:
tree_list(m, i);
i += 2;
break;
case MESSAGE:
tree_message(m, i);
i += 3;
break;
case MESSAGE_EXPR:
tree_message_expr(m, i);
i += 2;
break;
case PASS:
tree_pass(m, i);
i += 3;
break;
/*
* binary operators
*/
case ADD: case SUB: case MUL: case DIV: case MOD:
case EQ: case NE: case GT: case GE: case LT: case LE:
case INDEX: case IN: case LSUBSET: case RSUBSET:
tree_binop(m, i);
i++;
break;
/*
* ternary operators
*/
case SUBSET:
tree_ternop(m, i);
i++;
break;
/*
* unary operators
*/
case NEGATE: case NOT:
tree_unop(m, i);
i++;
break;
/*
* ignore these; effectively pushes LHS
*/
case AND: case OR:
i += 2;
break;
/*
* actually do something here
*/
case ENDAND: case ENDOR:
tree_binop(m, i);
i++;
break;
case PUSHPC:
i++;
break;
case STOP:
stopped = 1;
break;
/*
* functions
*/
default:
tree_func(m, i);
i += 2;
break;
}
}
return s;
}
static String *
decompile_expr(String *s, Object *o, Method *m, Inst *t, int prec)
{
Objid obj;
int tprec; /* precedence of current statement */
const char *funcname; /* function name, for unparsing func() */
int n;
if (!t) {
s = string_cat(s, " /* Expression too complex */ ");
return s;
}
tprec = expr_prec (t[0]);
if (tprec && (tprec < prec || full_bracketing)) {
s = string_cat(s, "(");
}
switch(t[0]) {
case GETLVAR:
n = var_find_local(m, t[1])->name;
s = string_cat(s, sym_get(o, n)->str);
break;
case GETGVAR:
s = string_cat(s, sym_get(o, t[1])->str);
break;
case MESSAGE:
s = decompile_expr(s, o, m, (Inst *) t[2], 0);
s = string_cat(s, ".");
s = string_cat(s, sym_get(o, t[1])->str);
if (t[3]) {
s = string_cat(s, "(");
s = decompile_args(s, o, m, (Inst) (t + 3));
s = string_cat(s, ")");
}
break;
case MESSAGE_EXPR:
s = decompile_expr(s, o, m, (Inst *) t[1], 0);
s = string_cat(s, ".(");
s = decompile_expr(s, o, m, (Inst *) t[2], 0);
s = string_cat(s, ")");
if (t[3]) {
s = string_cat(s, "(");
s = decompile_args(s, o, m, (Inst) (t + 3));
s = string_cat(s, ")");
}
break;
case PASS:
s = string_cat(s, "pass(");
s = decompile_args(s, o, m, (Inst) (t + 2));
s = string_cat(s, ")");
if (t[1] != o->parents->el[0].v.obj.id) {
s = string_cat(s, " to #");
s = string_catnum(s, t[1]);
}
break;
case INDEX:
s = decompile_expr(s, o, m, (Inst *) t[2], tprec);
s = string_cat(s, "[");
s = decompile_expr(s, o, m, (Inst *) t[1], tprec);
s = string_cat(s, "]");
break;
case SUBSET:
s = decompile_expr(s, o, m, (Inst *) t[3], tprec);
s = string_cat(s, "[");
s = decompile_expr(s, o, m, (Inst *) t[2], 0);
s = string_cat(s, "..");
s = decompile_expr(s, o, m, (Inst *) t[1], 0);
s = string_cat(s, "]");
break;
case LSUBSET:
s = decompile_expr(s, o, m, (Inst *) t[2], tprec);
s = string_cat(s, "[..");
s = decompile_expr(s, o, m, (Inst *) t[1], 0);
s = string_cat(s, "]");
break;
case RSUBSET:
s = decompile_expr(s, o, m, (Inst *) t[2], tprec);
s = string_cat(s, "[");
s = decompile_expr(s, o, m, (Inst *) t[1], 0);
s = string_cat(s, "..]");
break;
case NUMPUSH:
s = string_catnum(s, t[1]);
break;
case STRPUSH:
s = string_cat(s, "\"");
s = string_backslash(s, sym_get(o, t[1])->str);
s = string_cat(s, "\"");
break;
case OBJPUSH:
obj.id = t[1]; obj.server = t[2];
s = string_catobj(s, obj, obj.server);
break;
case LISTPUSH:
s = string_cat(s, "{");
s = decompile_args(s, o, m, (Inst) (t + 1));
s = string_cat(s, "}");
break;
case ERRPUSH:
s = string_cat(s, err_id2name(t[1]));
break;
case ADD:
UNPARSE_BINOP(" + ");
break;
case SUB:
UNPARSE_BINOP(" - ");
break;
case MUL:
UNPARSE_BINOP(" * ");
break;
case DIV:
UNPARSE_BINOP(" / ");
break;
case MOD:
UNPARSE_BINOP(" % ");
break;
case EQ:
UNPARSE_BINOP(" == ");
break;
case NE:
UNPARSE_BINOP(" != ");
break;
case GT:
UNPARSE_BINOP(" > ");
break;
case GE:
UNPARSE_BINOP(" >= ");
break;
case LT:
UNPARSE_BINOP(" < ");
break;
case LE:
UNPARSE_BINOP(" <= ");
break;
case AND:
case OR:
/* ignore 'em */
break;
case ENDAND:
UNPARSE_BINOP(" && ");
break;
case ENDOR:
UNPARSE_BINOP(" || ");
break;
case IN:
UNPARSE_BINOP(" in ");
break;
case NOT:
s = string_cat(s, "!");
s = decompile_expr(s, o, m, (Inst *) t[1], tprec);
break;
case NEGATE:
s = string_cat(s, "-");
s = decompile_expr(s, o, m, (Inst *) t[1], tprec);
break;
case PARENTS:
s = string_cat(s, "parents");
break;
case THIS:
s = string_cat(s, "this");
break;
case PLAYER:
s = string_cat(s, "player");
break;
case CALLER:
s = string_cat(s, "caller");
break;
case ARGS:
s = string_cat(s, "args");
break;
default:
if (!(funcname = bf_id2name(t[0]))) {
writelog();
fprintf(stderr, "decompile_expr(): Unknown opcode %d\n", t[0]);
} else {
s = string_cat(s, funcname);
s = string_cat(s, "(");
s = decompile_args(s, o, m, (Inst) (t + 1));
s = string_cat(s, ")");
}
break;
}
if (tprec && (tprec < prec || full_bracketing)) {
s = string_cat(s, ")");
}
return s;
}
static String *
decompile_args(String *s, Object *o, Method *m, Inst in)
{
Inst *t = (Inst *) in;
int i;
for (i = 0; i < t[0]; i++) {
s = decompile_expr(s, o, m, (Inst *) t[i + 1], 0);
if (i < t[0] - 1) {
s = string_cat(s, ", ");
}
}
return s;
}
static void
tree_func(Method *m, int i)
{
Inst *start = tree + tptr;
if (tptr + 1 >= MAX_TREE) { /* not enough tree mem left */
tpush(0);
} else {
tree[tptr++] = m->code[i]; /* func */
tree_args(m->code[i + 1]);
tpush(start);
}
}
static void
tree_args(int len)
{
int i;
tree[tptr++] = len;
for (i = 1; i <= len; i++) {
tree[tptr + len - i] = (Inst) tpop();
}
tptr += len;
}
static void
tree_list(Method *m, int i)
{
Inst *start = tree + tptr;
if (tptr + m->code[i + 1] + 2 >= MAX_TREE) {
tpush(0); /* not enough tree mem left */
} else {
tree[tptr++] = LISTPUSH;
tree_args(m->code[i + 1]);
tpush(start);
}
}
static void
tree_pass(Method *m, int i)
{
Inst *start = tree + tptr;
if (tptr + 3 + m->code[i + 1] >= MAX_TREE) {
tpush(0); /* not enough tree mem left */
} else {
tree[tptr++] = PASS;
tree[tptr++] = m->code[i + 2]; /* parent */
tree_args(m->code[i + 1]);
tpush(start);
}
}
static void
tree_message(Method *m, int i)
{
Inst *start = tree + tptr;
Inst *toref;
if (tptr + 4 + m->code[i + 1] >= MAX_TREE) {
tpush(0); /* not enough tree mem left */
} else {
tree[tptr++] = MESSAGE;
tree[tptr++] = m->code[i + 2]; /* message */
toref = &(tree[tptr++]); /* save address of dest expr */
tree_args(m->code[i + 1]);
*toref = (Inst) tpop(); /* store destination expr */
tpush(start);
}
}
static void
tree_message_expr(Method *m, int i)
{
Inst *start = tree + tptr;
Inst *toref, *msgref;
if (tptr + 4 + m->code[i + 1] >= MAX_TREE) {
tpush(0); /* not enough tree mem left */
} else {
tree[tptr++] = MESSAGE_EXPR;
toref = &(tree[tptr++]); /* save address of dest expr */
msgref = &(tree[tptr++]); /* save address of msg expr */
tree_args(m->code[i + 1]);
*msgref = (Inst) tpop(); /* store message expr */
*toref = (Inst) tpop(); /* store destination expr */
tpush(start);
}
}
static void
tree_ternop(Method *m, int i)
{
Inst *start = tree + tptr;
if (tptr + 4 >= MAX_TREE) {
tpush(0);
} else {
tree[tptr++] = m->code[i];
tree[tptr++] = (Inst) tpop(); /* left argument */
tree[tptr++] = (Inst) tpop(); /* middle argument */
tree[tptr++] = (Inst) tpop(); /* right argument */
tpush(start);
}
}
static void
tree_binop(Method *m, int i)
{
Inst *start = tree + tptr;
if (tptr + 3 >= MAX_TREE) { /* not enough tree mem left */
tpush(0);
} else {
tree[tptr++] = m->code[i]; /* store opcode */
tree[tptr++] = (Inst) tpop(); /* store right argument */
tree[tptr++] = (Inst) tpop(); /* store left argument */
tpush(start); /* push address of node */
}
}
static void
tree_unop(Method *m, int i)
{
Inst *start = tree + tptr;
if (tptr + 2 >= MAX_TREE) { /* not enough tree mem left */
tpush(0);
} else {
tree[tptr++] = m->code[i]; /* store opcode */
tree[tptr++] = (Inst) tpop(); /* store arg */
tpush(start); /* push address of node */
}
}
static String *
line_start(String *str, int ind, const char *s)
{
char buf[INT_SIZE + 3];
if (number_lines) {
sprintf(buf, "%3d: ", lineno);
str = string_cat(str, buf);
}
str = string_indent_cat(str, ind, s);
return str;
}
String *
decompile_object(Object *o)
{
String *s;
if (!o) return 0;
s = string_new(0);
s = string_cat(s, "object ");
s = string_catobj(s, o->id, 0);
s = string_cat(s, "\r\n");
s = decompile_parents(s, o);
s = decompile_global_vars(s, o);
s = decompile_verbs(s, o);
s = decompile_methods(s, o);
s = string_cat(s, "endobject\r\n\r\n");
return s;
} /* decompile_object() */
static String *
decompile_parents(String *s, Object *o)
{
int i;
if (o->parents->len > 0) {
s = string_cat(s, " parents ");
for (i = 0; i < o->parents->len - 1; i++) {
s = string_catobj(s, o->parents->el[i].v.obj, 0);
s = string_cat(s, ", ");
}
s = string_catobj(s, o->parents->el[i].v.obj, 0);
s = string_cat(s, ";\r\n\r\n");
} /* if */
return s;
} /* decompile_parents() */
static String *
decompile_global_vars(String *s, Object *o)
{
Vardef *var;
int hval;
if (!o->vars) return s;
for (hval = 0; hval < o->vars->size; hval++) {
for (var = o->vars->table[hval]; var; var = var->next) {
switch (var->value.type) {
case STR:
s = string_cat(s, " str "); break;
case NUM:
s = string_cat(s, " num "); break;
case OBJ:
s = string_cat(s, " obj "); break;
case LIST:
s = string_cat(s, " list "); break;
case ERR:
s = string_cat(s, " err "); break;
case PC: /* should never happen */
break;
} /* switch */
s = string_cat(s, sym_get(o, var->name)->str);
s = string_cat(s, " = ");
s = var_tostring(s, var->value, 1);
s = string_cat(s, ";\r\n");
} /* for */
} /* for */
s = string_cat(s, "\r\n");
return s;
} /* decompile_global_vars */
static String *
decompile_verbs(String *s, Object *o)
{
Verbdef *v;
for (v = o->verbs; v; v = v->next) {
s = string_cat(s, " verb \"");
s = string_cat(s, sym_get(o, v->verb)->str);
s = string_cat(s, "\"");
if (v->prep >= 0) {
s = string_cat(s, " : \"");
s = string_cat(s, sym_get(o, v->prep)->str);
s = string_cat(s, "\"");
} /* if */
s = string_cat(s, " = ");
s = string_cat(s, sym_get(o, v->method)->str);
s = string_cat(s, ";\r\n");
} /* for */
s = string_cat(s, "\r\n");
return s;
} /* decompile_verbs() */
static String *
decompile_methods(String *s, Object *o)
{
Method *m;
int hval;
if (!o->methods) return s;
for (hval = 0; hval < o->methods->size; hval++) {
for (m = o->methods->table[hval]; m; m = m->next) {
if (m->blocked) {
s = string_cat(s, " blocked method ");
} else {
s = string_cat(s, " method ");
} /* if */
s = string_cat(s, sym_get(o, m->name)->str);
s = string_cat(s, "\r\n");
s = decompile_method(s, o, m, 0, 0, 2, 4, 0, 0);
s = string_cat(s, "\r\n");
s = string_cat(s, " endmethod\r\n\r\n");
} /* for */
}
return s;
} /* decompile_methods */