mirror of
https://github.com/ProgramSnail/Lama.git
synced 2025-12-05 22:38:44 +00:00
fixes, cleanup, some copies removed
This commit is contained in:
parent
2589f6166f
commit
d90a8cf89f
16 changed files with 373 additions and 666 deletions
2
byterun/.gitignore
vendored
2
byterun/.gitignore
vendored
|
|
@ -1,4 +1,4 @@
|
|||
byterun.exe
|
||||
*.exe
|
||||
byterun
|
||||
|
||||
build/
|
||||
|
|
|
|||
26
byterun/dune
26
byterun/dune
|
|
@ -5,7 +5,7 @@
|
|||
(:main src/cli.cpp)
|
||||
(:parser src/parser.cpp)
|
||||
(:analyzer src/analyzer.cpp)
|
||||
(:obj types.o parser.o interpreter.o)
|
||||
(:obj types.o interpreter.o)
|
||||
(:runtime ../runtime/runtime.a))
|
||||
(mode
|
||||
(promote (until-clean)))
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
(:main src/cli.cpp)
|
||||
(:parser src/parser.cpp)
|
||||
(:analyzer src/analyzer.cpp)
|
||||
(:obj old_types.o old_parser.o old_interpreter.o)
|
||||
(:obj old_types.o old_interpreter.o)
|
||||
(:runtime ../runtime/runtime.a))
|
||||
(mode
|
||||
(promote (until-clean)))
|
||||
|
|
@ -37,17 +37,6 @@
|
|||
(action
|
||||
(run gcc -Iinclude/ -DWITH_CHECK -c %{src} -o %{target})))
|
||||
|
||||
(rule
|
||||
(target parser.o)
|
||||
(deps
|
||||
(:include (source_tree include))
|
||||
(:src src/parser.c)
|
||||
(:runtime ../runtime/runtime.a))
|
||||
(mode
|
||||
(promote (until-clean)))
|
||||
(action
|
||||
(run gcc -Iinclude/ -DWITH_CHECK -c %{src} -o %{target})))
|
||||
|
||||
(rule
|
||||
(target interpreter.o)
|
||||
(deps
|
||||
|
|
@ -70,17 +59,6 @@
|
|||
(action
|
||||
(run gcc -Iinclude/ -c %{src} -o %{target})))
|
||||
|
||||
(rule
|
||||
(target old_parser.o)
|
||||
(deps
|
||||
(:include (source_tree include))
|
||||
(:src src/parser.c)
|
||||
(:runtime ../runtime/runtime.a))
|
||||
(mode
|
||||
(promote (until-clean)))
|
||||
(action
|
||||
(run gcc -Iinclude/ -c %{src} -o %{target})))
|
||||
|
||||
(rule
|
||||
(target old_interpreter.o)
|
||||
(deps
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "parser.h"
|
||||
#include "utils.h"
|
||||
|
||||
void run(Bytefile *bf, int argc, char **argv);
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@
|
|||
DEF(CMD_BINOP_AND, &&) \
|
||||
DEF(CMD_BINOP_OR, ||)
|
||||
|
||||
const char *read_cmd(char *ip);
|
||||
const char *read_cmd(char *ip, const Bytefile *bf);
|
||||
|
||||
Bytefile *read_file(char *fname);
|
||||
|
||||
// void dump_file(FILE *f, bytefile *bf);
|
||||
// Bytefile *read_file(const char *fname);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <ostream>
|
||||
|
||||
extern "C" {
|
||||
#include "parser.h"
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
|
|
@ -46,29 +47,12 @@ enum class Cmd : int8_t {
|
|||
|
||||
Bytefile *read_file(const char *fname);
|
||||
|
||||
static inline int ip_read_int(char **ip, const Bytefile &bf) {
|
||||
if (*ip + sizeof(int) > bf.code_ptr + bf.code_size) {
|
||||
failure("last command is invalid, int parameter can not be read\n");
|
||||
}
|
||||
*ip += sizeof(int);
|
||||
return *(int *)((*ip) - sizeof(int));
|
||||
}
|
||||
|
||||
static inline uint8_t ip_read_byte(char **ip, const Bytefile &bf) {
|
||||
if (*ip + sizeof(char) > bf.code_ptr + bf.code_size) {
|
||||
failure("last command is invalid, byte parameter can not be read\n");
|
||||
}
|
||||
return *(*ip)++;
|
||||
}
|
||||
|
||||
static inline uint8_t ip_read_byte_unsafe(char **ip) { return *(*ip)++; }
|
||||
|
||||
static inline const char *ip_read_string(char **ip, const Bytefile &bf) {
|
||||
return get_string(&bf, ip_read_int(ip, bf));
|
||||
}
|
||||
|
||||
std::pair<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::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);
|
||||
|
|
|
|||
|
|
@ -196,9 +196,11 @@ static inline void s_enter_f(char *rp, bool is_closure_call, auint args_sz,
|
|||
}
|
||||
|
||||
static inline void s_exit_f() {
|
||||
#ifndef WITH_CHECK
|
||||
if (s.fp == NULL) {
|
||||
s_failure(&s, "exit: no func");
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Frame frame = *s.fp;
|
||||
|
||||
|
|
@ -274,13 +276,15 @@ static inline void **var_by_category(enum VarCategory category, size_t id) {
|
|||
#endif
|
||||
var = f_args(s.fp) + (f_args_sz(s.fp) - id - 1);
|
||||
break;
|
||||
case VAR_CLOSURE: // TODO: check that clojure vars are used only in clojures
|
||||
case VAR_CLOSURE:
|
||||
#ifndef WITH_CHECK
|
||||
if (s.fp == NULL) {
|
||||
s_failure(&s, "can't read closure parameter outside of function");
|
||||
}
|
||||
if (s.fp->closure == NULL) {
|
||||
s_failure(&s, "can't read closure parameter not in closure");
|
||||
}
|
||||
#endif
|
||||
if (UNBOXED(s.fp->closure)) {
|
||||
s_failure(&s, "not boxed value expected in closure index");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,12 +69,12 @@ void construct_state(Bytefile *bf, struct State *s, void **stack);
|
|||
void cleanup_state(struct State *state);
|
||||
|
||||
static inline void s_failure(struct State *s, const char *msg) {
|
||||
exec_failure(read_cmd(s->instr_ip), s->current_line,
|
||||
exec_failure(read_cmd(s->instr_ip, s->bf), s->current_line,
|
||||
s->instr_ip - s->bf->code_ptr, msg);
|
||||
}
|
||||
|
||||
static inline void ip_failure(char *ip, Bytefile *bf, const char *msg) {
|
||||
exec_failure(read_cmd(ip), 0, ip - bf->code_ptr, msg);
|
||||
exec_failure(read_cmd(ip, bf), 0, ip - bf->code_ptr, msg);
|
||||
}
|
||||
|
||||
static inline void ip_safe_failure(char *ip, Bytefile *bf, const char *msg) {
|
||||
|
|
@ -99,7 +99,7 @@ static inline enum VarCategory to_var_category(uint8_t category) {
|
|||
return (enum VarCategory)category;
|
||||
}
|
||||
|
||||
enum CMD {
|
||||
enum CMD_TOPLVL {
|
||||
CMD_BINOP = 0,
|
||||
CMD_BASIC,
|
||||
CMD_LD,
|
||||
|
|
@ -112,7 +112,7 @@ enum CMD {
|
|||
};
|
||||
|
||||
enum CMD_BINOPS {
|
||||
CMD_BINOP_ADD = 1, // +
|
||||
CMD_BINOP_ADD = 0, // +
|
||||
CMD_BINOP_SUB, // -
|
||||
CMD_BINOP_MULT, // *
|
||||
CMD_BINOP_DIV, // /
|
||||
|
|
|
|||
|
|
@ -26,28 +26,106 @@ static inline void exec_failure(const char *cmd, int line, aint offset,
|
|||
msg);
|
||||
}
|
||||
|
||||
// --- unsafe versions
|
||||
|
||||
// access data
|
||||
|
||||
/* Gets a string from a string table by an index */
|
||||
static inline const char *get_string(const Bytefile *f, size_t pos) {
|
||||
if (pos >= f->stringtab_size) {
|
||||
failure("strinpg pos is out of range: %zu >= %i\n", pos, f->stringtab_size);
|
||||
}
|
||||
return &f->string_ptr[pos];
|
||||
static inline const char *get_string_unsafe(const Bytefile *bf, size_t pos) {
|
||||
return &bf->string_ptr[pos];
|
||||
}
|
||||
|
||||
/* Gets a name offset for a public symbol */
|
||||
static inline size_t get_public_name_offset_unsafe(const Bytefile *bf,
|
||||
size_t i) {
|
||||
return bf->public_ptr[i * 2];
|
||||
}
|
||||
|
||||
/* Gets a name for a public symbol */
|
||||
static inline const char *get_public_name(const Bytefile *f, size_t i) {
|
||||
if (i >= f->public_symbols_number) {
|
||||
failure("public number is out of range: %zu >= %i\n", i,
|
||||
f->public_symbols_number);
|
||||
}
|
||||
return get_string(f, f->public_ptr[i * 2]);
|
||||
static inline const char *get_public_name_unsafe(const Bytefile *bf, size_t i) {
|
||||
return get_string_unsafe(bf, get_public_name_offset_unsafe(bf, i));
|
||||
}
|
||||
|
||||
/* Gets an offset for a publie symbol */
|
||||
static inline size_t get_public_offset(const Bytefile *f, size_t i) {
|
||||
static inline size_t get_public_offset_unsafe(const Bytefile *bf, size_t i) {
|
||||
return bf->public_ptr[i * 2 + 1];
|
||||
}
|
||||
|
||||
// read from ip
|
||||
|
||||
static inline uint16_t ip_read_half_int_unsafe(char **ip) {
|
||||
*ip += sizeof(uint16_t);
|
||||
return *(uint16_t *)((*ip) - sizeof(uint16_t));
|
||||
}
|
||||
|
||||
static inline int32_t ip_read_int_unsafe(char **ip) {
|
||||
*ip += sizeof(int32_t);
|
||||
return *(int32_t *)((*ip) - sizeof(int32_t));
|
||||
}
|
||||
|
||||
static inline uint8_t ip_read_byte_unsafe(char **ip) { return *(*ip)++; }
|
||||
|
||||
static inline const char *ip_read_string_unsafe(char **ip, const Bytefile *bf) {
|
||||
return get_string_unsafe(bf, ip_read_int_unsafe(ip));
|
||||
}
|
||||
// --- safe versions
|
||||
|
||||
// access data
|
||||
|
||||
/* Gets a string from a string table by an index */
|
||||
static inline const char *get_string_safe(const Bytefile *f, size_t pos) {
|
||||
if (pos >= f->stringtab_size) {
|
||||
failure("string pos is out of range: %zu >= %i\n", pos, f->stringtab_size);
|
||||
}
|
||||
return get_string_unsafe(f, pos);
|
||||
}
|
||||
|
||||
/* Gets a name offset for a public symbol */
|
||||
static inline size_t get_public_name_offset_safe(const Bytefile *f, size_t i) {
|
||||
if (i >= f->public_symbols_number) {
|
||||
failure("public number is out of range: %zu >= %i\n", i,
|
||||
f->public_symbols_number);
|
||||
}
|
||||
return f->public_ptr[i * 2 + 1];
|
||||
return get_public_name_offset_unsafe(f, i);
|
||||
}
|
||||
|
||||
/* Gets a name for a public symbol */
|
||||
static inline const char *get_public_name_safe(const Bytefile *f, size_t i) {
|
||||
return get_string_safe(f, get_public_name_offset_safe(f, i));
|
||||
}
|
||||
|
||||
/* Gets an offset for a publie symbol */
|
||||
static inline size_t get_public_offset_safe(const Bytefile *f, size_t i) {
|
||||
if (i >= f->public_symbols_number) {
|
||||
failure("public number is out of range: %zu >= %i\n", i,
|
||||
f->public_symbols_number);
|
||||
}
|
||||
return get_public_offset_unsafe(f, i);
|
||||
}
|
||||
|
||||
// read from ip
|
||||
|
||||
static inline uint16_t ip_read_half_int_safe(char **ip, const Bytefile *bf) {
|
||||
if (*ip + sizeof(uint16_t) > bf->code_ptr + bf->code_size) {
|
||||
failure("last command is invalid, int parameter can not be read\n");
|
||||
}
|
||||
return ip_read_half_int_unsafe(ip);
|
||||
}
|
||||
|
||||
static inline int32_t ip_read_int_safe(char **ip, const Bytefile *bf) {
|
||||
if (*ip + sizeof(int32_t) > bf->code_ptr + bf->code_size) {
|
||||
failure("last command is invalid, int parameter can not be read\n");
|
||||
}
|
||||
return ip_read_int_unsafe(ip);
|
||||
}
|
||||
|
||||
static inline uint8_t ip_read_byte_safe(char **ip, const Bytefile *bf) {
|
||||
if (*ip + sizeof(char) > bf->code_ptr + bf->code_size) {
|
||||
failure("last command is invalid, byte parameter can not be read\n");
|
||||
}
|
||||
return ip_read_byte_unsafe(ip);
|
||||
}
|
||||
|
||||
static inline const char *ip_read_string_safe(char **ip, const Bytefile *bf) {
|
||||
return get_string_safe(bf, ip_read_int_safe(ip, bf));
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -19,4 +19,11 @@ time ./old_byterun.exe -i Sort.bc > /dev/null
|
|||
echo "Byterun:"
|
||||
time ./byterun.exe -vi Sort.bc > /dev/null
|
||||
|
||||
echo "Byterun (verefication only):"
|
||||
time ./byterun.exe -v Sort.bc > /dev/null
|
||||
|
||||
echo "Byterun (run only):"
|
||||
time ./byterun.exe -i Sort.bc > /dev/null
|
||||
|
||||
rm Sort.*
|
||||
rm *.o
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "analyzer.hpp"
|
||||
#include "parser.hpp"
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
extern "C" {
|
||||
#include "types.h"
|
||||
|
|
@ -20,6 +21,7 @@ void analyze(Bytefile *bf) {
|
|||
const uint globals_count = bf->global_area_size;
|
||||
uint current_locals_count = 0;
|
||||
uint current_args_count = 0;
|
||||
bool is_in_closure = false;
|
||||
uint16_t *current_begin_counter = nullptr;
|
||||
|
||||
char *ip = bf->code_ptr;
|
||||
|
|
@ -33,7 +35,6 @@ void analyze(Bytefile *bf) {
|
|||
visited[offset] = current_stack_depth;
|
||||
to_visit_jmp.push_back(offset);
|
||||
} else if (visited[offset] != current_stack_depth) {
|
||||
// TODO: is this condition same for calls?
|
||||
ip_failure(saved_current_ip, bf,
|
||||
"different stack depth on same point is not allowed");
|
||||
}
|
||||
|
|
@ -61,8 +62,8 @@ void analyze(Bytefile *bf) {
|
|||
};
|
||||
|
||||
auto const check_correct_var = [&saved_current_ip, &bf, &globals_count,
|
||||
¤t_locals_count,
|
||||
¤t_args_count](uint8_t l, uint id) {
|
||||
¤t_locals_count, ¤t_args_count,
|
||||
&is_in_closure](uint8_t l, uint id) {
|
||||
if (l > 3) {
|
||||
ip_failure(saved_current_ip, bf, "unexpected variable category");
|
||||
}
|
||||
|
|
@ -84,7 +85,11 @@ void analyze(Bytefile *bf) {
|
|||
}
|
||||
break;
|
||||
case VAR_CLOSURE:
|
||||
// NOTE: impossible to properly check there (?)
|
||||
if (!is_in_closure) {
|
||||
ip_failure(saved_current_ip, bf,
|
||||
"can't access closure vars outside of closure");
|
||||
}
|
||||
// NOTE: impossible to properly check bounds there
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
|
@ -92,7 +97,7 @@ void analyze(Bytefile *bf) {
|
|||
// add publics
|
||||
to_visit_func.reserve(bf->public_symbols_number);
|
||||
for (size_t i = 0; i < bf->public_symbols_number; ++i) {
|
||||
func_control_push(get_public_offset(bf, i));
|
||||
func_control_push(get_public_offset_safe(bf, i));
|
||||
}
|
||||
|
||||
if (to_visit_func.size() == 0) {
|
||||
|
|
@ -129,9 +134,9 @@ void analyze(Bytefile *bf) {
|
|||
saved_current_ip = current_ip;
|
||||
|
||||
#ifdef DEBUG_VERSION
|
||||
const auto [cmd, l] = parse_command(&ip, *bf, std::cout);
|
||||
const auto [cmd, l] = parse_command(&ip, bf, std::cout);
|
||||
#else
|
||||
const auto [cmd, l] = parse_command(&ip, *bf);
|
||||
const auto [cmd, l] = parse_command(&ip, bf);
|
||||
#endif
|
||||
|
||||
if (current_begin_counter == nullptr && cmd != Cmd::BEGIN &&
|
||||
|
|
@ -167,8 +172,8 @@ void analyze(Bytefile *bf) {
|
|||
++current_stack_depth;
|
||||
break;
|
||||
case Cmd::SEXP:
|
||||
ip_read_string(¤t_ip, *bf);
|
||||
current_stack_depth -= ip_read_int(¤t_ip, *bf);
|
||||
ip_read_string_unsafe(¤t_ip, bf);
|
||||
current_stack_depth -= ip_read_int_unsafe(¤t_ip);
|
||||
if (current_stack_depth < 0) {
|
||||
ip_failure(saved_current_ip, bf, "not enough elements in stack");
|
||||
}
|
||||
|
|
@ -215,15 +220,15 @@ void analyze(Bytefile *bf) {
|
|||
++current_stack_depth;
|
||||
break;
|
||||
case Cmd::LD:
|
||||
check_correct_var(l, ip_read_int(¤t_ip, *bf));
|
||||
check_correct_var(l, ip_read_int_unsafe(¤t_ip));
|
||||
++current_stack_depth;
|
||||
break;
|
||||
case Cmd::LDA:
|
||||
check_correct_var(l, ip_read_int(¤t_ip, *bf));
|
||||
check_correct_var(l, ip_read_int_unsafe(¤t_ip));
|
||||
++current_stack_depth;
|
||||
break;
|
||||
case Cmd::ST:
|
||||
check_correct_var(l, ip_read_int(¤t_ip, *bf));
|
||||
check_correct_var(l, ip_read_int_unsafe(¤t_ip));
|
||||
if (current_stack_depth < 1) {
|
||||
ip_failure(saved_current_ip, bf, "not enough elements in stack");
|
||||
}
|
||||
|
|
@ -237,47 +242,60 @@ void analyze(Bytefile *bf) {
|
|||
if (current_begin_counter != nullptr) {
|
||||
ip_failure(saved_current_ip, bf, "unexpected function beginning");
|
||||
}
|
||||
current_args_count = ip_read_int(¤t_ip, *bf);
|
||||
current_args_count = ip_read_int_unsafe(¤t_ip);
|
||||
current_begin_counter = (uint16_t *)(current_ip + sizeof(uint16_t));
|
||||
current_locals_count = ip_read_int(¤t_ip, *bf);
|
||||
// TODO: check uint16_t max ??
|
||||
current_locals_count = ip_read_int_unsafe(¤t_ip);
|
||||
if (current_locals_count >= std::numeric_limits<uint16_t>::max()) {
|
||||
ip_failure(saved_current_ip, bf, "too many locals in functions");
|
||||
}
|
||||
(*(uint16_t *)(current_ip - sizeof(uint16_t))) = current_locals_count;
|
||||
*current_begin_counter = 0;
|
||||
is_in_closure = (cmd == Cmd::CBEGIN);
|
||||
break;
|
||||
case Cmd::CLOSURE: {
|
||||
ip_read_int(&ip, *bf); // offset
|
||||
size_t args_count = ip_read_int(¤t_ip, *bf); // args count
|
||||
uint closure_offset = ip_read_int_unsafe(¤t_ip); // closure offset
|
||||
size_t args_count = ip_read_int_unsafe(¤t_ip); // args count
|
||||
extra_stack_during_opr = args_count;
|
||||
for (aint i = 0; i < args_count; i++) {
|
||||
aint arg_type = ip_read_byte(¤t_ip, *bf);
|
||||
aint arg_id = ip_read_int(¤t_ip, *bf);
|
||||
aint arg_type = ip_read_byte_unsafe(¤t_ip);
|
||||
aint arg_id = ip_read_int_unsafe(¤t_ip);
|
||||
check_correct_var(arg_type, arg_id);
|
||||
}
|
||||
++current_stack_depth;
|
||||
|
||||
if (closure_offset >= bf->code_size) {
|
||||
ip_failure(saved_current_ip, bf, "jump/call out of file");
|
||||
}
|
||||
|
||||
if (!is_command_name(bf->code_ptr + closure_offset, bf, Cmd::CBEGIN)) {
|
||||
ip_failure(saved_current_ip, bf, "closure should point to cbegin");
|
||||
}
|
||||
} break;
|
||||
case Cmd::CALLC: {
|
||||
uint args_count = ip_read_int(¤t_ip, *bf);
|
||||
uint args_count = ip_read_int_unsafe(¤t_ip);
|
||||
current_stack_depth -= args_count + 1; // + closure itself
|
||||
if (current_stack_depth < 0) {
|
||||
ip_failure(saved_current_ip, bf, "not enough elements in stack");
|
||||
}
|
||||
++current_stack_depth;
|
||||
// NOTE: can't check args == cbegin args (?)
|
||||
// NOTE: can't check args == cbegin args
|
||||
} break;
|
||||
case Cmd::CALL: {
|
||||
uint call_offset = ip_read_int(¤t_ip, *bf); // call offset
|
||||
uint args_count = ip_read_int(¤t_ip, *bf);
|
||||
uint call_offset = ip_read_int_unsafe(¤t_ip); // call offset
|
||||
uint args_count = ip_read_int_unsafe(¤t_ip);
|
||||
current_stack_depth -= args_count;
|
||||
if (current_stack_depth < 0) {
|
||||
ip_failure(saved_current_ip, bf, "not enough elements in stack");
|
||||
}
|
||||
++current_stack_depth;
|
||||
|
||||
// TODO: unify with next loop
|
||||
if (call_offset >= bf->code_size) {
|
||||
ip_failure(saved_current_ip, bf, "jump/call out of file");
|
||||
}
|
||||
|
||||
if (!is_command_name(bf->code_ptr + call_offset, bf, Cmd::BEGIN)) {
|
||||
ip_failure(saved_current_ip, bf, "call should point to begin");
|
||||
}
|
||||
if (args_count != *(uint *)(bf->code_ptr + call_offset + 1)) {
|
||||
ip_failure(saved_current_ip, bf, "wrong call argument count");
|
||||
}
|
||||
|
|
@ -318,7 +336,7 @@ void analyze(Bytefile *bf) {
|
|||
}
|
||||
break;
|
||||
case Cmd::Barray:
|
||||
current_stack_depth -= ip_read_int(¤t_ip, *bf); // elem count
|
||||
current_stack_depth -= ip_read_int_unsafe(¤t_ip); // elem count
|
||||
if (current_stack_depth < 0) {
|
||||
ip_failure(saved_current_ip, bf, "not enough elements in stack");
|
||||
}
|
||||
|
|
@ -362,7 +380,7 @@ void analyze(Bytefile *bf) {
|
|||
case Cmd::JMP: {
|
||||
bool is_call = (cmd == Cmd::CLOSURE || cmd == Cmd::CALL);
|
||||
|
||||
uint jmp_p = ip_read_int(¤t_ip, *bf);
|
||||
uint jmp_p = ip_read_int_unsafe(¤t_ip);
|
||||
if (jmp_p >= bf->code_size) {
|
||||
// NOTE: maybe also should check that > begin (?)
|
||||
ip_failure(saved_current_ip, bf, "jump/call out of file");
|
||||
|
|
|
|||
|
|
@ -18,14 +18,18 @@ int main(int argc, char **argv) {
|
|||
bool do_verification = false;
|
||||
bool do_interpretation = false;
|
||||
bool do_print = false;
|
||||
if (strcmp(argv[1], "-vi") == 0) {
|
||||
do_verification = true;
|
||||
if (strcmp(argv[1], "-i") == 0) {
|
||||
do_interpretation = true;
|
||||
} else if (strcmp(argv[1], "-i") == 0) {
|
||||
}
|
||||
#ifdef WITH_CHECK
|
||||
else if (strcmp(argv[1], "-vi") == 0) {
|
||||
do_verification = true;
|
||||
do_interpretation = true;
|
||||
} else if (strcmp(argv[1], "-v") == 0) {
|
||||
do_verification = true;
|
||||
} else if (strcmp(argv[1], "-p") == 0) {
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(argv[1], "-p") == 0) {
|
||||
do_print = true;
|
||||
} else {
|
||||
failure("wrong execution option (acceptable options - '-i', '-v', '-vi')");
|
||||
|
|
@ -36,20 +40,21 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
Bytefile *f = read_file(argv[2]);
|
||||
// #ifdef DEBUG_VERSION
|
||||
// dump_file (stdout, f);
|
||||
// #endif
|
||||
#ifdef DEBUG_VERSION
|
||||
dump_file(stdout, f);
|
||||
#endif
|
||||
if (do_print) {
|
||||
print_file(*f, std::cout);
|
||||
}
|
||||
if (do_verification) {
|
||||
analyze(f);
|
||||
}
|
||||
if (do_interpretation) { // TODO: switch between enabled/disabled verification
|
||||
if (do_interpretation) {
|
||||
run(f, argc - 2, argv + 2);
|
||||
}
|
||||
|
||||
free(f->global_ptr);
|
||||
// // NOTE: not used for now
|
||||
// // free(f->global_ptr);
|
||||
free(f);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@
|
|||
#include "types.h"
|
||||
#include "utils.h"
|
||||
|
||||
void *__start_custom_data;
|
||||
void *__stop_custom_data;
|
||||
|
||||
#define ASSERT_UNBOXED(memo, x) \
|
||||
do \
|
||||
if (!UNBOXED(x)) \
|
||||
|
|
@ -17,36 +20,35 @@
|
|||
struct State s;
|
||||
|
||||
static inline uint16_t ip_read_half_int(char **ip) {
|
||||
#ifndef WITH_CHECK
|
||||
if (*ip + sizeof(uint16_t) > s.bf->code_ptr + s.bf->code_size) {
|
||||
failure("last command is invalid, int parameter can not be read\n");
|
||||
}
|
||||
#ifdef WITH_CHECK
|
||||
return ip_read_half_int_unsafe(ip);
|
||||
#else
|
||||
return ip_read_half_int_safe(ip, s.bf);
|
||||
#endif
|
||||
*ip += sizeof(uint16_t);
|
||||
return *(uint16_t *)((*ip) - sizeof(uint16_t));
|
||||
}
|
||||
|
||||
static inline int ip_read_int(char **ip) {
|
||||
#ifndef WITH_CHECK
|
||||
if (*ip + sizeof(int) > s.bf->code_ptr + s.bf->code_size) {
|
||||
failure("last command is invalid, int parameter can not be read\n");
|
||||
}
|
||||
#ifdef WITH_CHECK
|
||||
return ip_read_int_unsafe(ip);
|
||||
#else
|
||||
return ip_read_int_safe(ip, s.bf);
|
||||
#endif
|
||||
*ip += sizeof(int);
|
||||
return *(int *)((*ip) - sizeof(int));
|
||||
}
|
||||
|
||||
static inline uint8_t ip_read_byte(char **ip) {
|
||||
#ifndef WITH_CHECK
|
||||
if (*ip + sizeof(char) > s.bf->code_ptr + s.bf->code_size) {
|
||||
failure("last command is invalid, byte parameter can not be read\n");
|
||||
}
|
||||
#ifdef WITH_CHECK
|
||||
return ip_read_byte_unsafe(ip);
|
||||
#else
|
||||
return ip_read_byte_safe(ip, s.bf);
|
||||
#endif
|
||||
return *(*ip)++;
|
||||
}
|
||||
|
||||
static inline const char *ip_read_string(char **ip) {
|
||||
return get_string(s.bf, ip_read_int(ip));
|
||||
#ifdef WITH_CHECK
|
||||
return get_string_unsafe(s.bf, ip_read_int(ip));
|
||||
#else
|
||||
return get_string_safe(s.bf, ip_read_int(ip));
|
||||
#endif
|
||||
}
|
||||
|
||||
const size_t BUFFER_SIZE = 1000;
|
||||
|
|
@ -107,7 +109,7 @@ void run(Bytefile *bf, int argc, char **argv) {
|
|||
if (l == CMD_BINOP_SUB) {
|
||||
s_push_i(Ls__Infix_45(fst, snd));
|
||||
} else {
|
||||
switch (l) {
|
||||
switch (l - 1) {
|
||||
#define BINOP_OPR(val, op) \
|
||||
case val: \
|
||||
ASSERT_UNBOXED("captured op:1", fst); \
|
||||
|
|
@ -305,7 +307,6 @@ void run(Bytefile *bf, int argc, char **argv) {
|
|||
s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz,
|
||||
locals_sz);
|
||||
#ifndef WITH_CHECK
|
||||
// TODO
|
||||
if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) {
|
||||
s_failure(&s, "stack owerflow");
|
||||
}
|
||||
|
|
@ -329,7 +330,6 @@ void run(Bytefile *bf, int argc, char **argv) {
|
|||
#endif
|
||||
s_enter_f(s.call_ip /*ip from call*/, s.is_closure_call, args_sz,
|
||||
locals_sz);
|
||||
// TODO: add ifdef
|
||||
#ifdef WITH_CHECK
|
||||
if ((void **)__gc_stack_top + (aint)max_additional_stack_sz - 1 <= s.stack) {
|
||||
s_failure(&s, "stack owerflow");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
// }
|
||||
|
||||
|
|
@ -8,88 +8,35 @@
|
|||
#include "parser.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
enum CMD_TOPLVL {
|
||||
CMD_BINOP = 0,
|
||||
CMD_BASIC,
|
||||
CMD_LD,
|
||||
CMD_LDA,
|
||||
CMD_ST,
|
||||
CMD_CTRL,
|
||||
CMD_PATT,
|
||||
CMD_BUILTIN,
|
||||
CMD_EXIT = 15,
|
||||
};
|
||||
|
||||
enum CMD_BASICS {
|
||||
CMD_BASIC_CONST = 0,
|
||||
CMD_BASIC_STRING,
|
||||
CMD_BASIC_SEXP,
|
||||
CMD_BASIC_STI,
|
||||
CMD_BASIC_STA,
|
||||
CMD_BASIC_JMP,
|
||||
CMD_BASIC_END,
|
||||
CMD_BASIC_RET,
|
||||
CMD_BASIC_DROP,
|
||||
CMD_BASIC_DUP,
|
||||
CMD_BASIC_SWAP,
|
||||
CMD_BASIC_ELEM,
|
||||
};
|
||||
|
||||
enum CMD_CTRLS {
|
||||
CMD_CTRL_CJMPz = 0,
|
||||
CMD_CTRL_CJMPnz,
|
||||
CMD_CTRL_BEGIN,
|
||||
CMD_CTRL_CBEGIN,
|
||||
CMD_CTRL_CLOSURE,
|
||||
CMD_CTRL_CALLC,
|
||||
CMD_CTRL_CALL,
|
||||
CMD_CTRL_TAG,
|
||||
CMD_CTRL_ARRAY,
|
||||
CMD_CTRL_FAIL,
|
||||
CMD_CTRL_LINE,
|
||||
};
|
||||
|
||||
enum CMD_PATTS {
|
||||
CMD_PATT_STR = 0,
|
||||
CMD_PATT_STR_TAG,
|
||||
CMD_PATT_ARRAY_TAG,
|
||||
CMD_PATT_SEXP_TAG,
|
||||
CMD_PATT_REF_TAG,
|
||||
CMD_PATT_VAL_TAG,
|
||||
CMD_PATT_FUN_TAG,
|
||||
};
|
||||
|
||||
enum CMD_BUILTINS {
|
||||
CMD_BUILTIN_Lread = 0,
|
||||
CMD_BUILTIN_Lwrite,
|
||||
CMD_BUILTIN_Llength,
|
||||
CMD_BUILTIN_Lstring,
|
||||
CMD_BUILTIN_Barray,
|
||||
};
|
||||
|
||||
enum class ArgT {
|
||||
INT,
|
||||
OFFSET,
|
||||
STR,
|
||||
};
|
||||
|
||||
#define FORALL_BINOP(DEF) \
|
||||
DEF(0, +) \
|
||||
DEF(1, -) \
|
||||
DEF(2, *) \
|
||||
DEF(3, /) \
|
||||
DEF(4, %) \
|
||||
DEF(5, <) \
|
||||
DEF(6, <=) \
|
||||
DEF(7, >) \
|
||||
DEF(8, >=) \
|
||||
DEF(9, ==) \
|
||||
DEF(10, !=) \
|
||||
DEF(11, &&) \
|
||||
DEF(12, ||)
|
||||
// #define FORALL_BINOP(DEF) \
|
||||
// DEF(0, +) \
|
||||
// DEF(1, -) \
|
||||
// DEF(2, *) \
|
||||
// DEF(3, /) \
|
||||
// DEF(4, %) \
|
||||
// DEF(5, <) \
|
||||
// DEF(6, <=) \
|
||||
// DEF(7, >) \
|
||||
// DEF(8, >=) \
|
||||
// DEF(9, ==) \
|
||||
// DEF(10, !=) \
|
||||
// DEF(11, &&) \
|
||||
// DEF(12, ||)
|
||||
|
||||
// extern "C" {
|
||||
|
||||
// void *__start_custom_data;
|
||||
// void *__stop_custom_data;
|
||||
|
||||
// Reads a binary bytecode file by name and unpacks it
|
||||
Bytefile *read_file(const char *fname) {
|
||||
|
|
@ -97,11 +44,11 @@ Bytefile *read_file(const char *fname) {
|
|||
Bytefile *file;
|
||||
|
||||
if (f == 0) {
|
||||
failure(strerror(errno));
|
||||
failure("%s\n", strerror(errno));
|
||||
}
|
||||
|
||||
if (fseek(f, 0, SEEK_END) == -1) {
|
||||
failure(strerror(errno));
|
||||
failure("%s\n", strerror(errno));
|
||||
}
|
||||
|
||||
long size = ftell(f);
|
||||
|
|
@ -113,48 +60,78 @@ Bytefile *read_file(const char *fname) {
|
|||
char *file_end = file_begin + size;
|
||||
|
||||
if (file == 0) {
|
||||
failure("unable to allocate memory to store file data");
|
||||
failure("unable to allocate memory to store file data\n");
|
||||
}
|
||||
|
||||
rewind(f);
|
||||
|
||||
if (size != fread(&file->stringtab_size, 1, size, f)) {
|
||||
failure(strerror(errno));
|
||||
failure("%s\n", strerror(errno));
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
long public_symbols_size = file->public_symbols_number * 2 * sizeof(int);
|
||||
if (file->buffer + public_symbols_size >= file_end) {
|
||||
failure("public symbols are out of the file size");
|
||||
failure("public symbols are out of the file size\n");
|
||||
}
|
||||
if (file->string_ptr + file->stringtab_size > file_end) {
|
||||
failure("strings table is out of the file size");
|
||||
failure("strings table is out of the file size\n");
|
||||
}
|
||||
// if (file->stringtab_size > 0 &&
|
||||
// file->string_ptr[file->stringtab_size - 1] != 0) {
|
||||
// failure("strings table is not zero-ended\n");
|
||||
// }
|
||||
if (file->code_size < 0 || public_symbols_size < 0 ||
|
||||
file->stringtab_size < 0) {
|
||||
failure("file zones sizes should be >= 0");
|
||||
failure("file zones sizes should be >= 0\n");
|
||||
}
|
||||
|
||||
file->string_ptr = &file->buffer[public_symbols_size];
|
||||
file->public_ptr = (int *)file->buffer;
|
||||
file->code_ptr = &file->string_ptr[file->stringtab_size];
|
||||
file->global_ptr = (int *)calloc(file->global_area_size, sizeof(int));
|
||||
// NOTE: not used for now
|
||||
// file->global_ptr = (int *)calloc(file->global_area_size, sizeof(int));
|
||||
file->global_ptr = nullptr;
|
||||
|
||||
file->code_size = size - public_symbols_size - file->stringtab_size;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
std::string command_name(Cmd cmd, int8_t l) {
|
||||
const char *command_name(Cmd cmd, int8_t l) {
|
||||
static const char *const ops[] = {
|
||||
#define OP_TO_STR(id, op) #op,
|
||||
#define OP_TO_STR(id, op) "BINOP:" #op,
|
||||
FORALL_BINOP(OP_TO_STR)
|
||||
#undef OP_TO_STR
|
||||
};
|
||||
static const char *const pats[] = {"=str", "#string", "#array", "#sexp",
|
||||
"#ref", "#val", "#fun"};
|
||||
static const char *const ldts[] = {"G", "L", "A", "C"};
|
||||
static const char *const pats[] = {
|
||||
"PATT:=str", "PATT:#string", "PATT:#array", "PATT:#sexp",
|
||||
"PATT:#ref", "PATT:#val", "PATT:#fun"};
|
||||
|
||||
#define FORALL_LDTS(DEF) \
|
||||
DEF(G) \
|
||||
DEF(L) \
|
||||
DEF(A) \
|
||||
DEF(C)
|
||||
|
||||
static const char *const ld_ldts[] = {
|
||||
#define LDT_TO_STR(type) "LD:" #type,
|
||||
FORALL_LDTS(LDT_TO_STR)
|
||||
#undef LDT_TO_STR
|
||||
};
|
||||
static const char *const lda_ldts[] = {
|
||||
#define LDT_TO_STR(type) "LDA:" #type,
|
||||
FORALL_LDTS(LDT_TO_STR)
|
||||
#undef LDT_TO_STR
|
||||
};
|
||||
static const char *const st_ldts[] = {
|
||||
#define LDT_TO_STR(type) "ST:" #type,
|
||||
FORALL_LDTS(LDT_TO_STR)
|
||||
#undef LDT_TO_STR
|
||||
};
|
||||
|
||||
#undef FORALL_LDTS
|
||||
|
||||
switch (cmd) {
|
||||
case Cmd::EXIT:
|
||||
|
|
@ -163,7 +140,7 @@ std::string command_name(Cmd cmd, int8_t l) {
|
|||
if (l - 1 >= sizeof(ops) / sizeof(char *)) {
|
||||
return "_UNDEF_BINOP_";
|
||||
}
|
||||
return "BINOP:" + std::string{ops[l - 1]};
|
||||
return ops[l - 1];
|
||||
case Cmd::CONST:
|
||||
return "CONST";
|
||||
case Cmd::STRING:
|
||||
|
|
@ -189,20 +166,20 @@ std::string command_name(Cmd cmd, int8_t l) {
|
|||
case Cmd::ELEM:
|
||||
return "ELEM";
|
||||
case Cmd::LD:
|
||||
if (l >= sizeof(ldts) / sizeof(char *)) {
|
||||
if (l >= sizeof(ld_ldts) / sizeof(char *)) {
|
||||
return "_UNDEF_LD_";
|
||||
}
|
||||
return "LD:" + std::string{ldts[l]};
|
||||
return ld_ldts[l];
|
||||
case Cmd::LDA:
|
||||
if (l >= sizeof(ldts) / sizeof(char *)) {
|
||||
if (l >= sizeof(lda_ldts) / sizeof(char *)) {
|
||||
return "_UNDEF_LDA_";
|
||||
}
|
||||
return "LDA:" + std::string{ldts[l]};
|
||||
return lda_ldts[l];
|
||||
case Cmd::ST:
|
||||
if (l >= sizeof(ldts) / sizeof(char *)) {
|
||||
if (l >= sizeof(st_ldts) / sizeof(char *)) {
|
||||
return "_UNDEF_ST_";
|
||||
}
|
||||
return "ST:" + std::string{ldts[l]};
|
||||
return st_ldts[l];
|
||||
case Cmd::CJMPz:
|
||||
return "CJMPz";
|
||||
case Cmd::CJMPnz:
|
||||
|
|
@ -229,7 +206,7 @@ std::string command_name(Cmd cmd, int8_t l) {
|
|||
if (l >= sizeof(pats) / sizeof(char *)) {
|
||||
return "_UNDEF_PATT_";
|
||||
}
|
||||
return "PATT:" + std::string{pats[l]};
|
||||
return pats[l];
|
||||
case Cmd::Lread:
|
||||
return "CALL\tLread";
|
||||
case Cmd::Lwrite:
|
||||
|
|
@ -246,6 +223,7 @@ std::string command_name(Cmd cmd, int8_t l) {
|
|||
|
||||
exit(1);
|
||||
}
|
||||
// } // extern "C"
|
||||
|
||||
template <bool use_out, typename T>
|
||||
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)
|
||||
static inline uint read_print_val(char **ip, const Bytefile &bf,
|
||||
std::ostream &out) {
|
||||
uint val = ip_read_int(ip, bf);
|
||||
uint val = ip_read_int_safe(ip, &bf);
|
||||
if constexpr (use_out) {
|
||||
out << val;
|
||||
}
|
||||
|
|
@ -276,9 +254,9 @@ template <bool use_out, ArgT arg>
|
|||
requires(arg == ArgT::OFFSET)
|
||||
static inline uint read_print_val(char **ip, const Bytefile &bf,
|
||||
std::ostream &out) {
|
||||
uint val = ip_read_int(ip, bf);
|
||||
uint val = ip_read_int_safe(ip, &bf);
|
||||
if constexpr (use_out) {
|
||||
out << val; // TODO
|
||||
out << val;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
|
@ -287,7 +265,7 @@ template <bool use_out, ArgT arg>
|
|||
requires(arg == ArgT::STR)
|
||||
static inline const char *read_print_val(char **ip, const Bytefile &bf,
|
||||
std::ostream &out) {
|
||||
const char *val = ip_read_string(ip, bf);
|
||||
const char *val = ip_read_string_safe(ip, &bf);
|
||||
if constexpr (use_out) {
|
||||
out << val;
|
||||
}
|
||||
|
|
@ -320,11 +298,20 @@ static inline void read_print_cmd_seq(Cmd cmd, uint8_t l, char **ip,
|
|||
read_print_seq<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::ostream &out) {
|
||||
static const char *const ops[] = {
|
||||
#define OP_TO_STR(id, op) "op",
|
||||
#define OP_TO_STR(id, op) #op,
|
||||
FORALL_BINOP(OP_TO_STR)
|
||||
#undef OP_TO_STR
|
||||
};
|
||||
|
|
@ -346,7 +333,7 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
|
|||
Cmd cmd = Cmd::_UNDEF_;
|
||||
|
||||
char *instr_ip = *ip;
|
||||
uint8_t x = ip_read_byte(ip, bf), h = (x & 0xF0) >> 4, l = x & 0x0F;
|
||||
uint8_t x = ip_read_byte_safe(ip, &bf), h = (x & 0xF0) >> 4, l = x & 0x0F;
|
||||
|
||||
#ifdef DEBUG_VERSION
|
||||
printf("0x%.8lx ", *ip - bf.code_ptr - 1);
|
||||
|
|
@ -356,68 +343,72 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
|
|||
switch (h) {
|
||||
case 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;
|
||||
|
||||
/* BINOP */
|
||||
case CMD_BINOP: // BINOP ops[l-1]
|
||||
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;
|
||||
|
||||
case CMD_BASIC:
|
||||
switch (l) {
|
||||
case CMD_BASIC_CONST: // CONST %d
|
||||
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;
|
||||
case CMD_BASIC_STRING: // STRING %s
|
||||
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;
|
||||
|
||||
case CMD_BASIC_SEXP: // SEXP %s %d
|
||||
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;
|
||||
|
||||
case CMD_BASIC_STI: // STI - write by ref (?)
|
||||
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;
|
||||
case CMD_BASIC_STA: // STA - write to array elem
|
||||
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;
|
||||
|
||||
case CMD_BASIC_JMP: // JMP 0x%.8x
|
||||
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;
|
||||
|
||||
case CMD_BASIC_END: // 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;
|
||||
case CMD_BASIC_RET: // 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;
|
||||
case CMD_BASIC_DROP: // 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;
|
||||
case CMD_BASIC_DUP: // 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;
|
||||
case CMD_BASIC_SWAP: // 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;
|
||||
case CMD_BASIC_ELEM: // 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;
|
||||
|
||||
default:
|
||||
|
|
@ -430,89 +421,104 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
|
|||
if (l > sizeof(ldts) / sizeof(char *)) {
|
||||
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;
|
||||
case CMD_LDA: // LDA %d
|
||||
cmd = Cmd::LDA;
|
||||
if (l > sizeof(ldts) / sizeof(char *)) {
|
||||
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;
|
||||
case CMD_ST: // ST %d
|
||||
cmd = Cmd::ST;
|
||||
if (l > sizeof(ldts) / sizeof(char *)) {
|
||||
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;
|
||||
|
||||
case CMD_CTRL:
|
||||
switch (l) {
|
||||
case CMD_CTRL_CJMPz: // CJMPnz 0x%.8x
|
||||
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;
|
||||
case CMD_CTRL_CJMPnz: // CJMPnz 0x%.8x
|
||||
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;
|
||||
|
||||
case CMD_CTRL_BEGIN: // BEGIN %d %d // function 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;
|
||||
case CMD_CTRL_CBEGIN: // CBEGIN %d %d
|
||||
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;
|
||||
|
||||
case CMD_CTRL_CLOSURE: { // CLOSURE 0x%.8x
|
||||
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);
|
||||
size_t call_p = read_print_val<use_out, ArgT::OFFSET>(ip, bf, out);
|
||||
print_space<use_out>(out);
|
||||
size_t args_count = read_print_val<use_out, ArgT::INT>(ip, bf, out);
|
||||
for (size_t i = 0; i < args_count; i++) {
|
||||
uint8_t arg_type = ip_read_byte(ip, bf);
|
||||
if (arg_type > sizeof(ldts) / sizeof(char *)) {
|
||||
failure("wrong closure argument type");
|
||||
if constexpr (do_read_args) {
|
||||
size_t call_p = read_print_val<use_out, ArgT::OFFSET>(ip, bf, out);
|
||||
print_space<use_out>(out);
|
||||
size_t args_count = read_print_val<use_out, ArgT::INT>(ip, bf, out);
|
||||
for (size_t i = 0; i < args_count; i++) {
|
||||
uint8_t arg_type = ip_read_byte_safe(ip, &bf);
|
||||
if (arg_type > sizeof(ldts) / sizeof(char *)) {
|
||||
failure("wrong closure argument type");
|
||||
}
|
||||
print_space<use_out>(out);
|
||||
print_val<use_out>(out, ldts[arg_type]);
|
||||
print_space<use_out>(out);
|
||||
read_print_val<use_out, ArgT::INT>(ip, bf, out);
|
||||
}
|
||||
print_space<use_out>(out);
|
||||
print_val<use_out>(out, ldts[arg_type]);
|
||||
print_space<use_out>(out);
|
||||
read_print_val<use_out, ArgT::INT>(ip, bf, out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_CTRL_CALLC: // CALLC %d // call clojure
|
||||
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;
|
||||
|
||||
case CMD_CTRL_CALL: // CALL 0x%.8x %d // call function
|
||||
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;
|
||||
|
||||
case CMD_CTRL_TAG: // TAG %s %d
|
||||
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;
|
||||
case CMD_CTRL_FAIL: // FAIL %d %d
|
||||
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;
|
||||
|
||||
case CMD_CTRL_ARRAY: // ARRAY %d
|
||||
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;
|
||||
case CMD_CTRL_LINE: // LINE %d
|
||||
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;
|
||||
|
||||
default:
|
||||
|
|
@ -526,31 +532,32 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
|
|||
failure("invalid opcode");
|
||||
}
|
||||
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;
|
||||
|
||||
case CMD_BUILTIN: {
|
||||
switch (l) {
|
||||
case CMD_BUILTIN_Lread: // CALL 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;
|
||||
case CMD_BUILTIN_Lwrite: // CALL 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;
|
||||
case CMD_BUILTIN_Llength: // CALL 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;
|
||||
case CMD_BUILTIN_Lstring: // CALL 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;
|
||||
|
||||
case CMD_BUILTIN_Barray: // CALL Barray %d
|
||||
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;
|
||||
|
||||
default:
|
||||
|
|
@ -567,13 +574,21 @@ std::pair<Cmd, uint8_t> parse_command_impl(char **ip, const Bytefile &bf,
|
|||
return {cmd, l};
|
||||
}
|
||||
|
||||
std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile &bf) {
|
||||
return parse_command_impl<false>(ip, bf, std::clog);
|
||||
std::pair<Cmd, uint8_t> parse_command(char **ip, const Bytefile *bf) {
|
||||
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) {
|
||||
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) {
|
||||
|
|
@ -582,7 +597,7 @@ void print_file(const Bytefile &bf, std::ostream &out) {
|
|||
while (true) {
|
||||
out << std::setfill('0') << std::setw(8) << std::hex << ip - bf.code_ptr
|
||||
<< ": ";
|
||||
const auto [cmd, l] = parse_command(&ip, bf, out);
|
||||
const auto [cmd, l] = parse_command(&ip, &bf, out);
|
||||
out << '\n';
|
||||
|
||||
if (cmd == Cmd::EXIT) {
|
||||
|
|
@ -590,3 +605,11 @@ void print_file(const Bytefile &bf, std::ostream &out) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
const char *read_cmd(char *ip, const Bytefile *bf) {
|
||||
const auto [cmd, l] = parse_command_impl<false, false>(&ip, *bf, std::clog);
|
||||
return command_name(cmd, l);
|
||||
return "";
|
||||
}
|
||||
} // extern "C"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue