ADD: if-then-else expression.
parent
9bb5a60b2a
commit
ba26851487
|
@ -24,13 +24,17 @@ void compile_node(compiler* self, node* root, program* prog)
|
||||||
assert(root);
|
assert(root);
|
||||||
assert(prog);
|
assert(prog);
|
||||||
|
|
||||||
if (root->type == NODE_DO)
|
if (root->type == NODE_BLOCK)
|
||||||
{
|
{
|
||||||
symtable_enter_scope(self->sym);
|
symtable_enter_scope(self->sym);
|
||||||
compile_children(self, root, prog);
|
compile_children(self, root, prog);
|
||||||
symtable_leave_scope(self->sym);
|
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)
|
else if (root->type == NODE_INDEX)
|
||||||
{
|
{
|
||||||
compile_children(self, root, prog);
|
compile_children(self, root, prog);
|
||||||
|
@ -507,6 +511,36 @@ type* compile_get_type(compiler* self, node* root)
|
||||||
return ty;
|
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,
|
void compile_number(compiler* self, node* root, program* prog,
|
||||||
int integer_op,
|
int integer_op,
|
||||||
int float_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,
|
void compile_number(compiler* self, node* root, program* prog,
|
||||||
int integer_op,
|
int integer_op,
|
||||||
int float_op);
|
int float_op);
|
||||||
|
|
||||||
|
void compile_if(compiler* self, node* root, program* prog);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,6 +43,14 @@ type* cstatic_resolve_new(cstatic* self, symtable* sym, node* ast)
|
||||||
return ty;
|
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)
|
if (ast->type == NODE_DO)
|
||||||
{
|
{
|
||||||
type* ty = cstatic_resolve_new(self,
|
type* ty = cstatic_resolve_new(self,
|
||||||
|
@ -229,8 +237,8 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(ast);
|
assert(ast);
|
||||||
|
|
||||||
// DO BLOCK
|
// BLOCK
|
||||||
if (ast->type == NODE_DO)
|
if (ast->type == NODE_BLOCK)
|
||||||
{
|
{
|
||||||
symtable_enter_scope(sym);
|
symtable_enter_scope(sym);
|
||||||
|
|
||||||
|
@ -318,6 +326,26 @@ int cstatic_check(cstatic* self, node* ast, symtable* sym, char* msg, size_t siz
|
||||||
|
|
||||||
return 1;
|
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)
|
else if (ast->type == NODE_ARRAY)
|
||||||
{
|
{
|
||||||
assert(ast->children.size > 0);
|
assert(ast->children.size > 0);
|
||||||
|
|
|
@ -25,6 +25,8 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
|
||||||
yylval.str = str_new(yytext);
|
yylval.str = str_new(yytext);
|
||||||
return TYPE;
|
return TYPE;
|
||||||
}
|
}
|
||||||
|
"if" { return IF_COND; }
|
||||||
|
"else" { return ELSE_COND; }
|
||||||
"is" { return IS; }
|
"is" { return IS; }
|
||||||
"do" { return DO; }
|
"do" { return DO; }
|
||||||
"end" { return END; }
|
"end" { return END; }
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
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), G(NODE_DO), G(NODE_IS)
|
G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO), G(NODE_IS), \
|
||||||
|
G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK)
|
||||||
|
|
||||||
|
|
||||||
#include "mutils.h"
|
#include "mutils.h"
|
||||||
|
|
|
@ -45,7 +45,9 @@
|
||||||
G(OP_STORE), \
|
G(OP_STORE), \
|
||||||
G(OP_LOAD), \
|
G(OP_LOAD), \
|
||||||
G(OP_ASTORE), \
|
G(OP_ASTORE), \
|
||||||
G(OP_TEQ)
|
G(OP_TEQ), \
|
||||||
|
G(OP_BRF), \
|
||||||
|
G(OP_BR)
|
||||||
|
|
||||||
|
|
||||||
enum Opcodes {
|
enum Opcodes {
|
||||||
|
|
116
src/parser.y
116
src/parser.y
|
@ -21,10 +21,12 @@
|
||||||
size_t n_children;
|
size_t n_children;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
%token IF_COND
|
||||||
|
%token ELSE_COND
|
||||||
%left ASSERT
|
%left ASSERT
|
||||||
%token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT
|
%token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT
|
||||||
%type <n_children> expr exprs prog array builtins
|
%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 EQ NE
|
||||||
%left LT GT LE GE
|
%left LT GT LE GE
|
||||||
%left AND
|
%left AND
|
||||||
|
@ -36,7 +38,7 @@
|
||||||
%token OPAR CPAR
|
%token OPAR CPAR
|
||||||
%token OSQUARE CSQUARE COMMA
|
%token OSQUARE CSQUARE COMMA
|
||||||
%token LET LET_MUT ASSIGN DO END
|
%token LET LET_MUT ASSIGN DO END
|
||||||
%type <n_children> expr_unop
|
%type <n_children> expr_unop block if_rec
|
||||||
%left IS
|
%left IS
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@ -75,6 +77,7 @@ exprs:
|
||||||
exprs expr { $$ = $1 + $2; }
|
exprs expr { $$ = $1 + $2; }
|
||||||
|
|
||||||
| expr { $$ = $1; }
|
| expr { $$ = $1; }
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,29 +96,19 @@ expr:
|
||||||
stack_push(n);
|
stack_push(n);
|
||||||
$$ = 1;
|
$$ = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
| if {}
|
||||||
|
|
||||||
// BLOCK
|
// BLOCK
|
||||||
| DO exprs END {
|
| DO block END {
|
||||||
node* n = malloc(sizeof(node));
|
node* n = malloc(sizeof(node));
|
||||||
node_init(n, NODE_DO, "", line);
|
node_init(n, NODE_DO, "", line);
|
||||||
|
|
||||||
size_t const SZ = $2;
|
node_add_child(n, stack_pop());
|
||||||
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);
|
stack_push(n);
|
||||||
|
|
||||||
$$ = 1;
|
$$ = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// INDEX
|
// INDEX
|
||||||
|
@ -391,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:
|
expr_unop:
|
||||||
ADD expr {
|
ADD expr {
|
||||||
node *n = malloc(sizeof(node));
|
node *n = malloc(sizeof(node));
|
||||||
|
@ -415,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:
|
||||||
TYPE LT type_list GT {
|
TYPE LT type_list GT {
|
||||||
node* n = malloc(sizeof(node));
|
node* n = malloc(sizeof(node));
|
||||||
|
|
|
@ -37,7 +37,27 @@ void program_free(program* self)
|
||||||
self->pool.capacity = 0;
|
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);
|
assert(self);
|
||||||
|
|
||||||
|
@ -62,6 +82,8 @@ void program_add_instr(program* self, int opcode, int param)
|
||||||
self->instrs.data[idx]->param = param;
|
self->instrs.data[idx]->param = param;
|
||||||
|
|
||||||
self->instrs.size++;
|
self->instrs.size++;
|
||||||
|
|
||||||
|
return self->instrs.size - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t program_add_pool(program* self, value* val)
|
size_t program_add_pool(program* self, value* val)
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
|
||||||
#define NO_PARAM (-1)
|
#define NO_PARAM (-1)
|
||||||
|
#define MARK_PARAM (-2)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int opcode;
|
int opcode;
|
||||||
|
@ -29,7 +30,10 @@ typedef struct {
|
||||||
void program_init(program* self);
|
void program_init(program* self);
|
||||||
void program_free(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_add_pool(program* self, value* val);
|
||||||
|
|
||||||
size_t program_str(program* self, char* buffer, size_t size);
|
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);
|
assert(self);
|
||||||
size_t id = symtable_declare(self, name, ty, sym_node);
|
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;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
25
src/vm.c
25
src/vm.c
|
@ -104,6 +104,9 @@ void vm_exec(vm* self, program* prog)
|
||||||
case OP_STORE: vm_store(self, param); break;
|
case OP_STORE: vm_store(self, param); break;
|
||||||
case OP_ASTORE: vm_astore(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;
|
case OP_TEQ: vm_teq(self); break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
@ -1117,3 +1120,25 @@ void vm_teq(vm* self)
|
||||||
self->pc++;
|
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;
|
||||||
|
}
|
||||||
|
|
3
src/vm.h
3
src/vm.h
|
@ -92,4 +92,7 @@ void vm_astore(vm* self, int param);
|
||||||
|
|
||||||
void vm_teq(vm* self);
|
void vm_teq(vm* self);
|
||||||
|
|
||||||
|
void vm_brf(vm* self, int param);
|
||||||
|
void vm_br(vm* self, int param);
|
||||||
|
|
||||||
#endif
|
#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
|
Loading…
Reference in New Issue