Compare commits
2 Commits
76497315da
...
ba26851487
Author | SHA1 | Date |
---|---|---|
bog | ba26851487 | |
bog | 9bb5a60b2a |
|
@ -24,13 +24,17 @@ void compile_node(compiler* self, node* root, program* prog)
|
|||
assert(root);
|
||||
assert(prog);
|
||||
|
||||
if (root->type == NODE_DO)
|
||||
if (root->type == NODE_BLOCK)
|
||||
{
|
||||
symtable_enter_scope(self->sym);
|
||||
compile_children(self, root, prog);
|
||||
symtable_leave_scope(self->sym);
|
||||
}
|
||||
|
||||
else if (root->type == NODE_IF)
|
||||
{
|
||||
compile_if(self, root, prog);
|
||||
program_set_mark_params(prog, prog->instrs.size);
|
||||
}
|
||||
else if (root->type == NODE_INDEX)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
|
@ -60,6 +64,11 @@ void compile_node(compiler* self, node* root, program* prog)
|
|||
free(ty);
|
||||
cstatic_free(&cs);
|
||||
}
|
||||
else if (root->type == NODE_IS)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
program_add_instr(prog, OP_TEQ, NO_PARAM);
|
||||
}
|
||||
else if (root->type == NODE_VARDECL)
|
||||
{
|
||||
cstatic cs;
|
||||
|
@ -463,6 +472,11 @@ type* compile_get_type(compiler* self, node* root)
|
|||
type_init(ty, TY_BOOLEAN);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "type") == 0)
|
||||
{
|
||||
type_init(ty, TY_TYPE);
|
||||
}
|
||||
|
||||
else if (strcmp(root->value, "array") == 0)
|
||||
{
|
||||
type_init(ty, TY_ARRAY);
|
||||
|
@ -497,6 +511,36 @@ type* compile_get_type(compiler* self, node* root)
|
|||
return ty;
|
||||
}
|
||||
|
||||
void compile_if(compiler* self, node* root, program* prog)
|
||||
{
|
||||
if (root->children.size == 1)
|
||||
{
|
||||
compile_children(self, root, prog);
|
||||
return;
|
||||
}
|
||||
|
||||
// if cond
|
||||
node* cond = root->children.data[0];
|
||||
compile_node(self, cond, prog);
|
||||
size_t const cond_addr = prog->instrs.size;
|
||||
program_add_instr(prog, OP_BRF, 0 /* to next */);
|
||||
|
||||
// then block
|
||||
node* then_block = root->children.data[1];
|
||||
compile_node(self, then_block, prog);
|
||||
program_add_instr(prog, OP_BR, MARK_PARAM);
|
||||
|
||||
// next
|
||||
program_set_instr(prog, cond_addr, OP_BRF, prog->instrs.size);
|
||||
|
||||
if (root->children.size >= 3)
|
||||
{
|
||||
node* next_node = root->children.data[2];
|
||||
//char c [512]; node_str(next_node, c, 512); printf("=> %s\n", c);
|
||||
compile_if(self, next_node, prog);
|
||||
}
|
||||
}
|
||||
|
||||
void compile_number(compiler* self, node* root, program* prog,
|
||||
int integer_op,
|
||||
int float_op)
|
||||
|
|
|
@ -22,4 +22,7 @@ type* compile_get_type(compiler* self, node* root);
|
|||
void compile_number(compiler* self, node* root, program* prog,
|
||||
int integer_op,
|
||||
int float_op);
|
||||
|
||||
void compile_if(compiler* self, node* root, program* prog);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,6 +43,14 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
|
|||
return ty;
|
||||
}
|
||||
|
||||
if (ast->type == NODE_IF)
|
||||
{
|
||||
type* ty = cstatic_resolve_new(self,
|
||||
sym,
|
||||
ast->children.data[1]);
|
||||
return ty;
|
||||
}
|
||||
|
||||
if (ast->type == NODE_DO)
|
||||
{
|
||||
type* ty = cstatic_resolve_new(self,
|
||||
|
@ -201,7 +209,8 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
|
|||
|| ast->type == NODE_GT
|
||||
|| ast->type == NODE_GE
|
||||
|| ast->type == NODE_EQ
|
||||
|| ast->type == NODE_NE)
|
||||
|| ast->type == NODE_NE
|
||||
|| ast->type == NODE_IS)
|
||||
|
||||
{
|
||||
return cstatic_new_type(self, TY_BOOLEAN);
|
||||
|
@ -228,8 +237,8 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
|
|||
assert(self);
|
||||
assert(ast);
|
||||
|
||||
// DO BLOCK
|
||||
if (ast->type == NODE_DO)
|
||||
// BLOCK
|
||||
if (ast->type == NODE_BLOCK)
|
||||
{
|
||||
symtable_enter_scope(sym);
|
||||
|
||||
|
@ -317,6 +326,26 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
|
|||
|
||||
return 1;
|
||||
}
|
||||
else if (ast->type == NODE_IF && ast->children.size > 1)
|
||||
{
|
||||
assert(ast->children.size > 0);
|
||||
type* right = cstatic_resolve_new(self, sym, ast->children.data[0]);
|
||||
type* left = cstatic_new_type(self, TY_BOOLEAN);
|
||||
|
||||
int status = cstatic_check_same_type_ptr(
|
||||
self,
|
||||
ast->children.data[0],
|
||||
left, right, sym, msg, size
|
||||
);
|
||||
|
||||
if (status)
|
||||
{
|
||||
type_free(left); free(left);
|
||||
type_free(right); free(right);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
else if (ast->type == NODE_ARRAY)
|
||||
{
|
||||
assert(ast->children.size > 0);
|
||||
|
|
|
@ -13,7 +13,7 @@ BOOLEAN true|false
|
|||
INTEGER -?[0-9]+
|
||||
FLOAT -?[0-9]+\.[0-9]+
|
||||
STRING \"[^"]*\"
|
||||
TYPE (int|float|bool|str|array)
|
||||
TYPE (int|float|bool|str|array|type)
|
||||
IDENT [_A-Za-z][_A-Za-z0-9]*
|
||||
|
||||
%%
|
||||
|
@ -25,7 +25,9 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
|
|||
yylval.str = str_new(yytext);
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
"if" { return IF_COND; }
|
||||
"else" { return ELSE_COND; }
|
||||
"is" { return IS; }
|
||||
"do" { return DO; }
|
||||
"end" { return END; }
|
||||
"let!" { return LET_MUT; }
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
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_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT), \
|
||||
G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO)
|
||||
G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO), G(NODE_IS), \
|
||||
G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK)
|
||||
|
||||
|
||||
#include "mutils.h"
|
||||
|
|
|
@ -44,7 +44,10 @@
|
|||
G(OP_FGE), \
|
||||
G(OP_STORE), \
|
||||
G(OP_LOAD), \
|
||||
G(OP_ASTORE)
|
||||
G(OP_ASTORE), \
|
||||
G(OP_TEQ), \
|
||||
G(OP_BRF), \
|
||||
G(OP_BR)
|
||||
|
||||
|
||||
enum Opcodes {
|
||||
|
|
134
src/parser.y
134
src/parser.y
|
@ -21,10 +21,12 @@
|
|||
size_t n_children;
|
||||
};
|
||||
|
||||
%token IF_COND
|
||||
%token ELSE_COND
|
||||
%left ASSERT
|
||||
%token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT
|
||||
%type <n_children> expr exprs prog array builtins
|
||||
%type <n_children> expr_list type type_list ident
|
||||
%type <n_children> expr_list type type_list ident if
|
||||
%left EQ NE
|
||||
%left LT GT LE GE
|
||||
%left AND
|
||||
|
@ -36,7 +38,8 @@
|
|||
%token OPAR CPAR
|
||||
%token OSQUARE CSQUARE COMMA
|
||||
%token LET LET_MUT ASSIGN DO END
|
||||
%type <n_children> expr_unop
|
||||
%type <n_children> expr_unop block if_rec
|
||||
%left IS
|
||||
|
||||
%%
|
||||
|
||||
|
@ -74,32 +77,38 @@ exprs:
|
|||
exprs expr { $$ = $1 + $2; }
|
||||
|
||||
| expr { $$ = $1; }
|
||||
|
||||
;
|
||||
|
||||
|
||||
expr:
|
||||
// TYPE OPERATORS
|
||||
expr IS type {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IS, "", line);
|
||||
|
||||
node* rhs = stack_pop();
|
||||
node* lhs = stack_pop();
|
||||
|
||||
node_add_child(n, lhs);
|
||||
node_add_child(n, rhs);
|
||||
|
||||
stack_push(n);
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| if {}
|
||||
|
||||
// BLOCK
|
||||
DO exprs END {
|
||||
node *n = malloc(sizeof(node));
|
||||
| DO block END {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_DO, "", line);
|
||||
|
||||
size_t const SZ = $2;
|
||||
node* all[SZ];
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
all[SZ - 1 - i] = stack_pop();
|
||||
}
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
node_add_child(n, all[i]);
|
||||
}
|
||||
node_add_child(n, stack_pop());
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
|
||||
}
|
||||
|
||||
// INDEX
|
||||
|
@ -375,6 +384,73 @@ expr:
|
|||
|
||||
;
|
||||
|
||||
if_rec:
|
||||
ELSE_COND IF_COND expr block if_rec {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IF, "", line);
|
||||
|
||||
node* next_node = stack_pop();
|
||||
node* block_node = stack_pop();
|
||||
node* expr_node = stack_pop();
|
||||
|
||||
node_add_child(n, expr_node);
|
||||
node_add_child(n, block_node);
|
||||
node_add_child(n, next_node);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| ELSE_COND expr END {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IF, "", line);
|
||||
|
||||
node* expr_node = stack_pop();
|
||||
|
||||
node_add_child(n, expr_node);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
;
|
||||
|
||||
if:
|
||||
IF_COND expr block if_rec {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IF, "", line);
|
||||
|
||||
node* rec_node = stack_pop();
|
||||
node* block_node = stack_pop();
|
||||
node* expr_node = stack_pop();
|
||||
|
||||
node_add_child(n, expr_node);
|
||||
node_add_child(n, block_node);
|
||||
node_add_child(n, rec_node);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
| IF_COND expr block END {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IF, "", line);
|
||||
|
||||
node* block_node = stack_pop();
|
||||
node* expr_node = stack_pop();
|
||||
|
||||
node_add_child(n, expr_node);
|
||||
node_add_child(n, block_node);
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
expr_unop:
|
||||
ADD expr {
|
||||
node *n = malloc(sizeof(node));
|
||||
|
@ -399,6 +475,30 @@ type_list:
|
|||
|
||||
;
|
||||
|
||||
block:
|
||||
exprs {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_BLOCK, "", line);
|
||||
|
||||
size_t const SZ = $1;
|
||||
node* all[SZ];
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
all[SZ - 1 - i] = stack_pop();
|
||||
}
|
||||
|
||||
for (size_t i=0; i<SZ; i++)
|
||||
{
|
||||
node_add_child(n, all[i]);
|
||||
}
|
||||
|
||||
stack_push(n);
|
||||
|
||||
$$ = 1;
|
||||
}
|
||||
;
|
||||
|
||||
type:
|
||||
TYPE LT type_list GT {
|
||||
node* n = malloc(sizeof(node));
|
||||
|
|
|
@ -37,7 +37,27 @@ void program_free(program* self)
|
|||
self->pool.capacity = 0;
|
||||
}
|
||||
|
||||
void program_add_instr(program* self, int opcode, int param)
|
||||
void program_set_instr(program* self, size_t index, int opcode, int param)
|
||||
{
|
||||
assert(self);
|
||||
assert(index < self->instrs.size);
|
||||
|
||||
self->instrs.data[index]->opcode = opcode;
|
||||
self->instrs.data[index]->param = param;
|
||||
}
|
||||
|
||||
void program_set_mark_params(program* self, int param)
|
||||
{
|
||||
for (size_t i=0; i<self->instrs.size; i++)
|
||||
{
|
||||
if (self->instrs.data[i]->param == MARK_PARAM)
|
||||
{
|
||||
self->instrs.data[i]->param = param;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t program_add_instr(program* self, int opcode, int param)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
|
@ -62,6 +82,8 @@ void program_add_instr(program* self, int opcode, int param)
|
|||
self->instrs.data[idx]->param = param;
|
||||
|
||||
self->instrs.size++;
|
||||
|
||||
return self->instrs.size - 1;
|
||||
}
|
||||
|
||||
size_t program_add_pool(program* self, value* val)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "value.h"
|
||||
|
||||
#define NO_PARAM (-1)
|
||||
#define MARK_PARAM (-2)
|
||||
|
||||
typedef struct {
|
||||
int opcode;
|
||||
|
@ -29,7 +30,10 @@ typedef struct {
|
|||
void program_init(program* self);
|
||||
void program_free(program* self);
|
||||
|
||||
void program_add_instr(program* self, int opcode, int param);
|
||||
size_t program_add_instr(program* self, int opcode, int param);
|
||||
void program_set_instr(program* self, size_t index, int opcode, int param);
|
||||
void program_set_mark_params(program* self, int param);
|
||||
|
||||
size_t program_add_pool(program* self, value* val);
|
||||
|
||||
size_t program_str(program* self, char* buffer, size_t size);
|
||||
|
|
|
@ -47,7 +47,7 @@ size_t symtable_declare_mut(symtable* self, char const* name, type* ty, node* sy
|
|||
assert(self);
|
||||
size_t id = symtable_declare(self, name, ty, sym_node);
|
||||
|
||||
self->entries.data[id]->is_mut = 1;
|
||||
self->entries.data[self->entries.size - 1]->is_mut = 1;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
|
49
src/vm.c
49
src/vm.c
|
@ -104,6 +104,11 @@ void vm_exec(vm* self, program* prog)
|
|||
case OP_STORE: vm_store(self, param); break;
|
||||
case OP_ASTORE: vm_astore(self, param); break;
|
||||
|
||||
case OP_BRF: vm_brf(self, param); break;
|
||||
case OP_BR: vm_br(self, param); break;
|
||||
|
||||
case OP_TEQ: vm_teq(self); break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "unknown opcode %s\n",
|
||||
OpcodesStr[opcode]);
|
||||
|
@ -1093,3 +1098,47 @@ void vm_astore(vm* self, int param)
|
|||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_teq(vm* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
value* type_val = vm_pop_value(self);
|
||||
value* expr_val = vm_pop_value(self);
|
||||
|
||||
type* ty = type_val->val.type_val;
|
||||
|
||||
int equals = type_equals(ty, expr_val->type);
|
||||
|
||||
value* val = malloc(sizeof(value));
|
||||
value_init_boolean(val, equals, expr_val->lineno);
|
||||
|
||||
vm_push_value(self, val);
|
||||
|
||||
value_free(type_val); free(type_val);
|
||||
value_free(expr_val); free(expr_val);
|
||||
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
void vm_brf(vm* self, int param)
|
||||
{
|
||||
assert(self);
|
||||
value* val = vm_pop_value(self);
|
||||
|
||||
if (!val->val.boolean)
|
||||
{
|
||||
self->pc = param;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->pc++;
|
||||
}
|
||||
|
||||
value_free(val); free(val);
|
||||
}
|
||||
|
||||
void vm_br(vm* self, int param)
|
||||
{
|
||||
assert(self);
|
||||
self->pc = param;
|
||||
}
|
||||
|
|
5
src/vm.h
5
src/vm.h
|
@ -90,4 +90,9 @@ void vm_store(vm* self, int param);
|
|||
void vm_load(vm* self, int param);
|
||||
void vm_astore(vm* self, int param);
|
||||
|
||||
void vm_teq(vm* self);
|
||||
|
||||
void vm_brf(vm* self, int param);
|
||||
void vm_br(vm* self, int param);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
if 4 0 end
|
||||
if int 0 end
|
||||
if "salut" 0 end
|
||||
if 400.7 0 end
|
|
@ -0,0 +1,45 @@
|
|||
let! a = 0
|
||||
let b = 12
|
||||
|
||||
if true
|
||||
a = 1
|
||||
let b = 34
|
||||
assert 34 == b
|
||||
end
|
||||
|
||||
assert 1 == a
|
||||
assert 12 == b
|
||||
|
||||
|
||||
if false
|
||||
a = 2
|
||||
let b = 76
|
||||
assert 76 == b
|
||||
end
|
||||
|
||||
assert 1 == a
|
||||
assert 12 == b
|
||||
|
||||
let! c = 0
|
||||
|
||||
if true
|
||||
c = 1
|
||||
else
|
||||
c = 2
|
||||
end
|
||||
|
||||
assert 1 == c
|
||||
|
||||
if false
|
||||
c = 3
|
||||
else
|
||||
c = 4
|
||||
end
|
||||
|
||||
assert 4 == c
|
||||
|
||||
let d = if true 1 else 2 end
|
||||
assert 1 == d
|
||||
|
||||
let e = if false 1 else 2 end
|
||||
assert 2 == e
|
|
@ -0,0 +1,16 @@
|
|||
assert 5 is int
|
||||
assert 5.9 is float
|
||||
assert false is bool
|
||||
assert "salut" is str
|
||||
|
||||
assert !(5 is float)
|
||||
assert !(5.9 is bool)
|
||||
assert !(false is str)
|
||||
assert !("salut" is int)
|
||||
|
||||
assert [2, 4, 6] is array<int>
|
||||
assert [[2, 4], [7, 9]] is array<array<int>>
|
||||
|
||||
assert int is type
|
||||
assert type is type
|
||||
assert (5.2 is int) is bool
|
Loading…
Reference in New Issue