fixes, cleanup, some copies removed

This commit is contained in:
ProgramSnail 2024-12-15 16:19:54 +03:00
parent 2589f6166f
commit d90a8cf89f
16 changed files with 373 additions and 666 deletions

2
byterun/.gitignore vendored
View file

@ -1,4 +1,4 @@
byterun.exe *.exe
byterun byterun
build/ build/

View file

@ -5,7 +5,7 @@
(:main src/cli.cpp) (:main src/cli.cpp)
(:parser src/parser.cpp) (:parser src/parser.cpp)
(:analyzer src/analyzer.cpp) (:analyzer src/analyzer.cpp)
(:obj types.o parser.o interpreter.o) (:obj types.o interpreter.o)
(:runtime ../runtime/runtime.a)) (:runtime ../runtime/runtime.a))
(mode (mode
(promote (until-clean))) (promote (until-clean)))
@ -19,7 +19,7 @@
(:main src/cli.cpp) (:main src/cli.cpp)
(:parser src/parser.cpp) (:parser src/parser.cpp)
(:analyzer src/analyzer.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)) (:runtime ../runtime/runtime.a))
(mode (mode
(promote (until-clean))) (promote (until-clean)))
@ -37,17 +37,6 @@
(action (action
(run gcc -Iinclude/ -DWITH_CHECK -c %{src} -o %{target}))) (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 (rule
(target interpreter.o) (target interpreter.o)
(deps (deps
@ -70,17 +59,6 @@
(action (action
(run gcc -Iinclude/ -c %{src} -o %{target}))) (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 (rule
(target old_interpreter.o) (target old_interpreter.o)
(deps (deps

View file

@ -1,5 +1,5 @@
#pragma once #pragma once
#include "parser.h" #include "utils.h"
void run(Bytefile *bf, int argc, char **argv); void run(Bytefile *bf, int argc, char **argv);

View file

@ -19,8 +19,6 @@
DEF(CMD_BINOP_AND, &&) \ DEF(CMD_BINOP_AND, &&) \
DEF(CMD_BINOP_OR, ||) DEF(CMD_BINOP_OR, ||)
const char *read_cmd(char *ip); const char *read_cmd(char *ip, const Bytefile *bf);
Bytefile *read_file(char *fname); // Bytefile *read_file(const char *fname);
// void dump_file(FILE *f, bytefile *bf);

View file

@ -3,6 +3,7 @@
#include <ostream> #include <ostream>
extern "C" { extern "C" {
#include "parser.h"
#include "utils.h" #include "utils.h"
} }
@ -46,29 +47,12 @@ enum class Cmd : int8_t {
Bytefile *read_file(const char *fname); Bytefile *read_file(const char *fname);
static inline int ip_read_int(char **ip, const Bytefile &bf) { std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile *bf);
if (*ip + sizeof(int) > bf.code_ptr + bf.code_size) { std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile *bf,
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<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf);
std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf,
std::ostream &out); std::ostream &out);
std::pair<Cmd, uint8_t> 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); void print_file(const Bytefile &bf, std::ostream &out);

View file

@ -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() { static inline void s_exit_f() {
#ifndef WITH_CHECK
if (s.fp == NULL) { if (s.fp == NULL) {
s_failure(&s, "exit: no func"); s_failure(&s, "exit: no func");
} }
#endif
struct Frame frame = *s.fp; struct Frame frame = *s.fp;
@ -274,13 +276,15 @@ static inline void **var_by_category(enum VarCategory category, size_t id) {
#endif #endif
var = f_args(s.fp) + (f_args_sz(s.fp) - id - 1); var = f_args(s.fp) + (f_args_sz(s.fp) - id - 1);
break; break;
case VAR_CLOSURE: // TODO: check that clojure vars are used only in clojures case VAR_CLOSURE:
#ifndef WITH_CHECK
if (s.fp == NULL) { if (s.fp == NULL) {
s_failure(&s, "can't read closure parameter outside of function"); s_failure(&s, "can't read closure parameter outside of function");
} }
if (s.fp->closure == NULL) { if (s.fp->closure == NULL) {
s_failure(&s, "can't read closure parameter not in closure"); s_failure(&s, "can't read closure parameter not in closure");
} }
#endif
if (UNBOXED(s.fp->closure)) { if (UNBOXED(s.fp->closure)) {
s_failure(&s, "not boxed value expected in closure index"); s_failure(&s, "not boxed value expected in closure index");
} }

View file

@ -69,12 +69,12 @@ void construct_state(Bytefile *bf, struct State *s, void **stack);
void cleanup_state(struct State *state); void cleanup_state(struct State *state);
static inline void s_failure(struct State *s, const char *msg) { 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); s->instr_ip - s->bf->code_ptr, msg);
} }
static inline void ip_failure(char *ip, Bytefile *bf, const char *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) { 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; return (enum VarCategory)category;
} }
enum CMD { enum CMD_TOPLVL {
CMD_BINOP = 0, CMD_BINOP = 0,
CMD_BASIC, CMD_BASIC,
CMD_LD, CMD_LD,
@ -112,7 +112,7 @@ enum CMD {
}; };
enum CMD_BINOPS { enum CMD_BINOPS {
CMD_BINOP_ADD = 1, // + CMD_BINOP_ADD = 0, // +
CMD_BINOP_SUB, // - CMD_BINOP_SUB, // -
CMD_BINOP_MULT, // * CMD_BINOP_MULT, // *
CMD_BINOP_DIV, // / CMD_BINOP_DIV, // /

View file

@ -26,28 +26,106 @@ static inline void exec_failure(const char *cmd, int line, aint offset,
msg); msg);
} }
// --- unsafe versions
// access data
/* Gets a string from a string table by an index */ /* 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_unsafe(const Bytefile *bf, size_t pos) {
if (pos >= f->stringtab_size) { return &bf->string_ptr[pos];
failure("strinpg pos is out of range: %zu >= %i\n", pos, f->stringtab_size); }
}
return &f->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 */ /* 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_unsafe(const Bytefile *bf, size_t i) {
if (i >= f->public_symbols_number) { return get_string_unsafe(bf, get_public_name_offset_unsafe(bf, i));
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 */ /* 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) { if (i >= f->public_symbols_number) {
failure("public number is out of range: %zu >= %i\n", i, failure("public number is out of range: %zu >= %i\n", i,
f->public_symbols_number); 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));
} }

Binary file not shown.

Binary file not shown.

View file

@ -19,4 +19,11 @@ time ./old_byterun.exe -i Sort.bc > /dev/null
echo "Byterun:" echo "Byterun:"
time ./byterun.exe -vi Sort.bc > /dev/null 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 Sort.*
rm *.o

View file

@ -1,6 +1,7 @@
#include "analyzer.hpp" #include "analyzer.hpp"
#include "parser.hpp" #include "parser.hpp"
#include <iostream> #include <iostream>
#include <limits>
extern "C" { extern "C" {
#include "types.h" #include "types.h"
@ -20,6 +21,7 @@ void analyze(Bytefile *bf) {
const uint globals_count = bf->global_area_size; const uint globals_count = bf->global_area_size;
uint current_locals_count = 0; uint current_locals_count = 0;
uint current_args_count = 0; uint current_args_count = 0;
bool is_in_closure = false;
uint16_t *current_begin_counter = nullptr; uint16_t *current_begin_counter = nullptr;
char *ip = bf->code_ptr; char *ip = bf->code_ptr;
@ -33,7 +35,6 @@ void analyze(Bytefile *bf) {
visited[offset] = current_stack_depth; visited[offset] = current_stack_depth;
to_visit_jmp.push_back(offset); to_visit_jmp.push_back(offset);
} else if (visited[offset] != current_stack_depth) { } else if (visited[offset] != current_stack_depth) {
// TODO: is this condition same for calls?
ip_failure(saved_current_ip, bf, ip_failure(saved_current_ip, bf,
"different stack depth on same point is not allowed"); "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, auto const check_correct_var = [&saved_current_ip, &bf, &globals_count,
&current_locals_count, &current_locals_count, &current_args_count,
&current_args_count](uint8_t l, uint id) { &is_in_closure](uint8_t l, uint id) {
if (l > 3) { if (l > 3) {
ip_failure(saved_current_ip, bf, "unexpected variable category"); ip_failure(saved_current_ip, bf, "unexpected variable category");
} }
@ -84,7 +85,11 @@ void analyze(Bytefile *bf) {
} }
break; break;
case VAR_CLOSURE: 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; break;
} }
}; };
@ -92,7 +97,7 @@ void analyze(Bytefile *bf) {
// add publics // add publics
to_visit_func.reserve(bf->public_symbols_number); to_visit_func.reserve(bf->public_symbols_number);
for (size_t i = 0; i < bf->public_symbols_number; ++i) { 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) { if (to_visit_func.size() == 0) {
@ -129,9 +134,9 @@ void analyze(Bytefile *bf) {
saved_current_ip = current_ip; saved_current_ip = current_ip;
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
const auto [cmd, l] = parse_command(&ip, *bf, std::cout); const auto [cmd, l] = parse_command(&ip, bf, std::cout);
#else #else
const auto [cmd, l] = parse_command(&ip, *bf); const auto [cmd, l] = parse_command(&ip, bf);
#endif #endif
if (current_begin_counter == nullptr && cmd != Cmd::BEGIN && if (current_begin_counter == nullptr && cmd != Cmd::BEGIN &&
@ -167,8 +172,8 @@ void analyze(Bytefile *bf) {
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::SEXP: case Cmd::SEXP:
ip_read_string(&current_ip, *bf); ip_read_string_unsafe(&current_ip, bf);
current_stack_depth -= ip_read_int(&current_ip, *bf); current_stack_depth -= ip_read_int_unsafe(&current_ip);
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
@ -215,15 +220,15 @@ void analyze(Bytefile *bf) {
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::LD: case Cmd::LD:
check_correct_var(l, ip_read_int(&current_ip, *bf)); check_correct_var(l, ip_read_int_unsafe(&current_ip));
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::LDA: case Cmd::LDA:
check_correct_var(l, ip_read_int(&current_ip, *bf)); check_correct_var(l, ip_read_int_unsafe(&current_ip));
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::ST: case Cmd::ST:
check_correct_var(l, ip_read_int(&current_ip, *bf)); check_correct_var(l, ip_read_int_unsafe(&current_ip));
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
@ -237,47 +242,60 @@ void analyze(Bytefile *bf) {
if (current_begin_counter != nullptr) { if (current_begin_counter != nullptr) {
ip_failure(saved_current_ip, bf, "unexpected function beginning"); ip_failure(saved_current_ip, bf, "unexpected function beginning");
} }
current_args_count = ip_read_int(&current_ip, *bf); current_args_count = ip_read_int_unsafe(&current_ip);
current_begin_counter = (uint16_t *)(current_ip + sizeof(uint16_t)); current_begin_counter = (uint16_t *)(current_ip + sizeof(uint16_t));
current_locals_count = ip_read_int(&current_ip, *bf); current_locals_count = ip_read_int_unsafe(&current_ip);
// TODO: check uint16_t max ?? if (current_locals_count >= std::numeric_limits<uint16_t>::max()) {
ip_failure(saved_current_ip, bf, "too many locals in functions");
}
(*(uint16_t *)(current_ip - sizeof(uint16_t))) = current_locals_count; (*(uint16_t *)(current_ip - sizeof(uint16_t))) = current_locals_count;
*current_begin_counter = 0; *current_begin_counter = 0;
is_in_closure = (cmd == Cmd::CBEGIN);
break; break;
case Cmd::CLOSURE: { case Cmd::CLOSURE: {
ip_read_int(&ip, *bf); // offset uint closure_offset = ip_read_int_unsafe(&current_ip); // closure offset
size_t args_count = ip_read_int(&current_ip, *bf); // args count size_t args_count = ip_read_int_unsafe(&current_ip); // args count
extra_stack_during_opr = args_count; extra_stack_during_opr = args_count;
for (aint i = 0; i < args_count; i++) { for (aint i = 0; i < args_count; i++) {
aint arg_type = ip_read_byte(&current_ip, *bf); aint arg_type = ip_read_byte_unsafe(&current_ip);
aint arg_id = ip_read_int(&current_ip, *bf); aint arg_id = ip_read_int_unsafe(&current_ip);
check_correct_var(arg_type, arg_id); check_correct_var(arg_type, arg_id);
} }
++current_stack_depth; ++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; } break;
case Cmd::CALLC: { case Cmd::CALLC: {
uint args_count = ip_read_int(&current_ip, *bf); uint args_count = ip_read_int_unsafe(&current_ip);
current_stack_depth -= args_count + 1; // + closure itself current_stack_depth -= args_count + 1; // + closure itself
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
// NOTE: can't check args == cbegin args (?) // NOTE: can't check args == cbegin args
} break; } break;
case Cmd::CALL: { case Cmd::CALL: {
uint call_offset = ip_read_int(&current_ip, *bf); // call offset uint call_offset = ip_read_int_unsafe(&current_ip); // call offset
uint args_count = ip_read_int(&current_ip, *bf); uint args_count = ip_read_int_unsafe(&current_ip);
current_stack_depth -= args_count; current_stack_depth -= args_count;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
// TODO: unify with next loop
if (call_offset >= bf->code_size) { if (call_offset >= bf->code_size) {
ip_failure(saved_current_ip, bf, "jump/call out of file"); 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)) { if (args_count != *(uint *)(bf->code_ptr + call_offset + 1)) {
ip_failure(saved_current_ip, bf, "wrong call argument count"); ip_failure(saved_current_ip, bf, "wrong call argument count");
} }
@ -318,7 +336,7 @@ void analyze(Bytefile *bf) {
} }
break; break;
case Cmd::Barray: case Cmd::Barray:
current_stack_depth -= ip_read_int(&current_ip, *bf); // elem count current_stack_depth -= ip_read_int_unsafe(&current_ip); // elem count
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
@ -362,7 +380,7 @@ void analyze(Bytefile *bf) {
case Cmd::JMP: { case Cmd::JMP: {
bool is_call = (cmd == Cmd::CLOSURE || cmd == Cmd::CALL); bool is_call = (cmd == Cmd::CLOSURE || cmd == Cmd::CALL);
uint jmp_p = ip_read_int(&current_ip, *bf); uint jmp_p = ip_read_int_unsafe(&current_ip);
if (jmp_p >= bf->code_size) { if (jmp_p >= bf->code_size) {
// NOTE: maybe also should check that > begin (?) // NOTE: maybe also should check that > begin (?)
ip_failure(saved_current_ip, bf, "jump/call out of file"); ip_failure(saved_current_ip, bf, "jump/call out of file");

View file

@ -18,14 +18,18 @@ int main(int argc, char **argv) {
bool do_verification = false; bool do_verification = false;
bool do_interpretation = false; bool do_interpretation = false;
bool do_print = false; bool do_print = false;
if (strcmp(argv[1], "-vi") == 0) { if (strcmp(argv[1], "-i") == 0) {
do_verification = true;
do_interpretation = true; 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; do_interpretation = true;
} else if (strcmp(argv[1], "-v") == 0) { } else if (strcmp(argv[1], "-v") == 0) {
do_verification = true; do_verification = true;
} else if (strcmp(argv[1], "-p") == 0) { }
#endif
else if (strcmp(argv[1], "-p") == 0) {
do_print = true; do_print = true;
} else { } else {
failure("wrong execution option (acceptable options - '-i', '-v', '-vi')"); 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]); Bytefile *f = read_file(argv[2]);
// #ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
// dump_file (stdout, f); dump_file(stdout, f);
// #endif #endif
if (do_print) { if (do_print) {
print_file(*f, std::cout); print_file(*f, std::cout);
} }
if (do_verification) { if (do_verification) {
analyze(f); analyze(f);
} }
if (do_interpretation) { // TODO: switch between enabled/disabled verification if (do_interpretation) {
run(f, argc - 2, argv + 2); run(f, argc - 2, argv + 2);
} }
free(f->global_ptr); // // NOTE: not used for now
// // free(f->global_ptr);
free(f); free(f);
return 0; return 0;

View file

@ -8,6 +8,9 @@
#include "types.h" #include "types.h"
#include "utils.h" #include "utils.h"
void *__start_custom_data;
void *__stop_custom_data;
#define ASSERT_UNBOXED(memo, x) \ #define ASSERT_UNBOXED(memo, x) \
do \ do \
if (!UNBOXED(x)) \ if (!UNBOXED(x)) \
@ -17,36 +20,35 @@
struct State s; struct State s;
static inline uint16_t ip_read_half_int(char **ip) { static inline uint16_t ip_read_half_int(char **ip) {
#ifndef WITH_CHECK #ifdef WITH_CHECK
if (*ip + sizeof(uint16_t) > s.bf->code_ptr + s.bf->code_size) { return ip_read_half_int_unsafe(ip);
failure("last command is invalid, int parameter can not be read\n"); #else
} return ip_read_half_int_safe(ip, s.bf);
#endif #endif
*ip += sizeof(uint16_t);
return *(uint16_t *)((*ip) - sizeof(uint16_t));
} }
static inline int ip_read_int(char **ip) { static inline int ip_read_int(char **ip) {
#ifndef WITH_CHECK #ifdef WITH_CHECK
if (*ip + sizeof(int) > s.bf->code_ptr + s.bf->code_size) { return ip_read_int_unsafe(ip);
failure("last command is invalid, int parameter can not be read\n"); #else
} return ip_read_int_safe(ip, s.bf);
#endif #endif
*ip += sizeof(int);
return *(int *)((*ip) - sizeof(int));
} }
static inline uint8_t ip_read_byte(char **ip) { static inline uint8_t ip_read_byte(char **ip) {
#ifndef WITH_CHECK #ifdef WITH_CHECK
if (*ip + sizeof(char) > s.bf->code_ptr + s.bf->code_size) { return ip_read_byte_unsafe(ip);
failure("last command is invalid, byte parameter can not be read\n"); #else
} return ip_read_byte_safe(ip, s.bf);
#endif #endif
return *(*ip)++;
} }
static inline const char *ip_read_string(char **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; const size_t BUFFER_SIZE = 1000;
@ -107,7 +109,7 @@ void run(Bytefile *bf, int argc, char **argv) {
if (l == CMD_BINOP_SUB) { if (l == CMD_BINOP_SUB) {
s_push_i(Ls__Infix_45(fst, snd)); s_push_i(Ls__Infix_45(fst, snd));
} else { } else {
switch (l) { switch (l - 1) {
#define BINOP_OPR(val, op) \ #define BINOP_OPR(val, op) \
case val: \ case val: \
ASSERT_UNBOXED("captured op:1", fst); \ 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, s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz,
locals_sz); locals_sz);
#ifndef WITH_CHECK #ifndef WITH_CHECK
// TODO
if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) {
s_failure(&s, "stack owerflow"); s_failure(&s, "stack owerflow");
} }
@ -329,7 +330,6 @@ void run(Bytefile *bf, int argc, char **argv) {
#endif #endif
s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz, s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz,
locals_sz); locals_sz);
// TODO: add ifdef
#ifdef WITH_CHECK #ifdef WITH_CHECK
if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) { if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) {
s_failure(&s, "stack owerflow"); s_failure(&s, "stack owerflow");

View file

@ -1,388 +0,0 @@
/* Lama SM Bytecode interpreter */
#include <string.h>
#include <errno.h>
#include <malloc.h>
#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; i++) {
// switch (BYTE) {
// 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:
// fprintf (f, "CALLC\t%d", INT);
// break;
// case 6:
// fprintf (f, "CALL\t0x%.8x ", INT);
// fprintf (f, "%d", INT);
// break;
// case 7:
// fprintf (f, "TAG\t%s ", STRING);
// fprintf (f, "%d", INT);
// break;
// case 8:
// fprintf (f, "ARRAY\t%d", INT);
// break;
// case 9:
// fprintf (f, "FAIL\t%d", INT);
// fprintf (f, "%d", INT);
// break;
// case 10:
// fprintf (f, "LINE\t%d", INT);
// break;
// default:
// FAIL;
// }
// break;
// case 6:
// fprintf (f, "PATT\t%s", pats[l]);
// break;
// case 7: {
// switch (l) {
// case 0:
// fprintf (f, "CALL\tLread");
// break;
// case 1:
// fprintf (f, "CALL\tLwrite");
// break;
// case 2:
// fprintf (f, "CALL\tLlength");
// break;
// case 3:
// fprintf (f, "CALL\tLstring");
// break;
// case 4:
// fprintf (f, "CALL\tBarray\t%d", INT);
// break;
// default:
// FAIL;
// }
// }
// break;
// default:
// FAIL;
// }
// fprintf (f, "\n");
// }
// while (1);
// stop: fprintf (f, "<end>\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);
// }

View file

@ -8,88 +8,35 @@
#include "parser.hpp" #include "parser.hpp"
extern "C" { extern "C" {
#include "types.h"
#include "utils.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 { enum class ArgT {
INT, INT,
OFFSET, OFFSET,
STR, STR,
}; };
#define FORALL_BINOP(DEF) \ // #define FORALL_BINOP(DEF) \
DEF(0, +) \ // DEF(0, +) \
DEF(1, -) \ // DEF(1, -) \
DEF(2, *) \ // DEF(2, *) \
DEF(3, /) \ // DEF(3, /) \
DEF(4, %) \ // DEF(4, %) \
DEF(5, <) \ // DEF(5, <) \
DEF(6, <=) \ // DEF(6, <=) \
DEF(7, >) \ // DEF(7, >) \
DEF(8, >=) \ // DEF(8, >=) \
DEF(9, ==) \ // DEF(9, ==) \
DEF(10, !=) \ // DEF(10, !=) \
DEF(11, &&) \ // DEF(11, &&) \
DEF(12, ||) // DEF(12, ||)
// extern "C" {
// void *__start_custom_data;
// void *__stop_custom_data;
// Reads a binary bytecode file by name and unpacks it // Reads a binary bytecode file by name and unpacks it
Bytefile *read_file(const char *fname) { Bytefile *read_file(const char *fname) {
@ -97,11 +44,11 @@ Bytefile *read_file(const char *fname) {
Bytefile *file; Bytefile *file;
if (f == 0) { if (f == 0) {
failure(strerror(errno)); failure("%s\n", strerror(errno));
} }
if (fseek(f, 0, SEEK_END) == -1) { if (fseek(f, 0, SEEK_END) == -1) {
failure(strerror(errno)); failure("%s\n", strerror(errno));
} }
long size = ftell(f); long size = ftell(f);
@ -113,48 +60,78 @@ Bytefile *read_file(const char *fname) {
char *file_end = file_begin + size; char *file_end = file_begin + size;
if (file == 0) { if (file == 0) {
failure("unable to allocate memory to store file data"); failure("unable to allocate memory to store file data\n");
} }
rewind(f); rewind(f);
if (size != fread(&file->stringtab_size, 1, size, f)) { if (size != fread(&file->stringtab_size, 1, size, f)) {
failure(strerror(errno)); failure("%s\n", strerror(errno));
} }
fclose(f); fclose(f);
long public_symbols_size = file->public_symbols_number * 2 * sizeof(int); long public_symbols_size = file->public_symbols_number * 2 * sizeof(int);
if (file->buffer + public_symbols_size >= file_end) { 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) { 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 || if (file->code_size < 0 || public_symbols_size < 0 ||
file->stringtab_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->string_ptr = &file->buffer[public_symbols_size];
file->public_ptr = (int *)file->buffer; file->public_ptr = (int *)file->buffer;
file->code_ptr = &file->string_ptr[file->stringtab_size]; 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; file->code_size = size - public_symbols_size - file->stringtab_size;
return file; 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[] = { 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) FORALL_BINOP(OP_TO_STR)
#undef OP_TO_STR #undef OP_TO_STR
}; };
static const char *const pats[] = {"=str", "#string", "#array", "#sexp", static const char *const pats[] = {
"#ref", "#val", "#fun"}; "PATT:=str", "PATT:#string", "PATT:#array", "PATT:#sexp",
static const char *const ldts[] = {"G", "L", "A", "C"}; "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) { switch (cmd) {
case Cmd::EXIT: case Cmd::EXIT:
@ -163,7 +140,7 @@ std::string command_name(Cmd cmd, int8_t l) {
if (l - 1 >= sizeof(ops) / sizeof(char *)) { if (l - 1 >= sizeof(ops) / sizeof(char *)) {
return "_UNDEF_BINOP_"; return "_UNDEF_BINOP_";
} }
return "BINOP:" + std::string{ops[l - 1]}; return ops[l - 1];
case Cmd::CONST: case Cmd::CONST:
return "CONST"; return "CONST";
case Cmd::STRING: case Cmd::STRING:
@ -189,20 +166,20 @@ std::string command_name(Cmd cmd, int8_t l) {
case Cmd::ELEM: case Cmd::ELEM:
return "ELEM"; return "ELEM";
case Cmd::LD: case Cmd::LD:
if (l >= sizeof(ldts) / sizeof(char *)) { if (l >= sizeof(ld_ldts) / sizeof(char *)) {
return "_UNDEF_LD_"; return "_UNDEF_LD_";
} }
return "LD:" + std::string{ldts[l]}; return ld_ldts[l];
case Cmd::LDA: case Cmd::LDA:
if (l >= sizeof(ldts) / sizeof(char *)) { if (l >= sizeof(lda_ldts) / sizeof(char *)) {
return "_UNDEF_LDA_"; return "_UNDEF_LDA_";
} }
return "LDA:" + std::string{ldts[l]}; return lda_ldts[l];
case Cmd::ST: case Cmd::ST:
if (l >= sizeof(ldts) / sizeof(char *)) { if (l >= sizeof(st_ldts) / sizeof(char *)) {
return "_UNDEF_ST_"; return "_UNDEF_ST_";
} }
return "ST:" + std::string{ldts[l]}; return st_ldts[l];
case Cmd::CJMPz: case Cmd::CJMPz:
return "CJMPz"; return "CJMPz";
case Cmd::CJMPnz: case Cmd::CJMPnz:
@ -229,7 +206,7 @@ std::string command_name(Cmd cmd, int8_t l) {
if (l >= sizeof(pats) / sizeof(char *)) { if (l >= sizeof(pats) / sizeof(char *)) {
return "_UNDEF_PATT_"; return "_UNDEF_PATT_";
} }
return "PATT:" + std::string{pats[l]}; return pats[l];
case Cmd::Lread: case Cmd::Lread:
return "CALL\tLread"; return "CALL\tLread";
case Cmd::Lwrite: case Cmd::Lwrite:
@ -246,6 +223,7 @@ std::string command_name(Cmd cmd, int8_t l) {
exit(1); exit(1);
} }
// } // extern "C"
template <bool use_out, typename T> template <bool use_out, typename T>
static inline const T &print_val(std::ostream &out, const T &val) { static inline const T &print_val(std::ostream &out, const T &val) {
@ -265,7 +243,7 @@ template <bool use_out, ArgT arg>
requires(arg == ArgT::INT) requires(arg == ArgT::INT)
static inline uint read_print_val(char **ip, const Bytefile &bf, static inline uint read_print_val(char **ip, const Bytefile &bf,
std::ostream &out) { std::ostream &out) {
uint val = ip_read_int(ip, bf); uint val = ip_read_int_safe(ip, &bf);
if constexpr (use_out) { if constexpr (use_out) {
out << val; out << val;
} }
@ -276,9 +254,9 @@ template <bool use_out, ArgT arg>
requires(arg == ArgT::OFFSET) requires(arg == ArgT::OFFSET)
static inline uint read_print_val(char **ip, const Bytefile &bf, static inline uint read_print_val(char **ip, const Bytefile &bf,
std::ostream &out) { std::ostream &out) {
uint val = ip_read_int(ip, bf); uint val = ip_read_int_safe(ip, &bf);
if constexpr (use_out) { if constexpr (use_out) {
out << val; // TODO out << val;
} }
return val; return val;
} }
@ -287,7 +265,7 @@ template <bool use_out, ArgT arg>
requires(arg == ArgT::STR) requires(arg == ArgT::STR)
static inline const char *read_print_val(char **ip, const Bytefile &bf, static inline const char *read_print_val(char **ip, const Bytefile &bf,
std::ostream &out) { std::ostream &out) {
const char *val = ip_read_string(ip, bf); const char *val = ip_read_string_safe(ip, &bf);
if constexpr (use_out) { if constexpr (use_out) {
out << val; out << val;
} }
@ -320,11 +298,20 @@ static inline void read_print_cmd_seq(Cmd cmd, uint8_t l, char **ip,
read_print_seq<use_out, args...>(ip, bf, out); read_print_seq<use_out, args...>(ip, bf, out);
} }
template <bool use_out> template <bool do_read, bool use_out, ArgT... args>
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<use_out, args...>(cmd, l, ip, bf, out);
}
}
template <bool use_out, bool do_read_args = true>
std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf, std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
std::ostream &out) { std::ostream &out) {
static const char *const ops[] = { static const char *const ops[] = {
#define OP_TO_STR(id, op) "op", #define OP_TO_STR(id, op) #op,
FORALL_BINOP(OP_TO_STR) FORALL_BINOP(OP_TO_STR)
#undef OP_TO_STR #undef OP_TO_STR
}; };
@ -346,7 +333,7 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
Cmd cmd = Cmd::_UNDEF_; Cmd cmd = Cmd::_UNDEF_;
char *instr_ip = *ip; 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 #ifdef DEBUG_VERSION
printf("0x%.8lx ", *ip - bf.code_ptr - 1); printf("0x%.8lx ", *ip - bf.code_ptr - 1);
@ -356,68 +343,72 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
switch (h) { switch (h) {
case CMD_EXIT: case CMD_EXIT:
cmd = Cmd::EXIT; cmd = Cmd::EXIT;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
/* BINOP */ /* BINOP */
case CMD_BINOP: // BINOP ops[l-1] case CMD_BINOP: // BINOP ops[l-1]
cmd = Cmd::BINOP; cmd = Cmd::BINOP;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BASIC: case CMD_BASIC:
switch (l) { switch (l) {
case CMD_BASIC_CONST: // CONST %d case CMD_BASIC_CONST: // CONST %d
cmd = Cmd::CONST; cmd = Cmd::CONST;
read_print_cmd_seq<use_out, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out);
break; break;
case CMD_BASIC_STRING: // STRING %s case CMD_BASIC_STRING: // STRING %s
cmd = Cmd::STRING; cmd = Cmd::STRING;
read_print_cmd_seq<use_out, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out);
break; break;
case CMD_BASIC_SEXP: // SEXP %s %d case CMD_BASIC_SEXP: // SEXP %s %d
cmd = Cmd::SEXP; cmd = Cmd::SEXP;
read_print_cmd_seq<use_out, ArgT::STR, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::STR, ArgT::INT>(
cmd, l, ip, bf, out);
break; break;
case CMD_BASIC_STI: // STI - write by ref (?) case CMD_BASIC_STI: // STI - write by ref (?)
cmd = Cmd::STI; cmd = Cmd::STI;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BASIC_STA: // STA - write to array elem case CMD_BASIC_STA: // STA - write to array elem
cmd = Cmd::STA; cmd = Cmd::STA;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BASIC_JMP: // JMP 0x%.8x case CMD_BASIC_JMP: // JMP 0x%.8x
cmd = Cmd::JMP; cmd = Cmd::JMP;
read_print_cmd_seq<use_out, ArgT::OFFSET>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::OFFSET>(cmd, l, ip,
bf, out);
break; break;
case CMD_BASIC_END: // END case CMD_BASIC_END: // END
cmd = Cmd::END; cmd = Cmd::END;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BASIC_RET: // RET case CMD_BASIC_RET: // RET
cmd = Cmd::RET; cmd = Cmd::RET;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BASIC_DROP: // DROP case CMD_BASIC_DROP: // DROP
cmd = Cmd::DROP; cmd = Cmd::DROP;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BASIC_DUP: // DUP case CMD_BASIC_DUP: // DUP
cmd = Cmd::DUP; cmd = Cmd::DUP;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BASIC_SWAP: // SWAP case CMD_BASIC_SWAP: // SWAP
cmd = Cmd::SWAP; cmd = Cmd::SWAP;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BASIC_ELEM: // ELEM case CMD_BASIC_ELEM: // ELEM
cmd = Cmd::ELEM; cmd = Cmd::ELEM;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
default: default:
@ -430,52 +421,60 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
if (l > sizeof(ldts) / sizeof(char *)) { if (l > sizeof(ldts) / sizeof(char *)) {
failure("wrong ld argument type"); failure("wrong ld argument type");
} }
read_print_cmd_seq<use_out, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out);
break; break;
case CMD_LDA: // LDA %d case CMD_LDA: // LDA %d
cmd = Cmd::LDA; cmd = Cmd::LDA;
if (l > sizeof(ldts) / sizeof(char *)) { if (l > sizeof(ldts) / sizeof(char *)) {
failure("wrong lda argument type"); failure("wrong lda argument type");
} }
read_print_cmd_seq<use_out, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out);
break; break;
case CMD_ST: // ST %d case CMD_ST: // ST %d
cmd = Cmd::ST; cmd = Cmd::ST;
if (l > sizeof(ldts) / sizeof(char *)) { if (l > sizeof(ldts) / sizeof(char *)) {
failure("wrong st argument type"); failure("wrong st argument type");
} }
read_print_cmd_seq<use_out, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out);
break; break;
case CMD_CTRL: case CMD_CTRL:
switch (l) { switch (l) {
case CMD_CTRL_CJMPz: // CJMPnz 0x%.8x case CMD_CTRL_CJMPz: // CJMPnz 0x%.8x
cmd = Cmd::CJMPz; cmd = Cmd::CJMPz;
read_print_cmd_seq<use_out, ArgT::OFFSET>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::OFFSET>(cmd, l, ip,
bf, out);
break; break;
case CMD_CTRL_CJMPnz: // CJMPnz 0x%.8x case CMD_CTRL_CJMPnz: // CJMPnz 0x%.8x
cmd = Cmd::CJMPnz; cmd = Cmd::CJMPnz;
read_print_cmd_seq<use_out, ArgT::OFFSET>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::OFFSET>(cmd, l, ip,
bf, out);
break; break;
case CMD_CTRL_BEGIN: // BEGIN %d %d // function begin case CMD_CTRL_BEGIN: // BEGIN %d %d // function begin
cmd = Cmd::BEGIN; cmd = Cmd::BEGIN;
read_print_cmd_seq<use_out, ArgT::INT, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT, ArgT::INT>(
cmd, l, ip, bf, out);
break; break;
case CMD_CTRL_CBEGIN: // CBEGIN %d %d case CMD_CTRL_CBEGIN: // CBEGIN %d %d
cmd = Cmd::CBEGIN; cmd = Cmd::CBEGIN;
read_print_cmd_seq<use_out, ArgT::INT, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT, ArgT::INT>(
cmd, l, ip, bf, out);
break; break;
case CMD_CTRL_CLOSURE: { // CLOSURE 0x%.8x case CMD_CTRL_CLOSURE: { // CLOSURE 0x%.8x
cmd = Cmd::CLOSURE; cmd = Cmd::CLOSURE;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
print_space<use_out>(out); print_space<use_out>(out);
if constexpr (do_read_args) {
size_t call_p = read_print_val<use_out, ArgT::OFFSET>(ip, bf, out); size_t call_p = read_print_val<use_out, ArgT::OFFSET>(ip, bf, out);
print_space<use_out>(out); print_space<use_out>(out);
size_t args_count = read_print_val<use_out, ArgT::INT>(ip, bf, out); size_t args_count = read_print_val<use_out, ArgT::INT>(ip, bf, out);
for (size_t i = 0; i < args_count; i++) { for (size_t i = 0; i < args_count; i++) {
uint8_t arg_type = ip_read_byte(ip, bf); uint8_t arg_type = ip_read_byte_safe(ip, &bf);
if (arg_type > sizeof(ldts) / sizeof(char *)) { if (arg_type > sizeof(ldts) / sizeof(char *)) {
failure("wrong closure argument type"); failure("wrong closure argument type");
} }
@ -484,35 +483,42 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
print_space<use_out>(out); print_space<use_out>(out);
read_print_val<use_out, ArgT::INT>(ip, bf, out); read_print_val<use_out, ArgT::INT>(ip, bf, out);
} }
}
break; break;
} }
case CMD_CTRL_CALLC: // CALLC %d // call clojure case CMD_CTRL_CALLC: // CALLC %d // call clojure
cmd = Cmd::CALLC; cmd = Cmd::CALLC;
read_print_cmd_seq<use_out, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out);
break; break;
case CMD_CTRL_CALL: // CALL 0x%.8x %d // call function case CMD_CTRL_CALL: // CALL 0x%.8x %d // call function
cmd = Cmd::CALL; cmd = Cmd::CALL;
read_print_cmd_seq<use_out, ArgT::OFFSET, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::OFFSET, ArgT::INT>(
cmd, l, ip, bf, out);
break; break;
case CMD_CTRL_TAG: // TAG %s %d case CMD_CTRL_TAG: // TAG %s %d
cmd = Cmd::TAG; cmd = Cmd::TAG;
read_print_cmd_seq<use_out, ArgT::STR, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::STR, ArgT::INT>(
cmd, l, ip, bf, out);
break; break;
case CMD_CTRL_FAIL: // FAIL %d %d case CMD_CTRL_FAIL: // FAIL %d %d
cmd = Cmd::FAIL; cmd = Cmd::FAIL;
read_print_cmd_seq<use_out, ArgT::INT, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT, ArgT::INT>(
cmd, l, ip, bf, out);
break; break;
case CMD_CTRL_ARRAY: // ARRAY %d case CMD_CTRL_ARRAY: // ARRAY %d
cmd = Cmd::ARRAY; cmd = Cmd::ARRAY;
read_print_cmd_seq<use_out, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out);
break; break;
case CMD_CTRL_LINE: // LINE %d case CMD_CTRL_LINE: // LINE %d
cmd = Cmd::LINE; cmd = Cmd::LINE;
read_print_cmd_seq<use_out, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out);
break; break;
default: default:
@ -526,31 +532,32 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
failure("invalid opcode"); failure("invalid opcode");
} }
cmd = Cmd::PATT; cmd = Cmd::PATT;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BUILTIN: { case CMD_BUILTIN: {
switch (l) { switch (l) {
case CMD_BUILTIN_Lread: // CALL Lread case CMD_BUILTIN_Lread: // CALL Lread
cmd = Cmd::Lread; cmd = Cmd::Lread;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BUILTIN_Lwrite: // CALL Lwrite case CMD_BUILTIN_Lwrite: // CALL Lwrite
cmd = Cmd::Lwrite; cmd = Cmd::Lwrite;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BUILTIN_Llength: // CALL Llength case CMD_BUILTIN_Llength: // CALL Llength
cmd = Cmd::Llength; cmd = Cmd::Llength;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BUILTIN_Lstring: // CALL Lstring case CMD_BUILTIN_Lstring: // CALL Lstring
cmd = Cmd::Lstring; cmd = Cmd::Lstring;
read_print_cmd_seq<use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
break; break;
case CMD_BUILTIN_Barray: // CALL Barray %d case CMD_BUILTIN_Barray: // CALL Barray %d
cmd = Cmd::Barray; cmd = Cmd::Barray;
read_print_cmd_seq<use_out, ArgT::INT>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out);
break; break;
default: default:
@ -567,13 +574,21 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
return {cmd, l}; return {cmd, l};
} }
std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf) { std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile *bf) {
return parse_command_impl<false>(ip, bf, std::clog); return parse_command_impl<false>(ip, *bf, std::clog);
} }
std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf, std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile *bf,
std::ostream &out) { std::ostream &out) {
return parse_command_impl<true>(ip, bf, out); return parse_command_impl<true>(ip, *bf, out);
}
std::pair<Cmd, uint8_t> parse_command_name(char **ip, const Bytefile *bf) {
return parse_command_impl<false, false>(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) { void print_file(const Bytefile &bf, std::ostream &out) {
@ -582,7 +597,7 @@ void print_file(const Bytefile &bf, std::ostream &out) {
while (true) { while (true) {
out << std::setfill('0') << std::setw(8) << std::hex << ip - bf.code_ptr 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'; out << '\n';
if (cmd == Cmd::EXIT) { 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<false, false>(&ip, *bf, std::clog);
return command_name(cmd, l);
return "";
}
} // extern "C"