lama_byterun/byterun/src/interpreter.c

273 lines
6.8 KiB
C
Raw Normal View History

#include "../include/interpreter.h"
2024-10-20 16:42:57 +03:00
#include "../include/types.h"
#include "../include/builtin.h"
#include "../include/operations.h"
#include "../../runtime/runtime.h"
#include "../../runtime/gc.h"
2024-10-20 16:42:57 +03:00
int ip_read_int(char** ip) {
*ip += sizeof(int);
return *(int*)((*ip) - sizeof(int));
}
2024-10-20 16:42:57 +03:00
char ip_read_byte(char** ip) {
return *(*ip)++;
}
2024-10-20 16:42:57 +03:00
char* ip_read_string(char** ip, bytefile* bf) {
return get_string(bf, ip_read_int(ip));
}
// TODO: store globals in some way ?? // maybe some first vars ??
void run(bytefile *bf) {
struct State s = init_state(bf);
const size_t OPS_SIZE = 13;
const char *ops [] = {"+", "-", "*", "/", "%", "<", "<=", ">", ">=", "==", "!=", "&&", "!!"};
const size_t PATS_SIZE = 7;
const char *pats[] = {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"};
do {
2024-10-12 00:37:28 +03:00
char* before_op_ip = s.ip; // save to set s.prev_ip
2024-10-20 16:42:57 +03:00
char x = ip_read_byte(&s.ip),
h = (x & 0xF0) >> 4,
l = x & 0x0F;
// fprintf (f, "0x%.8x:\t", ip-bf->code_ptr-1);
switch (h) {
case 15:
goto stop;
/* BINOP */
2024-10-12 00:37:28 +03:00
case 0: // BINOP ops[l-1]
if (l > OPS_SIZE) {
failure("BINOP: l > OPS_SIZE");
}
if (l < 1) {
failure("BINOP: l < 1");
}
f_binop(&s, ops[l-1]);
break;
case 1:
switch (l) {
2024-10-12 00:37:28 +03:00
case 0: // CONST %d
2024-10-20 16:42:57 +03:00
s_put_i(&s, ip_read_int(&s.ip));
break;
2024-10-12 00:37:28 +03:00
case 1: // STRING %s
2024-10-20 16:42:57 +03:00
s_put_const_str(&s, ip_read_string(&s.ip, bf));
break;
case 2: // SEXP %s %d // create sexpr with tag=%s and %d elements from stack
// TODO: params??
s_put_sexp(&s, ip_read_string(&s.ip, bf), ip_read_int(&s.ip));
break;
2024-10-12 00:37:28 +03:00
case 3: // STI
// TODO
break;
2024-10-12 00:37:28 +03:00
case 4: // STA
// TODO
break;
2024-10-12 00:37:28 +03:00
case 5: // JMP 0x%.8x
2024-10-20 16:42:57 +03:00
s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
break;
2024-10-12 00:37:28 +03:00
case 6: // END
s_exit_f(&s); // TODO: always ??, check that it is enough
break;
2024-10-12 00:37:28 +03:00
case 7: // RET
// TODO
break;
2024-10-12 00:37:28 +03:00
case 8: // DROP
s_drop_var(&s);
break;
2024-10-12 00:37:28 +03:00
case 9: // DUP
{ // guess
if (s.vp == s.stack || (s.fp != NULL && s.vp == s.fp->end)) {
failure("can't DUP: no value on stack");
}
*s.vp = *(s.vp - 1);
++s.vp;
2024-10-12 00:37:28 +03:00
break;
}
case 10: // SWAP
{ // guess
struct NilT* v = *s.vp;
2024-10-12 00:37:28 +03:00
*s.vp = *(s.vp - 1);
*(s.vp - 1) = v;
}
break;
2024-10-12 00:37:28 +03:00
case 11: // ELEM
{
union VarT* array = s_take_var(&s);
union VarT* index = s_take_var(&s);
if (dh_type(array->nil.data_header) != ARRAY_T) {
failure("ELEM: elem, previous element is not array");
2024-10-12 00:37:28 +03:00
}
if (dh_type(index->nil.data_header) != INT_T) {
failure("ELEM: elem, last element is not int");
2024-10-12 00:37:28 +03:00
}
if (index->int_t.value < 0) {
failure("ELEM: can't access by index < 0");
}
if (index->int_t.value >= dh_param(array->array.data_header)) {
failure("ELEM: array index is out of range");
}
s_put_var(&s, array->array.values[index->int_t.value]);
2024-10-12 00:37:28 +03:00
free_var_ptr(array);
free_var_ptr(index);
2024-10-12 00:37:28 +03:00
}
break;
default:
failure("invalid opcode %d-%d\n", h, l);
}
break;
case 2: { // LD %d
int8_t category = ip_read_byte(&s.ip);
union VarT* var = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip));
// TODO
break;
}
case 3: { // LDA %d
int8_t category = ip_read_byte(&s.ip);
union VarT* var = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip));
// TODO
break;
}
case 4: { // ST %d
int8_t category = ip_read_byte(&s.ip);
union VarT* var = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip));
// TODO
break;
}
case 5:
switch (l) {
2024-10-12 00:37:28 +03:00
case 0: { // CJMPz 0x%.8x
// FIXME: TODO: jump by top stack condition ??
2024-10-20 16:42:57 +03:00
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
if (s_take_i(&s) != 0) {
2024-10-12 00:37:28 +03:00
s.ip = new_ip;
}
break;
2024-10-12 00:37:28 +03:00
}
case 1: { // CJMPnz 0x%.8x
// FIXME: TODO: jump by top stack condition ??
2024-10-20 16:42:57 +03:00
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
if (s_take_i(&s) == 0) {
2024-10-12 00:37:28 +03:00
s.ip = new_ip;
}
break;
2024-10-12 00:37:28 +03:00
}
case 2: // BEGIN %d %d // function begin
2024-10-20 16:42:57 +03:00
s_enter_f(&s, s.prev_ip/*ip from call*/, ip_read_int(&s.ip), ip_read_int(&s.ip));
break;
case 3: // CBEGIN %d %d // TODO: clojure begin ??
2024-10-20 16:42:57 +03:00
s_enter_f(&s, s.prev_ip/*ip from call*/, ip_read_int(&s.ip), ip_read_int(&s.ip));
break;
2024-10-12 00:37:28 +03:00
case 4: // CLOSURE 0x%.8x
{
2024-10-20 16:42:57 +03:00
int n = ip_read_int(&s.ip);
2024-10-12 00:37:28 +03:00
for (int i = 0; i < n; i++) {
2024-10-20 16:42:57 +03:00
switch (ip_read_byte(&s.ip)) {
2024-10-12 00:37:28 +03:00
// case 0: // G(%d)
// case 1: // L(%d)
// case 2: // A(%d)
// case 3: // C(%d)
default:
failure("invalid opcode %d-%d\n", h, l);
2024-10-12 00:37:28 +03:00
}
}
};
break;
case 5: // CALLC %d // call clojure
// TODO FIXME: call clojure
// s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
break;
case 6: // CALL 0x%.8x %d // call function
// FIXME: second arg ??
2024-10-20 16:42:57 +03:00
s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
break;
2024-10-12 00:37:28 +03:00
case 7: // TAG %s
// TODO: ??
break;
2024-10-12 00:37:28 +03:00
case 8: // ARRAY %d
2024-10-20 16:42:57 +03:00
s_put_array(&s, ip_read_int(&s.ip));
break;
2024-10-12 00:37:28 +03:00
case 9: // FAIL %d %d
failure("[FAIL]: %d-%d\n", ip_read_int(&s.ip), ip_read_int(&s.ip));
break;
2024-10-12 00:37:28 +03:00
case 10: // LINE %d
// maybe some metainfo should be collected
break;
default:
failure("invalid opcode %d-%d\n", h, l);
}
break;
2024-10-12 00:37:28 +03:00
case 6: // PATT pats[l]
// TODO: JMP if same to pattern ??
break;
case 7: {
switch (l) {
2024-10-12 00:37:28 +03:00
case 0: // CALL Lread
f_read(&s);
break;
2024-10-12 00:37:28 +03:00
case 1: // CALL Lwrite
f_write(&s);
break;
2024-10-12 00:37:28 +03:00
case 2: // CALL Llength
f_length(&s);
break;
2024-10-12 00:37:28 +03:00
case 3: // CALL Lstring
f_string(&s);
break;
2024-10-12 00:37:28 +03:00
case 4: // CALL Barray %d
2024-10-20 16:42:57 +03:00
f_array(&s, ip_read_int(&s.ip));
break;
default:
failure("invalid opcode %d-%d\n", h, l);
}
}
break;
default:
failure("invalid opcode %d-%d\n", h, l);
}
2024-10-12 00:37:28 +03:00
s.prev_ip = before_op_ip;
}
while (1);
2024-10-12 00:37:28 +03:00
stop:;
destruct_state(&s);
}