✨ if statement.
parent
bb300a1a93
commit
3b7b0b4295
|
@ -30,6 +30,26 @@ int compiler_compile(struct compiler* self,
|
|||
|
||||
switch (node->type)
|
||||
{
|
||||
case NODE_IF: {
|
||||
struct vec to_end;
|
||||
vec_init(&to_end, 1);
|
||||
|
||||
compiler_compile_if(self, node, program, &to_end);
|
||||
|
||||
size_t end = program->instructions.size;
|
||||
|
||||
for (size_t i=0; i<to_end.size; i++)
|
||||
{
|
||||
size_t* addr = to_end.data[i];
|
||||
|
||||
((struct instruction*) program->instructions.data[*addr])->param
|
||||
= end;
|
||||
}
|
||||
|
||||
vec_free_elements(&to_end);
|
||||
vec_free(&to_end);
|
||||
} break;
|
||||
|
||||
case NODE_BLOCK: {
|
||||
int stack_base = self->stack_size;
|
||||
|
||||
|
@ -343,6 +363,56 @@ int compiler_compile(struct compiler* self,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int compiler_compile_if(struct compiler* self,
|
||||
struct node* node,
|
||||
struct program* program,
|
||||
struct vec* to_end)
|
||||
{
|
||||
assert(node->children.size >= 2);
|
||||
|
||||
struct instruction* instr = NULL;
|
||||
|
||||
// if expr
|
||||
if (compiler_compile(self, node->children.data[0], program) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t goto_else = compiler_gen_instr(self, program, OP_BRF, 0);
|
||||
|
||||
// block
|
||||
if (compiler_compile(self, node->children.data[1], program) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t* goto_end = malloc(sizeof(size_t));
|
||||
*goto_end = compiler_gen_instr(self, program, OP_BR, 0);
|
||||
vec_push(to_end, goto_end);
|
||||
|
||||
instr = program->instructions.data[goto_else];
|
||||
instr->param = program->instructions.size;
|
||||
|
||||
// else block
|
||||
if (node->children.size > 2
|
||||
&& ((struct node*) node->children.data[2])->type == NODE_BLOCK
|
||||
&& compiler_compile(self, node->children.data[2], program) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// else
|
||||
if (node->children.size > 2
|
||||
&& ((struct node*) node->children.data[2])->type == NODE_IF
|
||||
&& compiler_compile_if(self, node->children.data[2], program,
|
||||
to_end) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t compiler_gen_instr(struct compiler* self,
|
||||
struct program* program,
|
||||
enum Opcodes op,
|
||||
|
|
|
@ -20,6 +20,11 @@ int compiler_compile(struct compiler* self,
|
|||
struct node* node,
|
||||
struct program* program);
|
||||
|
||||
int compiler_compile_if(struct compiler* self,
|
||||
struct node* node,
|
||||
struct program* program,
|
||||
struct vec* to_end);
|
||||
|
||||
size_t compiler_gen_instr(struct compiler* self,
|
||||
struct program* program,
|
||||
enum Opcodes op,
|
||||
|
|
|
@ -13,7 +13,14 @@ LEXPR ::=
|
|||
| CONSTDECL
|
||||
| ASSIGN
|
||||
|
||||
BEXPR ::= BLOCK
|
||||
BEXPR ::=
|
||||
| BLOCK
|
||||
| IF
|
||||
|
||||
IF ::=
|
||||
| if EXPR BLOCK
|
||||
| if EXPR BLOCK else BLOCK
|
||||
| if EXPR BLOCK else IF
|
||||
|
||||
BLOCK ::= obrace INSTR* cbrace
|
||||
VARDECL ::= var ident colon type? assign EXPR
|
||||
|
|
|
@ -12,6 +12,12 @@ void lexer_init(struct lexer* self, char const* source)
|
|||
|
||||
vec_init(&self->toks, 1);
|
||||
|
||||
lexer_add_tok(self, "if", NODE_IF, "", 1);
|
||||
lexer_add_tok(self, "else", NODE_ELSE, "", 1);
|
||||
lexer_add_tok(self, "cond", NODE_COND, "", 1);
|
||||
lexer_add_tok(self, "while", NODE_WHILE, "", 1);
|
||||
lexer_add_tok(self, "for", NODE_FOR, "", 1);
|
||||
|
||||
lexer_add_tok(self, "var", NODE_VAR, "", 1);
|
||||
|
||||
lexer_add_tok(self, "int", NODE_TYPE, "int", 1);
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
G(NODE_MOD), G(NODE_POW), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
|
||||
G(NODE_GE), G(NODE_COLON), G(NODE_ASSIGN), G(NODE_IDENT), \
|
||||
G(NODE_TYPE), G(NODE_VARDECL), G(NODE_CONSTDECL), G(NODE_VAR), \
|
||||
G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_BLOCK)
|
||||
G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_BLOCK), \
|
||||
G(NODE_IF), G(NODE_ELSE), G(NODE_COND), G(NODE_WHILE), G(NODE_FOR)
|
||||
|
||||
|
||||
GUX_ENUM_H(NodeType, NODE_TYPE);
|
||||
|
||||
|
|
|
@ -132,7 +132,8 @@ int parser_start_bexpr(struct parser* self)
|
|||
assert(self);
|
||||
struct node* tok = self->tokens.data[self->cursor];
|
||||
|
||||
return tok->type == NODE_OBRACE;
|
||||
return tok->type == NODE_OBRACE
|
||||
|| tok->type == NODE_IF;
|
||||
}
|
||||
|
||||
struct node* parser_try_new_root(struct parser* self, char const* source)
|
||||
|
@ -254,9 +255,41 @@ struct node* parser_try_new_lexpr(struct parser* self)
|
|||
struct node* parser_try_new_bexpr(struct parser* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
if (parser_type_is(self, NODE_IF, 0))
|
||||
{
|
||||
return parser_try_new_if(self);
|
||||
}
|
||||
|
||||
return parser_try_new_block(self);
|
||||
}
|
||||
|
||||
struct node* parser_try_new_if(struct parser* self)
|
||||
{
|
||||
assert(self);
|
||||
struct node* node = malloc(sizeof(struct node));
|
||||
node_init(node, NODE_IF, "", parser_current_line(self));
|
||||
|
||||
self->cursor++; // if
|
||||
node_add_child(node, parser_try_new_expr(self));
|
||||
node_add_child(node, parser_try_new_block(self));
|
||||
|
||||
if (parser_try_consume(self, NODE_ELSE) == 0)
|
||||
{
|
||||
if (parser_type_is(self, NODE_IF, 0))
|
||||
{
|
||||
node_add_child(node, parser_try_new_if(self));
|
||||
}
|
||||
|
||||
if (parser_type_is(self, NODE_OBRACE, 0))
|
||||
{
|
||||
node_add_child(node, parser_try_new_block(self));
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct node* parser_try_new_block(struct parser* self)
|
||||
{
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ struct node* parser_try_new_instr(struct parser* self);
|
|||
struct node* parser_try_new_expr(struct parser* self);
|
||||
struct node* parser_try_new_lexpr(struct parser* self);
|
||||
struct node* parser_try_new_bexpr(struct parser* self);
|
||||
struct node* parser_try_new_if(struct parser* self);
|
||||
struct node* parser_try_new_block(struct parser* self);
|
||||
struct node* parser_try_new_assign(struct parser* self);
|
||||
struct node* parser_try_new_vardecl(struct parser* self);
|
||||
|
|
|
@ -27,6 +27,42 @@ int type_checker_check(struct type_checker* self,
|
|||
|
||||
switch (node->type)
|
||||
{
|
||||
case NODE_IF: {
|
||||
struct type expr;
|
||||
type_init(&expr, TYPE_VOID);
|
||||
|
||||
if (type_resolver_resolve(&self->resolver,
|
||||
node->children.data[0],
|
||||
&expr) != 0)
|
||||
{
|
||||
type_free(&expr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!type_is(&expr, "BOOL"))
|
||||
{
|
||||
struct type bool_ty;
|
||||
type_init(&bool_ty, TYPE_BOOL);
|
||||
|
||||
type_checker_error_msg(self, node, &bool_ty, &expr);
|
||||
|
||||
type_free(&bool_ty);
|
||||
type_free(&expr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
type_free(&expr);
|
||||
|
||||
if (node->children.size > 2)
|
||||
{
|
||||
if (type_checker_check(self, node->children.data[2]) != 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
} return 0;
|
||||
|
||||
case NODE_ASSIGN: {
|
||||
struct node* ident = node->children.data[0];
|
||||
struct node* expr = node->children.data[1];
|
||||
|
|
|
@ -125,3 +125,8 @@ Test(lexer, var_types) {
|
|||
Test(lexer, blocks) {
|
||||
test_lexer("{}", 2, "OBRACE", "CBRACE");
|
||||
}
|
||||
|
||||
Test(lexer, flow_control) {
|
||||
test_lexer("if else cond while for", 5,
|
||||
"IF", "ELSE", "COND", "WHILE", "FOR");
|
||||
}
|
||||
|
|
|
@ -132,3 +132,20 @@ Test(parser, block) {
|
|||
test_parser("ROOT(BLOCK(ASSIGN(IDENT[x],INT[2]),ADD(INT[1],INT[1])))",
|
||||
"{ x = 2; 1 + 1;}");
|
||||
}
|
||||
|
||||
Test(parser, if_block) {
|
||||
test_parser("ROOT(IF(IDENT[a],BLOCK(INT[0])))",
|
||||
"if a { 0; }");
|
||||
|
||||
test_parser("ROOT(IF(IDENT[a],BLOCK(INT[0]),BLOCK(INT[1])))",
|
||||
"if a { 0; } else { 1; }");
|
||||
|
||||
test_parser("ROOT(IF(IDENT[a],BLOCK("
|
||||
"INT[0]"
|
||||
"),IF(IDENT[b],BLOCK("
|
||||
"INT[1]"
|
||||
"),BLOCK("
|
||||
"INT[2]"
|
||||
"))))",
|
||||
"if a { 0; } else if b { 1; } else { 2; }");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
var a := 0;
|
||||
|
||||
if true { a = 1; }
|
||||
assert a == 1;
|
||||
|
||||
if false { a = 2; }
|
||||
assert a == 1;
|
||||
|
||||
if true { a = 3; } else { a = 4; }
|
||||
assert a == 3;
|
||||
|
||||
if false { a = 3; } else { a = 4; }
|
||||
assert a == 4;
|
||||
|
||||
if true {
|
||||
a = 5;
|
||||
} else if false {
|
||||
a = 6;
|
||||
} else if false {
|
||||
a = 7;
|
||||
} else {
|
||||
a = 8;
|
||||
}
|
||||
|
||||
assert a == 5;
|
||||
|
||||
if false {
|
||||
a = 5;
|
||||
} else if true {
|
||||
a = 6;
|
||||
} else if false {
|
||||
a = 7;
|
||||
} else {
|
||||
a = 8;
|
||||
}
|
||||
|
||||
assert a == 6;
|
||||
|
||||
if false {
|
||||
a = 5;
|
||||
} else if false {
|
||||
a = 6;
|
||||
} else if true {
|
||||
a = 7;
|
||||
} else {
|
||||
a = 8;
|
||||
}
|
||||
|
||||
assert a == 7;
|
||||
|
||||
if false {
|
||||
a = 5;
|
||||
} else if false {
|
||||
a = 6;
|
||||
} else if false {
|
||||
a = 7;
|
||||
} else {
|
||||
a = 8;
|
||||
}
|
||||
|
||||
assert a == 8;
|
Loading…
Reference in New Issue