fix interpreter and analyzer with new algorithm (with bugs)

This commit is contained in:
ProgramSnail 2025-03-02 15:05:09 +03:00
parent 343a21ee2d
commit 58c9fd77c2
21 changed files with 3489 additions and 559 deletions

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)
(:module_manager module_manager.o) (:module_manager src/module_manager.cpp)
(:obj types.o interpreter.o) (:obj types.o interpreter.o)
(:runtime ../runtime/runtime.a)) (:runtime ../runtime/runtime.a))
(mode (mode
@ -34,14 +34,3 @@
(promote (until-clean))) (promote (until-clean)))
(action (action
(run gcc -Wall -Wextra -Iinclude/ -DWITH_CHECK -c %{src} -o %{target}))) (run gcc -Wall -Wextra -Iinclude/ -DWITH_CHECK -c %{src} -o %{target})))
(rule
(target module_manager.o)
(deps
(:include (source_tree include))
(:src src/module_manager.cpp)
(:runtime ../runtime/runtime.a))
(mode
(promote (until-clean)))
(action
(run g++ -Wall -Wextra -std=c++20 -Iinclude/ -c %{src} -o %{target})))

View file

@ -4,4 +4,6 @@ extern "C" {
#include "utils.h" #include "utils.h"
} }
void analyze(uint32_t mod_id); #include <vector>
void analyze(Bytefile *bf, std::vector<size_t> &&add_publics = {});

View file

@ -7,10 +7,8 @@
void run_init(size_t *stack); void run_init(size_t *stack);
void run_mod_rec(uint mod_id, int argc, char **argv, bool do_verification); void set_argc_argv(int argc, char **argv);
void run_prepare_exec(int argc, char **argv); void run_main(Bytefile *bf, int argc, char **argv);
void run_mod(uint mod_id, int argc, char **argv);
void run_cleanup(); void run_cleanup();

View file

@ -5,26 +5,55 @@
#include "utils.h" #include "utils.h"
struct ModSearchResult { Bytefile *run_with_imports(Bytefile *root, int argc, char **argv,
size_t symbol_offset; bool do_verification);
uint32_t mod_id;
Bytefile *mod_file; // = NULL => not found // ---
enum BUILTIN : uint {
BUILTIN_Luppercase,
BUILTIN_Llowercase,
BUILTIN_Lassert,
BUILTIN_Lstring,
BUILTIN_Llength,
BUILTIN_LstringInt,
BUILTIN_Lread,
BUILTIN_Lwrite,
BUILTIN_LmakeArray,
BUILTIN_LmakeString,
BUILTIN_Lstringcat,
BUILTIN_LmatchSubString,
BUILTIN_Lsprintf,
BUILTIN_Lsubstring,
BUILTIN_Li__Infix_4343, // ++
BUILTIN_Lclone,
BUILTIN_Lhash,
BUILTIN_LtagHash,
BUILTIN_Lcompare,
BUILTIN_LflatCompare,
BUILTIN_Lfst,
BUILTIN_Lsnd,
BUILTIN_Lhd,
BUILTIN_Ltl,
BUILTIN_Lprintf,
BUILTIN_LreadLine,
BUILTIN_Lfopen,
BUILTIN_Lfclose,
BUILTIN_Lfread,
BUILTIN_Lfwrite,
BUILTIN_Lfexists,
BUILTIN_Lfprintf,
BUILTIN_Lregexp,
BUILTIN_LregexpMatch,
BUILTIN_Lfailure,
BUILTIN_Lsystem,
BUILTIN_LgetEnv,
BUILTIN_Lrandom,
BUILTIN_Ltime,
BUILTIN_Barray, // can't be run with run_stdlib_func
BUILTIN_NONE,
}; };
void mod_cleanup(); enum BUILTIN id_by_builtin(const char *name);
void mod_add_search_path(const char *path); void run_stdlib_func(enum BUILTIN id, size_t args_count);
const char *mod_get_name(uint32_t id);
Bytefile *mod_get(uint32_t id);
int32_t find_mod_loaded(const char *name); // < 0 => not found
int32_t mod_load(const char *name, bool do_verification); // < 0 => not found
uint32_t mod_add(Bytefile *module, bool do_verification);
struct ModSearchResult mod_search_pub_symbol(const char *name);
bool run_stdlib_func(const char *name, size_t args_count);

View file

@ -36,7 +36,7 @@ enum class Cmd : int8_t {
ARRAY, ARRAY,
FAIL, FAIL,
LINE, LINE,
// CALLF, BUILTIN,
PATT, PATT,
// NOTE: no longer used // NOTE: no longer used
// Lread, // Lread,
@ -50,8 +50,6 @@ enum class Cmd : int8_t {
Bytefile *read_file(const char *fname); Bytefile *read_file(const char *fname);
Bytefile *merge_files(const std::vector<Bytefile> &bytefiles);
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::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);

View file

@ -155,8 +155,8 @@ static inline void s_rotate_n(size_t n) {
// //
// where |> defines corresponding frame pointer, | is stack pointer // where |> defines corresponding frame pointer, | is stack pointer
// location before / after new frame added // location before / after new frame added
static inline void s_enter_f(char *rp, aint ret_module_id, bool is_closure_call, static inline void s_enter_f(char *rp, bool is_closure_call, auint args_sz,
auint args_sz, auint locals_sz) { auint locals_sz) {
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
printf("-> %i args sz\n", args_sz); printf("-> %i args sz\n", args_sz);
printf("-> %i locals sz\n", locals_sz); printf("-> %i locals sz\n", locals_sz);
@ -186,7 +186,6 @@ static inline void s_enter_f(char *rp, aint ret_module_id, bool is_closure_call,
.ret = NULL, // field in frame itself .ret = NULL, // field in frame itself
.rp = rp, .rp = rp,
.prev_fp = (void **)s.fp, .prev_fp = (void **)s.fp,
.ret_module_box = BOX(ret_module_id),
.args_sz_box = BOX(args_sz), .args_sz_box = BOX(args_sz),
.locals_sz_box = BOX(locals_sz), .locals_sz_box = BOX(locals_sz),
}; };
@ -227,9 +226,6 @@ static inline void s_exit_f() {
} }
s.ip = frame.rp; s.ip = frame.rp;
s.current_module_id = UNBOX(frame.ret_module_box);
s.bf = mod_get(s.current_module_id);
} }
static inline void print_stack(struct State *state) { static inline void print_stack(struct State *state) {

View file

@ -28,7 +28,6 @@ struct Frame {
char *rp; // ret instruction pointer [not gc pointer] char *rp; // ret instruction pointer [not gc pointer]
void **prev_fp; // ret function frame pointer [boxed value, not gc void **prev_fp; // ret function frame pointer [boxed value, not gc
// pointer] // pointer]
aint ret_module_box; // module to return [boxed value, not gc pointer]
aint args_sz_box; // store arguments [boxed value, not gc pointer] aint args_sz_box; // store arguments [boxed value, not gc pointer]
aint locals_sz_box; // store locals [boxed value, not gc pointer] aint locals_sz_box; // store locals [boxed value, not gc pointer]
}; };
@ -62,33 +61,27 @@ struct State {
bool is_closure_call; bool is_closure_call;
uint current_module_id;
uint call_module_id;
char *ip; // instruction pointer char *ip; // instruction pointer
char *instr_ip; // poiter to current instruction char *instr_ip; // poiter to current instruction
char *call_ip; // prev instruction pointer (to remember jmp locations) char *call_ip; // prev instruction pointer (to remember jmp locations)
}; };
void init_state(struct State *s, void **stack); void init_state(struct State *s, void **stack);
void init_mod_state(uint mod_id, struct State *s); void prepare_state(Bytefile *bf, struct State *s);
void init_mod_state_globals(struct State *s); void push_globals(struct State *s);
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->bf), mod_get_name(s->current_module_id), exec_failure(read_cmd(s->instr_ip, s->bf), s->current_line,
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, uint32_t mod_id, const char *msg) { static inline void ip_failure(char *ip, Bytefile *bf, const char *msg) {
Bytefile *bf = mod_get(mod_id); exec_failure(read_cmd(ip, bf), 0, ip - bf->code_ptr, msg);
exec_failure(read_cmd(ip, bf), mod_get_name(mod_id), 0, ip - bf->code_ptr,
msg);
} }
static inline void ip_safe_failure(char *ip, uint32_t mod_id, const char *msg) { static inline void ip_safe_failure(char *ip, Bytefile *bf, const char *msg) {
Bytefile *bf = mod_get(mod_id); exec_failure("_UNDEF_", 0, ip - bf->code_ptr, msg);
exec_failure("_UNDEF_", mod_get_name(mod_id), 0, ip - bf->code_ptr, msg);
} }
// ------ VarCategory ------ // ------ VarCategory ------
@ -164,7 +157,7 @@ enum CMD_CTRLS {
CMD_CTRL_ARRAY, CMD_CTRL_ARRAY,
CMD_CTRL_FAIL, CMD_CTRL_FAIL,
CMD_CTRL_LINE, CMD_CTRL_LINE,
// CMD_CTRL_CALLF, CMD_CTRL_BUILTIN,
}; };
enum CMD_PATTS { enum CMD_PATTS {

View file

@ -7,11 +7,6 @@
#include "../../runtime/runtime.h" #include "../../runtime/runtime.h"
#include "../../runtime/runtime_common.h" #include "../../runtime/runtime_common.h"
typedef struct {
uint offset;
char label[0];
} Subst;
/* The unpacked representation of bytecode file */ /* The unpacked representation of bytecode file */
typedef struct { typedef struct {
uint main_offset; /* offset of the function 'main' */ uint main_offset; /* offset of the function 'main' */
@ -30,10 +25,10 @@ typedef struct {
char buffer[0]; char buffer[0];
} Bytefile; } Bytefile;
static inline void exec_failure(const char *cmd, const char *module_name, static inline void exec_failure(const char *cmd, int line, aint offset,
int line, aint offset, const char *msg) { const char *msg) {
failure("*** RUNTIME ERROR: %s:%i(0x%.8x):%s error: %s\n", module_name, line, failure("*** RUNTIME ERROR: %i(0x%.8x):%s error: %s\n", line, offset, cmd,
offset, cmd, msg); msg);
} }
// --- unsafe versions // --- unsafe versions
@ -166,3 +161,9 @@ static inline uint8_t ip_read_byte_safe(char **ip, const Bytefile *bf) {
static inline const char *ip_read_string_safe(char **ip, const Bytefile *bf) { static inline const char *ip_read_string_safe(char **ip, const Bytefile *bf) {
return get_string_safe(bf, ip_read_int_safe(ip, bf)); return get_string_safe(bf, ip_read_int_safe(ip, bf));
} }
// ---
static inline size_t calc_publics_size(size_t publics_number) {
return publics_number * 2 * sizeof(int);
}

View file

@ -10,12 +10,13 @@ compiler=../_build/default/src/Driver.exe
echo "Used compiler path:" echo "Used compiler path:"
echo $compiler echo $compiler
for test in ../regression/*.lama; do for test in ../regression/*009.lama; do
echo $test echo $test
$compiler -b $test > /dev/null $compiler -b $test > /dev/null
test_file="${test%.*}" test_file="${test%.*}"
echo $test_file echo $test_file
cat $test_file.input | ./byterun.exe -vi test*.bc > /dev/null cat $test_file.input | ./byterun.exe -p test*.bc #> /dev/null
cat $test_file.input | ./byterun.exe -vi test*.bc #> /dev/null
rm test*.bc rm test*.bc
echo "done" echo "done"
done done

View file

@ -9,13 +9,11 @@ extern "C" {
#include <vector> #include <vector>
void analyze(uint32_t mod_id) { void analyze(Bytefile *bf, std::vector<size_t> &&add_publics) {
Bytefile *bf = mod_get(mod_id);
static constexpr const int NOT_VISITED = -1; static constexpr const int NOT_VISITED = -1;
std::vector<int> visited(bf->code_size, NOT_VISITED); // store stack depth std::vector<int> visited(bf->code_size, NOT_VISITED); // store stack depth
std::vector<size_t> to_visit_func; std::vector<size_t> to_visit_func = std::move(add_publics);
std::vector<size_t> to_visit_jmp; std::vector<size_t> to_visit_jmp;
int current_stack_depth = 0; int current_stack_depth = 0;
@ -30,57 +28,55 @@ void analyze(uint32_t mod_id) {
char *current_ip = ip; char *current_ip = ip;
char *saved_current_ip = current_ip; char *saved_current_ip = current_ip;
auto const jmp_to_visit_push = [&saved_current_ip, mod_id, &visited, auto const jmp_to_visit_push = [&saved_current_ip, bf, &visited,
&current_stack_depth, &current_stack_depth,
&to_visit_jmp](size_t offset) { &to_visit_jmp](size_t offset) {
if (visited[offset] == NOT_VISITED) { if (visited[offset] == NOT_VISITED) {
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) {
ip_failure(saved_current_ip, mod_id, ip_failure(saved_current_ip, bf,
"different stack depth on same point is not allowed"); "different stack depth on same point is not allowed");
} }
}; };
auto const func_to_visit_push = [&saved_current_ip, mod_id, &visited, auto const func_to_visit_push = [&saved_current_ip, bf, &visited,
&to_visit_func](size_t offset) { &to_visit_func](size_t offset) {
if (visited[offset] == NOT_VISITED) { if (visited[offset] == NOT_VISITED) {
visited[offset] = 0; visited[offset] = 0;
to_visit_func.push_back(offset); to_visit_func.push_back(offset);
} else if (visited[offset] != 0) { } else if (visited[offset] != 0) {
ip_failure(saved_current_ip, mod_id, ip_failure(saved_current_ip, bf,
"different stack depth on same point is not allowed"); "different stack depth on same point is not allowed");
} }
}; };
auto const check_correct_var = [&saved_current_ip, mod_id, &globals_count, auto const check_correct_var = [&saved_current_ip, bf, &globals_count,
&current_locals_count, &current_args_count, &current_locals_count, &current_args_count,
&is_in_closure](uint8_t l, uint id) { &is_in_closure](uint8_t l, uint id) {
if (l > 3) { if (l > 3) {
ip_failure(saved_current_ip, mod_id, "unexpected variable category"); ip_failure(saved_current_ip, bf, "unexpected variable category");
} }
VarCategory category = to_var_category(l); VarCategory category = to_var_category(l);
switch (category) { switch (category) {
case VAR_GLOBAL: case VAR_GLOBAL:
if (id >= globals_count) { if (id >= globals_count) {
ip_failure(saved_current_ip, mod_id, ip_failure(saved_current_ip, bf, "global var index is out of range");
"global var index is out of range");
} }
break; break;
case VAR_LOCAL: case VAR_LOCAL:
if (id >= current_locals_count) { if (id >= current_locals_count) {
ip_failure(saved_current_ip, mod_id, "local var index is out of range"); ip_failure(saved_current_ip, bf, "local var index is out of range");
} }
break; break;
case VAR_ARGUMENT: case VAR_ARGUMENT:
if (id >= current_args_count) { if (id >= current_args_count) {
ip_failure(saved_current_ip, mod_id, ip_failure(saved_current_ip, bf, "argument var index is out of range");
"argument var index is out of range");
} }
break; break;
case VAR_CLOSURE: case VAR_CLOSURE:
if (!is_in_closure) { if (!is_in_closure) {
ip_failure(saved_current_ip, mod_id, ip_failure(saved_current_ip, bf,
"can't access closure vars outside of closure"); "can't access closure vars outside of closure");
} }
// NOTE: impossible to properly check bounds there // NOTE: impossible to properly check bounds there
@ -89,13 +85,13 @@ void analyze(uint32_t mod_id) {
}; };
// add publics // add publics
to_visit_func.reserve(bf->public_symbols_number); to_visit_func.reserve(bf->public_symbols_number + to_visit_func.size());
for (size_t i = 0; i < bf->public_symbols_number; ++i) { for (size_t i = 0; i < bf->public_symbols_number; ++i) {
func_to_visit_push(get_public_offset_safe(bf, i)); func_to_visit_push(get_public_offset_safe(bf, i));
} }
if (to_visit_func.size() == 0) { if (to_visit_func.size() == 0) {
failure("no public symbols detected"); failure("no public symbols detected\n");
} }
while (true) { while (true) {
@ -112,7 +108,8 @@ void analyze(uint32_t mod_id) {
if (to_visit_jmp.empty()) { if (to_visit_jmp.empty()) {
current_begin_counter = nullptr; current_begin_counter = nullptr;
if (func_end_found != 1) { if (func_end_found != 1) {
failure("each function should have exactly one end"); failure("each function should have exactly one end (%zu found)\n",
func_end_found);
} }
continue; continue;
} }
@ -121,12 +118,11 @@ void analyze(uint32_t mod_id) {
} }
if (ip >= bf->code_ptr + bf->code_size) { if (ip >= bf->code_ptr + bf->code_size) {
ip_safe_failure(ip, mod_id, ip_safe_failure(ip, bf, "instruction pointer is out of range (>= size)");
"instruction pointer is out of range (>= size)");
} }
if (ip < bf->code_ptr) { if (ip < bf->code_ptr) {
ip_safe_failure(ip, mod_id, "instruction pointer is out of range (< 0)"); ip_safe_failure(ip, bf, "instruction pointer is out of range (< 0)");
} }
current_ip = ip; current_ip = ip;
@ -134,18 +130,18 @@ void analyze(uint32_t mod_id) {
#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);
std::cout << '\n';
#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 &&
cmd != Cmd::CBEGIN) { cmd != Cmd::CBEGIN) {
ip_failure(saved_current_ip, mod_id, ip_failure(saved_current_ip, bf, "function does not start with begin");
"function does not start with begin");
} }
if (visited[current_ip - bf->code_ptr] == NOT_VISITED) { if (visited[current_ip - bf->code_ptr] == NOT_VISITED) {
ip_failure(saved_current_ip, mod_id, "not visited command"); ip_failure(saved_current_ip, bf, "not visited command");
} }
current_stack_depth = visited[current_ip - bf->code_ptr]; current_stack_depth = visited[current_ip - bf->code_ptr];
@ -161,7 +157,7 @@ void analyze(uint32_t mod_id) {
case Cmd::BINOP: case Cmd::BINOP:
current_stack_depth -= 2; current_stack_depth -= 2;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -175,21 +171,21 @@ void analyze(uint32_t mod_id) {
ip_read_string_unsafe(&current_ip, bf); ip_read_string_unsafe(&current_ip, bf);
current_stack_depth -= ip_read_int_unsafe(&current_ip); current_stack_depth -= ip_read_int_unsafe(&current_ip);
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::STI: case Cmd::STI:
current_stack_depth -= 2; current_stack_depth -= 2;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::STA: case Cmd::STA:
current_stack_depth -= 3; current_stack_depth -= 3;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -207,19 +203,19 @@ void analyze(uint32_t mod_id) {
break; break;
case Cmd::DUP: case Cmd::DUP:
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
case Cmd::SWAP: case Cmd::SWAP:
if (current_stack_depth < 2) { if (current_stack_depth < 2) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
break; break;
case Cmd::ELEM: case Cmd::ELEM:
current_stack_depth -= 2; current_stack_depth -= 2;
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -234,7 +230,7 @@ void analyze(uint32_t mod_id) {
case Cmd::ST: case Cmd::ST:
check_correct_var(l, ip_read_int_unsafe(&current_ip)); 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, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
break; break;
case Cmd::CJMPz: case Cmd::CJMPz:
@ -244,13 +240,14 @@ void analyze(uint32_t mod_id) {
case Cmd::BEGIN: case Cmd::BEGIN:
case Cmd::CBEGIN: case Cmd::CBEGIN:
if (current_begin_counter != nullptr) { if (current_begin_counter != nullptr) {
ip_failure(saved_current_ip, mod_id, "unexpected function beginning"); ip_failure(saved_current_ip, bf, "unexpected function beginning");
} }
current_args_count = ip_read_int_unsafe(&current_ip); 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_unsafe(&current_ip); current_locals_count = ip_read_int_unsafe(&current_ip);
if (current_locals_count >= std::numeric_limits<uint16_t>::max()) { if (current_locals_count >= std::numeric_limits<uint16_t>::max()) {
ip_failure(saved_current_ip, mod_id, "too many locals in functions"); std::cerr << current_locals_count << " locals" << '\n';
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;
@ -269,12 +266,12 @@ void analyze(uint32_t mod_id) {
++current_stack_depth; ++current_stack_depth;
// if (closure_offset >= bf->code_size) { // if (closure_offset >= bf->code_size) {
// ip_failure(saved_current_ip, mod_id, "jump/call out of file"); // ip_failure(saved_current_ip, bf, "jump/call out of file");
// } // }
// NOTE: is not always true // NOTE: is not always true
// if (!is_command_name(bf->code_ptr + closure_offset, bf, Cmd::CBEGIN)) { // if (!is_command_name(bf->code_ptr + closure_offset, bf, Cmd::CBEGIN)) {
// ip_failure(saved_current_ip, mod_id, "closure should point to // ip_failure(saved_current_ip, bf, "closure should point to
// cbegin"); // cbegin");
// } // }
} break; } break;
@ -282,7 +279,7 @@ void analyze(uint32_t mod_id) {
uint args_count = ip_read_int_unsafe(&current_ip); 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, mod_id, "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
@ -292,29 +289,29 @@ void analyze(uint32_t mod_id) {
uint args_count = ip_read_int_unsafe(&current_ip); 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, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
if ((int)call_offset >= bf->code_size) { if ((int)call_offset >= bf->code_size) {
ip_failure(saved_current_ip, mod_id, "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)) { if (!is_command_name(bf->code_ptr + call_offset, bf, Cmd::BEGIN)) {
ip_failure(saved_current_ip, mod_id, "call should point to 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, mod_id, "wrong call argument count"); ip_failure(saved_current_ip, bf, "wrong call argument count");
} }
} break; } break;
case Cmd::TAG: case Cmd::TAG:
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
break; break;
case Cmd::ARRAY: case Cmd::ARRAY:
if (current_stack_depth < 1) { if (current_stack_depth < 1) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
break; break;
case Cmd::FAIL: case Cmd::FAIL:
@ -322,25 +319,31 @@ void analyze(uint32_t mod_id) {
break; break;
case Cmd::LINE: case Cmd::LINE:
break; break;
// case Cmd::CALLF: { case Cmd::BUILTIN: {
// // TODO: find link to real function and replace call (need to save all std::cout << "builtin\n";
// // modules in one space) <- optimization // TODO: find link to real function and replace call (need to save all
// modules in one space) <- optimization
// ip_read_int_unsafe(&current_ip); // function name (str) size_t id = ip_read_int_unsafe(&current_ip); // builtin id
// uint args_count = ip_read_int_unsafe(&current_ip);
// current_stack_depth -= args_count; if (id >= BUILTIN_NONE) {
// if (current_stack_depth < 0) { ip_failure(saved_current_ip, bf, "undefined builtin id");
// ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); }
// }
// ++current_stack_depth; uint args_count = ip_read_int_unsafe(&current_ip);
// } break; current_stack_depth -= args_count;
if (current_stack_depth < 0) {
ip_failure(saved_current_ip, bf, "not enough elements in stack");
}
++current_stack_depth;
} break;
case Cmd::PATT: case Cmd::PATT:
--current_stack_depth; --current_stack_depth;
if (l == CMD_PATT_STR) { if (l == CMD_PATT_STR) {
--current_stack_depth; --current_stack_depth;
} }
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
++current_stack_depth; ++current_stack_depth;
break; break;
@ -352,32 +355,31 @@ void analyze(uint32_t mod_id) {
// case Cmd::Llength: // case Cmd::Llength:
// case Cmd::Lstring: // case Cmd::Lstring:
// if (current_stack_depth < 1) { // if (current_stack_depth < 1) {
// ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); // ip_failure(saved_current_ip, bf, "not enough elements in stack");
// } // }
// break; // break;
// case Cmd::Barray: // case Cmd::Barray:
// current_stack_depth -= ip_read_int_unsafe(&current_ip); // 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, mod_id, "not enough elements in stack"); // ip_failure(saved_current_ip, bf, "not enough elements in stack");
// } // }
// ++current_stack_depth; // ++current_stack_depth;
// break; // break;
case Cmd::EXIT: case Cmd::EXIT:
ip_failure(saved_current_ip, mod_id, ip_failure(saved_current_ip, bf,
"exit should be unreachable"); // NOTE: not sure "exit should be unreachable"); // NOTE: not sure
break; break;
case Cmd::_UNDEF_: case Cmd::_UNDEF_:
ip_failure(saved_current_ip, mod_id, "undefined command"); ip_failure(saved_current_ip, bf, "undefined command");
break; break;
} }
if (current_begin_counter == nullptr) { if (current_begin_counter == nullptr) {
ip_failure(saved_current_ip, mod_id, ip_failure(saved_current_ip, bf, "function does not start with begin");
"function does not start with begin");
} }
if (current_stack_depth < 0) { if (current_stack_depth < 0) {
ip_failure(saved_current_ip, mod_id, "not enough elements in stack"); ip_failure(saved_current_ip, bf, "not enough elements in stack");
} }
*current_begin_counter = *current_begin_counter =
@ -404,7 +406,7 @@ void analyze(uint32_t mod_id) {
uint jmp_p = ip_read_int_unsafe(&current_ip); uint jmp_p = ip_read_int_unsafe(&current_ip);
if ((int)jmp_p >= bf->code_size) { if ((int)jmp_p >= bf->code_size) {
// NOTE: maybe also should check that > begin (?) // NOTE: maybe also should check that > begin (?)
ip_failure(saved_current_ip, mod_id, "jump/call out of file"); ip_failure(saved_current_ip, bf, "jump/call out of file");
} }
if (is_call) { if (is_call) {
func_to_visit_push(jmp_p); func_to_visit_push(jmp_p);
@ -415,7 +417,7 @@ void analyze(uint32_t mod_id) {
} }
case Cmd::_UNDEF_: case Cmd::_UNDEF_:
ip_failure(saved_current_ip, mod_id, "undefined command"); ip_failure(saved_current_ip, bf, "undefined command");
break; break;
default: default:

View file

@ -42,42 +42,32 @@ int main(int argc, char **argv) {
} }
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
std::cerr << "- read code file" << std::endl; std::cout << "- read code file" << std::endl;
#endif #endif
Bytefile *f = read_file(argv[2]); Bytefile *f = read_file(argv[2]);
if (do_print) { if (do_print) {
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
std::cerr << "- print code file" << std::endl; std::cout << "- print code file" << std::endl;
#endif #endif
print_file(*f, std::cout); print_file(*f, std::cout);
free(f);
} }
if (do_verification || do_interpretation) { if (do_verification || do_interpretation) {
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
std::cerr << "- init stack" << std::endl; std::cout << "- init stack" << std::endl;
#endif #endif
size_t stack[STACK_SIZE]; size_t stack[STACK_SIZE];
run_init(stack); run_init(stack);
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
std::cerr << "- add main module" << std::endl; std::cout << "- run with imports" << std::endl;
#endif #endif
uint main_mod_id = mod_add(f, do_verification); f = run_with_imports(f, argc - 2, argv + 2, do_verification);
if (do_interpretation) {
#ifdef DEBUG_VERSION
std::cerr << "- start interpretation" << std::endl;
#endif
run_mod_rec(main_mod_id, argc - 2, argv + 2, do_verification);
}
} }
mod_cleanup(); free(f);
return 0; return 0;
} }

View file

@ -328,7 +328,7 @@ struct ArgumentLocation {
}; };
/* We need to know the word size to calculate offsets correctly */ /* We need to know the word size to calculate offsets correctly */
constexpr auto word_size = 8; constexpr size_t word_size = 8;
const Register::T &as_register(const Opnd &opnd) { const Register::T &as_register(const Opnd &opnd) {
return std::visit( return std::visit(
@ -1278,7 +1278,7 @@ std::vector<Instr> compile_binop(Env &env, Opr op) {
switch (op) { switch (op) {
case Opr::DIV: case Opr::DIV:
return with_rdx([&x, &y](const auto &rdx) -> std::vector<Instr> { return with_rdx([&x, &y](const auto &rdx) -> std::vector<Instr> {
return {Mov{y, rax}, Sar1{rax}, Binop{"^", rdx, rdx}, return {Mov{y, rax}, Sar1{rax}, Binop{Opr::XOR, rdx, rdx},
Cltd{}, Sar1{x}, IDiv{x}, Cltd{}, Sar1{x}, IDiv{x},
Sal1{rax}, Or1{rax}, Mov{rax, y}}; Sal1{rax}, Or1{rax}, Mov{rax, y}};
}); });
@ -1301,7 +1301,7 @@ std::vector<Instr> compile_binop(Env &env, Opr op) {
return { return {
Binop{Opr::XOR, rax, rax}, Binop{Opr::XOR, rax, rax},
Mov{x, extra}, Mov{x, extra},
Binop{"cmp", extra, y}, Binop{Opr::CMP, extra, y},
Set{suffix(op), Registers::rax}, Set{suffix(op), Registers::rax},
Sal1{rax}, Sal1{rax},
Or1{rax}, Or1{rax},

View file

@ -58,7 +58,7 @@ void run_init(size_t *stack) {
init_state(&s, (void**)stack); init_state(&s, (void**)stack);
} }
void run_prepare_exec(int argc, char **argv) { void set_argc_argv(int argc, char **argv) {
s_push_i(BOX(argc)); s_push_i(BOX(argc));
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
printf("- argc: %i\n", argc); printf("- argc: %i\n", argc);
@ -80,38 +80,7 @@ void run_prepare_exec(int argc, char **argv) {
#endif #endif
} }
void run_mod_rec(uint mod_id, int argc, char **argv, bool do_verification) { void call_Barray(size_t elem_count, char** ip, void** buffer) {
Bytefile* mod = mod_get(mod_id);
#ifdef DEBUG_VERSION
printf("- run mod rec, %i imports\n", mod->imports_number);
#endif
for (size_t i = 0; i < mod->imports_number; ++i) {
const char* import_str = get_import_safe(mod, i);
if (find_mod_loaded(import_str) < 0 && strcmp(import_str, "Std") != 0) { // not loaded
#ifdef DEBUG_VERSION
printf("- mod load <%s>\n", import_str);
#endif
int32_t import_mod = mod_load(import_str, do_verification);
if (import_mod < 0) {
failure("module <%s> not found\n", import_str);
}
#ifdef DEBUG_VERSION
printf("- mod run <%s>\n", import_str);
#endif
run_mod_rec(import_mod, argc, argv, do_verification);
}
}
init_mod_state(mod_id, &s);
init_mod_state_globals(&s);
run_prepare_exec(argc, argv); // args for module main
run_mod(mod_id, argc, argv);
cleanup_state(&s);
}
static inline void call_Barray(size_t elem_count, char** ip, void** buffer) {
// size_t elem_count = ip_read_int(ip); // size_t elem_count = ip_read_int(ip);
bool use_new_buffer = (elem_count > BUFFER_SIZE); bool use_new_buffer = (elem_count > BUFFER_SIZE);
@ -149,17 +118,17 @@ static inline void call_Barray(size_t elem_count, char** ip, void** buffer) {
} }
} }
void run_mod(uint mod_id, int argc, char **argv) { void run_main(Bytefile* bf, int argc, char **argv) {
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
printf("--- module init state ---\n"); printf("--- init state ---\n");
#endif #endif
init_mod_state(mod_id, &s); prepare_state(bf, &s);
void *buffer[BUFFER_SIZE]; void *buffer[BUFFER_SIZE];
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
printf("--- module run begin ---\n"); printf("--- run begin ---\n");
#endif #endif
do { do {
@ -178,9 +147,9 @@ void run_mod(uint mod_id, int argc, char **argv) {
s.instr_ip = s.ip; s.instr_ip = s.ip;
uint8_t x = ip_read_byte(&s.ip), h = (x & 0xF0) >> 4, l = x & 0x0F; uint8_t x = ip_read_byte(&s.ip), h = (x & 0xF0) >> 4, l = x & 0x0F;
#ifdef DEBUG_VERSION // #ifdef DEBUG_VERSION
printf("0x%.8x: %s\n", s.ip - s.bf->code_ptr - 1, read_cmd(s.ip - 1, s.bf)); printf("0x%.8x: %s\n", s.ip - s.bf->code_ptr - 1, read_cmd(s.ip - 1, s.bf));
#endif // #endif
switch (h) { switch (h) {
case CMD_EXIT: case CMD_EXIT:
@ -207,7 +176,7 @@ void run_mod(uint mod_id, int argc, char **argv) {
#undef BINOP_OPR #undef BINOP_OPR
default: default:
s_failure(&s, "invalid opcode"); // %d-%d\n", h, l); s_failure(&s, "interpreter: invalid opcode"); // %d-%d\n", h, l);
break; break;
} }
} }
@ -343,7 +312,7 @@ void run_mod(uint mod_id, int argc, char **argv) {
} break; } break;
default: default:
s_failure(&s, "invalid opcode"); // %d-%d\n", h, l); s_failure(&s, "interpreter: basic, invalid opcode"); // %d-%d\n", h, l);
} }
break; break;
@ -407,7 +376,7 @@ void run_mod(uint mod_id, int argc, char **argv) {
s_failure(&s, "begin should only be called after call"); s_failure(&s, "begin should only be called after call");
} }
#endif #endif
s_enter_f(s.call_ip /*ip from call*/, s.call_module_id, s_enter_f(s.call_ip /*ip from call*/,
s.is_closure_call, args_sz, locals_sz); s.is_closure_call, args_sz, locals_sz);
#ifndef WITH_CHECK #ifndef 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) {
@ -431,7 +400,7 @@ void run_mod(uint mod_id, int argc, char **argv) {
s_failure(&s, "begin should only be called after call"); s_failure(&s, "begin should only be called after call");
} }
#endif #endif
s_enter_f(s.call_ip /*ip from call*/, s.call_module_id, s_enter_f(s.call_ip /*ip from call*/,
s.is_closure_call, args_sz, locals_sz); s.is_closure_call, args_sz, locals_sz);
#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) {
@ -474,7 +443,6 @@ void run_mod(uint mod_id, int argc, char **argv) {
call_happened = true; call_happened = true;
s.is_closure_call = true; s.is_closure_call = true;
s.call_ip = s.ip; s.call_ip = s.ip;
s.call_module_id = s.current_module_id;
s.ip = (char*)Belem(*s_nth(args_count), BOX(0)); // use offset instead ?? s.ip = (char*)Belem(*s_nth(args_count), BOX(0)); // use offset instead ??
break; break;
@ -487,7 +455,6 @@ void run_mod(uint mod_id, int argc, char **argv) {
call_happened = true; call_happened = true;
s.is_closure_call = false; s.is_closure_call = false;
s.call_ip = s.ip; s.call_ip = s.ip;
s.call_module_id = s.current_module_id;
#ifndef WITH_CHECK #ifndef WITH_CHECK
if (call_p >= s.bf->code_size) { if (call_p >= s.bf->code_size) {
@ -527,42 +494,29 @@ void run_mod(uint mod_id, int argc, char **argv) {
// maybe some metainfo should be collected // maybe some metainfo should be collected
break; break;
// case CMD_CTRL_CALLF: { // CALLF %s %d // call external function case CMD_CTRL_BUILTIN: { // BUILTIN %d %d // call builtin
// const char *call_func_name = ip_read_string(&s.ip); size_t builtin_id = ip_read_int(&s.ip);
// size_t args_count = ip_read_int(&s.ip); // args count size_t args_count = ip_read_int(&s.ip); // args count
// if (run_stdlib_func(call_func_name, args_count)) { printf("builtin id: %zu\n", builtin_id);
// // case of stdlib function // #ifndef WITH_CHECK
// break; if (builtin_id >= BUILTIN_NONE) {
// } s_failure(&s, "invalid builtin");
}
// #endif
// if (strcmp(call_func_name, ".array") == 0) { if (builtin_id == BUILTIN_Barray) {
// call_Barray(args_count, &s.ip, buffer); call_Barray(args_count, &s.ip, buffer);
// break; } else {
// } run_stdlib_func(builtin_id, args_count);
}
// struct ModSearchResult func = mod_search_pub_symbol(call_func_name); printf("builtin end\n");
// if (func.mod_file == NULL) { fflush(stdout);
// failure("RUNTIME ERROR: external function <%s> with <%zu> args not found\n", call_func_name, args_count); break;
// } }
// call_happened = true;
// s.is_closure_call = false;
// s.call_ip = s.ip;
// s.call_module_id = s.current_module_id;
// s.current_module_id = func.mod_id;
// s.bf = func.mod_file;
// if (func.symbol_offset >= s.bf->code_size) {
// s_failure(&s, "jump out of file");
// }
// s.ip = s.bf->code_ptr + func.symbol_offset;
// break;
// }
default: default:
s_failure(&s, "invalid opcode"); // %d-%d\n", h, l); s_failure(&s, "interpreter: ctrl, invalid opcode"); // %d-%d\n", h, l);
} }
break; break;
@ -650,7 +604,6 @@ void run_mod(uint mod_id, int argc, char **argv) {
if (!call_happened) { if (!call_happened) {
s.is_closure_call = false; s.is_closure_call = false;
s.call_ip = NULL; s.call_ip = NULL;
s.call_module_id = 0;
} }
if (s.fp == NULL) { if (s.fp == NULL) {

View file

@ -1,4 +1,6 @@
#include <iostream>
extern "C" { extern "C" {
#include "interpreter.h"
#include "module_manager.h" #include "module_manager.h"
#include "runtime_externs.h" #include "runtime_externs.h"
#include "stack.h" #include "stack.h"
@ -9,6 +11,7 @@ extern "C" {
#include "parser.hpp" #include "parser.hpp"
#include <filesystem> #include <filesystem>
#include <map>
#include <optional> #include <optional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
@ -42,146 +45,336 @@ void call_anyarg_func(void (*f)(), size_t n) {
} }
} }
struct ModSymbolPos { // ---
uint32_t mod_id;
size_t offset; struct Offsets {
size_t strings;
size_t globals;
size_t code;
size_t publics_num;
}; };
struct Module { void rewrite_code_with_offsets(Bytefile *bytefile, const Offsets &offsets) {
std::string name; // TODO: globals offsets
char *ip = bytefile->code_ptr;
while (ip - bytefile->code_ptr < bytefile->code_size) {
char *instr_ip = ip;
const auto [cmd, l] = parse_command(&ip, bytefile);
char *read_ip = instr_ip + 1;
char *write_ip = instr_ip + 1;
switch (cmd) {
case Cmd::STRING:
ip_write_int_unsafe(write_ip,
ip_read_int_unsafe(&read_ip) + offsets.strings);
break;
case Cmd::JMP:
case Cmd::CJMPnz:
case Cmd::CJMPz:
case Cmd::CALL:
ip_write_int_unsafe(write_ip,
ip_read_int_unsafe(&read_ip) + offsets.code);
break;
case Cmd::CLOSURE: {
ip_write_int_unsafe(write_ip,
ip_read_int_unsafe(&read_ip) + offsets.code);
size_t args_count = ip_read_int_unsafe(&read_ip);
for (size_t i = 0; i < args_count; ++i) {
uint8_t arg_type = ip_read_byte_unsafe(&read_ip);
if (to_var_category(arg_type) == VAR_GLOBAL) {
write_ip = read_ip;
ip_write_int_unsafe(write_ip,
ip_read_int_unsafe(&read_ip) + offsets.globals);
}
}
break;
}
case Cmd::LD:
case Cmd::ST:
case Cmd::STA:
if (to_var_category(l) == VAR_GLOBAL) {
ip_write_int_unsafe(write_ip,
ip_read_int_unsafe(&read_ip) + offsets.globals);
}
break;
default:
break;
}
}
}
void subst_in_code(Bytefile *bytefile,
const std::unordered_map<std::string, size_t> &publics) {
for (size_t i = 0; i < bytefile->substs_area_size; ++i) {
if (i + sizeof(uint32_t) >= bytefile->substs_area_size) {
failure("substitution %zu offset is out of area\n", i);
}
uint32_t offset = *(uint32_t *)(bytefile->substs_ptr + i);
i += sizeof(uint32_t);
const char *name = bytefile->substs_ptr + i;
i += strlen(name);
#ifdef DEBUG_VERSION
printf("subst: offset %u, name %s\n", offset, name);
#endif
if (i > bytefile->substs_area_size) {
failure("substitution %zu name is out of area\n", i);
}
BUILTIN builtin = id_by_builtin(name);
// NOTE: address is first argument of the call
if (builtin != BUILTIN_NONE) {
uint8_t cmd = ((CMD_CTRL << 4) | CMD_CTRL_BUILTIN);
#ifdef DEBUG_VERSION
printf("set builtin %i, offset %i, cmd %u = (%u << 4) | %u, h = %u, l = "
"%u\n",
builtin, offset, cmd, CMD_CTRL, CMD_CTRL_BUILTIN,
(cmd & 0xF0) >> 4, cmd & 0x0F);
#endif
*(uint8_t *)(bytefile->code_ptr + offset - 1) =
cmd; // set BUILTIN command
*(uint32_t *)(bytefile->code_ptr + offset) = builtin;
continue;
}
const auto it = publics.find(name);
if (it == publics.end()) {
failure("public name for substitution is not found: <%s>\n", name);
}
*(uint32_t *)(bytefile->code_ptr + offset) = it->second;
// TODO: check: +4 to match ?
}
}
Offsets calc_merge_sizes(const std::vector<Bytefile *> &bytefiles) {
Offsets sizes{.strings = 0, .globals = 0, .code = 0, .publics_num = 0};
for (size_t i = 0; i < bytefiles.size(); ++i) {
sizes.strings += bytefiles[i]->stringtab_size;
sizes.globals += bytefiles[i]->global_area_size;
sizes.code += bytefiles[i]->code_size;
sizes.publics_num += bytefiles[i]->public_symbols_number;
}
return sizes;
}
struct MergeResult {
Bytefile *bf; Bytefile *bf;
std::vector<size_t> main_offsets;
}; };
struct ModuleManager { MergeResult merge_files(std::vector<Bytefile *> &&bytefiles) {
std::unordered_map<std::string, uint32_t> loaded_modules; Offsets sizes = calc_merge_sizes(bytefiles);
std::unordered_map<std::string, ModSymbolPos> public_symbols_mods; size_t public_symbols_size = calc_publics_size(sizes.publics_num);
std::vector<Module> modules; Bytefile *result =
std::vector<std::filesystem::path> search_paths; (Bytefile *)malloc(sizeof(Bytefile) + sizes.strings + sizes.code +
}; public_symbols_size); // globals are on the stack
static ModuleManager manager; // collect publics
// TODO: add publics + updat name offsets too ?())
std::unordered_map<std::string, size_t> publics;
std::vector<size_t> main_offsets;
{
size_t code_offset = 0;
for (size_t i = 0; i < bytefiles.size(); ++i) {
#ifdef DEBUG_VERSION
printf("bytefile <%zu>\n", i);
#endif
for (size_t j = 0; j < bytefiles[i]->public_symbols_number; ++j) {
#ifdef DEBUG_VERSION
printf("symbol <%zu>:<%zu>\n", i, j);
#endif
const char *name = get_public_name_unsafe(bytefiles[i], j);
size_t offset = get_public_offset_unsafe(bytefiles[i], j) + code_offset;
uint32_t mod_add_impl(Bytefile *bf, bool do_verification,
std::optional<const char *> name = std::nullopt) {
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
std::cerr << "- add module (impl) '" << std::string{name ? *name : ""} printf("symbol %s : %zu (code offset %zu)\n", name, offset,
<< "'\n"; code_offset);
#endif #endif
uint32_t id = manager.modules.size(); if (strcmp(name, "main") == 0) {
manager.modules.push_back({.name = name ? *name : "", .bf = bf}); main_offsets.push_back(offset);
for (size_t i = 0; i < bf->public_symbols_number; ++i) { } else if (!publics.insert({name, offset}).second) {
const char *public_name = get_public_name_safe(bf, i); failure("public name found more then once: %s", name);
}
}
code_offset += bytefiles[i]->code_size;
}
}
// init result
result->code_size = sizes.code;
result->stringtab_size = sizes.strings;
result->global_area_size = sizes.globals;
result->substs_area_size = 0;
result->imports_number = 0;
result->public_symbols_number = sizes.publics_num;
result->main_offset = 0; // TODO: save al main offsets in some way (?)
result->public_ptr = (int *)result->buffer;
result->string_ptr = (char *)result->public_ptr + public_symbols_size;
result->code_ptr = result->string_ptr + result->stringtab_size;
result->imports_ptr = NULL;
result->global_ptr = NULL;
result->substs_ptr = NULL;
// update & merge code segments
Offsets offsets{.strings = 0, .globals = 0, .code = 0, .publics_num = 0};
// REMOVE printf("merge bytefiles\n");
for (size_t i = 0; i < bytefiles.size(); ++i) {
// REMOVE printf("rewrite offsets %zu\n", i);
rewrite_code_with_offsets(bytefiles[i], offsets);
// REMOVE printf("subst in code %zu\n", i);
subst_in_code(bytefiles[i], publics);
size_t publics_offset = calc_publics_size(offsets.publics_num);
// copy data to merged file
memcpy(result->string_ptr + offsets.strings, bytefiles[i]->string_ptr,
bytefiles[i]->stringtab_size);
memcpy(result->code_ptr + offsets.code, bytefiles[i]->code_ptr,
bytefiles[i]->code_size);
memcpy((char *)result->public_ptr + publics_offset,
(char *)bytefiles[i]->public_ptr,
calc_publics_size(
bytefiles[i]->public_symbols_number)); // TODO: recalc publics:
// offsets, strings
// update offsets
offsets.strings += bytefiles[i]->stringtab_size;
offsets.globals += bytefiles[i]->global_area_size;
offsets.code += bytefiles[i]->code_size;
offsets.publics_num += bytefiles[i]->public_symbols_number;
free(bytefiles[i]);
}
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
std::cerr << "- load public " << public_name << "\n"; std::cout << "- merged file:\n";
print_file(*result, std::cout);
#endif #endif
size_t public_offset = get_public_offset_safe(bf, i); return {result, main_offsets};
if (strcmp(public_name, "main") == 0) {
bf->main_offset = public_offset;
} else if (!manager.public_symbols_mods
.insert(
{public_name, {.mod_id = id, .offset = public_offset}})
.second) {
failure("public symbol '%s' loaded more then once\n",
get_public_name_safe(bf, i));
}
}
if (name) {
manager.loaded_modules.insert({*name, id});
}
if (do_verification) {
analyze(id);
}
return id;
} }
uint32_t path_mod_load(const char *name, std::filesystem::path &&path, // ---
bool do_verification) {
Bytefile *path_mod_load(const char *name, std::filesystem::path &&path) {
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
std::cerr << "- module path load '" << name << "'\n"; std::cout << "- module path load '" << name << "'\n";
#endif #endif
Bytefile *module = read_file(path.c_str()); return read_file(path.c_str());
return mod_add_impl(module, do_verification, name);
} }
static std::vector<std::filesystem::path> search_paths;
extern "C" { extern "C" {
void mod_cleanup() { void mod_add_search_path(const char *path) { search_paths.emplace_back(path); }
for (auto &mod : manager.modules) {
free(mod.bf);
}
}
void mod_add_search_path(const char *path) { Bytefile *mod_load(const char *name) {
manager.search_paths.emplace_back(path);
}
const char *mod_get_name(uint32_t id) {
if (id > manager.modules.size()) {
failure("module id is out of range\n");
}
return manager.modules[id].name.c_str();
}
Bytefile *mod_get(uint32_t id) {
if (id > manager.modules.size()) {
failure("module id is out of range\n");
}
return manager.modules[id].bf;
}
int32_t find_mod_loaded(const char *name) {
auto it = manager.loaded_modules.find(name);
// module already loaded
if (it != manager.loaded_modules.end()) {
return it->second;
}
return -1;
}
int32_t mod_load(const char *name, bool do_verification) {
std::string full_name = std::string{name} + ".bc"; std::string full_name = std::string{name} + ".bc";
auto it = manager.loaded_modules.find(name);
// module already loaded
if (it != manager.loaded_modules.end()) {
return it->second;
}
if (std::filesystem::exists(full_name)) { if (std::filesystem::exists(full_name)) {
return path_mod_load(name, full_name, do_verification); return path_mod_load(name, full_name);
} }
for (const auto &dir_path : manager.search_paths) { for (const auto &dir_path : search_paths) {
auto path = dir_path / full_name; auto path = dir_path / full_name;
if (std::filesystem::exists(path)) { if (std::filesystem::exists(path)) {
return path_mod_load(name, std::move(path), do_verification); return path_mod_load(name, std::move(path));
} }
} }
return -1; return NULL;
} }
uint32_t mod_add(Bytefile *module, bool do_verification) { } // extern "C"
// uint32_t mod_add(Bytefile *module, bool do_verification) {
// #ifdef DEBUG_VERSION
// std::cout << "- add module, no name\n";
// #endif
// return mod_add_impl(module, do_verification);
// }
// ModSearchResult mod_search_pub_symbol(const char *name) {
// auto it = manager.public_symbols_mods.find(name);
// if (it == manager.public_symbols_mods.end()) {
// return {.symbol_offset = 0, .mod_id = 0, .mod_file = NULL};
// }
// return {
// .symbol_offset = it->second.offset,
// .mod_id = it->second.mod_id,
// .mod_file = mod_get(it->second.mod_id),
// };
// }
void mod_load_rec(Bytefile *mod,
std::unordered_map<std::string, Bytefile *> &loaded,
std::vector<Bytefile *> &loaded_ord) {
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
std::cerr << "- add module, no name\n"; printf("- run mod rec, %i imports\n", mod->imports_number);
#endif #endif
return mod_add_impl(module, do_verification); for (size_t i = 0; i < mod->imports_number; ++i) {
const char *import_str = get_import_safe(mod, i);
if (loaded.count(import_str) == 0 &&
strcmp(import_str, "Std") != 0) { // not loaded
#ifdef DEBUG_VERSION
printf("- mod load <%s>\n", import_str);
#endif
Bytefile *import_mod = mod_load(import_str); // TODO
if (import_mod == NULL) {
failure("module <%s> not found\n", import_str);
}
loaded.insert({import_str, import_mod});
mod_load_rec(import_mod, loaded, loaded_ord);
// loaded_ord.push_back(import_mod);
}
}
loaded_ord.push_back(mod);
} }
ModSearchResult mod_search_pub_symbol(const char *name) { MergeResult load_with_imports(Bytefile *root, bool do_verification) {
auto it = manager.public_symbols_mods.find(name); std::unordered_map<std::string, Bytefile *> loaded;
if (it == manager.public_symbols_mods.end()) { std::vector<Bytefile *> loaded_ord;
return {.symbol_offset = 0, .mod_id = 0, .mod_file = NULL}; mod_load_rec(root, loaded, loaded_ord);
MergeResult result = merge_files(std::move(loaded_ord));
if (do_verification) {
// #ifdef DEBUG_VERSION
printf("main offsets count: %zu\n", result.main_offsets.size());
// #endif
analyze(result.bf /*, std::move(result.main_offsets)*/);
}
return result;
}
extern "C" {
Bytefile *run_with_imports(Bytefile *root, int argc, char **argv,
bool do_verification) {
MergeResult result = load_with_imports(root, do_verification);
Bytefile *bf = result.bf;
bf->main_offset = 0;
prepare_state(bf, &s); // NOTE: for push_globals
push_globals(&s);
for (size_t i = 0; i < result.main_offsets.size(); ++i) {
bf->main_offset = result.main_offsets[i];
set_argc_argv(argc, argv); // args for module main
run_main(bf, argc, argv);
} }
return { cleanup_state(&s);
.symbol_offset = it->second.offset,
.mod_id = it->second.mod_id, return bf;
.mod_file = mod_get(it->second.mod_id),
};
} }
} // extern "C"
struct StdFunc { struct StdFunc {
void (*ptr)(); void (*ptr)();
@ -189,75 +382,128 @@ struct StdFunc {
bool is_args = false; // one var for all args bool is_args = false; // one var for all args
bool is_vararg = false; bool is_vararg = false;
}; };
bool run_stdlib_func(const char *name, size_t args_count) {
static const std::unordered_map<std::string, StdFunc> std_func = { BUILTIN id_by_builtin(const char *name) {
{"Luppercase", {.ptr = (void (*)()) & Luppercase, .args_count = 1}}, static const std::unordered_map<std::string, BUILTIN> std_func = {
{"Llowercase", {.ptr = (void (*)()) & Llowercase, .args_count = 1}}, {"Luppercase", BUILTIN_Luppercase},
{"Lassert", {"Llowercase", BUILTIN_Llowercase},
{"Lassert", BUILTIN_Lassert},
{"Lstring", BUILTIN_Lstring},
{"Llength", BUILTIN_Llength},
{"LstringInt", BUILTIN_LstringInt},
{"Lread", BUILTIN_Lread},
{"Lwrite", BUILTIN_Lwrite},
{"LmakeArray", BUILTIN_LmakeArray},
{"LmakeString", BUILTIN_LmakeString},
{"Lstringcat", BUILTIN_Lstringcat},
{"LmatchSubString", BUILTIN_LmatchSubString},
{"Lsprintf", BUILTIN_Lsprintf},
{"Lsubstring", BUILTIN_Lsubstring},
{"Li__Infix_4343", BUILTIN_Li__Infix_4343}, // ++
{"Lclone", BUILTIN_Lclone},
{"Lhash", BUILTIN_Lhash},
{"LtagHash", BUILTIN_LtagHash},
{"Lcompare", BUILTIN_Lcompare},
{"LflatCompare", BUILTIN_LflatCompare},
{"Lfst", BUILTIN_Lfst},
{"Lsnd", BUILTIN_Lsnd},
{"Lhd", BUILTIN_Lhd},
{"Ltl", BUILTIN_Ltl},
{"LreadLine", BUILTIN_LreadLine},
{"Lprintf", BUILTIN_Lprintf},
{"Lfopen", BUILTIN_Lfopen},
{"Lfclose", BUILTIN_Lfclose},
{"Lfread", BUILTIN_Lfread},
{"Lfwrite", BUILTIN_Lfwrite},
{"Lfexists", BUILTIN_Lfexists},
{"Lfprintf", BUILTIN_Lfprintf},
{"Lregexp", BUILTIN_Lregexp},
{"LregexpMatch", BUILTIN_LregexpMatch},
{"Lfailure", BUILTIN_Lfailure},
{"Lsystem", BUILTIN_Lsystem},
{"LgetEnv", BUILTIN_LgetEnv},
{"Lrandom", BUILTIN_Lrandom},
{"Ltime", BUILTIN_Ltime},
{".array", BUILTIN_Barray},
};
auto const it = std_func.find(name);
return it == std_func.end() ? BUILTIN_NONE : it->second;
}
void run_stdlib_func(BUILTIN id, size_t args_count) {
static const std::map<BUILTIN, StdFunc> std_func = {
{BUILTIN_Luppercase, {.ptr = (void (*)()) & Luppercase, .args_count = 1}},
{BUILTIN_Llowercase, {.ptr = (void (*)()) & Llowercase, .args_count = 1}},
{BUILTIN_Lassert,
{.ptr = (void (*)()) & Lassert, .args_count = 2, .is_vararg = true}}, {.ptr = (void (*)()) & Lassert, .args_count = 2, .is_vararg = true}},
{"Lstring", {BUILTIN_Lstring,
{.ptr = (void (*)()) & Lstring, .args_count = 1, .is_args = true}}, {.ptr = (void (*)()) & Lstring, .args_count = 1, .is_args = true}},
{"Llength", {.ptr = (void (*)()) & Llength, .args_count = 1}}, {BUILTIN_Llength, {.ptr = (void (*)()) & Llength, .args_count = 1}},
{"LstringInt", {.ptr = (void (*)()) & LstringInt, .args_count = 1}}, {BUILTIN_LstringInt, {.ptr = (void (*)()) & LstringInt, .args_count = 1}},
{"Lread", {.ptr = (void (*)()) & Lread, .args_count = 0}}, {BUILTIN_Lread, {.ptr = (void (*)()) & Lread, .args_count = 0}},
{"Lwrite", {.ptr = (void (*)()) & Lwrite, .args_count = 1}}, {BUILTIN_Lwrite, {.ptr = (void (*)()) & Lwrite, .args_count = 1}},
{"LmakeArray", {.ptr = (void (*)()) & LmakeArray, .args_count = 1}}, {BUILTIN_LmakeArray, {.ptr = (void (*)()) & LmakeArray, .args_count = 1}},
{"LmakeString", {.ptr = (void (*)()) & LmakeString, .args_count = 1}}, {BUILTIN_LmakeString,
{"Lstringcat", {.ptr = (void (*)()) & LmakeString, .args_count = 1}},
{BUILTIN_Lstringcat,
{.ptr = (void (*)()) & Lstringcat, .args_count = 1, .is_args = true}}, {.ptr = (void (*)()) & Lstringcat, .args_count = 1, .is_args = true}},
{"LmatchSubString", {BUILTIN_LmatchSubString,
{.ptr = (void (*)()) & LmatchSubString, .args_count = 3}}, {.ptr = (void (*)()) & LmatchSubString, .args_count = 3}},
{"Lsprintf", {BUILTIN_Lsprintf,
{.ptr = (void (*)()) & Lsprintf, .args_count = 1, .is_vararg = true}}, {.ptr = (void (*)()) & Lsprintf, .args_count = 1, .is_vararg = true}},
{"Lsubstring", {BUILTIN_Lsubstring,
{.ptr = (void (*)()) & Lsubstring, .args_count = 3, .is_args = true}}, {.ptr = (void (*)()) & Lsubstring, .args_count = 3, .is_args = true}},
{"Li__Infix_4343", {BUILTIN_Li__Infix_4343,
{.ptr = (void (*)()) & Li__Infix_4343, {.ptr = (void (*)()) & Li__Infix_4343,
.args_count = 2, .args_count = 2,
.is_args = true}}, // ++ .is_args = true}}, // ++
{"Lclone", {BUILTIN_Lclone,
{.ptr = (void (*)()) & Lclone, .args_count = 1, .is_args = true}}, {.ptr = (void (*)()) & Lclone, .args_count = 1, .is_args = true}},
{"Lhash", {.ptr = (void (*)()) & Lhash, .args_count = 1}}, {BUILTIN_Lhash, {.ptr = (void (*)()) & Lhash, .args_count = 1}},
{"LtagHash", {.ptr = (void (*)()) & LtagHash, .args_count = 1}}, {BUILTIN_LtagHash, {.ptr = (void (*)()) & LtagHash, .args_count = 1}},
{"Lcompare", {.ptr = (void (*)()) & Lcompare, .args_count = 2}}, {BUILTIN_Lcompare, {.ptr = (void (*)()) & Lcompare, .args_count = 2}},
{"LflatCompare", {.ptr = (void (*)()) & LflatCompare, .args_count = 2}}, {BUILTIN_LflatCompare,
{"Lfst", {.ptr = (void (*)()) & Lfst, .args_count = 1}}, {.ptr = (void (*)()) & LflatCompare, .args_count = 2}},
{"Lsnd", {.ptr = (void (*)()) & Lsnd, .args_count = 1}}, {BUILTIN_Lfst, {.ptr = (void (*)()) & Lfst, .args_count = 1}},
{"Lhd", {.ptr = (void (*)()) & Lhd, .args_count = 1}}, {BUILTIN_Lsnd, {.ptr = (void (*)()) & Lsnd, .args_count = 1}},
{"Ltl", {.ptr = (void (*)()) & Ltl, .args_count = 1}}, {BUILTIN_Lhd, {.ptr = (void (*)()) & Lhd, .args_count = 1}},
{"LreadLine", {.ptr = (void (*)()) & LreadLine, .args_count = 0}}, {BUILTIN_Ltl, {.ptr = (void (*)()) & Ltl, .args_count = 1}},
{"Lprintf", {BUILTIN_LreadLine, {.ptr = (void (*)()) & LreadLine, .args_count = 0}},
{BUILTIN_Lprintf,
{.ptr = (void (*)()) & Lprintf, .args_count = 1, .is_vararg = true}}, {.ptr = (void (*)()) & Lprintf, .args_count = 1, .is_vararg = true}},
{"Lfopen", {.ptr = (void (*)()) & Lfopen, .args_count = 2}}, {BUILTIN_Lfopen, {.ptr = (void (*)()) & Lfopen, .args_count = 2}},
{"Lfclose", {.ptr = (void (*)()) & Lfclose, .args_count = 1}}, {BUILTIN_Lfclose, {.ptr = (void (*)()) & Lfclose, .args_count = 1}},
{"Lfread", {.ptr = (void (*)()) & Lfread, .args_count = 1}}, {BUILTIN_Lfread, {.ptr = (void (*)()) & Lfread, .args_count = 1}},
{"Lfwrite", {.ptr = (void (*)()) & Lfwrite, .args_count = 2}}, {BUILTIN_Lfwrite, {.ptr = (void (*)()) & Lfwrite, .args_count = 2}},
{"Lfexists", {.ptr = (void (*)()) & Lfexists, .args_count = 1}}, {BUILTIN_Lfexists, {.ptr = (void (*)()) & Lfexists, .args_count = 1}},
{"Lfprintf", {BUILTIN_Lfprintf,
{.ptr = (void (*)()) & Lfprintf, .args_count = 2, .is_vararg = true}}, {.ptr = (void (*)()) & Lfprintf, .args_count = 2, .is_vararg = true}},
{"Lregexp", {.ptr = (void (*)()) & Lregexp, .args_count = 1}}, {BUILTIN_Lregexp, {.ptr = (void (*)()) & Lregexp, .args_count = 1}},
{"LregexpMatch", {.ptr = (void (*)()) & LregexpMatch, .args_count = 3}}, {BUILTIN_LregexpMatch,
{"Lfailure", {.ptr = (void (*)()) & LregexpMatch, .args_count = 3}},
{BUILTIN_Lfailure,
{.ptr = (void (*)()) & Lfailure, .args_count = 1, .is_vararg = true}}, {.ptr = (void (*)()) & Lfailure, .args_count = 1, .is_vararg = true}},
{"Lsystem", {.ptr = (void (*)()) & Lsystem, .args_count = 1}}, {BUILTIN_Lsystem, {.ptr = (void (*)()) & Lsystem, .args_count = 1}},
{"LgetEnv", {.ptr = (void (*)()) & LgetEnv, .args_count = 1}}, {BUILTIN_LgetEnv, {.ptr = (void (*)()) & LgetEnv, .args_count = 1}},
{"Lrandom", {.ptr = (void (*)()) & Lrandom, .args_count = 1}}, {BUILTIN_Lrandom, {.ptr = (void (*)()) & Lrandom, .args_count = 1}},
{"Ltime", {.ptr = (void (*)()) & Ltime, .args_count = 0}}, {BUILTIN_Ltime, {.ptr = (void (*)()) & Ltime, .args_count = 0}},
}; };
// some functions do use on args pointer // some functions do use on args pointer
const auto it = std_func.find(name); const auto it = std_func.find(id);
if (it == std_func.end()) { if (it == std_func.end()) {
return false; failure("RUNTIME ERROR: stdlib function <%u> not found\n", id);
} }
// TODO: move to bytecode verifier // TODO: move to bytecode verifier
if ((!it->second.is_vararg && it->second.args_count != args_count) || if ((!it->second.is_vararg && it->second.args_count != args_count) ||
it->second.args_count > args_count) { it->second.args_count > args_count) {
failure("RUNTIME ERROR: stdlib function <%s> argument count <%zu> is not " failure("RUNTIME ERROR: stdlib function <%u> argument count <%zu> is not "
"expected (expected is <%s%zu>)\n", "expected (expected is <%s%zu>)\n",
name, it->second.args_count, it->second.is_vararg ? ">=" : "=", id, it->second.args_count, it->second.is_vararg ? ">=" : "=",
args_count); args_count);
} }
@ -268,7 +514,4 @@ bool run_stdlib_func(const char *name, size_t args_count) {
} else { } else {
call_anyarg_func<20>(it->second.ptr, args_count); call_anyarg_func<20>(it->second.ptr, args_count);
} }
return true;
} }
} // extern "C"

View file

@ -72,6 +72,8 @@ Bytefile *read_file(const char *fname) {
char *file_begin = (char *)file + additional_size; char *file_begin = (char *)file + additional_size;
char *file_end = file_begin + size; char *file_end = file_begin + size;
size_t buffer_size = size + additional_size - sizeof(Bytefile);
if (file == 0) { if (file == 0) {
failure("unable to allocate memory to store file data\n"); failure("unable to allocate memory to store file data\n");
} }
@ -85,7 +87,7 @@ Bytefile *read_file(const char *fname) {
fclose(f); fclose(f);
size_t imports_size = file->imports_number * sizeof(int); size_t imports_size = file->imports_number * sizeof(int);
size_t public_symbols_size = file->public_symbols_number * 2 * sizeof(int); size_t public_symbols_size = calc_publics_size(file->public_symbols_number);
size_t strings_buffer_offset = public_symbols_size + imports_size; size_t strings_buffer_offset = public_symbols_size + imports_size;
if (file->buffer + strings_buffer_offset >= file_end) { if (file->buffer + strings_buffer_offset >= file_end) {
@ -98,7 +100,7 @@ Bytefile *read_file(const char *fname) {
size_t substs_buffer_offset = strings_buffer_offset + file->stringtab_size; size_t substs_buffer_offset = strings_buffer_offset + file->stringtab_size;
file->substs_ptr = file->buffer + substs_buffer_offset; file->substs_ptr = file->buffer + substs_buffer_offset;
if ((char *)file->substs_ptr + file->substs_area_size > file_end) { if (file->substs_ptr + file->substs_area_size > file_end) {
failure("substitutions table is out of the file size\n"); failure("substitutions table is out of the file size\n");
} }
@ -106,7 +108,9 @@ Bytefile *read_file(const char *fname) {
// file->string_ptr[file->stringtab_size - 1] != 0) { // file->string_ptr[file->stringtab_size - 1] != 0) {
// failure("strings table is not zero-ended\n"); // failure("strings table is not zero-ended\n");
// } // }
file->code_size = size - substs_buffer_offset - file->substs_area_size; file->code_ptr = file->substs_ptr + file->substs_area_size;
// file->code_size = size - substs_buffer_offset - file->substs_area_size;
file->code_size = buffer_size - (file->code_ptr - file->buffer);
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) {
@ -116,144 +120,11 @@ Bytefile *read_file(const char *fname) {
file->imports_ptr = (int *)file->buffer; file->imports_ptr = (int *)file->buffer;
file->public_ptr = (int *)(file->buffer + imports_size); file->public_ptr = (int *)(file->buffer + imports_size);
file->global_ptr = NULL; // is allocated on module run on stack file->global_ptr = NULL; // is allocated on module run on stack
file->code_ptr = file->string_ptr + file->stringtab_size;
// file->global_ptr = (int*) calloc (file->global_area_size, sizeof (int)); // file->global_ptr = (int*) calloc (file->global_area_size, sizeof (int));
return file; return file;
} }
struct Offsets {
size_t strings;
size_t globals;
size_t code;
};
void rewrite_code_with_offsets(Bytefile *bytefile, const Offsets &offsets) {
char *ip = bytefile->code_ptr;
while (ip - bytefile->code_ptr < bytefile->code_size) {
const auto [cmd, l] = parse_command(&ip, bytefile);
char *cmd_ip = ip;
switch (cmd) {
case Cmd::STRING:
ip_write_int_unsafe(cmd_ip, ip_read_int_unsafe(&ip) +
offsets.strings); // TODO: check
break;
case Cmd::JMP:
case Cmd::CJMPnz:
case Cmd::CJMPz:
case Cmd::CLOSURE:
case Cmd::CALL:
ip_write_int_unsafe(cmd_ip, ip_read_int_unsafe(&ip) +
offsets.code); // TODO: check
break;
default:
break;
}
}
}
void subst_in_code(Bytefile *bytefile,
const std::unordered_map<std::string, size_t> &publics) {
for (size_t i = 0; i < bytefile->substs_area_size;) {
if (i + sizeof(uint32_t) >= bytefile->substs_area_size) {
failure("substitution %zu offset is out of area", i);
}
uint32_t offset = *(uint32_t *)(bytefile->substs_ptr + i);
i += sizeof(uint32_t);
const char *name = bytefile->substs_ptr + i;
i += strlen(name);
if (i > bytefile->substs_area_size) {
failure("substitution %zu name is out of area", i);
}
const auto it = publics.find(name);
if (it == publics.end()) {
failure("public name for substitution is not found: %s", name);
}
*(uint32_t *)(bytefile->code_ptr + offset) = it->second;
// TODO: check: +4 to match ?
}
}
Offsets calc_merge_sizes(const std::vector<Bytefile *> &bytefiles) {
Offsets sizes{.strings = 0, .globals = 0, .code = 0};
for (size_t i = 0; i < bytefiles.size(); ++i) {
sizes.strings += bytefiles[i]->stringtab_size;
sizes.strings += bytefiles[i]->global_area_size;
sizes.strings += bytefiles[i]->code_size;
}
return sizes;
}
Bytefile *merge_files(std::vector<Bytefile *> &&bytefiles) {
Offsets sizes = calc_merge_sizes(bytefiles);
Bytefile *result = (Bytefile *)malloc(sizeof(Bytefile) + sizes.strings +
sizes.code); // globals - on stack
// collect publics
std::unordered_map<std::string, size_t> publics;
std::vector<size_t> main_offsets;
{
size_t code_offset = 0;
for (size_t i = 0; i < bytefiles.size(); ++i) {
for (size_t j = 0; j < bytefiles[i]->public_symbols_number; ++j) {
const char *name = get_public_name_unsafe(bytefiles[i], j);
size_t offset =
get_public_name_offset_unsafe(bytefiles[i], j) + code_offset;
if (strcmp(name, "main") == 0) {
main_offsets.push_back(offset);
} else if (!publics.insert({name, offset}).second) {
failure("public name found more then once: %s", name);
}
}
code_offset += bytefiles[i]->code_size;
}
}
// init result
result->code_size = sizes.code;
result->stringtab_size = sizes.strings;
result->global_area_size = sizes.globals;
result->substs_area_size = 0;
result->imports_number = 0;
result->public_symbols_number = 0;
result->main_offset = 0; // TODO: save al main offsets in some way (?)
result->string_ptr = result->buffer;
result->imports_ptr = NULL;
result->public_ptr = NULL;
result->code_ptr = result->string_ptr + result->stringtab_size;
result->global_ptr = NULL;
result->substs_ptr = NULL;
// update & merge code segments
Offsets offsets{.strings = 0, .globals = 0, .code = 0};
for (size_t i = 0; i < bytefiles.size(); ++i) {
rewrite_code_with_offsets(bytefiles[i], offsets);
subst_in_code(bytefiles[i], publics);
// copy data to merged file
memcpy(result->string_ptr + offsets.strings, bytefiles[i]->string_ptr,
bytefiles[i]->stringtab_size);
memcpy(result->code_ptr + offsets.code, bytefiles[i]->code_ptr,
bytefiles[i]->code_size);
// update offsets
offsets.strings += bytefiles[i]->stringtab_size;
offsets.globals += bytefiles[i]->global_area_size;
offsets.code += bytefiles[i]->code_size;
free(bytefiles[i]);
}
return result;
}
const char *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) "BINOP:" #op, #define OP_TO_STR(id, op) "BINOP:" #op,
@ -349,6 +220,8 @@ const char *command_name(Cmd cmd, int8_t l) {
return "CALLC"; return "CALLC";
case Cmd::CALL: case Cmd::CALL:
return "CALL"; return "CALL";
case Cmd::BUILTIN:
return "BUILTIN";
case Cmd::TAG: case Cmd::TAG:
return "TAG"; return "TAG";
case Cmd::ARRAY: case Cmd::ARRAY:
@ -379,7 +252,7 @@ const char *command_name(Cmd cmd, int8_t l) {
return "_UNDEF_"; return "_UNDEF_";
} }
exit(1); failure("command_name: unexpected command %u", static_cast<uint>(cmd));
} }
// } // extern "C" // } // extern "C"
@ -569,14 +442,14 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
break; break;
default: default:
failure("invalid opcode"); failure("parser: basic, invalid opcode\n");
} }
break; break;
case CMD_LD: // LD %d case CMD_LD: // LD %d
cmd = Cmd::LD; cmd = Cmd::LD;
if (l > sizeof(ldts) / sizeof(char *)) { if (l > sizeof(ldts) / sizeof(char *)) {
failure("wrong ld argument type"); failure("wrong ld argument type\n");
} }
read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf, read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out); out);
@ -584,7 +457,7 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
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\n");
} }
read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf, read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out); out);
@ -592,7 +465,7 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
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\n");
} }
read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf, read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out); out);
@ -633,7 +506,7 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
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_safe(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\n");
} }
print_space<use_out>(out); print_space<use_out>(out);
print_val<use_out>(out, ldts[arg_type]); print_val<use_out>(out, ldts[arg_type]);
@ -677,22 +550,21 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf, read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT>(cmd, l, ip, bf,
out); out);
break; break;
// NOTE: is replaced case CMD_CTRL_BUILTIN: // BUILTIN %d %d // call builtin
// case CMD_CTRL_CALLF: // CALLF %s %d cmd = Cmd::BUILTIN;
// cmd = Cmd::CALLF; read_print_cmd_seq_opt<do_read_args, use_out, ArgT::INT, ArgT::INT>(
// read_print_cmd_seq_opt<do_read_args, use_out, ArgT::STR, ArgT::INT>( cmd, l, ip, bf, out);
// cmd, l, ip, bf, out); break;
// break;
default: default:
failure("invalid opcode"); failure("parser: ctrl, invalid opcode\n");
} }
break; break;
case CMD_PATT: // PATT pats[l] case CMD_PATT: // PATT pats[l]
// {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"} // {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"}
if (l >= sizeof(pats) / sizeof(char *)) { if (l >= sizeof(pats) / sizeof(char *)) {
failure("invalid opcode"); failure("parser: patt, invalid opcode\n");
} }
cmd = Cmd::PATT; cmd = Cmd::PATT;
read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out); read_print_cmd_seq_opt<do_read_args, use_out>(cmd, l, ip, bf, out);
@ -726,12 +598,12 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
// break; // break;
// default: // default:
// failure("invalid opcode"); // failure("parser: bultin, invalid opcode\n");
// } // }
// } break; // } break;
default: default:
failure("invalid opcode"); failure("parser: invalid opcode\n");
} }
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
std::cout << command_name(cmd, l) << '\n'; std::cout << command_name(cmd, l) << '\n';
@ -757,6 +629,7 @@ bool is_command_name(char *ip, const Bytefile *bf, Cmd cmd) {
} }
void print_file_info(const Bytefile &bf, std::ostream &out) { void print_file_info(const Bytefile &bf, std::ostream &out) {
out << "Code size : " << bf.code_size << '\n';
out << "String table size : " << bf.stringtab_size << '\n'; out << "String table size : " << bf.stringtab_size << '\n';
out << "Global area size : " << bf.global_area_size << '\n'; out << "Global area size : " << bf.global_area_size << '\n';
out << "Substitutions area size : " << bf.substs_area_size << '\n'; out << "Substitutions area size : " << bf.substs_area_size << '\n';
@ -774,6 +647,16 @@ void print_file_info(const Bytefile &bf, std::ostream &out) {
<< get_public_offset_safe(&bf, i) << ": " << std::dec << get_public_offset_safe(&bf, i) << ": " << std::dec
<< get_public_name_safe(&bf, i) << '\n'; << get_public_name_safe(&bf, i) << '\n';
} }
out << "Substs :\n";
for (size_t i = 0; i < bf.substs_area_size; i++) {
uint32_t offset = *(uint32_t *)(bf.substs_ptr + i);
i += sizeof(uint32_t);
const char *name = bf.substs_ptr + i;
out << " " << std::setfill('0') << std::setw(8) << std::hex << offset
<< ": " << std::dec << name << '\n';
i += strlen(name);
}
} }
void print_file_code(const Bytefile &bf, std::ostream &out) { void print_file_code(const Bytefile &bf, std::ostream &out) {
@ -786,6 +669,7 @@ void print_file_code(const Bytefile &bf, std::ostream &out) {
out << std::endl; out << std::endl;
if (cmd == Cmd::EXIT) { if (cmd == Cmd::EXIT) {
std::cout << "> EXIT" << std::endl;
break; break;
} }
} }
@ -796,7 +680,7 @@ void print_file(const Bytefile &bf, std::ostream &out) {
out << "Code:\n"; out << "Code:\n";
print_file_code(bf, out); print_file_code(bf, out);
out << "code end\n"; out << "Code end\n";
} }
extern "C" { extern "C" {

View file

@ -19,8 +19,6 @@ void init_state(struct State* s, void** stack) {
s->bf = NULL; s->bf = NULL;
s->current_line = 0; s->current_line = 0;
s->is_closure_call = false; s->is_closure_call = false;
s->current_module_id = 0;
s->call_module_id = 0;
s->ip = NULL; //s->bf->code_ptr; s->ip = NULL; //s->bf->code_ptr;
s->instr_ip = NULL; //s->bf->code_ptr; s->instr_ip = NULL; //s->bf->code_ptr;
s->call_ip = NULL; s->call_ip = NULL;
@ -38,16 +36,13 @@ void init_state(struct State* s, void** stack) {
#endif #endif
} }
void init_mod_state(uint mod_id, struct State* s) { void prepare_state(Bytefile* bf, struct State* s) {
// init module data // init data
s->bf = mod_get(mod_id); s->bf = bf;
s->current_module_id = mod_id;
// clearup from previous executions // clearup from previous executions
s->is_closure_call = false; s->is_closure_call = false;
s->current_module_id = 0;
s->call_module_id = 0;
s->call_ip = NULL; s->call_ip = NULL;
s->current_line = 0; s->current_line = 0;
@ -62,7 +57,7 @@ void init_mod_state(uint mod_id, struct State* s) {
#endif #endif
} }
void init_mod_state_globals(struct State *s) { void push_globals(struct State *s) {
s_pushn_nil(s->bf->global_area_size); s_pushn_nil(s->bf->global_area_size);
s->bf->global_ptr = (void*)__gc_stack_top; s->bf->global_ptr = (void*)__gc_stack_top;

BIN
byterun/test046 Executable file

Binary file not shown.

1
byterun/test046.i Normal file
View file

@ -0,0 +1 @@
I,Std;

2351
byterun/test046.s Normal file

File diff suppressed because it is too large Load diff

490
byterun/test046.sm Normal file
View file

@ -0,0 +1,490 @@
IMPORT ("Std")
PUBLIC ("main")
EXTERN ("Llowercase")
EXTERN ("Luppercase")
EXTERN ("LtagHash")
EXTERN ("LflatCompare")
EXTERN ("LcompareTags")
EXTERN ("LkindOf")
EXTERN ("Ltime")
EXTERN ("Lrandom")
EXTERN ("LdisableGC")
EXTERN ("LenableGC")
EXTERN ("Ls__Infix_37")
EXTERN ("Ls__Infix_47")
EXTERN ("Ls__Infix_42")
EXTERN ("Ls__Infix_45")
EXTERN ("Ls__Infix_43")
EXTERN ("Ls__Infix_62")
EXTERN ("Ls__Infix_6261")
EXTERN ("Ls__Infix_60")
EXTERN ("Ls__Infix_6061")
EXTERN ("Ls__Infix_3361")
EXTERN ("Ls__Infix_6161")
EXTERN ("Ls__Infix_3838")
EXTERN ("Ls__Infix_3333")
EXTERN ("Ls__Infix_58")
EXTERN ("Li__Infix_4343")
EXTERN ("Lcompare")
EXTERN ("Lwrite")
EXTERN ("Lread")
EXTERN ("Lfailure")
EXTERN ("Lfexists")
EXTERN ("Lfwrite")
EXTERN ("Lfread")
EXTERN ("Lfclose")
EXTERN ("Lfopen")
EXTERN ("Lfprintf")
EXTERN ("Lprintf")
EXTERN ("LmakeString")
EXTERN ("Lsprintf")
EXTERN ("LregexpMatch")
EXTERN ("Lregexp")
EXTERN ("Lsubstring")
EXTERN ("LmatchSubString")
EXTERN ("Lstringcat")
EXTERN ("LreadLine")
EXTERN ("Ltl")
EXTERN ("Lhd")
EXTERN ("Lsnd")
EXTERN ("Lfst")
EXTERN ("Lhash")
EXTERN ("Lclone")
EXTERN ("Llength")
EXTERN ("Lstring")
EXTERN ("LmakeArray")
EXTERN ("LstringInt")
EXTERN ("global_sysargs")
EXTERN ("Lsystem")
EXTERN ("LgetEnv")
EXTERN ("Lassert")
LABEL ("main")
BEGIN ("main", 2, 4, [], [], [])
SLABEL ("L1")
LINE (3)
CALL ("Lread", 0, false)
LINE (1)
ST (Global ("n"))
DROP
CONST (3)
DUP
SLABEL ("L11")
DROP
DUP
ST (Local (0))
DROP
DROP
SLABEL ("L13")
LINE (6)
LD (Local (0))
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L14")
JMP ("L7")
SLABEL ("L12")
JMP ("L7")
LABEL ("L7")
CONST (3)
DUP
SLABEL ("L20")
DROP
DUP
ST (Local (0))
DROP
DROP
SLABEL ("L22")
LINE (11)
LD (Local (0))
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L23")
SLABEL ("L21")
JMP ("L17")
LABEL ("L17")
CONST (3)
DUP
SLABEL ("L29")
DROP
DUP
ST (Local (0))
DROP
DROP
SLABEL ("L31")
LINE (15)
LD (Local (0))
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L32")
SLABEL ("L30")
JMP ("L26")
LABEL ("L26")
CONST (1)
CONST (2)
CONST (3)
SEXP ("A", 3)
DUP
SLABEL ("L44")
DUP
TAG ("A", 0)
CJMP ("nz", "L42")
LABEL ("L43")
DROP
JMP ("L41")
LABEL ("L42")
DROP
DROP
SLABEL ("L46")
LINE (19)
CONST (1)
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L47")
JMP ("L35")
SLABEL ("L45")
SLABEL ("L52")
LABEL ("L41")
DUP
DUP
TAG ("A", 3)
CJMP ("nz", "L50")
LABEL ("L51")
DROP
JMP ("L36")
LABEL ("L50")
DUP
CONST (0)
ELEM
DROP
DUP
CONST (1)
ELEM
DROP
DUP
CONST (2)
ELEM
DROP
DROP
DUP
ST (Local (0))
DROP
DROP
SLABEL ("L54")
LINE (20)
LD (Local (0))
DUP
SLABEL ("L60")
DUP
TAG ("A", 3)
CJMP ("nz", "L58")
LABEL ("L59")
DROP
JMP ("L56")
LABEL ("L58")
DUP
CONST (0)
ELEM
DROP
DUP
CONST (1)
ELEM
DROP
DUP
CONST (2)
ELEM
DROP
DROP
DUP
CONST (0)
ELEM
ST (Local (3))
DROP
DUP
CONST (1)
ELEM
ST (Local (2))
DROP
DUP
CONST (2)
ELEM
ST (Local (1))
DROP
DROP
SLABEL ("L62")
LINE (21)
LD (Local (3))
CALL ("Lwrite", 1, false)
DROP
LD (Local (2))
CALL ("Lwrite", 1, false)
DROP
LD (Local (1))
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L63")
SLABEL ("L61")
JMP ("L35")
LABEL ("L56")
FAIL ((20, 24), false)
JMP ("L35")
SLABEL ("L55")
SLABEL ("L53")
JMP ("L35")
LABEL ("L36")
FAIL ((18, 5), false)
JMP ("L35")
LABEL ("L35")
CONST (1)
CONST (2)
CONST (3)
CONST (4)
CONST (5)
SEXP ("A", 5)
DUP
SLABEL ("L83")
DUP
TAG ("A", 0)
CJMP ("nz", "L81")
LABEL ("L82")
DROP
JMP ("L80")
LABEL ("L81")
DROP
DROP
SLABEL ("L85")
LINE (26)
CONST (0)
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L86")
JMP ("L72")
SLABEL ("L84")
SLABEL ("L92")
LABEL ("L80")
DUP
DUP
TAG ("A", 1)
CJMP ("nz", "L90")
LABEL ("L91")
DROP
JMP ("L89")
LABEL ("L90")
DUP
CONST (0)
ELEM
DROP
DROP
DROP
SLABEL ("L94")
LINE (27)
CONST (1)
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L95")
JMP ("L72")
SLABEL ("L93")
SLABEL ("L101")
LABEL ("L89")
DUP
DUP
TAG ("A", 2)
CJMP ("nz", "L99")
LABEL ("L100")
DROP
JMP ("L98")
LABEL ("L99")
DUP
CONST (0)
ELEM
DROP
DUP
CONST (1)
ELEM
DROP
DROP
DROP
SLABEL ("L103")
LINE (28)
CONST (2)
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L104")
JMP ("L72")
SLABEL ("L102")
SLABEL ("L110")
LABEL ("L98")
DUP
DUP
TAG ("A", 3)
CJMP ("nz", "L108")
LABEL ("L109")
DROP
JMP ("L107")
LABEL ("L108")
DUP
CONST (0)
ELEM
DROP
DUP
CONST (1)
ELEM
DROP
DUP
CONST (2)
ELEM
DROP
DROP
DROP
SLABEL ("L112")
LINE (29)
CONST (3)
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L113")
JMP ("L72")
SLABEL ("L111")
SLABEL ("L119")
LABEL ("L107")
DUP
DUP
TAG ("A", 4)
CJMP ("nz", "L117")
LABEL ("L118")
DROP
JMP ("L116")
LABEL ("L117")
DUP
CONST (0)
ELEM
DROP
DUP
CONST (1)
ELEM
DROP
DUP
CONST (2)
ELEM
DROP
DUP
CONST (3)
ELEM
DROP
DROP
DROP
SLABEL ("L121")
LINE (30)
CONST (4)
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L122")
JMP ("L72")
SLABEL ("L120")
SLABEL ("L127")
LABEL ("L116")
DUP
DUP
TAG ("A", 5)
CJMP ("nz", "L125")
LABEL ("L126")
DROP
JMP ("L73")
LABEL ("L125")
DUP
CONST (0)
ELEM
DROP
DUP
CONST (1)
ELEM
DROP
DUP
CONST (2)
ELEM
DROP
DUP
CONST (3)
ELEM
DROP
DUP
CONST (4)
ELEM
DROP
DROP
DROP
SLABEL ("L129")
LINE (31)
CONST (5)
CALL ("Lwrite", 1, false)
DROP
SLABEL ("L130")
SLABEL ("L128")
JMP ("L72")
LABEL ("L73")
FAIL ((25, 5), false)
JMP ("L72")
LABEL ("L72")
LINE (32)
CONST (1)
CONST (2)
CONST (3)
CONST (4)
CONST (5)
SEXP ("A", 5)
CALL ("Llength", 1, false)
CALL ("Lwrite", 1, false)
DROP
LINE (34)
CONST (1)
CONST (2)
CONST (3)
CONST (4)
CONST (5)
SEXP ("A", 5)
CONST (0)
ELEM
CALL ("Lwrite", 1, false)
DROP
LINE (36)
CONST (1)
CONST (2)
CONST (3)
CONST (4)
CONST (5)
SEXP ("A", 5)
CONST (1)
ELEM
CALL ("Lwrite", 1, false)
DROP
LINE (37)
CONST (1)
CONST (2)
CONST (3)
CONST (4)
CONST (5)
SEXP ("A", 5)
CONST (2)
ELEM
CALL ("Lwrite", 1, false)
DROP
LINE (38)
CONST (1)
CONST (2)
CONST (3)
CONST (4)
CONST (5)
SEXP ("A", 5)
CONST (3)
ELEM
CALL ("Lwrite", 1, false)
DROP
LINE (39)
CONST (1)
CONST (2)
CONST (3)
CONST (4)
CONST (5)
SEXP ("A", 5)
CONST (4)
ELEM
CALL ("Lwrite", 1, false)
SLABEL ("L2")
END

14
byterun/xmake.lua Normal file
View file

@ -0,0 +1,14 @@
-- add_rules("mode.debug", "mode.release")
-- add_rules("c++.unity_build")
set_languages("c++20", "c20")
target("byterun")
set_kind("binary")
add_includedirs("include")
add_files("../runtime/runtime.a")
add_files("src/**.cpp", "src/**.c")
remove_files("src/compiler.cpp")
set_warnings("allextra")
set_rundir("$(projectdir)")