diff --git a/byterun/dune b/byterun/dune index cf66e1d40..c3f6eae02 100644 --- a/byterun/dune +++ b/byterun/dune @@ -2,11 +2,45 @@ (target byterun.exe) (deps (:include (source_tree include)) - (:main src/cli.c src/interpreter.c) - (:parser src/parser.c) - (:utils src/types.c) + (:main src/cli.cpp) + (:parser src/parser.cpp) + (:analyzer src/analyzer.cpp) + (:obj types.o parser.o interpreter.o) (:runtime ../runtime/runtime.a)) (mode (promote (until-clean))) (action - (run gcc -Iinclude/ %{main} %{parser} %{utils} %{runtime} -o %{target}))) + (run g++ -std=c++20 -Iinclude/ %{main} %{parser} %{analyzer} %{runtime} %{obj} -o %{target}))) + +(rule + (target types.o) + (deps + (:include (source_tree include)) + (:src src/types.c) + (:runtime ../runtime/runtime.a)) + (mode + (promote (until-clean))) + (action + (run gcc -Iinclude/ -c %{src} -o %{target}))) + +(rule + (target parser.o) + (deps + (:include (source_tree include)) + (:src src/parser.c) + (:runtime ../runtime/runtime.a)) + (mode + (promote (until-clean))) + (action + (run gcc -Iinclude/ -c %{src} -o %{target}))) + +(rule + (target interpreter.o) + (deps + (:include (source_tree include)) + (:src src/interpreter.c) + (:runtime ../runtime/runtime.a)) + (mode + (promote (until-clean))) + (action + (run gcc -Iinclude/ -c %{src} -o %{target}))) diff --git a/byterun/include/analyzer.hpp b/byterun/include/analyzer.hpp new file mode 100644 index 000000000..249ea679e --- /dev/null +++ b/byterun/include/analyzer.hpp @@ -0,0 +1,7 @@ +#pragma once + +extern "C" { +#include "utils.h" +} + +void analyze(const Bytefile &bf); diff --git a/byterun/include/interpreter.h b/byterun/include/interpreter.h index aae9ad99e..60d2e59f5 100644 --- a/byterun/include/interpreter.h +++ b/byterun/include/interpreter.h @@ -2,4 +2,4 @@ #include "parser.h" -void run(bytefile *bf, int argc, char **argv); +void run(Bytefile *bf, int argc, char **argv); diff --git a/byterun/include/parser.h b/byterun/include/parser.h index 381fa5c62..897e62ece 100644 --- a/byterun/include/parser.h +++ b/byterun/include/parser.h @@ -21,6 +21,6 @@ const char *read_cmd(char *ip); -bytefile *read_file(char *fname); +Bytefile *read_file(char *fname); // void dump_file(FILE *f, bytefile *bf); diff --git a/byterun/include/parser.hpp b/byterun/include/parser.hpp new file mode 100644 index 000000000..969b4f1eb --- /dev/null +++ b/byterun/include/parser.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include + +extern "C" { +#include "utils.h" +} + +enum class Cmd : int8_t { + BINOP, + CONST, + STRING, + SEXP, + STI, + STA, + JMP, + END, + RET, + DROP, + DUP, + SWAP, + ELEM, + LD, + LDA, + ST, + CJMPz, + CJMPnz, + BEGIN, + CBEGIN, + CLOSURE, + CALLC, + CALL, + TAG, + ARRAY, + FAIL, + LINE, + PATT, + Lread, + Lwrite, + Llength, + Lstring, + Barray, + EXIT, + _UNDEF_, +}; + +Bytefile *read_file(const char *fname); + +static inline int ip_read_int(char **ip, const Bytefile &bf) { + if (*ip + sizeof(int) > bf.code_ptr + bf.code_size) { + failure("last command is invalid, int parameter can not be read\n"); + } + *ip += sizeof(int); + return *(int *)((*ip) - sizeof(int)); +} + +static inline uint8_t ip_read_byte(char **ip, const Bytefile &bf) { + if (*ip + sizeof(char) > bf.code_ptr + bf.code_size) { + failure("last command is invalid, byte parameter can not be read\n"); + } + return *(*ip)++; +} + +static inline uint8_t ip_read_byte_unsafe(char **ip) { return *(*ip)++; } + +static inline const char *ip_read_string(char **ip, const Bytefile &bf) { + return get_string(&bf, ip_read_int(ip, bf)); +} + +Cmd parse_command(char **ip, const Bytefile &bf); +Cmd parse_command(char **ip, const Bytefile &bf, std::ostream &out); diff --git a/byterun/include/types.h b/byterun/include/types.h index e4d4a928f..cd8f8279d 100644 --- a/byterun/include/types.h +++ b/byterun/include/types.h @@ -55,7 +55,7 @@ struct State { void **stack; // void **sp; // stack pointer struct Frame *fp; // function frame pointer - bytefile *bf; + Bytefile *bf; int current_line; bool is_closure_call; @@ -65,7 +65,7 @@ struct State { char *call_ip; // prev instruction pointer (to remember jmp locations) }; -void construct_state(bytefile *bf, struct State *s, void **stack); +void construct_state(Bytefile *bf, struct State *s, void **stack); void cleanup_state(struct State *state); static inline void s_failure(struct State *s, const char *msg) { diff --git a/byterun/include/utils.h b/byterun/include/utils.h index 13219725c..f8da4389d 100644 --- a/byterun/include/utils.h +++ b/byterun/include/utils.h @@ -18,7 +18,7 @@ typedef struct { uint global_area_size; /* The size (in words) of global area */ uint public_symbols_number; /* The number of public symbols */ char buffer[0]; -} bytefile; +} Bytefile; static inline void exec_failure(const char *cmd, int line, aint offset, const char *msg) { @@ -27,7 +27,7 @@ static inline void exec_failure(const char *cmd, int line, aint offset, } /* Gets a string from a string table by an index */ -static inline const char *get_string(const bytefile *f, size_t pos) { +static inline const char *get_string(const Bytefile *f, size_t pos) { if (pos >= f->stringtab_size) { failure("strinpg pos is out of range: %zu >= %i\n", pos, f->stringtab_size); } @@ -35,18 +35,18 @@ static inline const char *get_string(const bytefile *f, size_t pos) { } /* Gets a name for a public symbol */ -static inline const char *get_public_name(const bytefile *f, size_t i) { +static inline const char *get_public_name(const Bytefile *f, size_t i) { if (i >= f->public_symbols_number) { - failure("public number is out of range: %zu >= %i\n", i * 2, + failure("public number is out of range: %zu >= %i\n", i, f->public_symbols_number); } return get_string(f, f->public_ptr[i * 2]); } /* Gets an offset for a publie symbol */ -static inline size_t get_public_offset(const bytefile *f, size_t i) { - if (i + 1 >= f->public_symbols_number) { - failure("public number is out of range: %zu >= %i\n", i * 2 + 1, +static inline size_t get_public_offset(const Bytefile *f, size_t i) { + if (i >= f->public_symbols_number) { + failure("public number is out of range: %zu >= %i\n", i, f->public_symbols_number); } return f->public_ptr[i * 2 + 1]; diff --git a/byterun/lamac b/byterun/lamac deleted file mode 100644 index e69de29bb..000000000 diff --git a/byterun/src/analyzer.cpp b/byterun/src/analyzer.cpp new file mode 100644 index 000000000..7ffd47cb8 --- /dev/null +++ b/byterun/src/analyzer.cpp @@ -0,0 +1,88 @@ +#include "analyzer.hpp" +#include "parser.hpp" + +#include + +// TODO +void analyze(const Bytefile &bf) { + std::vector to_visit; + std::vector visited(bf.code_size, false); + std::vector control_flow_in(bf.code_size, false); + + // TODO: 2 control flow sets, for functions and for control flow inside + // functions + // + current stack depth + // + ast begin pos + + auto const to_visit_push = [&visited, &to_visit](size_t offset) { + if (!visited[offset]) { + visited[offset] = true; + to_visit.push_back(offset); + } + }; + + auto const control_push = [&to_visit_push, &control_flow_in](size_t offset) { + control_flow_in[offset] = true; + to_visit_push(offset); + }; + + // add publics + to_visit.reserve(bf.public_symbols_number); + for (size_t i = 0; i < bf.public_symbols_number; ++i) { + control_push(get_public_offset(&bf, i)); + } + + if (to_visit.size() == 0) { + failure("no public symbols detected"); + } + + while (!to_visit.empty()) { + char *ip = bf.code_ptr + to_visit.back(); + to_visit.pop_back(); + + if (ip >= bf.code_ptr + bf.code_size) { + failure("instruction pointer is out of range (>= size)"); + } + + if (ip < bf.code_ptr) { + failure("instruction pointer is out of range (< 0)"); + } + + char *current_ip = ip; + +#ifdef DEBUG_VERSION + printf("0x%.8lx \n", current_ip - bf.code_ptr - 1); +#endif + + Cmd cmd = parse_command(&ip, bf); + + ++current_ip; // skip command byte + switch (cmd) { + case Cmd::EXIT: + case Cmd::END: + break; + + case Cmd::CJMPz: + case Cmd::CJMPnz: + case Cmd::CLOSURE: + case Cmd::CALL: + to_visit_push(ip - bf.code_ptr); + case Cmd::JMP: { + uint jmp_p = ip_read_int(¤t_ip, bf); + if (jmp_p >= bf.code_size) { + failure("jump/call out of file"); + } + control_push(jmp_p); + break; + } + + case Cmd::_UNDEF_: + failure("undefined command"); + break; + + default: + to_visit_push(ip - bf.code_ptr); + break; + } + } +} diff --git a/byterun/src/cli.c b/byterun/src/cli.cpp similarity index 61% rename from byterun/src/cli.c rename to byterun/src/cli.cpp index b580ffb2c..f13463f15 100644 --- a/byterun/src/cli.c +++ b/byterun/src/cli.cpp @@ -1,17 +1,19 @@ +extern "C" { +#include "../../runtime/runtime.h" #include "interpreter.h" #include "parser.h" #include "utils.h" -#include "../../runtime/runtime.h" +} -int main(int argc, char** argv) { +int main(int argc, char **argv) { if (argc < 2) { failure("no file name provided"); } - bytefile *f = read_file(argv[1]); -// #ifdef DEBUG_VERSION -// dump_file (stdout, f); -// #endif + Bytefile *f = read_file(argv[1]); + // #ifdef DEBUG_VERSION + // dump_file (stdout, f); + // #endif run(f, argc - 1, argv + 1); free(f->global_ptr); diff --git a/byterun/src/interpreter.c b/byterun/src/interpreter.c index 29f4ca737..a098d74a2 100644 --- a/byterun/src/interpreter.c +++ b/byterun/src/interpreter.c @@ -37,7 +37,7 @@ static inline const char *ip_read_string(char **ip) { const size_t BUFFER_SIZE = 1000; -void run(bytefile *bf, int argc, char **argv) { +void run(Bytefile *bf, int argc, char **argv) { size_t stack[STACK_SIZE]; void *buffer[BUFFER_SIZE]; construct_state(bf, &s, (void **)stack); @@ -132,9 +132,9 @@ void run(bytefile *bf, int argc, char **argv) { args_count); #endif - void **opr_buffer = args_count >= BUFFER_SIZE + void **opr_buffer = (void**)(args_count >= BUFFER_SIZE ? alloc((args_count + 1) * sizeof(void *)) - : buffer; + : buffer); // s_put_nth(args_count, (void *)LtagHash((char *)name)); @@ -321,7 +321,7 @@ void run(bytefile *bf, int argc, char **argv) { s.is_closure_call = true; s.call_ip = s.ip; - s.ip = Belem(*s_nth(args_count), BOX(0)); // use offset instead ?? + s.ip = (char*)Belem(*s_nth(args_count), BOX(0)); // use offset instead ?? break; } @@ -427,9 +427,9 @@ void run(bytefile *bf, int argc, char **argv) { case CMD_BUILTIN_Barray: { // CALL Barray %d size_t elem_count = ip_read_int(&s.ip); - void **opr_buffer = elem_count > BUFFER_SIZE + void **opr_buffer = (void**)(elem_count > BUFFER_SIZE ? alloc(elem_count * sizeof(void *)) - : buffer; + : buffer); for (size_t i = 0; i < elem_count; ++i) { opr_buffer[elem_count - i - 1] = s_pop(); } diff --git a/byterun/src/parser.c b/byterun/src/parser.c index 6a704365f..9e43cd03e 100644 --- a/byterun/src/parser.c +++ b/byterun/src/parser.c @@ -14,9 +14,9 @@ void *__start_custom_data; void *__stop_custom_data; /* Reads a binary bytecode file by name and unpacks it */ -bytefile* read_file (char *fname) { +Bytefile* read_file (char *fname) { FILE *f = fopen (fname, "rb"); - bytefile *file; + Bytefile *file; if (f == 0) { failure ("%s\n", strerror (errno)); @@ -28,7 +28,7 @@ bytefile* read_file (char *fname) { long size = ftell (f); long additional_size = sizeof(void*) * 4 + sizeof(int); - file = (bytefile*) malloc (size + additional_size); // file itself + additional data + file = (Bytefile*) malloc (size + additional_size); // file itself + additional data char* file_begin = (char*)file + additional_size; char* file_end = file_begin + size; diff --git a/byterun/src/parser.cpp b/byterun/src/parser.cpp new file mode 100644 index 000000000..5274d8f11 --- /dev/null +++ b/byterun/src/parser.cpp @@ -0,0 +1,574 @@ +#include +#include +#include +#include +#include + +#include "parser.hpp" + +extern "C" { +#include "utils.h" +} + +enum CMD_TOPLVL { + CMD_BINOP = 0, + CMD_BASIC, + CMD_LD, + CMD_LDA, + CMD_ST, + CMD_CTRL, + CMD_PATT, + CMD_BUILTIN, + CMD_EXIT = 15, +}; + +enum CMD_BASICS { + CMD_BASIC_CONST = 0, + CMD_BASIC_STRING, + CMD_BASIC_SEXP, + CMD_BASIC_STI, + CMD_BASIC_STA, + CMD_BASIC_JMP, + CMD_BASIC_END, + CMD_BASIC_RET, + CMD_BASIC_DROP, + CMD_BASIC_DUP, + CMD_BASIC_SWAP, + CMD_BASIC_ELEM, +}; + +enum CMD_CTRLS { + CMD_CTRL_CJMPz = 0, + CMD_CTRL_CJMPnz, + CMD_CTRL_BEGIN, + CMD_CTRL_CBEGIN, + CMD_CTRL_CLOSURE, + CMD_CTRL_CALLC, + CMD_CTRL_CALL, + CMD_CTRL_TAG, + CMD_CTRL_ARRAY, + CMD_CTRL_FAIL, + CMD_CTRL_LINE, +}; + +enum CMD_PATTS { + CMD_PATT_STR = 0, + CMD_PATT_STR_TAG, + CMD_PATT_ARRAY_TAG, + CMD_PATT_SEXP_TAG, + CMD_PATT_REF_TAG, + CMD_PATT_VAL_TAG, + CMD_PATT_FUN_TAG, +}; + +enum CMD_BUILTINS { + CMD_BUILTIN_Lread = 0, + CMD_BUILTIN_Lwrite, + CMD_BUILTIN_Llength, + CMD_BUILTIN_Lstring, + CMD_BUILTIN_Barray, +}; + +enum class ArgT { + INT, + OFFSET, + STR, +}; + +#define FORALL_BINOP(DEF) \ + DEF(0, +) \ + DEF(1, -) \ + DEF(2, *) \ + DEF(3, /) \ + DEF(4, %) \ + DEF(5, <) \ + DEF(6, <=) \ + DEF(7, >) \ + DEF(8, >=) \ + DEF(9, ==) \ + DEF(10, !=) \ + DEF(11, &&) \ + DEF(12, ||) + +// Reads a binary bytecode file by name and unpacks it +Bytefile *read_file(const char *fname) { + FILE *f = fopen(fname, "rb"); + Bytefile *file; + + if (f == 0) { + failure(strerror(errno)); + } + + if (fseek(f, 0, SEEK_END) == -1) { + failure(strerror(errno)); + } + + long size = ftell(f); + long additional_size = sizeof(void *) * 4 + sizeof(int); + file = (Bytefile *)malloc(size + + additional_size); // file itself + additional data + + char *file_begin = (char *)file + additional_size; + char *file_end = file_begin + size; + + if (file == 0) { + failure("unable to allocate memory to store file data"); + } + + rewind(f); + + if (size != fread(&file->stringtab_size, 1, size, f)) { + failure(strerror(errno)); + } + + fclose(f); + + long public_symbols_size = file->public_symbols_number * 2 * sizeof(int); + if (file->buffer + public_symbols_size >= file_end) { + failure("public symbols are out of the file size"); + } + if (file->string_ptr + file->stringtab_size > file_end) { + failure("strings table is out of the file size"); + } + if (file->code_size < 0 || public_symbols_size < 0 || + file->stringtab_size < 0) { + failure("file zones sizes should be >= 0"); + } + + file->string_ptr = &file->buffer[public_symbols_size]; + file->public_ptr = (int *)file->buffer; + file->code_ptr = &file->string_ptr[file->stringtab_size]; + file->global_ptr = (int *)calloc(file->global_area_size, sizeof(int)); + + file->code_size = size - public_symbols_size - file->stringtab_size; + + return file; +} + +std::string command_name(Cmd cmd, int8_t l) { + static const char *const ops[] = { +#define OP_TO_STR(id, op) #op, + FORALL_BINOP(OP_TO_STR) +#undef OP_TO_STR + }; + static const char *const pats[] = {"=str", "#string", "#array", "#sexp", + "#ref", "#val", "#fun"}; + static const char *const ldts[] = {"G", "L", "A", "C"}; + + switch (cmd) { + case Cmd::EXIT: + return "EXIT"; + case Cmd::BINOP: + if (l - 1 >= sizeof(ops) / sizeof(char *)) { + return "_UNDEF_BINOP_"; + } + return "BINOP:" + std::string{ops[l - 1]}; + case Cmd::CONST: + return "CONST"; + case Cmd::STRING: + return "STRING"; + case Cmd::SEXP: + return "SEXP "; + case Cmd::STI: + return "STI"; + case Cmd::STA: + return "STA"; + case Cmd::JMP: + return "JMP"; + case Cmd::END: + return "END"; + case Cmd::RET: + return "RET"; + case Cmd::DROP: + return "DROP"; + case Cmd::DUP: + return "DUP"; + case Cmd::SWAP: + return "SWAP"; + case Cmd::ELEM: + return "ELEM"; + case Cmd::LD: + if (l >= sizeof(ldts) / sizeof(char *)) { + return "_UNDEF_LD_"; + } + return "LD:" + std::string{ldts[l]}; + case Cmd::LDA: + if (l >= sizeof(ldts) / sizeof(char *)) { + return "_UNDEF_LDA_"; + } + return "LDA:" + std::string{ldts[l]}; + case Cmd::ST: + if (l >= sizeof(ldts) / sizeof(char *)) { + return "_UNDEF_ST_"; + } + return "ST:" + std::string{ldts[l]}; + case Cmd::CJMPz: + return "CJMPz"; + case Cmd::CJMPnz: + return "CJMPnz"; + case Cmd::BEGIN: + return "BEGIN"; + case Cmd::CBEGIN: + return "CBEGIN"; + case Cmd::CLOSURE: + return "CLOSURE"; + case Cmd::CALLC: + return "CALLC"; + case Cmd::CALL: + return "CALL"; + case Cmd::TAG: + return "TAG"; + case Cmd::ARRAY: + return "ARRAY"; + case Cmd::FAIL: + return "FAIL"; + case Cmd::LINE: + return "LINE"; + case Cmd::PATT: + if (l >= sizeof(pats) / sizeof(char *)) { + return "_UNDEF_PATT_"; + } + return "PATT:" + std::string{pats[l]}; + case Cmd::Lread: + return "CALL\tLread"; + case Cmd::Lwrite: + return "CALL\tLwrite"; + case Cmd::Llength: + return "CALL\tLlength"; + case Cmd::Lstring: + return "CALL\tLstring"; + case Cmd::Barray: + return "CALL\tBarray\t%d"; + case Cmd::_UNDEF_: + return "_UNDEF_"; + } + + exit(1); +} + +template +static inline const T &print_val(std::ostream &out, const T &val) { + if constexpr (use_out) { + out << val; + } + return val; +} + +template static inline void print_space(std::ostream &out) { + if constexpr (use_out) { + out << ' '; + } +} + +template + requires(arg == ArgT::INT) +static inline uint read_print_val(char **ip, const Bytefile &bf, + std::ostream &out) { + uint val = ip_read_int(ip, bf); + if constexpr (use_out) { + out << val; + } + return val; +} + +template + requires(arg == ArgT::OFFSET) +static inline uint read_print_val(char **ip, const Bytefile &bf, + std::ostream &out) { + uint val = ip_read_int(ip, bf); + if constexpr (use_out) { + out << val; // TODO + } + return val; +} + +template + requires(arg == ArgT::STR) +static inline const char *read_print_val(char **ip, const Bytefile &bf, + std::ostream &out) { + const char *val = ip_read_string(ip, bf); + if constexpr (use_out) { + out << val; + } + return val; +} + +template +static inline void read_print_seq(char **ip, const Bytefile &bf, + std::ostream &out) {} + +template +static inline void read_print_seq(char **ip, const Bytefile &bf, + std::ostream &out) { + read_print_val(ip, bf, out); + if constexpr (use_out && sizeof...(args) != 0) { + out << ' '; + } + read_print_seq(ip, bf, out); +} + +template +static inline void read_print_cmd_seq(Cmd cmd, uint8_t l, char **ip, + const Bytefile &bf, std::ostream &out) { + if constexpr (use_out) { + out << command_name(cmd, l); + if constexpr (sizeof...(args) != 0) { + out << ' '; + } + } + read_print_seq(ip, bf, out); +} + +template +Cmd parse_command_impl(char **ip, const Bytefile &bf, std::ostream &out) { + static const char *const ops[] = { +#define OP_TO_STR(id, op) "op", + FORALL_BINOP(OP_TO_STR) +#undef OP_TO_STR + }; + + static const char *const pats[] = {"=str", "#string", "#array", "#sexp", + "#ref", "#val", "#fun"}; + static const char *const ldts[] = {"G", "L", "A", "C"}; + + // + + if (*ip >= bf.code_ptr + bf.code_size) { + failure("instruction pointer is out of range (>= size)"); + } + + if (*ip < bf.code_ptr) { + failure("instruction pointer is out of range (< 0)"); + } + + Cmd cmd = Cmd::_UNDEF_; + + char *instr_ip = *ip; + uint8_t x = ip_read_byte(ip, bf), h = (x & 0xF0) >> 4, l = x & 0x0F; + +#ifdef DEBUG_VERSION + printf("0x%.8lx ", *ip - bf.code_ptr - 1); + std::cout << ' ' << (int)x << ' ' << (int)h << ' ' << (int)l << ' '; +#endif + + switch (h) { + case CMD_EXIT: + cmd = Cmd::EXIT; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + /* BINOP */ + case CMD_BINOP: // BINOP ops[l-1] + cmd = Cmd::BINOP; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_BASIC: + switch (l) { + case CMD_BASIC_CONST: // CONST %d + cmd = Cmd::CONST; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BASIC_STRING: // STRING %s + cmd = Cmd::STRING; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_BASIC_SEXP: // SEXP %s %d + cmd = Cmd::SEXP; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_BASIC_STI: // STI - write by ref (?) + cmd = Cmd::STI; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BASIC_STA: // STA - write to array elem + cmd = Cmd::STA; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_BASIC_JMP: // JMP 0x%.8x + cmd = Cmd::JMP; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_BASIC_END: // END + cmd = Cmd::END; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BASIC_RET: // RET + cmd = Cmd::RET; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BASIC_DROP: // DROP + cmd = Cmd::DROP; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BASIC_DUP: // DUP + cmd = Cmd::DUP; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BASIC_SWAP: // SWAP + cmd = Cmd::SWAP; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BASIC_ELEM: // ELEM + cmd = Cmd::ELEM; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + default: + failure("invalid opcode"); + } + break; + + case CMD_LD: // LD %d + cmd = Cmd::LD; + if (l > sizeof(ldts) / sizeof(char *)) { + failure("wrong ld argument type"); + } + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_LDA: // LDA %d + cmd = Cmd::LDA; + if (l > sizeof(ldts) / sizeof(char *)) { + failure("wrong lda argument type"); + } + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_ST: // ST %d + cmd = Cmd::ST; + if (l > sizeof(ldts) / sizeof(char *)) { + failure("wrong st argument type"); + } + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_CTRL: + switch (l) { + case CMD_CTRL_CJMPz: // CJMPnz 0x%.8x + cmd = Cmd::CJMPz; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_CTRL_CJMPnz: // CJMPnz 0x%.8x + cmd = Cmd::CJMPnz; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_CTRL_BEGIN: // BEGIN %d %d // function begin + cmd = Cmd::BEGIN; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_CTRL_CBEGIN: // CBEGIN %d %d + cmd = Cmd::CBEGIN; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_CTRL_CLOSURE: { // CLOSURE 0x%.8x + cmd = Cmd::CLOSURE; + read_print_cmd_seq(cmd, l, ip, bf, out); + print_space(out); + size_t call_p = read_print_val(ip, bf, out); + print_space(out); + size_t args_count = read_print_val(ip, bf, out); + for (size_t i = 0; i < args_count; i++) { + uint8_t arg_type = ip_read_byte(ip, bf); + if (arg_type > sizeof(ldts) / sizeof(char *)) { + failure("wrong closure argument type"); + } + print_space(out); + print_val(out, ldts[arg_type]); + print_space(out); + read_print_val(ip, bf, out); + } + break; + } + + case CMD_CTRL_CALLC: // CALLC %d // call clojure + cmd = Cmd::CALLC; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_CTRL_CALL: // CALL 0x%.8x %d // call function + cmd = Cmd::CALL; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_CTRL_TAG: // TAG %s %d + cmd = Cmd::TAG; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_CTRL_FAIL: // FAIL %d %d + cmd = Cmd::FAIL; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_CTRL_ARRAY: // ARRAY %d + cmd = Cmd::ARRAY; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_CTRL_LINE: // LINE %d + cmd = Cmd::LINE; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + default: + failure("invalid opcode"); + } + break; + + case CMD_PATT: // PATT pats[l] + // {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"} + if (l >= sizeof(pats) / sizeof(char *)) { + failure("invalid opcode"); + } + cmd = Cmd::PATT; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_BUILTIN: { + switch (l) { + case CMD_BUILTIN_Lread: // CALL Lread + cmd = Cmd::Lread; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BUILTIN_Lwrite: // CALL Lwrite + cmd = Cmd::Lwrite; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BUILTIN_Llength: // CALL Llength + cmd = Cmd::Llength; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + case CMD_BUILTIN_Lstring: // CALL Lstring + cmd = Cmd::Lstring; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + case CMD_BUILTIN_Barray: // CALL Barray %d + cmd = Cmd::Barray; + read_print_cmd_seq(cmd, l, ip, bf, out); + break; + + default: + failure("invalid opcode"); + } + } break; + + default: + failure("invalid opcode"); + } +#ifdef DEBUG_VERSION + std::cout << command_name(cmd, l) << '\n'; +#endif + return cmd; +} + +Cmd parse_command(char **ip, const Bytefile &bf) { + return parse_command_impl(ip, bf, std::clog); +} + +Cmd parse_command(char **ip, const Bytefile &bf, std::ostream &out) { + return parse_command_impl(ip, bf, out); +} diff --git a/byterun/src/types.c b/byterun/src/types.c index b6772142c..f42025240 100644 --- a/byterun/src/types.c +++ b/byterun/src/types.c @@ -11,7 +11,7 @@ extern size_t __gc_stack_top, __gc_stack_bottom; // --- State --- -static void init_state(bytefile *bf, struct State* s, void** stack) { +static void init_state(Bytefile *bf, struct State* s, void** stack) { s->stack = stack; s->bf = bf; s->is_closure_call = false; @@ -30,7 +30,7 @@ static void init_state(bytefile *bf, struct State* s, void** stack) { s->fp = NULL; } -void construct_state(bytefile *bf, struct State* s, void** stack) { +void construct_state(Bytefile *bf, struct State* s, void** stack) { __init(); init_state(bf, s, stack); __gc_stack_bottom = (size_t)(s->stack + STACK_SIZE);