mirror of
https://github.com/ProgramSnail/Lama.git
synced 2025-12-06 06:48:48 +00:00
interpreter part
This commit is contained in:
parent
0cdfa3911d
commit
fb1ec1c7ae
1 changed files with 224 additions and 98 deletions
|
|
@ -13,7 +13,6 @@ char read_byte(char** ip) {
|
|||
char* read_string(char** ip, bytefile* bf) {
|
||||
return get_string(bf, read_int(ip));
|
||||
}
|
||||
#define FAIL failure ("ERROR: invalid opcode %d-%d\n", h, l)
|
||||
|
||||
//
|
||||
|
||||
|
|
@ -55,6 +54,7 @@ struct State {
|
|||
struct Frame* fp; // function pointer
|
||||
|
||||
char* ip; // instruction pointer
|
||||
char* prev_ip; // prev instruction pointer
|
||||
};
|
||||
|
||||
struct State init_state(bytefile *bf) {
|
||||
|
|
@ -62,6 +62,7 @@ struct State init_state(bytefile *bf) {
|
|||
.vars = calloc(1000/* TODO */, sizeof(struct Var)),
|
||||
.funcs = calloc(1000/* TODO */, sizeof(struct Frame)),
|
||||
.ip = bf->code_ptr,
|
||||
.prev_ip = NULL,
|
||||
};
|
||||
|
||||
// TODO: init vars vith NIL_T ??
|
||||
|
|
@ -80,6 +81,7 @@ void free_state(struct State* state) {
|
|||
state->vp = NULL;
|
||||
state->fp = NULL;
|
||||
state->ip = NULL;
|
||||
state->prev_ip = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -142,6 +144,47 @@ struct Frame clear_frame() {
|
|||
return frame;
|
||||
}
|
||||
|
||||
struct Var deep_copy_var(struct Var var) {
|
||||
switch (var.type) {
|
||||
case INT_T:
|
||||
break;
|
||||
case CONST_STR_T:
|
||||
break;
|
||||
case STR_T: {
|
||||
char* old_str = var.value.str_v;
|
||||
var.value.str_v = calloc(var.size + 1, sizeof(char));
|
||||
strcpy(var.value.str_v, old_str);
|
||||
break;
|
||||
}
|
||||
case LIST_T:
|
||||
if (var.value.list_v.elem != NULL) {
|
||||
struct Var* old_elem = var.value.list_v.elem;
|
||||
var.value.list_v.elem = calloc(1, sizeof(struct Var));
|
||||
*var.value.list_v.elem = deep_copy_var(*old_elem);
|
||||
}
|
||||
if (var.value.list_v.next != NULL) {
|
||||
struct Var* old_next = var.value.list_v.next;
|
||||
var.value.list_v.next = calloc(1, sizeof(struct Var));
|
||||
*var.value.list_v.next = deep_copy_var(*old_next);
|
||||
}
|
||||
break;
|
||||
case ARRAY_T: {
|
||||
struct Var *old_array = var.value.array_v;
|
||||
var.value.array_v = calloc(var.size, sizeof(char));
|
||||
for (size_t i = 0; i < var.size; ++i) {
|
||||
var.value.array_v[i] = deep_copy_var(*(old_array + i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FUN_T:
|
||||
break;
|
||||
case NIL_T:
|
||||
break;
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void s_put_var(struct State* s, struct Var val) {
|
||||
|
|
@ -162,13 +205,34 @@ void s_put_i(struct State* s, int val) {
|
|||
s_put_var(s, var);
|
||||
}
|
||||
void s_put_const_str(struct State* s, const char* val) { // memory controlled externally
|
||||
struct Var var = {.type = CONST_STR_T, .value.const_str_v = val, .size = 0}; // TODO: size ?
|
||||
struct Var var = {.type = CONST_STR_T, .value.const_str_v = val, .size = strlen(val)};
|
||||
s_put_var(s, var);
|
||||
}
|
||||
void s_put_str(struct State* s, char* val) { // memory controlled by var
|
||||
struct Var var = {.type = STR_T, .value.str_v = val, .size = 0}; // TODO: size ?
|
||||
struct Var var = {.type = STR_T, .value.str_v = val, .size = strlen(val)};
|
||||
s_put_var(s, var);
|
||||
}
|
||||
void s_put_array(struct State* s, int sz) { // memory controlled by var
|
||||
struct Var var = {
|
||||
.type = ARRAY_T,
|
||||
.value.array_v = calloc(sz, sizeof(struct Var)),
|
||||
.size = sz,
|
||||
};
|
||||
s_put_var(s, var);
|
||||
|
||||
// fill array with nils ?
|
||||
}
|
||||
|
||||
void s_put_list(struct State* s, struct Var* first_elem) { // memory controlled by var
|
||||
struct Var var = {
|
||||
.type = LIST_T,
|
||||
.value.list_v = {.elem = first_elem, .next = NULL},
|
||||
.size = 0,
|
||||
}; // TODO: size ?
|
||||
s_put_var(s, var);
|
||||
|
||||
*first_elem = clear_var();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
|
|
@ -183,6 +247,14 @@ struct Var s_take_var(struct State* s) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
int s_take_i(struct State* s) {
|
||||
struct Var v = s_take_var(s);
|
||||
if (v.type != INT_T) {
|
||||
failure("take int: not int");
|
||||
}
|
||||
return v.value.int_v;
|
||||
}
|
||||
|
||||
void s_drop_var(struct State* s) {
|
||||
if (s->vp == s->vars) {
|
||||
failure("drop: no var");
|
||||
|
|
@ -213,7 +285,7 @@ void s_exit_f(struct State* s) {
|
|||
s_put_var(s, ret);
|
||||
s->ip = s->fp->rp;
|
||||
|
||||
s->fp = clear_frame(); // clear top frame
|
||||
*s->fp = clear_frame(); // clear top frame
|
||||
}
|
||||
|
||||
void s_enter_f(struct State* s, char* func_ip, size_t params_sz, size_t locals_sz) {
|
||||
|
|
@ -234,7 +306,32 @@ void s_enter_f(struct State* s, char* func_ip, size_t params_sz, size_t locals_s
|
|||
|
||||
//
|
||||
|
||||
// TODO: builtin calls
|
||||
// --- builtin calls
|
||||
void f_read(struct State* s) {
|
||||
int x = 0;
|
||||
printf("> "); // TODO: ??
|
||||
scanf("%i", &x);
|
||||
s_put_i(s, x);
|
||||
}
|
||||
|
||||
void f_write(struct State* s) {
|
||||
int x = s_take_i(s);
|
||||
printf("%i", x);
|
||||
// put 0 ??
|
||||
}
|
||||
void f_length(struct State* s) {
|
||||
// TODO
|
||||
}
|
||||
void f_string(struct State* s) {
|
||||
// TODO
|
||||
}
|
||||
void f_array(struct State* s, int sz) {
|
||||
// TODO
|
||||
}
|
||||
void f_cons(struct State* s) {
|
||||
|
||||
// TODO
|
||||
}
|
||||
//
|
||||
|
||||
void run(bytefile *bf) {
|
||||
|
|
@ -244,6 +341,8 @@ void run(bytefile *bf) {
|
|||
const char *pats[] = {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"};
|
||||
const char *lds [] = {"LD", "LDA", "ST"};
|
||||
do {
|
||||
char* before_op_ip = s.ip; // save to set s.prev_ip
|
||||
|
||||
char x = read_byte(&s.ip),
|
||||
h = (x & 0xF0) >> 4,
|
||||
l = x & 0x0F;
|
||||
|
|
@ -255,66 +354,83 @@ void run(bytefile *bf) {
|
|||
goto stop;
|
||||
|
||||
/* BINOP */
|
||||
case 0:
|
||||
// fprintf (f, "BINOP\t%s", ops[l-1]);
|
||||
case 0: // BINOP ops[l-1]
|
||||
// TODO: all binops
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch (l) {
|
||||
case 0:
|
||||
stack_put_i(read_int(&ip));
|
||||
// fprintf (f, "CONST\t%d", INT);
|
||||
case 0: // CONST %d
|
||||
s_put_i(&s, read_int(&s.ip));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
stack_put_str(read_string(&ip, bf));
|
||||
// fprintf (f, "STRING\t%s", STRING);
|
||||
case 1: // STRING %s
|
||||
s_put_const_str(&s, read_string(&s.ip, bf));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 2: // SEXP %s %d
|
||||
// TODO: call sexp ??
|
||||
// fprintf (f, "SEXP\t%s ", STRING);
|
||||
// fprintf (f, "%d", INT);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// fprintf (f, "STI");
|
||||
case 3: // STI
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// fprintf (f, "STA");
|
||||
case 4: // STA
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case 5:
|
||||
// fprintf (f, "JMP\t0x%.8x", INT);
|
||||
case 5: // JMP 0x%.8x
|
||||
s.ip = (char*)(long)read_int(&s.ip); // TODO: check
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// fprintf (f, "END");
|
||||
case 6: // END
|
||||
s_exit_f(&s); // TODO: always ??, check that it is enough
|
||||
break;
|
||||
|
||||
case 7:
|
||||
// fprintf (f, "RET");
|
||||
case 7: // RET
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case 8:
|
||||
// fprintf (f, "DROP");
|
||||
case 8: // DROP
|
||||
s_drop_var(&s);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// fprintf (f, "DUP");
|
||||
break;
|
||||
|
||||
case 10:
|
||||
// fprintf (f, "SWAP");
|
||||
case 9: // DUP
|
||||
{ // guess
|
||||
struct Var v = deep_copy_var(*s.vp);
|
||||
s_put_var(&s, v);
|
||||
break;
|
||||
}
|
||||
|
||||
case 10: // SWAP
|
||||
{ // guess
|
||||
struct Var v = *s.vp;
|
||||
*s.vp = *(s.vp - 1);
|
||||
*(s.vp - 1) = v;
|
||||
}
|
||||
break;
|
||||
|
||||
case 11:
|
||||
// fprintf (f, "ELEM");
|
||||
case 11: // ELEM
|
||||
{
|
||||
struct Var array = s_take_var(&s);
|
||||
struct Var index = s_take_var(&s);
|
||||
if (array.type != ARRAY_T) {
|
||||
failure("ERROR: elem, previous element is not array", h, l);
|
||||
}
|
||||
if (index.type != INT_T) {
|
||||
failure("ERROR: elem, last element is not int", h, l);
|
||||
}
|
||||
s_put_var(&s, array.value.array_v[index.value.int_v]);
|
||||
|
||||
free_var(array);
|
||||
free_var(index);
|
||||
// FIXME: deal vith deletion of shallow copies of locals
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL;
|
||||
failure("ERROR: invalid opcode %d-%d\n", h, l);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -327,118 +443,128 @@ void run(bytefile *bf) {
|
|||
// 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;
|
||||
default:
|
||||
failure("ERROR: invalid opcode %d-%d\n", h, l);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
switch (l) {
|
||||
case 0:
|
||||
// fprintf (f, "CJMPz\t0x%.8x", INT);
|
||||
case 0: { // CJMPz 0x%.8x
|
||||
// FIXME: TODO: jump by top stack condition ??
|
||||
char* new_ip = (char*)(long)read_int(&s.ip); // TODO: check
|
||||
if (s_take_i(&s) != 0) { // FIXME: bools ??, other vars ??
|
||||
s.ip = new_ip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: { // CJMPnz 0x%.8x
|
||||
// FIXME: TODO: jump by top stack condition ??i
|
||||
char* new_ip = (char*)(long)read_int(&s.ip); // TODO: check
|
||||
if (s_take_i(&s) == 0) { // FIXME: bools ??, other vars ??
|
||||
s.ip = new_ip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: // BEGIN %d %d
|
||||
s_enter_f(&s, s.prev_ip/*ip from call*/, read_int(&s.ip), read_int(&s.ip));
|
||||
// TODO: is func enter ?
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// fprintf (f, "CJMPnz\t0x%.8x", INT);
|
||||
case 3: // CBEGIN %d %d
|
||||
s_enter_f(&s, s.prev_ip/*ip from call*/, read_int(&s.ip), read_int(&s.ip));
|
||||
// TODO: is func enter ?
|
||||
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;
|
||||
}
|
||||
}
|
||||
case 4: // CLOSURE 0x%.8x
|
||||
{
|
||||
int n = read_int(&s.ip);
|
||||
for (int i = 0; i < n; i++) {
|
||||
switch (read_byte(&s.ip)) {
|
||||
// case 0: // G(%d)
|
||||
// case 1: // L(%d)
|
||||
// case 2: // A(%d)
|
||||
// case 3: // C(%d)
|
||||
default:
|
||||
failure("ERROR: invalid opcode %d-%d\n", h, l);
|
||||
}
|
||||
}
|
||||
};
|
||||
break;
|
||||
|
||||
case 5:
|
||||
// fprintf (f, "CALLC\t%d", INT);
|
||||
case 5: // CALLC %d
|
||||
// TODO: no arguments given ??
|
||||
// TODO: jump only ??
|
||||
s.ip = (char*)(long)read_int(&s.ip); // TODO: check
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// fprintf (f, "CALL\t0x%.8x ", INT);
|
||||
// fprintf (f, "%d", INT);
|
||||
case 6: // CALL 0x%.8x %d
|
||||
// TODO: second arg is given params amount ??
|
||||
// TODO: jump only ??
|
||||
s.ip = (char*)(long)read_int(&s.ip); // TODO: check
|
||||
break;
|
||||
|
||||
case 7:
|
||||
// fprintf (f, "TAG\t%s ", STRING);
|
||||
// fprintf (f, "%d", INT);
|
||||
case 7: // TAG %s
|
||||
// TODO: ??
|
||||
break;
|
||||
|
||||
case 8:
|
||||
// fprintf (f, "ARRAY\t%d", INT);
|
||||
case 8: // ARRAY %d
|
||||
s_put_array(&s, read_int(&s.ip));
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// fprintf (f, "FAIL\t%d", INT);
|
||||
// fprintf (f, "%d", INT);
|
||||
case 9: // FAIL %d %d
|
||||
// TODO: ??
|
||||
failure("FAIL: %d-%d\n", read_int(&s.ip), read_int(&s.ip));
|
||||
break;
|
||||
|
||||
case 10:
|
||||
// fprintf (f, "LINE\t%d", INT);
|
||||
case 10: // LINE %d
|
||||
// maybe some metainfo should be collected
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL;
|
||||
failure("ERROR: invalid opcode %d-%d\n", h, l);
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// fprintf (f, "PATT\t%s", pats[l]);
|
||||
case 6: // PATT pats[l]
|
||||
// TODO: JMP if same to pattern ??
|
||||
break;
|
||||
|
||||
case 7: {
|
||||
switch (l) {
|
||||
case 0:
|
||||
// fprintf (f, "CALL\tLread");
|
||||
read_int();
|
||||
case 0: // CALL Lread
|
||||
f_read(&s);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// fprintf (f, "CALL\tLwrite");
|
||||
write_int();
|
||||
case 1: // CALL Lwrite
|
||||
f_write(&s);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// fprintf (f, "CALL\tLlength");
|
||||
case 2: // CALL Llength
|
||||
f_length(&s);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// fprintf (f, "CALL\tLstring");
|
||||
case 3: // CALL Lstring
|
||||
f_string(&s);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// fprintf (f, "CALL\tBarray\t%d", INT);
|
||||
case 4: // CALL Barray %d
|
||||
f_array(&s, read_int(&s.ip));
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL;
|
||||
failure("ERROR: invalid opcode %d-%d\n", h, l);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL;
|
||||
failure("ERROR: invalid opcode %d-%d\n", h, l);
|
||||
}
|
||||
|
||||
// fprintf (f, "\n");
|
||||
s.prev_ip = before_op_ip;
|
||||
}
|
||||
while (1);
|
||||
stop:; // fprintf (f, "<end>\n");i
|
||||
stop:;
|
||||
free_state(&s);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue