mirror of
https://github.com/ProgramSnail/Lama.git
synced 2025-12-07 23:38:47 +00:00
part of migration to gc
This commit is contained in:
parent
fb1ec1c7ae
commit
d782934f0c
5 changed files with 457 additions and 337 deletions
35
byterun/include/builtin.h
Normal file
35
byterun/include/builtin.h
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "operations.h"
|
||||||
|
|
||||||
|
inline void f_read(struct State *s) {
|
||||||
|
int x = 0;
|
||||||
|
printf("> "); // TODO: ??
|
||||||
|
scanf("%i", &x);
|
||||||
|
s_put_i(s, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void f_write(struct State *s) {
|
||||||
|
int x = s_take_i(s);
|
||||||
|
printf("%i", x);
|
||||||
|
// put 0 ??
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void f_length(struct State *s) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void f_string(struct State *s) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void f_array(struct State *s, int sz) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void f_cons(struct State *s) {
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
255
byterun/include/operations.h
Normal file
255
byterun/include/operations.h
Normal file
|
|
@ -0,0 +1,255 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../runtime/runtime.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
// TODO: use gc
|
||||||
|
|
||||||
|
// ------ general ------
|
||||||
|
|
||||||
|
// TODO: use gc
|
||||||
|
inline void free_var_ptr(union VarT *var);
|
||||||
|
|
||||||
|
inline void free_var(union VarT var) {
|
||||||
|
switch (dh_type(var.nil.data_header)) {
|
||||||
|
case NIL_T:
|
||||||
|
break;
|
||||||
|
case INT_T:
|
||||||
|
break;
|
||||||
|
case CONST_STR_T:
|
||||||
|
break;
|
||||||
|
case STR_T:
|
||||||
|
free(var.str.value);
|
||||||
|
break;
|
||||||
|
case LIST_T:
|
||||||
|
if (var.list.value != NULL) {
|
||||||
|
free_var_ptr(to_var(var.list.value));
|
||||||
|
}
|
||||||
|
if (var.list.next != NULL) {
|
||||||
|
free_var_ptr(to_var(var.list.next));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ARRAY_T:
|
||||||
|
// dh param is size
|
||||||
|
for (size_t i = 0; i < dh_param(var.array.data_header); ++i) {
|
||||||
|
free_var_ptr(to_var(var.array.values[i]));
|
||||||
|
}
|
||||||
|
free(var.array.values);
|
||||||
|
break;
|
||||||
|
case SEXP_T:
|
||||||
|
// tag is const string, no need to free
|
||||||
|
if (var.sexp.next != NULL) {
|
||||||
|
free(var.sexp.next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FUN_T:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use gc
|
||||||
|
inline void free_var_ptr(union VarT *var) {
|
||||||
|
free_var(*var);
|
||||||
|
free((void *)var);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
inline NilT clear_var() { return NilT{.data_header = NIL_T}; }
|
||||||
|
|
||||||
|
// usually not required, because frame is located on shared stack
|
||||||
|
inline struct Frame clear_frame() {
|
||||||
|
struct Frame frame = {
|
||||||
|
.ret_ip = NULL,
|
||||||
|
.rp = NULL,
|
||||||
|
.ret = NULL,
|
||||||
|
.params = NULL,
|
||||||
|
.locals = NULL,
|
||||||
|
.end = NULL,
|
||||||
|
};
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: not required ??
|
||||||
|
// inline 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;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ------ put on stack ---
|
||||||
|
|
||||||
|
inline void s_put_var(struct State *s, struct NilT *val) { // any var
|
||||||
|
*s->vp = val;
|
||||||
|
++s->vp;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void s_put_nil(struct State *s) {
|
||||||
|
struct NilT *var = alloc();
|
||||||
|
var->data_header = NIL_T; // no param
|
||||||
|
s_put_var(s, var);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void s_putn_nil(struct State *s, size_t n) {
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
s_put_nil(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void s_put_i(struct State *s, int val) {
|
||||||
|
struct IntT *var = alloc();
|
||||||
|
var->data_header = INT_T; // no param
|
||||||
|
var->value = val;
|
||||||
|
s_put_var(s, (NilT *)var);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void s_put_const_str(struct State *s,
|
||||||
|
const char *val) { // memory controlled externally
|
||||||
|
struct ConstStrT *var = alloc();
|
||||||
|
var->data_header = CONST_STR_T; // no param
|
||||||
|
var->value = val;
|
||||||
|
s_put_var(s, (NilT *)var);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void s_put_str(struct State *s, char *val) { // memory controlled by var
|
||||||
|
struct StrT *var = alloc();
|
||||||
|
var->data_header = STR_T; // no param
|
||||||
|
var->value = val;
|
||||||
|
s_put_var(s, (NilT *)var);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
inline 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 ?
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void s_put_list(struct State *s,
|
||||||
|
struct NilT *first_elem) { // memory controlled by var
|
||||||
|
struct ListT *var;
|
||||||
|
var->data_header = LIST_T; // no param
|
||||||
|
var->value = first_elem;
|
||||||
|
var->next = NULL;
|
||||||
|
|
||||||
|
s_put_var(s, (NilT *)var);
|
||||||
|
|
||||||
|
*first_elem = clear_var();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------ take from stack ------
|
||||||
|
|
||||||
|
inline union VarT *s_take_var(struct State *s) {
|
||||||
|
if (s->vp == s->fp->end) {
|
||||||
|
failure("take: no var");
|
||||||
|
}
|
||||||
|
--s->vp;
|
||||||
|
|
||||||
|
union VarT *ret = *s->vp;
|
||||||
|
*s->vp = NULL; // clear top var
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int s_take_i(struct State *s) {
|
||||||
|
union VarT *v = s_take_var(s);
|
||||||
|
if (dh_type(v->nil.data_header) != INT_T) {
|
||||||
|
failure("take int: not int");
|
||||||
|
}
|
||||||
|
return v->int_t.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void s_drop_var(struct State *s) {
|
||||||
|
if (s->vp == s->fp->end) {
|
||||||
|
failure("drop: no var");
|
||||||
|
}
|
||||||
|
--s->vp;
|
||||||
|
free_var_ptr(*s->vp);
|
||||||
|
*s->vp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void s_dropn_var(struct State *s, size_t n) {
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
s_drop_var(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------ functions ------
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
inline void s_exit_f(struct State *s) {
|
||||||
|
if (s->fp == (void *)s->stack) {
|
||||||
|
failure("exit: no func");
|
||||||
|
}
|
||||||
|
--s->fp;
|
||||||
|
s_dropn_var(s, s->vp - s->fp->locals);
|
||||||
|
// drop local var stack and locals // TODO: check +-1
|
||||||
|
union VarT *ret = *s->vp;
|
||||||
|
--s->vp;
|
||||||
|
s_dropn_var(s, s->vp - s->fp->params);
|
||||||
|
// drop params // TODO: check +-1
|
||||||
|
s_put_var(s, ret);
|
||||||
|
s->ip = s->fp->rp;
|
||||||
|
|
||||||
|
// *s->fp = clear_frame(); // clear top frame
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
inline void s_enter_f(struct State *s, char *func_ip, size_t params_sz,
|
||||||
|
size_t locals_sz) {
|
||||||
|
struct Frame frame = {
|
||||||
|
.rp = s->ip, // ??
|
||||||
|
.ret = s->vp,
|
||||||
|
.params = s->vp - params_sz, // TODO: check +-1
|
||||||
|
.locals = s->vp + 1,
|
||||||
|
.end = s->vp + locals_sz + 1, // ??
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
s_put_nil(s); // ret
|
||||||
|
s_putn_nil(s, locals_sz); // locals
|
||||||
|
s->ip = func_ip;
|
||||||
|
(*s->fp) = frame;
|
||||||
|
++s->fp;
|
||||||
|
}
|
||||||
120
byterun/include/types.h
Normal file
120
byterun/include/types.h
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// ------ Var ------
|
||||||
|
|
||||||
|
// TODO: clojures
|
||||||
|
enum Type {
|
||||||
|
NIL_T = 0x00000000,
|
||||||
|
INT_T = 0x00000001,
|
||||||
|
CONST_STR_T = 0x00000002,
|
||||||
|
STR_T = 0x00000003,
|
||||||
|
LIST_T = 0x00000004,
|
||||||
|
ARRAY_T = 0x00000005,
|
||||||
|
SEXP_T = 0x00000006,
|
||||||
|
FUN_T = 0x00000007
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NilT { // AnyVarT too
|
||||||
|
int32_t data_header;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntT {
|
||||||
|
int32_t data_header;
|
||||||
|
int32_t value; // int value => size = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConstStrT {
|
||||||
|
int32_t data_header;
|
||||||
|
const char *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StrT {
|
||||||
|
int32_t data_header;
|
||||||
|
char *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ListT {
|
||||||
|
int32_t data_header;
|
||||||
|
struct NilT *value;
|
||||||
|
struct NilT *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ArrayT {
|
||||||
|
int32_t data_header;
|
||||||
|
struct NilT **values;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SExpT {
|
||||||
|
int32_t data_header;
|
||||||
|
const char *tag;
|
||||||
|
struct NilT *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FunT {
|
||||||
|
int32_t data_header;
|
||||||
|
char *fun_ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
union VarT {
|
||||||
|
struct NilT nil;
|
||||||
|
struct IntT int_t;
|
||||||
|
struct ConstStrT const_str;
|
||||||
|
struct StrT str;
|
||||||
|
struct ListT list;
|
||||||
|
struct ArrayT array;
|
||||||
|
struct SExpT sexp;
|
||||||
|
struct FunT fun;
|
||||||
|
};
|
||||||
|
|
||||||
|
// same to TAG in runtime
|
||||||
|
inline enum Type dh_type(int data_header) {
|
||||||
|
return (Type)(data_header & 0x00000007);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same to LEN in runtime
|
||||||
|
inline int dh_param(int data_header) { return (data_header & 0xFFFFFFF8) >> 3; }
|
||||||
|
|
||||||
|
inline union VarT *to_var(struct NilT *var) { return (union VarT *)var; }
|
||||||
|
|
||||||
|
// ------ Frame ------
|
||||||
|
|
||||||
|
struct Frame {
|
||||||
|
char *rp; // ret instruction pointer
|
||||||
|
struct NilT **ret; // store returned value
|
||||||
|
struct NilT **params; // store arguments
|
||||||
|
struct NilT **locals; // store locals
|
||||||
|
struct NilT **end; // store locals
|
||||||
|
};
|
||||||
|
|
||||||
|
inline uint64_t frame_locals_sz(struct Frame *frame) {
|
||||||
|
return frame->locals - frame->params;
|
||||||
|
}
|
||||||
|
inline uint64_t frame_params_sz(struct Frame *frame) {
|
||||||
|
return frame->end - frame->locals;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------ State ------
|
||||||
|
|
||||||
|
union StackValue {
|
||||||
|
union VarT *var;
|
||||||
|
union VarT **var_ptr;
|
||||||
|
// struct Frame frame; // TODO
|
||||||
|
char *addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// inline StackValue *to_sv(void *var) { return (StackValue *)var; }
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
union StackValue *stack; // vaid**
|
||||||
|
struct NilT **vp; // var pointer
|
||||||
|
struct Frame *fp; // function frame pointer
|
||||||
|
|
||||||
|
char *ip; // instruction pointer
|
||||||
|
char *prev_ip; // prev instruction pointer
|
||||||
|
};
|
||||||
|
|
||||||
|
struct State init_state(bytefile *bf);
|
||||||
|
void destruct_state(struct State *state);
|
||||||
|
|
@ -1,338 +1,21 @@
|
||||||
#include "../include/interpreter.h"
|
#include "../include/interpreter.h"
|
||||||
|
#include "../include/types.h"
|
||||||
#include "../../runtime/runtime.h"
|
#include "../../runtime/runtime.h"
|
||||||
|
|
||||||
int read_int(char** ip) {
|
int ip_read_int(char** ip) {
|
||||||
*ip += sizeof(int);
|
*ip += sizeof(int);
|
||||||
return *(int*)((*ip) - sizeof(int));
|
return *(int*)((*ip) - sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
char read_byte(char** ip) {
|
char ip_read_byte(char** ip) {
|
||||||
return *(*ip)++;
|
return *(*ip)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* read_string(char** ip, bytefile* bf) {
|
char* ip_read_string(char** ip, bytefile* bf) {
|
||||||
return get_string(bf, read_int(ip));
|
return get_string(bf, ip_read_int(ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
struct Var;
|
|
||||||
|
|
||||||
struct ListElem {
|
|
||||||
struct Var* elem;
|
|
||||||
struct Var* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Var {
|
|
||||||
enum Type { INT_T, CONST_STR_T, STR_T, LIST_T, ARRAY_T, FUN_T, NIL_T/*?*/ } type;
|
|
||||||
size_t size;
|
|
||||||
union {
|
|
||||||
int int_v; // int value => size = 1;
|
|
||||||
const char* const_str_v; // point to str in str table => size = string size (?)
|
|
||||||
char* str_v; // poitert ot string => size = string size (?)
|
|
||||||
struct ListElem list_v; // elem => size = list size
|
|
||||||
struct Var* array_v; // pointer to array of elements => size = array size
|
|
||||||
char* fun_v; // pointer to function definition => size = 1
|
|
||||||
} value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Frame {
|
|
||||||
struct Var* params; // store arguments
|
|
||||||
struct Var* ret; // store returned value
|
|
||||||
struct Var* locals; // store locals
|
|
||||||
size_t locals_sz;
|
|
||||||
size_t params_sz;
|
|
||||||
|
|
||||||
char* rp; // ret instruction pointer
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: store globals in some way ?? // maybe some first vars ??
|
// TODO: store globals in some way ?? // maybe some first vars ??
|
||||||
struct State {
|
|
||||||
struct Var* vars;
|
|
||||||
struct Frame* funcs;
|
|
||||||
struct Var* vp; // var pointer
|
|
||||||
struct Frame* fp; // function pointer
|
|
||||||
|
|
||||||
char* ip; // instruction pointer
|
|
||||||
char* prev_ip; // prev instruction pointer
|
|
||||||
};
|
|
||||||
|
|
||||||
struct State init_state(bytefile *bf) {
|
|
||||||
struct State state = {
|
|
||||||
.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 ??
|
|
||||||
|
|
||||||
state.vp = state.vars;
|
|
||||||
state.fp = state.funcs;
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_state(struct State* state) {
|
|
||||||
free(state->vars);
|
|
||||||
free(state->funcs);
|
|
||||||
|
|
||||||
state->vars = NULL;
|
|
||||||
state->funcs = NULL;
|
|
||||||
state->vp = NULL;
|
|
||||||
state->fp = NULL;
|
|
||||||
state->ip = NULL;
|
|
||||||
state->prev_ip = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
void free_var_ptr(struct Var* var);
|
|
||||||
|
|
||||||
void free_var(struct Var var) {
|
|
||||||
switch (var.type) {
|
|
||||||
case INT_T:
|
|
||||||
break;
|
|
||||||
case CONST_STR_T:
|
|
||||||
break;
|
|
||||||
case STR_T:
|
|
||||||
free(var.value.str_v);
|
|
||||||
break;
|
|
||||||
case LIST_T:
|
|
||||||
if (var.value.list_v.elem != NULL) {
|
|
||||||
free_var_ptr(var.value.list_v.elem);
|
|
||||||
}
|
|
||||||
if (var.value.list_v.next != NULL) {
|
|
||||||
free_var_ptr(var.value.list_v.next);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ARRAY_T:
|
|
||||||
for (size_t i = 0; i < var.size; ++i) {
|
|
||||||
free_var(*(var.value.array_v + i));
|
|
||||||
}
|
|
||||||
free(var.value.array_v);
|
|
||||||
break;
|
|
||||||
case FUN_T:
|
|
||||||
break;
|
|
||||||
case NIL_T:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_var_ptr(struct Var* var) {
|
|
||||||
free_var(*var);
|
|
||||||
free(var);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
struct Var clear_var() {
|
|
||||||
struct Var var = {
|
|
||||||
.type = NIL_T,
|
|
||||||
.size = 0,
|
|
||||||
};
|
|
||||||
return var;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Frame clear_frame() {
|
|
||||||
struct Frame frame = {
|
|
||||||
.params = NULL,
|
|
||||||
.ret = NULL,
|
|
||||||
.locals = NULL,
|
|
||||||
.params_sz = 0,
|
|
||||||
.locals_sz = 0,
|
|
||||||
};
|
|
||||||
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) {
|
|
||||||
*s->vp = val;
|
|
||||||
++s->vp;
|
|
||||||
}
|
|
||||||
void s_put_nil(struct State* s) {
|
|
||||||
struct Var var = {.type = NIL_T, .size = 0};
|
|
||||||
s_put_var(s, var);
|
|
||||||
}
|
|
||||||
void s_putn_nil(struct State* s, size_t n) {
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
s_put_nil(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void s_put_i(struct State* s, int val) {
|
|
||||||
struct Var var = {.type = INT_T, .value.int_v = val, .size = 1};
|
|
||||||
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 = 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 = 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
struct Var s_take_var(struct State* s) {
|
|
||||||
if (s->vp == s->vars) {
|
|
||||||
failure("take: no var");
|
|
||||||
}
|
|
||||||
--s->vp;
|
|
||||||
|
|
||||||
struct Var ret = *s->vp;
|
|
||||||
*s->vp = clear_var(); // clear top var
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
--s->vp;
|
|
||||||
free_var(*s->vp);
|
|
||||||
|
|
||||||
*s->vp = clear_var(); // clear top var
|
|
||||||
}
|
|
||||||
|
|
||||||
void s_dropn_var(struct State* s, size_t n) {
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
|
||||||
s_drop_var(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
void s_exit_f(struct State* s) {
|
|
||||||
if (s->fp == s->funcs) {
|
|
||||||
failure("exit: no func");
|
|
||||||
}
|
|
||||||
--s->fp;
|
|
||||||
s_dropn_var(s, s->vp - s->fp->locals); // drop local var stack and locals // TODO: check +-1
|
|
||||||
struct Var ret = *s->vp;
|
|
||||||
--s->vp;
|
|
||||||
s_dropn_var(s, s->vp - s->fp->params); // drop params // TODO: check +-1
|
|
||||||
s_put_var(s, ret);
|
|
||||||
s->ip = s->fp->rp;
|
|
||||||
|
|
||||||
*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) {
|
|
||||||
struct Frame frame = {
|
|
||||||
.params = s->vp - params_sz, // TODO: check +-1
|
|
||||||
.ret = s->vp,
|
|
||||||
.locals = s->vp + 1,
|
|
||||||
.params_sz = params_sz,
|
|
||||||
.locals_sz = locals_sz,
|
|
||||||
.rp = s->ip,
|
|
||||||
};
|
|
||||||
s_put_nil(s); // ret
|
|
||||||
s_putn_nil(s, locals_sz); // locals
|
|
||||||
s->ip = func_ip;
|
|
||||||
(*s->fp) = frame;
|
|
||||||
++s->fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
// --- 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) {
|
void run(bytefile *bf) {
|
||||||
struct State s = init_state(bf);
|
struct State s = init_state(bf);
|
||||||
|
|
@ -343,7 +26,7 @@ void run(bytefile *bf) {
|
||||||
do {
|
do {
|
||||||
char* before_op_ip = s.ip; // save to set s.prev_ip
|
char* before_op_ip = s.ip; // save to set s.prev_ip
|
||||||
|
|
||||||
char x = read_byte(&s.ip),
|
char x = ip_read_byte(&s.ip),
|
||||||
h = (x & 0xF0) >> 4,
|
h = (x & 0xF0) >> 4,
|
||||||
l = x & 0x0F;
|
l = x & 0x0F;
|
||||||
|
|
||||||
|
|
@ -361,11 +44,11 @@ void run(bytefile *bf) {
|
||||||
case 1:
|
case 1:
|
||||||
switch (l) {
|
switch (l) {
|
||||||
case 0: // CONST %d
|
case 0: // CONST %d
|
||||||
s_put_i(&s, read_int(&s.ip));
|
s_put_i(&s, ip_read_int(&s.ip));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: // STRING %s
|
case 1: // STRING %s
|
||||||
s_put_const_str(&s, read_string(&s.ip, bf));
|
s_put_const_str(&s, ip_read_string(&s.ip, bf));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: // SEXP %s %d
|
case 2: // SEXP %s %d
|
||||||
|
|
@ -381,7 +64,7 @@ void run(bytefile *bf) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5: // JMP 0x%.8x
|
case 5: // JMP 0x%.8x
|
||||||
s.ip = (char*)(long)read_int(&s.ip); // TODO: check
|
s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6: // END
|
case 6: // END
|
||||||
|
|
@ -452,7 +135,7 @@ void run(bytefile *bf) {
|
||||||
switch (l) {
|
switch (l) {
|
||||||
case 0: { // CJMPz 0x%.8x
|
case 0: { // CJMPz 0x%.8x
|
||||||
// FIXME: TODO: jump by top stack condition ??
|
// FIXME: TODO: jump by top stack condition ??
|
||||||
char* new_ip = (char*)(long)read_int(&s.ip); // TODO: check
|
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
|
||||||
if (s_take_i(&s) != 0) { // FIXME: bools ??, other vars ??
|
if (s_take_i(&s) != 0) { // FIXME: bools ??, other vars ??
|
||||||
s.ip = new_ip;
|
s.ip = new_ip;
|
||||||
}
|
}
|
||||||
|
|
@ -460,27 +143,27 @@ void run(bytefile *bf) {
|
||||||
}
|
}
|
||||||
case 1: { // CJMPnz 0x%.8x
|
case 1: { // CJMPnz 0x%.8x
|
||||||
// FIXME: TODO: jump by top stack condition ??i
|
// FIXME: TODO: jump by top stack condition ??i
|
||||||
char* new_ip = (char*)(long)read_int(&s.ip); // TODO: check
|
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
|
||||||
if (s_take_i(&s) == 0) { // FIXME: bools ??, other vars ??
|
if (s_take_i(&s) == 0) { // FIXME: bools ??, other vars ??
|
||||||
s.ip = new_ip;
|
s.ip = new_ip;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: // BEGIN %d %d
|
case 2: // BEGIN %d %d
|
||||||
s_enter_f(&s, s.prev_ip/*ip from call*/, read_int(&s.ip), read_int(&s.ip));
|
s_enter_f(&s, s.prev_ip/*ip from call*/, ip_read_int(&s.ip), ip_read_int(&s.ip));
|
||||||
// TODO: is func enter ?
|
// TODO: is func enter ?
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: // CBEGIN %d %d
|
case 3: // CBEGIN %d %d
|
||||||
s_enter_f(&s, s.prev_ip/*ip from call*/, read_int(&s.ip), read_int(&s.ip));
|
s_enter_f(&s, s.prev_ip/*ip from call*/, ip_read_int(&s.ip), ip_read_int(&s.ip));
|
||||||
// TODO: is func enter ?
|
// TODO: is func enter ?
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: // CLOSURE 0x%.8x
|
case 4: // CLOSURE 0x%.8x
|
||||||
{
|
{
|
||||||
int n = read_int(&s.ip);
|
int n = ip_read_int(&s.ip);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
switch (read_byte(&s.ip)) {
|
switch (ip_read_byte(&s.ip)) {
|
||||||
// case 0: // G(%d)
|
// case 0: // G(%d)
|
||||||
// case 1: // L(%d)
|
// case 1: // L(%d)
|
||||||
// case 2: // A(%d)
|
// case 2: // A(%d)
|
||||||
|
|
@ -495,13 +178,13 @@ void run(bytefile *bf) {
|
||||||
case 5: // CALLC %d
|
case 5: // CALLC %d
|
||||||
// TODO: no arguments given ??
|
// TODO: no arguments given ??
|
||||||
// TODO: jump only ??
|
// TODO: jump only ??
|
||||||
s.ip = (char*)(long)read_int(&s.ip); // TODO: check
|
s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6: // CALL 0x%.8x %d
|
case 6: // CALL 0x%.8x %d
|
||||||
// TODO: second arg is given params amount ??
|
// TODO: second arg is given params amount ??
|
||||||
// TODO: jump only ??
|
// TODO: jump only ??
|
||||||
s.ip = (char*)(long)read_int(&s.ip); // TODO: check
|
s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7: // TAG %s
|
case 7: // TAG %s
|
||||||
|
|
@ -509,12 +192,12 @@ void run(bytefile *bf) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8: // ARRAY %d
|
case 8: // ARRAY %d
|
||||||
s_put_array(&s, read_int(&s.ip));
|
s_put_array(&s, ip_read_int(&s.ip));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 9: // FAIL %d %d
|
case 9: // FAIL %d %d
|
||||||
// TODO: ??
|
// TODO: ??
|
||||||
failure("FAIL: %d-%d\n", read_int(&s.ip), read_int(&s.ip));
|
failure("FAIL: %d-%d\n", ip_read_int(&s.ip), ip_read_int(&s.ip));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 10: // LINE %d
|
case 10: // LINE %d
|
||||||
|
|
@ -549,7 +232,7 @@ void run(bytefile *bf) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: // CALL Barray %d
|
case 4: // CALL Barray %d
|
||||||
f_array(&s, read_int(&s.ip));
|
f_array(&s, ip_read_int(&s.ip));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
27
byterun/src/types.c
Normal file
27
byterun/src/types.c
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include "../include/types.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// TODO: gc use
|
||||||
|
|
||||||
|
struct State init_state(bytefile *bf) {
|
||||||
|
struct State state = {
|
||||||
|
.stack = calloc(1000/* TODO */, sizeof(void*)),
|
||||||
|
.ip = bf->code_ptr,
|
||||||
|
.prev_ip = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
state.vp = *state.stack;
|
||||||
|
state.fp = NULL;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destruct_state(struct State* state) {
|
||||||
|
free(state->stack);
|
||||||
|
|
||||||
|
state->vp = NULL;
|
||||||
|
state->fp = NULL;
|
||||||
|
state->ip = NULL;
|
||||||
|
state->prev_ip = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue