/* 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 int tree_count_args(void); 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 }, { NEGATE, 10 }, { SPLICE, 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); \ s = string_cat(s, (STR)); \ s = decompile_expr(s, o, m, (Inst *) t[1], tprec + 1); 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: case GETSYSVAR: tpush (m->code + i); i += 2; break; case OBJPUSH: tpush (m->code + i); i += 3; break; case LISTPUSH: tree_list (m, i); i += 1; break; case MAPPUSH: tree_map (m, i); i += 2; break; case MESSAGE: tree_message (m, i); i += 2; break; case MESSAGE_EXPR: tree_message_expr (m, i); i += 1; break; case PASS: tree_pass (m, i); i += 2; 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: case SPLICE: 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 ARGSTART: tpush((Inst *) ARGSTART); i++; break; case STOP: stopped = 1; break; /* * functions */ default: tree_func (m, i); i += 1; 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 GETSYSVAR: s = string_catc(s, '$'); 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 SPLICE: 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; int tnargs = tree_count_args(); if (tptr + tnargs >= MAX_TREE) { /* not enough tree mem left */ tpush (0); } else { tree[tptr++] = m->code[i]; /* func */ tree_args(tnargs); tpush (start); } } static int tree_count_args(void) { Inst *s = 0, *t; int count; for (count = 0; count < tsp; count++) { t = tstack[tsp - count - 1]; tstack[tsp - count - 1] = s; if (((Inst) t) == ARGSTART) { break; } s = t; } tsp--; return count; } 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; int len = tree_count_args(); if (tptr + len + 2 >= MAX_TREE) { tpush (0); /* not enough tree mem left */ } else { tree[tptr++] = LISTPUSH; tree_args(len); 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; int tnargs = tree_count_args(); if (tptr + 3 + tnargs >= MAX_TREE) { tpush (0); /* not enough tree mem left */ } else { tree[tptr++] = PASS; tree[tptr++] = m->code[i + 1]; /* parent */ tree_args(tnargs); tpush (start); } } static void tree_message (Method * m, int i) { Inst *start = tree + tptr; Inst *toref; int tnargs = tree_count_args(); if (tptr + 4 + tnargs >= MAX_TREE) { tpush (0); /* not enough tree mem left */ } else { tree[tptr++] = MESSAGE; tree[tptr++] = m->code[i + 1]; /* message */ toref = &(tree[tptr++]); /* save address of dest expr */ tree_args(tnargs); *toref = (Inst) tpop (); /* store destination expr */ tpush (start); } } static void tree_message_expr (Method * m, int i) { Inst *start = tree + tptr; Inst *toref, *msgref; int tnargs = tree_count_args(); if (tptr + 4 + tnargs >= 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(tnargs); *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 */