Compare commits

...

3 Commits

Author SHA1 Message Date
bog 502a31d5c9 ADD: vars index assignment. 2023-08-26 06:53:14 +02:00
bog b14bd5cc28 ADD: vars can be declared as mutable. 2023-08-25 18:38:06 +02:00
bog 067dfdc638 ADD: var index. 2023-08-25 18:22:44 +02:00
17 changed files with 476 additions and 21 deletions

View File

@ -30,6 +30,12 @@ void array_free(array* self)
free(self->type); self->type = NULL; free(self->type); self->type = NULL;
} }
struct value* array_deref(array* self, size_t index)
{
assert(index < self->children.size);
return (struct value*) self->children.data[index];
}
struct value* array_deref_copy(array* self, size_t index) struct value* array_deref_copy(array* self, size_t index)
{ {
assert(index < self->children.size); assert(index < self->children.size);

View File

@ -19,6 +19,7 @@ void array_init(array* self, type* elements_type);
void array_free(array* self); void array_free(array* self);
struct value* array_deref_copy(array* self, size_t index); struct value* array_deref_copy(array* self, size_t index);
struct value* array_deref(array* self, size_t index);
void array_push(array* self, struct value* element); void array_push(array* self, struct value* element);
size_t array_str(array* self, char* buffer, size_t size); size_t array_str(array* self, char* buffer, size_t size);

View File

@ -30,6 +30,29 @@ void compile_node(compiler* self, node* root, program* prog)
program_add_instr(prog, OP_ADEREF, NO_PARAM); program_add_instr(prog, OP_ADEREF, NO_PARAM);
} }
// Variables stuff // Variables stuff
else if (root->type == NODE_CONSTDECL)
{
cstatic cs;
cstatic_init(&cs);
type* ty = cstatic_resolve_new(&cs,
self->sym,
root->children.data[1]);
size_t id = symtable_declare(
self->sym,
root->children.data[0]->value,
ty,
root->children.data[1]
);
compile_node(self, root->children.data[1], prog);
program_add_instr(prog, OP_STORE, id);
type_free(ty);
free(ty);
cstatic_free(&cs);
}
else if (root->type == NODE_VARDECL) else if (root->type == NODE_VARDECL)
{ {
cstatic cs; cstatic cs;
@ -42,7 +65,8 @@ void compile_node(compiler* self, node* root, program* prog)
size_t id = symtable_declare( size_t id = symtable_declare(
self->sym, self->sym,
root->children.data[0]->value, root->children.data[0]->value,
ty ty,
root->children.data[1]
); );
compile_node(self, root->children.data[1], prog); compile_node(self, root->children.data[1], prog);
@ -52,6 +76,35 @@ void compile_node(compiler* self, node* root, program* prog)
free(ty); free(ty);
cstatic_free(&cs); cstatic_free(&cs);
} }
else if (root->type == NODE_ASSIGN)
{
node* ident_node = root->children.data[0];
symentry* entry = symtable_find(
self->sym,
ident_node->value
);
assert(entry);
if (root->children.size == 3)
{
node* array_node = root->children.data[1];
node* expr_node = root->children.data[2];
compile_node(self, array_node, prog);
compile_node(self, expr_node, prog);
program_add_instr(prog, OP_ASTORE, entry->id);
}
else
{
node* expr_node = root->children.data[1];
compile_node(self, expr_node, prog);
program_add_instr(prog, OP_STORE, entry->id);
}
}
else if (root->type == NODE_IDENT) else if (root->type == NODE_IDENT)
{ {
symentry* entry = symtable_find(self->sym, root->value); symentry* entry = symtable_find(self->sym, root->value);

View File

@ -51,6 +51,21 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
return ty; return ty;
} }
if (ast->type == NODE_ASSIGN)
{
size_t i = 1;
if (ast->children.size == 3)
{
i = 2;
}
type* ty = cstatic_resolve_new(self,
sym,
ast->children.data[i]);
return ty;
}
if (ast->type == NODE_ADD) if (ast->type == NODE_ADD)
{ {
type* lhs = cstatic_resolve_new(self, sym, ast->children.data[0]); type* lhs = cstatic_resolve_new(self, sym, ast->children.data[0]);
@ -120,6 +135,13 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
size_t dim = ast->children.data[1]->children.size; size_t dim = ast->children.data[1]->children.size;
node* iter = ast->children.data[0]; node* iter = ast->children.data[0];
if (iter->type == NODE_IDENT)
{
symentry* entry = symtable_find(sym,
iter->value);
iter = entry->sym_node;
}
for (size_t i=0; i<dim; i++) for (size_t i=0; i<dim; i++)
{ {
iter = iter->children.data[0]; iter = iter->children.data[0];
@ -220,13 +242,21 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
size_t real_dim = 0; size_t real_dim = 0;
node* iter = ast->children.data[0]; node* iter = ast->children.data[0];
if (iter->type == NODE_IDENT)
{
symentry* entry = symtable_find(sym,
iter->value);
iter = entry->sym_node;
}
while (iter->type == NODE_ARRAY) while (iter->type == NODE_ARRAY)
{ {
iter = iter->children.data[0]; iter = iter->children.data[0];
real_dim++; real_dim++;
} }
if (real_dim != dim) if (real_dim < dim)
{ {
snprintf(msg, size, snprintf(msg, size,
"E: array dimension mismatch:" "E: array dimension mismatch:"
@ -294,7 +324,97 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
return 1; return 1;
} }
if (ast->type == NODE_VARDECL) if (ast->type == NODE_ASSIGN)
{
char const* name = ast->children.data[0]->value;
if (!symtable_find(sym, name))
{
fprintf(stderr, "E(%d): '%s' is undefined.\n",
ast->lineno,
name);
exit(-1);
}
symentry* entry = symtable_find(sym, name);
if (!entry->is_mut)
{
fprintf(stderr, "E(%d): '%s' is not mutable.\n",
ast->lineno,
name);
exit(-1);
}
if (ast->children.size == 3)
{
type* expr_ty = cstatic_resolve_new(self,
sym,
ast->children.data[2]
);
type* array_ty = cstatic_resolve_new(self,
sym,
ast->children.data[0]
);
size_t dim = ast->children.data[1]->children.size;
type* iter = array_ty;
for (size_t i=0; i<dim; i++)
{
if (iter->sub_types.size == 0)
{
fprintf(stderr,
"E(%d): array assignement "
"wrong dimension, expected"
" '%ld', got '%ld'.\n", ast->lineno,
i, dim);
exit(-1);
}
iter = iter->sub_types.data[0];
}
int status =
cstatic_check_same_type_ptr(self,
ast->children.data[0],
iter,
expr_ty, sym,
msg, size);
if (!status)
{
return 0;
}
type_free(array_ty); free(array_ty);
type_free(expr_ty); free(expr_ty);
return 1;
}
else
{
int status = cstatic_check_same_type(
self,
ast->children.data[0],
ast->children.data[1],
sym,
msg,
size
);
if (!status)
{
return 0;
}
}
return 1;
}
if (ast->type == NODE_VARDECL
|| ast->type == NODE_CONSTDECL)
{ {
char const* name = ast->children.data[0]->value; char const* name = ast->children.data[0]->value;
@ -308,7 +428,16 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
type* ty = cstatic_resolve_new(self, sym, ast->children.data[1]); type* ty = cstatic_resolve_new(self, sym, ast->children.data[1]);
assert(ty); assert(ty);
symtable_declare(sym, name, ty);
if (ast->type == NODE_VARDECL)
{
symtable_declare_mut(sym, name, ty, ast->children.data[1]);
}
else
{
symtable_declare(sym, name, ty, ast->children.data[1]);
}
type_free(ty); type_free(ty);
free(ty); free(ty);
return 1; return 1;
@ -670,6 +799,30 @@ int cstatic_check_type_base(cstatic* self, node* lhs, symtable* sym,
return 0; return 0;
} }
int cstatic_check_same_type_ptr(cstatic* self, node* lhs,
type* left, type* right, symtable* sym, char* msg, size_t size)
{
assert(self);
if (!type_equals(left, right))
{
size_t sz = 0;
sz += snprintf(msg + sz, size - sz, "E(%d): expected '", lhs->lineno);
sz += type_str(left, msg + sz, size - sz);
sz += snprintf(msg + sz, size - sz, "', got '");
sz += type_str(right, msg + sz, size - sz);
sz += snprintf(msg + sz, size - sz, "'");
type_free(left); free(left);
type_free(right); free(right);
return 0;
}
return 1;
}
int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym, int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym,
char* msg, size_t size) char* msg, size_t size)
{ {

View File

@ -26,6 +26,10 @@ int cstatic_check_type(cstatic* self, node* lhs, symtable* sym,
int cstatic_check_type_base(cstatic* self, node* lhs, symtable* sym, int cstatic_check_type_base(cstatic* self, node* lhs, symtable* sym,
char* msg, size_t size, int types, ...); char* msg, size_t size, int types, ...);
int cstatic_check_same_type_ptr(cstatic* self,
node* lhs, type* left, type* right, symtable* sym,
char* msg, size_t size);
int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym, int cstatic_check_same_type(cstatic* self, node* lhs, node* rhs, symtable* sym,
char* msg, size_t size); char* msg, size_t size);

View File

@ -26,6 +26,7 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
return TYPE; return TYPE;
} }
"let!" { return LET_MUT; }
"let" { return LET; } "let" { return LET; }
"assert" { return ASSERT; } "assert" { return ASSERT; }
"<=" { return LE; } "<=" { return LE; }

View File

@ -36,6 +36,19 @@ void node_free(node* self)
self->children.capacity = 0; self->children.capacity = 0;
} }
node* node_new_clone(node* self)
{
assert(self);
node* clone = malloc(sizeof(node));
node_init(clone, self->type, self->value, self->lineno);
for (size_t i=0; i<self->children.size; i++)
{
node_add_child(clone, node_new_clone(self->children.data[i]));
}
return clone;
}
void node_add_child(node* self, node* child) void node_add_child(node* self, node* child)
{ {

View File

@ -11,7 +11,8 @@
G(NODE_UADD), G(NODE_USUB), G(NODE_ADD), G(NODE_SUB), \ G(NODE_UADD), G(NODE_USUB), G(NODE_ADD), G(NODE_SUB), \
G(NODE_MUL), G(NODE_DIV), G(NODE_MOD), G(NODE_POW), \ G(NODE_MUL), G(NODE_DIV), G(NODE_MOD), G(NODE_POW), \
G(NODE_ARRAY), G(NODE_INDEX), G(NODE_LT), G(NODE_LE), \ G(NODE_ARRAY), G(NODE_INDEX), G(NODE_LT), G(NODE_LE), \
G(NODE_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT) G(NODE_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT), \
G(NODE_CONSTDECL), G(NODE_ASSIGN)
#include "mutils.h" #include "mutils.h"
@ -38,6 +39,8 @@ typedef struct node {
void node_init(node* self, int type, char const* value, int lineno); void node_init(node* self, int type, char const* value, int lineno);
void node_free(node* self); void node_free(node* self);
node* node_new_clone(node* self);
void node_add_child(node* self, node* child); void node_add_child(node* self, node* child);
size_t node_str(node* self, char* buffer, size_t size); size_t node_str(node* self, char* buffer, size_t size);

View File

@ -43,7 +43,9 @@
G(OP_FGT), \ G(OP_FGT), \
G(OP_FGE), \ G(OP_FGE), \
G(OP_STORE), \ G(OP_STORE), \
G(OP_LOAD) G(OP_LOAD), \
G(OP_ASTORE)
enum Opcodes { enum Opcodes {
OPCODES(GEN_ENUM) OPCODES(GEN_ENUM)

View File

@ -35,7 +35,7 @@
%left NOT %left NOT
%token OPAR CPAR %token OPAR CPAR
%token OSQUARE CSQUARE COMMA %token OSQUARE CSQUARE COMMA
%token LET ASSIGN %token LET LET_MUT ASSIGN
%type <n_children> expr_unop %type <n_children> expr_unop
%% %%
@ -79,7 +79,24 @@ exprs:
expr: expr:
// INDEX // INDEX
array array { expr array ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_ASSIGN, "", line);
node* expr_node = stack_pop();
node* array_node = stack_pop();
node* ident_node = stack_pop();
node_add_child(n, ident_node);
node_add_child(n, array_node);
node_add_child(n, expr_node);
stack_push(n);
$$ = 1;
}
| expr array {
node *n = malloc(sizeof(node)); node *n = malloc(sizeof(node));
node_init(n, NODE_INDEX, "", line); node_init(n, NODE_INDEX, "", line);
size_t const SZ = $1 + $2; size_t const SZ = $1 + $2;
@ -102,7 +119,7 @@ expr:
| ident { | ident {
} }
| LET ident ASSIGN expr { | LET_MUT ident ASSIGN expr {
node* n = malloc(sizeof(node)); node* n = malloc(sizeof(node));
node_init(n, NODE_VARDECL, "", line); node_init(n, NODE_VARDECL, "", line);
@ -117,6 +134,36 @@ expr:
$$ = 1; $$ = 1;
} }
| LET ident ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_CONSTDECL, "", line);
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
| ident ASSIGN expr {
node* n = malloc(sizeof(node));
node_init(n, NODE_ASSIGN, "", line);
node* rhs = stack_pop();
node* lhs = stack_pop();
node_add_child(n, lhs);
node_add_child(n, rhs);
stack_push(n);
$$ = 1;
}
// EXPRESSIONS // EXPRESSIONS
| array { | array {
$$ = 1; $$ = 1;
@ -136,7 +183,6 @@ expr:
} }
| expr LT expr { | expr LT expr {
node *n = malloc(sizeof(node)); node *n = malloc(sizeof(node));
node_init(n, NODE_LT, "", line); node_init(n, NODE_LT, "", line);

View File

@ -17,6 +17,10 @@ void symtable_free(symtable* self)
for (size_t i=0; i<self->entries.size; i++) for (size_t i=0; i<self->entries.size; i++)
{ {
node_free(self->entries.data[i]->sym_node);
free(self->entries.data[i]->sym_node);
self->entries.data[i]->sym_node = NULL;
free(self->entries.data[i]->name); free(self->entries.data[i]->name);
type_free(self->entries.data[i]->ty); type_free(self->entries.data[i]->ty);
free(self->entries.data[i]->ty); free(self->entries.data[i]->ty);
@ -30,7 +34,17 @@ void symtable_free(symtable* self)
self->entries.data = NULL; self->entries.data = NULL;
} }
size_t symtable_declare(symtable* self, char const* name, type* ty) size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sym_node)
{
assert(self);
size_t id = symtable_declare(self, name, ty, sym_node);
self->entries.data[id]->is_mut = 1;
return id;
}
size_t symtable_declare(symtable* self, char const* name, type* ty, node* sym_node)
{ {
assert(self); assert(self);
@ -52,6 +66,8 @@ size_t symtable_declare(symtable* self, char const* name, type* ty)
self->entries.data[self->entries.size]->name = str_new(name); self->entries.data[self->entries.size]->name = str_new(name);
self->entries.data[self->entries.size]->ty = type_new_clone(ty); self->entries.data[self->entries.size]->ty = type_new_clone(ty);
self->entries.data[self->entries.size]->id = self->id; self->entries.data[self->entries.size]->id = self->id;
self->entries.data[self->entries.size]->is_mut = 0;
self->entries.data[self->entries.size]->sym_node = node_new_clone(sym_node);
self->entries.size++; self->entries.size++;
return self->id++; return self->id++;

View File

@ -3,11 +3,14 @@
#include "commons.h" #include "commons.h"
#include "type.h" #include "type.h"
#include "node.h"
typedef struct { typedef struct {
size_t id; size_t id;
int is_mut;
char* name; char* name;
type* ty; type* ty;
node* sym_node;
} symentry; } symentry;
typedef struct { typedef struct {
@ -23,7 +26,8 @@ typedef struct {
void symtable_init(symtable* self); void symtable_init(symtable* self);
void symtable_free(symtable* self); void symtable_free(symtable* self);
size_t symtable_declare(symtable* self, char const* name, type* ty); size_t symtable_declare(symtable* self, char const* name, type* ty, node* sym_node);
size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sym_node);
symentry* symtable_find(symtable* self, char const* name); symentry* symtable_find(symtable* self, char const* name);
#endif #endif

118
src/vm.c
View File

@ -102,6 +102,7 @@ void vm_exec(vm* self, program* prog)
case OP_LOAD: vm_load(self, param); break; case OP_LOAD: vm_load(self, param); break;
case OP_STORE: vm_store(self, param); break; case OP_STORE: vm_store(self, param); break;
case OP_ASTORE: vm_astore(self, param); break;
default: { default: {
fprintf(stderr, "unknown opcode %s\n", fprintf(stderr, "unknown opcode %s\n",
@ -167,7 +168,17 @@ void vm_set(vm* self, size_t addr, value* val)
assert(self); assert(self);
assert(val); assert(val);
if (self->vars.size > self->vars.capacity) if (vm_exists(self, addr))
{
size_t id = vm_find(self, addr);
value_free(self->vars.data[id]->val);
free(self->vars.data[id]->val);
self->vars.data[id]->val = value_new_clone(val);
return;
}
if (self->vars.size >= self->vars.capacity)
{ {
self->vars.capacity *= 2; self->vars.capacity *= 2;
self->vars.data = realloc( self->vars.data = realloc(
@ -179,9 +190,42 @@ void vm_set(vm* self, size_t addr, value* val)
self->vars.data[self->vars.size] = malloc(sizeof(var)); self->vars.data[self->vars.size] = malloc(sizeof(var));
self->vars.data[self->vars.size]->addr = addr; self->vars.data[self->vars.size]->addr = addr;
self->vars.data[self->vars.size]->val = value_new_clone(val); self->vars.data[self->vars.size]->val = value_new_clone(val);
self->vars.size++; self->vars.size++;
} }
int vm_exists(vm* self, size_t addr)
{
assert(self);
for (size_t i=0; i<self->vars.size; i++)
{
if (self->vars.data[i]->addr == addr)
{
return 1;
}
}
return 0;
}
size_t vm_find(vm* self, size_t addr)
{
assert(self);
for (size_t i=0; i<self->vars.size; i++)
{
if (self->vars.data[i]->addr == addr)
{
return i;
}
}
assert(0);
return 0;
}
value* vm_get(vm* self, size_t addr) value* vm_get(vm* self, size_t addr)
{ {
assert(self); assert(self);
@ -197,6 +241,38 @@ value* vm_get(vm* self, size_t addr)
return NULL; return NULL;
} }
value* vm_array_deref(vm* self, value* array_val, value* index_val)
{
assert(self);
value* idx = index_val;
value* arr = array_val;
array* idx_array = idx->val.array_val;
value* val = NULL;
for (size_t i=0; i<idx_array->children.size; i++)
{
size_t index = ((value*) idx_array->children.data[i])->val.integer;
val = (value*) array_deref(
arr->val.array_val,
index);
if (val->type->base_type == TY_ARRAY)
{
value_free(arr);
free(arr);
arr = val;
}
}
value_free(idx); free(idx);
return val;
}
void vm_push(vm* self, int param) void vm_push(vm* self, int param)
{ {
assert(self); assert(self);
@ -677,12 +753,17 @@ void vm_aderef(vm* self)
arr = val; arr = val;
} }
} }
assert(val); assert(val);
vm_push_value(self, val); vm_push_value(self, val);
value_free(idx); free(idx); value_free(idx); free(idx);
if (arr != val)
{
value_free(arr); free(arr); value_free(arr); free(arr);
}
self->pc++; self->pc++;
} }
@ -960,7 +1041,6 @@ void vm_store(vm* self, int param)
assert(self); assert(self);
value* val = vm_pop_value(self); value* val = vm_pop_value(self);
vm_set(self, param, val); vm_set(self, param, val);
value_free(val); value_free(val);
@ -979,3 +1059,37 @@ void vm_load(vm* self, int param)
self->pc++; self->pc++;
} }
void vm_astore(vm* self, int param)
{
assert(self);
value* expr_val = vm_pop_value(self);
value* index_val = vm_pop_value(self);
size_t id = vm_find(self, param);
value* array_val = self->vars.data[id]->val;
value* val = array_val;
for (size_t i=0; i<index_val->val.array_val->children.size - 1; i++)
{
value* v = (value*) index_val->val.array_val->children.data[i];
size_t index = v->val.integer;
val = (value*) val->val.array_val->children.data[index];
}
size_t last_i = index_val->val.array_val->children.size - 1;
value* v = (value*) index_val->val.array_val->children.data[last_i];
size_t index = v->val.integer;
value_free((value*) val->val.array_val->children.data[index]);
free(val->val.array_val->children.data[index]);
val->val.array_val->children.data[index] = (struct value*) expr_val;
value_free(index_val); free(index_val);
self->pc++;
}

View File

@ -36,6 +36,8 @@ value* vm_pop_value(vm* self);
size_t vm_str(vm* self, char* buffer, size_t size); size_t vm_str(vm* self, char* buffer, size_t size);
void vm_set(vm* self, size_t addr, value* val); void vm_set(vm* self, size_t addr, value* val);
size_t vm_find(vm* self, size_t addr);
int vm_exists(vm* self, size_t addr);
value* vm_get(vm* self, size_t addr); value* vm_get(vm* self, size_t addr);
void vm_push(vm* self, int param); void vm_push(vm* self, int param);
@ -86,5 +88,6 @@ void vm_fge(vm* self);
void vm_store(vm* self, int param); void vm_store(vm* self, int param);
void vm_load(vm* self, int param); void vm_load(vm* self, int param);
void vm_astore(vm* self, int param);
#endif #endif

View File

@ -1,3 +1,8 @@
let x = 0 x + 1.2 let x = 0 x + 1.2
let x = false x + "false" let x = false x + "false"
let x=0 let x=7 let x=0 let x=7
let x=[1, 2] x[7, 9]
let x = 0 x = 3.2
let x = 0 x = 7
let x=[1, 2] x[0] = 3.2
let x=[3, 4] x[0] = 7

View File

@ -25,4 +25,5 @@ assert [0, 1, 0, 1, 0, 1] == 3 * [0, 1]
assert [0, 0, 0, 0, 0, 0, 1] == 2 * (3 * [0]) + [1] assert [0, 0, 0, 0, 0, 0, 1] == 2 * (3 * [0]) + [1]
assert [2, 4] == [[2, 4], [7, 9]][0]
assert [7, 9] == [[2, 4], [7, 9]][1]

View File

@ -3,3 +3,33 @@ let b = 7
let c = a * b + 1 let c = a * b + 1
assert 29 == c assert 29 == c
let d = [[2, 4], [6, 8]]
assert 6 == d[1, 0]
assert [2, 4] == d[0]
assert [6, 8] == d[1]
let e = 0
let f = 1
assert [2, 4] == d[e]
assert [6, 8] == d[f]
let! g = 4
let! h = 7
let i = 3
h = h + i
assert 10 == h
let! j = [1, 2, 3]
j[0] = 12
j[1] = j[0] + 1
assert [12, 13, 3] == j
let! k = [[2, 4], [6, 8]]
k[1, 0] = 12
assert [[2, 4], [12, 8]] == k
k[1] = k[1] + [3]
assert [[2, 4], [12, 8, 3]] == k