/* disassembler.c -- Byte compiler and function evaluator */ /* Copyright (c) 2001, Juan Jose Garcia Ripoll. ECL is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See file '../Copyright' for full details. */ #include "ecl.h" #include "ecl-inl.h" #include "bytecodes.h" static cl_opcode *disassemble(cl_object bytecodes, cl_opcode *vector); static cl_opcode *base = NULL; static void print_noarg(const char *s) { princ_str(s, Cnil); } static void print_oparg(const char *s, cl_fixnum n) { princ_str(s, Cnil); princ(MAKE_FIXNUM(n), Cnil); } static void print_arg(const char *s, cl_object x) { princ_str(s, Cnil); princ(x, Cnil); } static void print_oparg_arg(const char *s, cl_fixnum n, cl_object x) { princ_str(s, Cnil); princ(MAKE_FIXNUM(n), Cnil); princ_str(",", Cnil); princ(x, Cnil); } static cl_object * disassemble_vars(const char *message, cl_object *data, cl_index step) { cl_object o = *(data++); cl_index n = fix(o); if (n) { terpri(Cnil); print_noarg(message); for (; n; n--, data+=step) { prin1(data[0], Cnil); if (n > 1) print_noarg(", "); } } return data; } static void disassemble_lambda(cl_object bytecodes) { cl_object *data; cl_opcode *vector; /* Name of LAMBDA */ print_arg("\nName:\t\t", bytecodes->bytecodes.name); /* Print required arguments */ data = bytecodes->bytecodes.data; data = disassemble_vars("Required:\t", data, 1); /* Print optional arguments */ data = disassemble_vars("Optionals:\t", data, 3); /* Print rest argument */ if (data[0] != Cnil) { print_arg("\nRest:\t\t", data[0]); } data++; /* Print keyword arguments */ if (data[0] == MAKE_FIXNUM(0)) { data++; goto NO_KEYS; } if (data[0] != Cnil) { print_arg("\nOther keys:\t", data[0]); } data++; data = disassemble_vars("Keywords:\t", data, 4); NO_KEYS: /* Print aux arguments */ print_arg("\nDocumentation:\t", *(data++)); print_arg("\nDeclarations:\t", *(data++)); base = vector = (cl_opcode *)bytecodes->bytecodes.code; disassemble(bytecodes, vector); } /* -------------------- DISASSEMBLER CORE -------------------- */ /* OP_DOLIST labelz, labelo ... ; code to bind the local variable OP_EXIT ... ; code executed on each iteration OP_EXIT labelo: ... ; code executed at the end OP_EXIT labelz: High level construct for the DOLIST iterator. The list over which we iterate is stored in VALUES(0). */ static cl_opcode * disassemble_dolist(cl_object bytecodes, cl_opcode *vector) { cl_opcode *exit, *output; cl_object lex_old = cl_env.lex_env; GET_LABEL(exit, vector); GET_LABEL(output, vector); print_oparg("DOLIST\t", exit-base); vector = disassemble(bytecodes, vector); print_noarg("\t\t; dolist binding"); vector = disassemble(bytecodes, vector); print_noarg("\t\t; dolist body"); vector = disassemble(bytecodes, vector); print_noarg("\t\t; dolist"); cl_env.lex_env = lex_old; return vector; } /* OP_TIMES labelz, labelo ... ; code to bind the local variable OP_EXIT ... ; code executed on each iteration OP_EXIT labelo: ... ; code executed at the end OP_EXIT labelz: High level construct for the DOTIMES iterator. The number of times we iterate is stored in VALUES(0). */ static cl_opcode * disassemble_dotimes(cl_object bytecodes, cl_opcode *vector) { cl_opcode *exit, *output; cl_object lex_old = cl_env.lex_env; GET_LABEL(exit, vector); GET_LABEL(output, vector); print_oparg("DOTIMES\t", exit-base); vector = disassemble(bytecodes, vector); print_noarg("\t\t; dotimes times"); vector = disassemble(bytecodes, vector); print_noarg("\t\t; dotimes body"); vector = disassemble(bytecodes, vector); print_noarg("\t\t; dotimes"); cl_env.lex_env = lex_old; return vector; } /* OP_FLET nfun{arg} fun1{object} ... funn{object} ... Executes the enclosed code in a lexical enviroment extended with the functions "fun1" ... "funn". */ static cl_opcode * disassemble_flet(cl_object bytecodes, cl_opcode *vector) { cl_index nfun = GET_OPARG(vector); print_noarg("FLET"); while (nfun--) { cl_object fun = GET_DATA(vector, bytecodes); print_arg("\n\tFLET\t", fun->bytecodes.name); } return vector; } /* OP_LABELS nfun{arg} fun1{object} ... funn{object} ... Executes the enclosed code in a lexical enviroment extended with the functions "fun1" ... "funn". */ static cl_opcode * disassemble_labels(cl_object bytecodes, cl_opcode *vector) { cl_index nfun = GET_OPARG(vector); print_noarg("LABELS"); while (nfun--) { cl_object fun = GET_DATA(vector, bytecodes); print_arg("\n\tLABELS\t", fun->bytecodes.name); } return vector; } /* OP_MSETQ n{arg} {fixnumn} ... {fixnum1} Sets N variables to the N values in VALUES(), filling with NIL when there are values missing. Local variables are denoted with an integer which points a position in the lexical environment, while special variables are denoted with a negative index X, which denotes the value -1-X in the table of constants. */ static cl_opcode * disassemble_msetq(cl_object bytecodes, cl_opcode *vector) { int i, n = GET_OPARG(vector); bool newline = FALSE; for (i=0; i= 0) { cl_format(4, Ct, make_constant_string("MSETQ\t~D,VALUES(~D)"), MAKE_FIXNUM(var), MAKE_FIXNUM(i)); } else { cl_object name = bytecodes->bytecodes.data[-1-var]; cl_format(4, Ct, make_constant_string("MSETQS\t~A,VALUES(~D)"), name, MAKE_FIXNUM(i)); } } return vector; } /* OP_PROGV bindings{list} ... OP_EXIT Execute the code enclosed with the special variables in BINDINGS set to the values in the list which was passed in VALUES(0). */ static cl_opcode * disassemble_progv(cl_object bytecodes, cl_opcode *vector) { print_noarg("PROGV"); vector = disassemble(bytecodes, vector); print_noarg("\t\t; progv"); return vector; } /* OP_TAGBODY n{arg} label1 ... labeln label1: ... labeln: ... OP_EXIT High level construct for the TAGBODY form. */ static cl_opcode * disassemble_tagbody(cl_object bytecodes, cl_opcode *vector) { cl_index i, ntags = GET_OPARG(vector); cl_object lex_old = cl_env.lex_env; cl_opcode *destination; print_noarg("TAGBODY"); for (i=0; ibytecodes.code_size, aet_b8); vector->vector.self.b8 = b->bytecodes.code; data = cl_alloc_simple_vector(b->bytecodes.data_size, aet_object); data->vector.self.t = b->bytecodes.data; @(return b->bytecodes.lex vector data) }