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