/* Copyright (c) 1993 Stephen F. White */
#include "cool.h"
#include "proto.h"
#include "y.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 String *decompile_map (String * s, Object * o, Method * m, Inst in);
static void tree_list (Method * m, int i);
static void tree_map (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 *i1;
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 [");
i1 = tpop ();
s = decompile_expr (s, o, m, tpop (), 0);
s = string_cat (s, "..");
s = decompile_expr (s, o, m, i1, 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 ASGNGVARINDEX:
s = line_start (s, indent, sym_get (o, m->code[i + 1])->str);
s = string_cat (s, "[");
i1 = tpop ();
s = decompile_expr (s, o, m, tpop (), 0);
s = string_cat (s, "] = ");
s = decompile_expr (s, o, m, i1, 0);
s = string_cat (s, ";\r\n");
lineno++;
tptr = 0;
i += 2;
break;
case ASGNLVARINDEX:
n = var_find_local (m, m->code[i + 1])->name;
s = line_start (s, indent, sym_get (o, n)->str);
i1 = tpop ();
s = string_cat (s, "[");
s = decompile_expr (s, o, m, tpop (), 0);
s = string_cat (s, "] = ");
s = decompile_expr (s, o, m, i1, 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 MAPPUSH:
tree_map (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 MAPPUSH:
s = string_cat (s, "[");
s = decompile_map (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 String *decompile_map (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 * 2 + 2], 0);
s = string_cat (s, " => ");
s = decompile_expr (s, o, m, (Inst *) t[i * 2 + 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_map (Method * m, int i)
{
Inst *start = tree + tptr;
int j, len = m->code[i + 1];
if (tptr + len * 2 + 2 >= MAX_TREE) {
tpush (0); /* not enough tree mem left */
} else {
tree[tptr++] = MAPPUSH;
tree[tptr++] = len;
for (j = 1; j <= len; j++) {
tree[tptr++] = (Inst) tpop ();
tree[tptr++] = (Inst) tpop ();
}
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 MAP:
s = string_cat (s, " map ");
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 */