builtin operations, some fixes, list made of sexpr, clojure

This commit is contained in:
ProgramSnail 2024-10-30 02:44:33 +03:00
parent 1c85bf553a
commit 23835d92fd
4 changed files with 234 additions and 51 deletions

View file

@ -6,7 +6,7 @@
inline void f_read(struct State *s) {
int x = 0;
printf("> "); // TODO: ??
printf("> ");
scanf("%i", &x);
s_put_i(s, x);
}
@ -14,70 +14,200 @@ inline void f_read(struct State *s) {
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
}
union VarT *x = s_take_var(s);
uint32_t type = dh_type(x->nil.data_header);
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
if (type == ARRAY_T || type == STR_T) {
s_put_i(s, dh_param(x->array.data_header));
} else if (type == CONST_STR_T) {
s_put_i(s, strlen(x->const_str.value));
} else if (type == STR_T) {
s_put_i(s, strlen(x->str.value));
} else { // TODO: lists ??
failure("no length func for type %ui", type);
}
}
// TODO
inline size_t str_sz(union VarT *var) {
switch (dh_type(var->nil.data_header)) {
case NIL_T: // <nil>
return strlen("<nil>");
case INT_T: // int
return snprintf(nullptr, 0, "%d", var->int_t.value);
case CONST_STR_T: // "str"
return strlen(var->const_str.value);
case STR_T: // "str"
return strlen(var->str.value);
case CLOJURE_T: // <clojure> // TODO
return strlen("<clojure>");
break;
case ARRAY_T: { // [a_1 a_2 a_3 ... a_n]
size_t sz = 0;
if (var->array.values != NULL) {
for (size_t i = 0; i < dh_param(var->array.data_header); ++i) {
sz += str_sz((VarT *)var->array.values[i]) + 1;
}
--sz; // extra space
}
return sz + 2; // '[', ']'
}
case SEXP_T: { // tag:{a_1 a_2 ...}
size_t sz = 0;
if (var->sexp.tag != NULL) {
sz += strlen(var->sexp.tag) + 1 // tag and ':'
}
if (var->sexp.values != NULL) {
for (size_t i = 0; i < dh_param(var->sexp.data_header); ++i) {
sz += str_sz((VarT *)var->sexp.values[i]) + 1;
}
--sz; // extra space
}
return sz + 2; // '{', '}'
}
case FUN_T: // <fun>
return strlen("<fun>");
}
}
// TODO
inline char *to_str(union VarT *var, char *str, size_t max_sz) {
str[0] = 0;
switch (dh_type(var->nil.data_header)) {
case NIL_T:
strcat(str, "<nil>");
break;
case INT_T:
snprintf(str, max_sz, "%d", var->int_t.value);
break;
case CONST_STR_T:
strcat(str, "\"");
strcat(str, var->const_str.value);
strcat(str, "\"");
break;
case STR_T:
strcat(str, "\"");
strcat(str, var->str.value);
strcat(str, "\"");
break;
case CLOJURE_T: // TODO
strcat(str, "<clojure>");
break;
case ARRAY_T:
strcat(str, "[");
++str;
for (size_t i = 0; i < dh_param(var->array.data_header); ++i) {
str = to_str((VarT *)var->array.values[i], str, max_sz);
strcat(str, " ");
++str;
}
strcat(str, "]");
break;
case SEXP_T:
if (var->sexp.tag != NULL) {
strcat(str, var->sexp.tag);
strcat(str, ":");
}
strcat(str, "{");
str += strlen(str);
for (size_t i = 0; i < dh_param(var->sexp.data_header); ++i) {
str = to_str((VarT *)var->sexp.values[i], str, max_sz);
strcat(str, " ");
++str;
}
strcat(str, "}");
break;
case FUN_T:
strcat(str, "<fun>");
break;
}
return str + strlen(str);
}
inline void f_string(struct State *s) {
union VarT *var = s_take_var(s);
size_t var_str_sz = str_sz(var);
char *var_str = (char *)malloc((var_str_sz + 1) * sizeof(char));
to_str(var, var_str, var_str_sz);
s_put_str(s, var_str);
free_var_ptr(var);
}
inline void f_array(struct State *s, int sz) { s_put_array(s, sz); }
inline void f_binop(struct State *s, const char *opr) {
size_t len = strlen(opr);
int y = s_take_i(s);
int x = s_take_i(s);
int z = 0;
if (len < 1) {
failure("empty operation");
failure("BINOP: empty operation");
}
switch (opr[0]) {
case '+':
z = x + y;
break;
case '-':
z = x - y;
break;
case '*':
z - x *y;
break;
case '/':
if (y == 0) {
failure("BINOP: can't divide by zero");
}
z = x / y;
break;
case '%':
if (y == 0) {
failure("BINOP: can't take by mod zero");
}
z = x % y;
break;
case '<':
if (len == 1) { // <
z = x < y;
} else { // <=
z = x <= y;
}
break;
case '>':
if (len == 1) { // >
z = x > y;
} else { // >=
z = x >= y;
}
break;
case '=': // ==
z = x == y;
break;
case '!':
if (len == 1) {
failure("'!...' opr len is 1");
failure("BINOP: '!...' opr len is 1");
}
if (opr[1] == '=') { // !=
z = x != y;
} else { // !!
z = x || y;
}
break;
case '&': // &&
z = x && y;
break;
default:
failure("unknown operation");
failure("BINOP: unknown operation");
}
s_put_i(s, z);
}

View file

@ -21,7 +21,7 @@ inline void free_var(union VarT var) {
case STR_T:
free(var.str.value);
break;
case LIST_T:
case CLOJURE_T:
if (var.list.value != NULL) {
free_var_ptr(to_var(var.list.value));
}
@ -107,10 +107,6 @@ inline void s_put_str(struct State *s, char *val) {
s_put_var(s, (NilT *)var);
}
inline void s_put_enum(struct State *s, const char *tag, int args_sz) {
// TODO FIXME
}
inline void s_put_array(struct State *s, int sz) {
struct ArrayT *var = (ArrayT *)alloc(sizeof(ArrayT));
@ -131,15 +127,42 @@ inline void s_put_array(struct State *s, int sz) {
s_put_var(s, (NilT *)var);
}
inline void s_put_list(struct State *s, struct NilT *first_elem) {
struct ListT *var = (ListT *)alloc(sizeof(ListT));
var->data_header = LIST_T; // no param
var->value = first_elem;
var->next = NULL;
inline union VarT *s_take_var(struct State *s);
inline void s_put_sexp(struct State *s, const char *tag, int sz) {
struct SExpT *var = (SExpT *)alloc(sizeof(SExpT));
if (sz < 0) {
failure("array size < 0");
}
if (sz > MAX_ARRAY_SIZE) {
failure("too big array size");
}
var->data_header = sz & SEXP_T;
var->values = (NilT **)alloc(sizeof(NilT *) * sz);
var->tag = tag;
for (size_t i = 0; i < sz; ++i) {
var->values[i] = (NilT *)s_take_var(s);
}
s_put_var(s, (NilT *)var);
}
*first_elem = clear_var();
// inline void s_put_empty_list(struct State *s, struct NilT *first_elem) {
// struct ListT *var = (ListT *)alloc(sizeof(ListT));
// var->data_header = LIST_T; // no param
// var->value = first_elem;
// var->next = NULL;
// s_put_var(s, (NilT *)var);
// *first_elem = clear_var();
// }
inline void s_put_sexp(struct State *s, , int args_sz) {
// TODO FIXME
}
// ------ take from stack ------
@ -236,7 +259,33 @@ inline void s_exit_f(struct State *s) {
s->fp = s->fp->prev_fp;
}
inline union VarT *var_by_category(struct State *s, enum VarCategory category,
int id) {
// TODO: FIXME
inline union VarT **var_by_category(struct State *s, enum VarCategory category,
int id) {
VarT **var = NULL;
switch (category) {
case VAR_GLOBAL:
// TODO: FIXME
break;
case VAR_LOCAL:
if (s->fp == NULL) {
failure("can't read local outside of function");
}
if (id < 0) {
failure("can't read local: negative id %i", id);
}
if (frame_locals_sz(s->fp) <= id) {
failure("can't read local: too big id, %i >= %ul", frame_locals_sz(s->fp),
id);
}
var = (VarT **)&s->fp->locals[id];
break;
case VAR_A:
// TODO
break;
case VAR_C:
// TODO
break;
}
return var;
}

View file

@ -6,13 +6,12 @@
// ------ Var ------
// TODO: clojures
enum Type {
NIL_T = 0x00000000,
INT_T = 0x00000001,
CONST_STR_T = 0x00000002,
STR_T = 0x00000003,
LIST_T = 0x00000004,
CLOJURE_T = 0x00000004,
ARRAY_T = 0x00000005,
SEXP_T = 0x00000006,
FUN_T = 0x00000007
@ -37,11 +36,17 @@ struct StrT {
char *value;
};
struct ListT {
struct ClojureT { // TODO
uint32_t data_header;
struct NilT *value;
struct NilT *next;
};
char *fun_ip;
struct ArrayT *vars;
}
// struct ListT {
// uint32_t data_header;
// struct NilT *value;
// struct NilT *next;
// };
struct ArrayT {
uint32_t data_header;
@ -52,7 +57,7 @@ const size_t MAX_ARRAY_SIZE = 0x11111110;
struct SExpT {
uint32_t data_header;
const char *tag;
struct NilT *next;
struct NilT **values;
};
struct FunT {
@ -65,7 +70,8 @@ union VarT {
struct IntT int_t;
struct ConstStrT const_str;
struct StrT str;
struct ListT list;
struct ClojureT clojure;
// struct ListT list;
struct ArrayT array;
struct SExpT sexp;
struct FunT fun;

View file

@ -63,7 +63,7 @@ void run(bytefile *bf) {
break;
case 2: // SEXP %s %d // create sexpr with tag=%s and %d elements from stack
// TODO: params??
// params read from stack
s_put_sexp(&s, ip_read_string(&s.ip, bf), ip_read_int(&s.ip));
break;
@ -139,26 +139,25 @@ void run(bytefile *bf) {
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
union VarT** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip));
s_put_var(&s, (struct NilT*)*var_ptr); // TODO: check
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));
union VarT** var_ptr = 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
union VarT** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip));
*var_ptr = s_take_var(&s); // TODO: check
break;
}
case 5:
switch (l) {
case 0: { // CJMPz 0x%.8x
// FIXME: TODO: jump by top stack condition ??
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
if (s_take_i(&s) != 0) {
s.ip = new_ip;
@ -166,7 +165,6 @@ void run(bytefile *bf) {
break;
}
case 1: { // CJMPnz 0x%.8x
// FIXME: TODO: jump by top stack condition ??
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
if (s_take_i(&s) == 0) {
s.ip = new_ip;