diff --git a/byterun/.gitignore b/byterun/.gitignore index a279bf827..187d7b353 100644 --- a/byterun/.gitignore +++ b/byterun/.gitignore @@ -1,4 +1,4 @@ -byterun.exe +*.exe byterun build/ diff --git a/byterun/dune b/byterun/dune index 27fd457f0..6329b01cc 100644 --- a/byterun/dune +++ b/byterun/dune @@ -5,7 +5,7 @@ (:main src/cli.cpp) (:parser src/parser.cpp) (:analyzer src/analyzer.cpp) - (:obj types.o parser.o interpreter.o) + (:obj types.o interpreter.o) (:runtime ../runtime/runtime.a)) (mode (promote (until-clean))) @@ -19,7 +19,7 @@ (:main src/cli.cpp) (:parser src/parser.cpp) (:analyzer src/analyzer.cpp) - (:obj old_types.o old_parser.o old_interpreter.o) + (:obj old_types.o old_interpreter.o) (:runtime ../runtime/runtime.a)) (mode (promote (until-clean))) @@ -37,17 +37,6 @@ (action (run gcc -Iinclude/ -DWITH_CHECK -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/ -DWITH_CHECK -c %{src} -o %{target}))) - (rule (target interpreter.o) (deps @@ -70,17 +59,6 @@ (action (run gcc -Iinclude/ -c %{src} -o %{target}))) -(rule - (target old_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 old_interpreter.o) (deps diff --git a/byterun/include/interpreter.h b/byterun/include/interpreter.h index 60d2e59f5..6c7e4a7f4 100644 --- a/byterun/include/interpreter.h +++ b/byterun/include/interpreter.h @@ -1,5 +1,5 @@ #pragma once -#include "parser.h" +#include "utils.h" void run(Bytefile *bf, int argc, char **argv); diff --git a/byterun/include/parser.h b/byterun/include/parser.h index 897e62ece..23ec0a768 100644 --- a/byterun/include/parser.h +++ b/byterun/include/parser.h @@ -19,8 +19,6 @@ DEF(CMD_BINOP_AND, &&) \ DEF(CMD_BINOP_OR, ||) -const char *read_cmd(char *ip); +const char *read_cmd(char *ip, const Bytefile *bf); -Bytefile *read_file(char *fname); - -// void dump_file(FILE *f, bytefile *bf); +// Bytefile *read_file(const char *fname); diff --git a/byterun/include/parser.hpp b/byterun/include/parser.hpp index db1c7d7d2..5b8f8b3b3 100644 --- a/byterun/include/parser.hpp +++ b/byterun/include/parser.hpp @@ -3,6 +3,7 @@ #include extern "C" { +#include "parser.h" #include "utils.h" } @@ -46,29 +47,12 @@ enum class Cmd : int8_t { 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)); -} - -std::pair parse_command(char **ip, const Bytefile &bf); -std::pair parse_command(char **ip, const Bytefile &bf, +std::pair parse_command(char **ip, const Bytefile *bf); +std::pair parse_command(char **ip, const Bytefile *bf, std::ostream &out); +std::pair parse_command_name(char **ip, const Bytefile *bf); + +bool is_command_name(char *ip, const Bytefile *bf, Cmd cmd); + void print_file(const Bytefile &bf, std::ostream &out); diff --git a/byterun/include/stack.h b/byterun/include/stack.h index e865a6d16..e04ecdb46 100644 --- a/byterun/include/stack.h +++ b/byterun/include/stack.h @@ -196,9 +196,11 @@ static inline void s_enter_f(char *rp, bool is_closure_call, auint args_sz, } static inline void s_exit_f() { +#ifndef WITH_CHECK if (s.fp == NULL) { s_failure(&s, "exit: no func"); } +#endif struct Frame frame = *s.fp; @@ -274,13 +276,15 @@ static inline void **var_by_category(enum VarCategory category, size_t id) { #endif var = f_args(s.fp) + (f_args_sz(s.fp) - id - 1); break; - case VAR_CLOSURE: // TODO: check that clojure vars are used only in clojures + case VAR_CLOSURE: +#ifndef WITH_CHECK if (s.fp == NULL) { s_failure(&s, "can't read closure parameter outside of function"); } if (s.fp->closure == NULL) { s_failure(&s, "can't read closure parameter not in closure"); } +#endif if (UNBOXED(s.fp->closure)) { s_failure(&s, "not boxed value expected in closure index"); } diff --git a/byterun/include/types.h b/byterun/include/types.h index 0ff7c63e2..9ef10daf7 100644 --- a/byterun/include/types.h +++ b/byterun/include/types.h @@ -69,12 +69,12 @@ 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) { - exec_failure(read_cmd(s->instr_ip), s->current_line, + exec_failure(read_cmd(s->instr_ip, s->bf), s->current_line, s->instr_ip - s->bf->code_ptr, msg); } static inline void ip_failure(char *ip, Bytefile *bf, const char *msg) { - exec_failure(read_cmd(ip), 0, ip - bf->code_ptr, msg); + exec_failure(read_cmd(ip, bf), 0, ip - bf->code_ptr, msg); } static inline void ip_safe_failure(char *ip, Bytefile *bf, const char *msg) { @@ -99,7 +99,7 @@ static inline enum VarCategory to_var_category(uint8_t category) { return (enum VarCategory)category; } -enum CMD { +enum CMD_TOPLVL { CMD_BINOP = 0, CMD_BASIC, CMD_LD, @@ -112,7 +112,7 @@ enum CMD { }; enum CMD_BINOPS { - CMD_BINOP_ADD = 1, // + + CMD_BINOP_ADD = 0, // + CMD_BINOP_SUB, // - CMD_BINOP_MULT, // * CMD_BINOP_DIV, // / diff --git a/byterun/include/utils.h b/byterun/include/utils.h index f8da4389d..60ee30956 100644 --- a/byterun/include/utils.h +++ b/byterun/include/utils.h @@ -26,28 +26,106 @@ static inline void exec_failure(const char *cmd, int line, aint offset, msg); } +// --- unsafe versions + +// access data + /* Gets a string from a string table by an index */ -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); - } - return &f->string_ptr[pos]; +static inline const char *get_string_unsafe(const Bytefile *bf, size_t pos) { + return &bf->string_ptr[pos]; +} + +/* Gets a name offset for a public symbol */ +static inline size_t get_public_name_offset_unsafe(const Bytefile *bf, + size_t i) { + return bf->public_ptr[i * 2]; } /* Gets a name for a public symbol */ -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, - f->public_symbols_number); - } - return get_string(f, f->public_ptr[i * 2]); +static inline const char *get_public_name_unsafe(const Bytefile *bf, size_t i) { + return get_string_unsafe(bf, get_public_name_offset_unsafe(bf, i)); } /* Gets an offset for a publie symbol */ -static inline size_t get_public_offset(const Bytefile *f, size_t i) { +static inline size_t get_public_offset_unsafe(const Bytefile *bf, size_t i) { + return bf->public_ptr[i * 2 + 1]; +} + +// read from ip + +static inline uint16_t ip_read_half_int_unsafe(char **ip) { + *ip += sizeof(uint16_t); + return *(uint16_t *)((*ip) - sizeof(uint16_t)); +} + +static inline int32_t ip_read_int_unsafe(char **ip) { + *ip += sizeof(int32_t); + return *(int32_t *)((*ip) - sizeof(int32_t)); +} + +static inline uint8_t ip_read_byte_unsafe(char **ip) { return *(*ip)++; } + +static inline const char *ip_read_string_unsafe(char **ip, const Bytefile *bf) { + return get_string_unsafe(bf, ip_read_int_unsafe(ip)); +} +// --- safe versions + +// access data + +/* Gets a string from a string table by an index */ +static inline const char *get_string_safe(const Bytefile *f, size_t pos) { + if (pos >= f->stringtab_size) { + failure("string pos is out of range: %zu >= %i\n", pos, f->stringtab_size); + } + return get_string_unsafe(f, pos); +} + +/* Gets a name offset for a public symbol */ +static inline size_t get_public_name_offset_safe(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]; + return get_public_name_offset_unsafe(f, i); +} + +/* Gets a name for a public symbol */ +static inline const char *get_public_name_safe(const Bytefile *f, size_t i) { + return get_string_safe(f, get_public_name_offset_safe(f, i)); +} + +/* Gets an offset for a publie symbol */ +static inline size_t get_public_offset_safe(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 get_public_offset_unsafe(f, i); +} + +// read from ip + +static inline uint16_t ip_read_half_int_safe(char **ip, const Bytefile *bf) { + if (*ip + sizeof(uint16_t) > bf->code_ptr + bf->code_size) { + failure("last command is invalid, int parameter can not be read\n"); + } + return ip_read_half_int_unsafe(ip); +} + +static inline int32_t ip_read_int_safe(char **ip, const Bytefile *bf) { + if (*ip + sizeof(int32_t) > bf->code_ptr + bf->code_size) { + failure("last command is invalid, int parameter can not be read\n"); + } + return ip_read_int_unsafe(ip); +} + +static inline uint8_t ip_read_byte_safe(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_read_byte_unsafe(ip); +} + +static inline const char *ip_read_string_safe(char **ip, const Bytefile *bf) { + return get_string_safe(bf, ip_read_int_safe(ip, bf)); } diff --git a/byterun/old-byterun.exe b/byterun/old-byterun.exe deleted file mode 100755 index 4ce4edcef..000000000 Binary files a/byterun/old-byterun.exe and /dev/null differ diff --git a/byterun/old_byterun.exe b/byterun/old_byterun.exe index 4ce4edcef..5dcb437a9 100755 Binary files a/byterun/old_byterun.exe and b/byterun/old_byterun.exe differ diff --git a/byterun/performance_check.sh b/byterun/performance_check.sh index 7175360f4..2305f9312 100755 --- a/byterun/performance_check.sh +++ b/byterun/performance_check.sh @@ -19,4 +19,11 @@ time ./old_byterun.exe -i Sort.bc > /dev/null echo "Byterun:" time ./byterun.exe -vi Sort.bc > /dev/null +echo "Byterun (verefication only):" +time ./byterun.exe -v Sort.bc > /dev/null + +echo "Byterun (run only):" +time ./byterun.exe -i Sort.bc > /dev/null + rm Sort.* +rm *.o diff --git a/byterun/src/analyzer.cpp b/byterun/src/analyzer.cpp index 202eb7879..87c2419c8 100644 --- a/byterun/src/analyzer.cpp +++ b/byterun/src/analyzer.cpp @@ -1,6 +1,7 @@ #include "analyzer.hpp" #include "parser.hpp" #include +#include extern "C" { #include "types.h" @@ -20,6 +21,7 @@ void analyze(Bytefile *bf) { const uint globals_count = bf->global_area_size; uint current_locals_count = 0; uint current_args_count = 0; + bool is_in_closure = false; uint16_t *current_begin_counter = nullptr; char *ip = bf->code_ptr; @@ -33,7 +35,6 @@ void analyze(Bytefile *bf) { visited[offset] = current_stack_depth; to_visit_jmp.push_back(offset); } else if (visited[offset] != current_stack_depth) { - // TODO: is this condition same for calls? ip_failure(saved_current_ip, bf, "different stack depth on same point is not allowed"); } @@ -61,8 +62,8 @@ void analyze(Bytefile *bf) { }; auto const check_correct_var = [&saved_current_ip, &bf, &globals_count, - ¤t_locals_count, - ¤t_args_count](uint8_t l, uint id) { + ¤t_locals_count, ¤t_args_count, + &is_in_closure](uint8_t l, uint id) { if (l > 3) { ip_failure(saved_current_ip, bf, "unexpected variable category"); } @@ -84,7 +85,11 @@ void analyze(Bytefile *bf) { } break; case VAR_CLOSURE: - // NOTE: impossible to properly check there (?) + if (!is_in_closure) { + ip_failure(saved_current_ip, bf, + "can't access closure vars outside of closure"); + } + // NOTE: impossible to properly check bounds there break; } }; @@ -92,7 +97,7 @@ void analyze(Bytefile *bf) { // add publics to_visit_func.reserve(bf->public_symbols_number); for (size_t i = 0; i < bf->public_symbols_number; ++i) { - func_control_push(get_public_offset(bf, i)); + func_control_push(get_public_offset_safe(bf, i)); } if (to_visit_func.size() == 0) { @@ -129,9 +134,9 @@ void analyze(Bytefile *bf) { saved_current_ip = current_ip; #ifdef DEBUG_VERSION - const auto [cmd, l] = parse_command(&ip, *bf, std::cout); + const auto [cmd, l] = parse_command(&ip, bf, std::cout); #else - const auto [cmd, l] = parse_command(&ip, *bf); + const auto [cmd, l] = parse_command(&ip, bf); #endif if (current_begin_counter == nullptr && cmd != Cmd::BEGIN && @@ -167,8 +172,8 @@ void analyze(Bytefile *bf) { ++current_stack_depth; break; case Cmd::SEXP: - ip_read_string(¤t_ip, *bf); - current_stack_depth -= ip_read_int(¤t_ip, *bf); + ip_read_string_unsafe(¤t_ip, bf); + current_stack_depth -= ip_read_int_unsafe(¤t_ip); if (current_stack_depth < 0) { ip_failure(saved_current_ip, bf, "not enough elements in stack"); } @@ -215,15 +220,15 @@ void analyze(Bytefile *bf) { ++current_stack_depth; break; case Cmd::LD: - check_correct_var(l, ip_read_int(¤t_ip, *bf)); + check_correct_var(l, ip_read_int_unsafe(¤t_ip)); ++current_stack_depth; break; case Cmd::LDA: - check_correct_var(l, ip_read_int(¤t_ip, *bf)); + check_correct_var(l, ip_read_int_unsafe(¤t_ip)); ++current_stack_depth; break; case Cmd::ST: - check_correct_var(l, ip_read_int(¤t_ip, *bf)); + check_correct_var(l, ip_read_int_unsafe(¤t_ip)); if (current_stack_depth < 1) { ip_failure(saved_current_ip, bf, "not enough elements in stack"); } @@ -237,47 +242,60 @@ void analyze(Bytefile *bf) { if (current_begin_counter != nullptr) { ip_failure(saved_current_ip, bf, "unexpected function beginning"); } - current_args_count = ip_read_int(¤t_ip, *bf); + current_args_count = ip_read_int_unsafe(¤t_ip); current_begin_counter = (uint16_t *)(current_ip + sizeof(uint16_t)); - current_locals_count = ip_read_int(¤t_ip, *bf); - // TODO: check uint16_t max ?? + current_locals_count = ip_read_int_unsafe(¤t_ip); + if (current_locals_count >= std::numeric_limits::max()) { + ip_failure(saved_current_ip, bf, "too many locals in functions"); + } (*(uint16_t *)(current_ip - sizeof(uint16_t))) = current_locals_count; *current_begin_counter = 0; + is_in_closure = (cmd == Cmd::CBEGIN); break; case Cmd::CLOSURE: { - ip_read_int(&ip, *bf); // offset - size_t args_count = ip_read_int(¤t_ip, *bf); // args count + uint closure_offset = ip_read_int_unsafe(¤t_ip); // closure offset + size_t args_count = ip_read_int_unsafe(¤t_ip); // args count extra_stack_during_opr = args_count; for (aint i = 0; i < args_count; i++) { - aint arg_type = ip_read_byte(¤t_ip, *bf); - aint arg_id = ip_read_int(¤t_ip, *bf); + aint arg_type = ip_read_byte_unsafe(¤t_ip); + aint arg_id = ip_read_int_unsafe(¤t_ip); check_correct_var(arg_type, arg_id); } ++current_stack_depth; + + if (closure_offset >= bf->code_size) { + ip_failure(saved_current_ip, bf, "jump/call out of file"); + } + + if (!is_command_name(bf->code_ptr + closure_offset, bf, Cmd::CBEGIN)) { + ip_failure(saved_current_ip, bf, "closure should point to cbegin"); + } } break; case Cmd::CALLC: { - uint args_count = ip_read_int(¤t_ip, *bf); + uint args_count = ip_read_int_unsafe(¤t_ip); current_stack_depth -= args_count + 1; // + closure itself if (current_stack_depth < 0) { ip_failure(saved_current_ip, bf, "not enough elements in stack"); } ++current_stack_depth; - // NOTE: can't check args == cbegin args (?) + // NOTE: can't check args == cbegin args } break; case Cmd::CALL: { - uint call_offset = ip_read_int(¤t_ip, *bf); // call offset - uint args_count = ip_read_int(¤t_ip, *bf); + uint call_offset = ip_read_int_unsafe(¤t_ip); // call offset + uint args_count = ip_read_int_unsafe(¤t_ip); current_stack_depth -= args_count; if (current_stack_depth < 0) { ip_failure(saved_current_ip, bf, "not enough elements in stack"); } ++current_stack_depth; - // TODO: unify with next loop if (call_offset >= bf->code_size) { ip_failure(saved_current_ip, bf, "jump/call out of file"); } + if (!is_command_name(bf->code_ptr + call_offset, bf, Cmd::BEGIN)) { + ip_failure(saved_current_ip, bf, "call should point to begin"); + } if (args_count != *(uint *)(bf->code_ptr + call_offset + 1)) { ip_failure(saved_current_ip, bf, "wrong call argument count"); } @@ -318,7 +336,7 @@ void analyze(Bytefile *bf) { } break; case Cmd::Barray: - current_stack_depth -= ip_read_int(¤t_ip, *bf); // elem count + current_stack_depth -= ip_read_int_unsafe(¤t_ip); // elem count if (current_stack_depth < 0) { ip_failure(saved_current_ip, bf, "not enough elements in stack"); } @@ -362,7 +380,7 @@ void analyze(Bytefile *bf) { case Cmd::JMP: { bool is_call = (cmd == Cmd::CLOSURE || cmd == Cmd::CALL); - uint jmp_p = ip_read_int(¤t_ip, *bf); + uint jmp_p = ip_read_int_unsafe(¤t_ip); if (jmp_p >= bf->code_size) { // NOTE: maybe also should check that > begin (?) ip_failure(saved_current_ip, bf, "jump/call out of file"); diff --git a/byterun/src/cli.cpp b/byterun/src/cli.cpp index 2f625becf..638562165 100644 --- a/byterun/src/cli.cpp +++ b/byterun/src/cli.cpp @@ -18,14 +18,18 @@ int main(int argc, char **argv) { bool do_verification = false; bool do_interpretation = false; bool do_print = false; - if (strcmp(argv[1], "-vi") == 0) { - do_verification = true; + if (strcmp(argv[1], "-i") == 0) { do_interpretation = true; - } else if (strcmp(argv[1], "-i") == 0) { + } +#ifdef WITH_CHECK + else if (strcmp(argv[1], "-vi") == 0) { + do_verification = true; do_interpretation = true; } else if (strcmp(argv[1], "-v") == 0) { do_verification = true; - } else if (strcmp(argv[1], "-p") == 0) { + } +#endif + else if (strcmp(argv[1], "-p") == 0) { do_print = true; } else { failure("wrong execution option (acceptable options - '-i', '-v', '-vi')"); @@ -36,20 +40,21 @@ int main(int argc, char **argv) { } Bytefile *f = read_file(argv[2]); - // #ifdef DEBUG_VERSION - // dump_file (stdout, f); - // #endif +#ifdef DEBUG_VERSION + dump_file(stdout, f); +#endif if (do_print) { print_file(*f, std::cout); } if (do_verification) { analyze(f); } - if (do_interpretation) { // TODO: switch between enabled/disabled verification + if (do_interpretation) { run(f, argc - 2, argv + 2); } - free(f->global_ptr); + // // NOTE: not used for now + // // free(f->global_ptr); free(f); return 0; diff --git a/byterun/src/interpreter.c b/byterun/src/interpreter.c index 57ed63f3b..3dc5475d6 100644 --- a/byterun/src/interpreter.c +++ b/byterun/src/interpreter.c @@ -8,6 +8,9 @@ #include "types.h" #include "utils.h" +void *__start_custom_data; +void *__stop_custom_data; + #define ASSERT_UNBOXED(memo, x) \ do \ if (!UNBOXED(x)) \ @@ -17,36 +20,35 @@ struct State s; static inline uint16_t ip_read_half_int(char **ip) { -#ifndef WITH_CHECK - if (*ip + sizeof(uint16_t) > s.bf->code_ptr + s.bf->code_size) { - failure("last command is invalid, int parameter can not be read\n"); - } +#ifdef WITH_CHECK + return ip_read_half_int_unsafe(ip); +#else + return ip_read_half_int_safe(ip, s.bf); #endif - *ip += sizeof(uint16_t); - return *(uint16_t *)((*ip) - sizeof(uint16_t)); } static inline int ip_read_int(char **ip) { -#ifndef WITH_CHECK - if (*ip + sizeof(int) > s.bf->code_ptr + s.bf->code_size) { - failure("last command is invalid, int parameter can not be read\n"); - } +#ifdef WITH_CHECK + return ip_read_int_unsafe(ip); +#else + return ip_read_int_safe(ip, s.bf); #endif - *ip += sizeof(int); - return *(int *)((*ip) - sizeof(int)); } static inline uint8_t ip_read_byte(char **ip) { -#ifndef WITH_CHECK - if (*ip + sizeof(char) > s.bf->code_ptr + s.bf->code_size) { - failure("last command is invalid, byte parameter can not be read\n"); - } +#ifdef WITH_CHECK + return ip_read_byte_unsafe(ip); +#else + return ip_read_byte_safe(ip, s.bf); #endif - return *(*ip)++; } static inline const char *ip_read_string(char **ip) { - return get_string(s.bf, ip_read_int(ip)); +#ifdef WITH_CHECK + return get_string_unsafe(s.bf, ip_read_int(ip)); +#else + return get_string_safe(s.bf, ip_read_int(ip)); +#endif } const size_t BUFFER_SIZE = 1000; @@ -107,7 +109,7 @@ void run(Bytefile *bf, int argc, char **argv) { if (l == CMD_BINOP_SUB) { s_push_i(Ls__Infix_45(fst, snd)); } else { - switch (l) { + switch (l - 1) { #define BINOP_OPR(val, op) \ case val: \ ASSERT_UNBOXED("captured op:1", fst); \ @@ -305,7 +307,6 @@ void run(Bytefile *bf, int argc, char **argv) { s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz, locals_sz); #ifndef WITH_CHECK - // TODO if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { s_failure(&s, "stack owerflow"); } @@ -329,7 +330,6 @@ void run(Bytefile *bf, int argc, char **argv) { #endif s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz, locals_sz); - // TODO: add ifdef #ifdef WITH_CHECK if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { s_failure(&s, "stack owerflow"); diff --git a/byterun/src/parser.c b/byterun/src/parser.c deleted file mode 100644 index 9e43cd03e..000000000 --- a/byterun/src/parser.c +++ /dev/null @@ -1,388 +0,0 @@ -/* Lama SM Bytecode interpreter */ - -#include -#include -#include - -#include "../../runtime/runtime.h" - -#include "types.h" -#include "utils.h" -#include "parser.h" - -void *__start_custom_data; -void *__stop_custom_data; - -/* Reads a binary bytecode file by name and unpacks it */ -Bytefile* read_file (char *fname) { - FILE *f = fopen (fname, "rb"); - Bytefile *file; - - if (f == 0) { - failure ("%s\n", strerror (errno)); - } - - if (fseek (f, 0, SEEK_END) == -1) { - failure ("%s\n", 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\n"); - } - - rewind (f); - - if (size != fread (&file->stringtab_size, 1, size, f)) { - failure ("%s\n", 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\n"); - } - file->string_ptr = &file->buffer[public_symbols_size]; - if (file->string_ptr + file->stringtab_size > file_end) { - failure ("strings table is out of the file size\n"); - } - if (file->stringtab_size > 0 && file->string_ptr[file->stringtab_size - 1] != 0) { - failure ("strings table is not zero-ended\n"); - } - if (file->code_size < 0 || public_symbols_size < 0 || file->stringtab_size < 0) { - failure ("file zones sizes should be >= 0\n"); - } - - 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; -} - -const char *read_cmd(char *ip) { - uint8_t x = (*ip++), h = (x & 0xF0) >> 4, l = x & 0x0F; - - switch (h) { - case CMD_EXIT: - return "END"; - case CMD_BINOP: - return "BINOP"; - case CMD_BASIC: - switch (l) { - case CMD_BASIC_CONST: - return "CONST"; - case CMD_BASIC_STRING: - return "STRING"; - case CMD_BASIC_SEXP: - return "SEXP "; - case CMD_BASIC_STI: - return "STI"; - case CMD_BASIC_STA: - return "STA"; - case CMD_BASIC_JMP: - return "JMP"; - case CMD_BASIC_END: - return "END"; - case CMD_BASIC_RET: - return "RET"; - case CMD_BASIC_DROP: - return "DROP"; - case CMD_BASIC_DUP: - return "DUP"; - case CMD_BASIC_SWAP: - return "SWAP"; - case CMD_BASIC_ELEM: - return "ELEM"; - default: - return "_UNDEF_CMD1_"; - } - break; - - case CMD_LD: - return "LD"; - case CMD_LDA: - return "LDA"; - case CMD_ST: - return "ST"; - case CMD_CTRL: - switch (l) { - case CMD_CTRL_CJMPz: - return "CJMPz"; - case CMD_CTRL_CJMPnz: - return "CJMPnz"; - case CMD_CTRL_BEGIN: - return "BEGIN"; - case CMD_CTRL_CBEGIN: - return "CBEGIN"; - case CMD_CTRL_CLOSURE: - return "CLOSURE"; - case CMD_CTRL_CALLC: - return "CALLC"; - case CMD_CTRL_CALL: - return "CALL"; - case CMD_CTRL_TAG: - return "TAG"; - case CMD_CTRL_ARRAY: - return "ARRAY"; - case CMD_CTRL_FAIL: - return "FAIL"; - case CMD_CTRL_LINE: - return "LINE"; - default: - return "_UNDEF_CMD5_"; - } - case CMD_PATT: - return "PATT"; - case CMD_BUILTIN: { - switch (l) { - case CMD_BUILTIN_Lread: - return "CALL\tLread"; - case CMD_BUILTIN_Lwrite: - return "CALL\tLwrite"; - case CMD_BUILTIN_Llength: - return "CALL\tLlength"; - case CMD_BUILTIN_Lstring: - return "CALL\tLstring"; - case CMD_BUILTIN_Barray: - return "CALL\tBarray\t%d"; - default: - return "_UNDEF_CALL_"; - } - } - default: - return "_UNDEF_CODE_"; - } -} - -// /* Disassembles the bytecode pool */ -// void disassemble (FILE *f, bytefile *bf) { - -// # define INT (ip += sizeof (int), *(int*)(ip - sizeof (int))) -// # define BYTE *ip++ -// # define STRING get_string (bf, INT) -// # define FAIL failure ("ERROR: invalid opcode %d-%d\n", h, l) - -// char *ip = bf->code_ptr; -// char *ops [] = {"+", "-", "*", "/", "%", "<", "<=", ">", ">=", "==", "!=", "&&", "!!"}; -// char *pats[] = {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"}; -// char *lds [] = {"LD", "LDA", "ST"}; -// do { -// uint8_t x = BYTE, -// h = (x & 0xF0) >> 4, -// l = x & 0x0F; - -// fprintf (f, "0x%.8x:\t", ip-bf->code_ptr-1); - -// switch (h) { -// case 15: -// goto stop; - -// /* BINOP */ -// case 0: -// fprintf (f, "BINOP\t%s", ops[l-1]); -// break; - -// case 1: -// switch (l) { -// case 0: -// fprintf (f, "CONST\t%d", INT); -// break; - -// case 1: -// fprintf (f, "STRING\t%s", STRING); -// break; - -// case 2: -// fprintf (f, "SEXP\t%s ", STRING); -// fprintf (f, "%d", INT); -// break; - -// case 3: -// fprintf (f, "STI"); -// break; - -// case 4: -// fprintf (f, "STA"); -// break; - -// case 5: -// fprintf (f, "JMP\t0x%.8x", INT); -// break; - -// case 6: -// fprintf (f, "END"); -// break; - -// case 7: -// fprintf (f, "RET"); -// break; - -// case 8: -// fprintf (f, "DROP"); -// break; - -// case 9: -// fprintf (f, "DUP"); -// break; - -// case 10: -// fprintf (f, "SWAP"); -// break; - -// case 11: -// fprintf (f, "ELEM"); -// break; - -// default: -// FAIL; -// } -// break; - -// case 2: -// case 3: -// case 4: -// fprintf (f, "%s\t", lds[h-2]); -// switch (l) { -// case 0: fprintf (f, "G(%d)", INT); break; -// case 1: fprintf (f, "L(%d)", INT); break; -// case 2: fprintf (f, "A(%d)", INT); break; -// case 3: fprintf (f, "C(%d)", INT); break; -// default: FAIL; -// } -// break; - -// case 5: -// switch (l) { -// case 0: -// fprintf (f, "CJMPz\t0x%.8x", INT); -// break; - -// case 1: -// fprintf (f, "CJMPnz\t0x%.8x", INT); -// break; - -// case 2: -// fprintf (f, "BEGIN\t%d ", INT); -// fprintf (f, "%d", INT); -// break; - -// case 3: -// fprintf (f, "CBEGIN\t%d ", INT); -// fprintf (f, "%d", INT); -// break; - -// case 4: -// fprintf (f, "CLOSURE\t0x%.8x", INT); -// {int n = INT; -// for (int i = 0; i\n"); -// } - -// /* Dumps the contents of the file */ -// void dump_file (FILE *f, bytefile *bf) { -// size_t i; - -// fprintf (f, "String table size : %d\n", bf->stringtab_size); -// fprintf (f, "Global area size : %d\n", bf->global_area_size); -// fprintf (f, "Number of public symbols: %d\n", bf->public_symbols_number); -// fprintf (f, "Public symbols :\n"); - -// for (i=0; i < bf->public_symbols_number; i++) -// fprintf (f, " 0x%.8x: %s\n", get_public_offset (bf, i), get_public_name (bf, i)); - -// fprintf (f, "Code:\n"); -// disassemble (f, bf); -// } - diff --git a/byterun/src/parser.cpp b/byterun/src/parser.cpp index 949084ebf..a2795a606 100644 --- a/byterun/src/parser.cpp +++ b/byterun/src/parser.cpp @@ -8,88 +8,35 @@ #include "parser.hpp" extern "C" { +#include "types.h" #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, ||) +// #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, ||) + +// extern "C" { + +// void *__start_custom_data; +// void *__stop_custom_data; // Reads a binary bytecode file by name and unpacks it Bytefile *read_file(const char *fname) { @@ -97,11 +44,11 @@ Bytefile *read_file(const char *fname) { Bytefile *file; if (f == 0) { - failure(strerror(errno)); + failure("%s\n", strerror(errno)); } if (fseek(f, 0, SEEK_END) == -1) { - failure(strerror(errno)); + failure("%s\n", strerror(errno)); } long size = ftell(f); @@ -113,48 +60,78 @@ Bytefile *read_file(const char *fname) { char *file_end = file_begin + size; if (file == 0) { - failure("unable to allocate memory to store file data"); + failure("unable to allocate memory to store file data\n"); } rewind(f); if (size != fread(&file->stringtab_size, 1, size, f)) { - failure(strerror(errno)); + failure("%s\n", 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"); + failure("public symbols are out of the file size\n"); } if (file->string_ptr + file->stringtab_size > file_end) { - failure("strings table is out of the file size"); + failure("strings table is out of the file size\n"); } + // if (file->stringtab_size > 0 && + // file->string_ptr[file->stringtab_size - 1] != 0) { + // failure("strings table is not zero-ended\n"); + // } if (file->code_size < 0 || public_symbols_size < 0 || file->stringtab_size < 0) { - failure("file zones sizes should be >= 0"); + failure("file zones sizes should be >= 0\n"); } 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)); + // NOTE: not used for now + // file->global_ptr = (int *)calloc(file->global_area_size, sizeof(int)); + file->global_ptr = nullptr; file->code_size = size - public_symbols_size - file->stringtab_size; return file; } -std::string command_name(Cmd cmd, int8_t l) { +const char *command_name(Cmd cmd, int8_t l) { static const char *const ops[] = { -#define OP_TO_STR(id, op) #op, +#define OP_TO_STR(id, op) "BINOP:" #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"}; + static const char *const pats[] = { + "PATT:=str", "PATT:#string", "PATT:#array", "PATT:#sexp", + "PATT:#ref", "PATT:#val", "PATT:#fun"}; + +#define FORALL_LDTS(DEF) \ + DEF(G) \ + DEF(L) \ + DEF(A) \ + DEF(C) + + static const char *const ld_ldts[] = { +#define LDT_TO_STR(type) "LD:" #type, + FORALL_LDTS(LDT_TO_STR) +#undef LDT_TO_STR + }; + static const char *const lda_ldts[] = { +#define LDT_TO_STR(type) "LDA:" #type, + FORALL_LDTS(LDT_TO_STR) +#undef LDT_TO_STR + }; + static const char *const st_ldts[] = { +#define LDT_TO_STR(type) "ST:" #type, + FORALL_LDTS(LDT_TO_STR) +#undef LDT_TO_STR + }; + +#undef FORALL_LDTS switch (cmd) { case Cmd::EXIT: @@ -163,7 +140,7 @@ std::string command_name(Cmd cmd, int8_t l) { if (l - 1 >= sizeof(ops) / sizeof(char *)) { return "_UNDEF_BINOP_"; } - return "BINOP:" + std::string{ops[l - 1]}; + return ops[l - 1]; case Cmd::CONST: return "CONST"; case Cmd::STRING: @@ -189,20 +166,20 @@ std::string command_name(Cmd cmd, int8_t l) { case Cmd::ELEM: return "ELEM"; case Cmd::LD: - if (l >= sizeof(ldts) / sizeof(char *)) { + if (l >= sizeof(ld_ldts) / sizeof(char *)) { return "_UNDEF_LD_"; } - return "LD:" + std::string{ldts[l]}; + return ld_ldts[l]; case Cmd::LDA: - if (l >= sizeof(ldts) / sizeof(char *)) { + if (l >= sizeof(lda_ldts) / sizeof(char *)) { return "_UNDEF_LDA_"; } - return "LDA:" + std::string{ldts[l]}; + return lda_ldts[l]; case Cmd::ST: - if (l >= sizeof(ldts) / sizeof(char *)) { + if (l >= sizeof(st_ldts) / sizeof(char *)) { return "_UNDEF_ST_"; } - return "ST:" + std::string{ldts[l]}; + return st_ldts[l]; case Cmd::CJMPz: return "CJMPz"; case Cmd::CJMPnz: @@ -229,7 +206,7 @@ std::string command_name(Cmd cmd, int8_t l) { if (l >= sizeof(pats) / sizeof(char *)) { return "_UNDEF_PATT_"; } - return "PATT:" + std::string{pats[l]}; + return pats[l]; case Cmd::Lread: return "CALL\tLread"; case Cmd::Lwrite: @@ -246,6 +223,7 @@ std::string command_name(Cmd cmd, int8_t l) { exit(1); } +// } // extern "C" template static inline const T &print_val(std::ostream &out, const T &val) { @@ -265,7 +243,7 @@ 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); + uint val = ip_read_int_safe(ip, &bf); if constexpr (use_out) { out << val; } @@ -276,9 +254,9 @@ 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); + uint val = ip_read_int_safe(ip, &bf); if constexpr (use_out) { - out << val; // TODO + out << val; } return val; } @@ -287,7 +265,7 @@ 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); + const char *val = ip_read_string_safe(ip, &bf); if constexpr (use_out) { out << val; } @@ -320,11 +298,20 @@ static inline void read_print_cmd_seq(Cmd cmd, uint8_t l, char **ip, read_print_seq(ip, bf, out); } -template +template +static inline void read_print_cmd_seq_opt(Cmd cmd, uint8_t l, char **ip, + const Bytefile &bf, + std::ostream &out) { + if constexpr (do_read) { + read_print_cmd_seq(cmd, l, ip, bf, out); + } +} + +template std::pair parse_command_impl(char **ip, const Bytefile &bf, std::ostream &out) { static const char *const ops[] = { -#define OP_TO_STR(id, op) "op", +#define OP_TO_STR(id, op) #op, FORALL_BINOP(OP_TO_STR) #undef OP_TO_STR }; @@ -346,7 +333,7 @@ std::pair parse_command_impl(char **ip, const Bytefile &bf, Cmd cmd = Cmd::_UNDEF_; char *instr_ip = *ip; - uint8_t x = ip_read_byte(ip, bf), h = (x & 0xF0) >> 4, l = x & 0x0F; + uint8_t x = ip_read_byte_safe(ip, &bf), h = (x & 0xF0) >> 4, l = x & 0x0F; #ifdef DEBUG_VERSION printf("0x%.8lx ", *ip - bf.code_ptr - 1); @@ -356,68 +343,72 @@ std::pair parse_command_impl(char **ip, const Bytefile &bf, switch (h) { case CMD_EXIT: cmd = Cmd::EXIT; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(cmd, l, ip, bf, + out); break; case CMD_BASIC_STRING: // STRING %s cmd = Cmd::STRING; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt( + 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); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(cmd, l, ip, + bf, out); break; case CMD_BASIC_END: // END cmd = Cmd::END; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; case CMD_BASIC_RET: // RET cmd = Cmd::RET; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; case CMD_BASIC_DROP: // DROP cmd = Cmd::DROP; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; case CMD_BASIC_DUP: // DUP cmd = Cmd::DUP; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; case CMD_BASIC_SWAP: // SWAP cmd = Cmd::SWAP; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; case CMD_BASIC_ELEM: // ELEM cmd = Cmd::ELEM; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; default: @@ -430,89 +421,104 @@ std::pair parse_command_impl(char **ip, const Bytefile &bf, if (l > sizeof(ldts) / sizeof(char *)) { failure("wrong ld argument type"); } - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt( + 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); + read_print_cmd_seq_opt( + 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); + read_print_cmd_seq_opt(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"); + if constexpr (do_read_args) { + 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_safe(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); } - 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); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt( + 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); + read_print_cmd_seq_opt( + 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); + read_print_cmd_seq_opt( + cmd, l, ip, bf, out); break; case CMD_CTRL_ARRAY: // ARRAY %d cmd = Cmd::ARRAY; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, + out); break; case CMD_CTRL_LINE: // LINE %d cmd = Cmd::LINE; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, + out); break; default: @@ -526,31 +532,32 @@ std::pair parse_command_impl(char **ip, const Bytefile &bf, failure("invalid opcode"); } cmd = Cmd::PATT; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; case CMD_BUILTIN_Lwrite: // CALL Lwrite cmd = Cmd::Lwrite; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; case CMD_BUILTIN_Llength: // CALL Llength cmd = Cmd::Llength; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(cmd, l, ip, bf, out); break; case CMD_BUILTIN_Lstring: // CALL Lstring cmd = Cmd::Lstring; - read_print_cmd_seq(cmd, l, ip, bf, out); + read_print_cmd_seq_opt(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); + read_print_cmd_seq_opt(cmd, l, ip, bf, + out); break; default: @@ -567,13 +574,21 @@ std::pair parse_command_impl(char **ip, const Bytefile &bf, return {cmd, l}; } -std::pair parse_command(char **ip, const Bytefile &bf) { - return parse_command_impl(ip, bf, std::clog); +std::pair parse_command(char **ip, const Bytefile *bf) { + return parse_command_impl(ip, *bf, std::clog); } -std::pair parse_command(char **ip, const Bytefile &bf, +std::pair parse_command(char **ip, const Bytefile *bf, std::ostream &out) { - return parse_command_impl(ip, bf, out); + return parse_command_impl(ip, *bf, out); +} + +std::pair parse_command_name(char **ip, const Bytefile *bf) { + return parse_command_impl(ip, *bf, std::clog); +} + +bool is_command_name(char *ip, const Bytefile *bf, Cmd cmd) { + return parse_command_name(&ip, bf).first == cmd; } void print_file(const Bytefile &bf, std::ostream &out) { @@ -582,7 +597,7 @@ void print_file(const Bytefile &bf, std::ostream &out) { while (true) { out << std::setfill('0') << std::setw(8) << std::hex << ip - bf.code_ptr << ": "; - const auto [cmd, l] = parse_command(&ip, bf, out); + const auto [cmd, l] = parse_command(&ip, &bf, out); out << '\n'; if (cmd == Cmd::EXIT) { @@ -590,3 +605,11 @@ void print_file(const Bytefile &bf, std::ostream &out) { } } } + +extern "C" { +const char *read_cmd(char *ip, const Bytefile *bf) { + const auto [cmd, l] = parse_command_impl(&ip, *bf, std::clog); + return command_name(cmd, l); + return ""; +} +} // extern "C"