✨ if-then-else expression.
parent
6d34100d67
commit
719abe66c4
|
@ -5,6 +5,9 @@ EXPR ::=
|
|||
| DECL
|
||||
| ASSIGN
|
||||
| BEGIN
|
||||
| IF end
|
||||
IF ::=
|
||||
| if EXPR BLOCK (else (IF | BLOCK))?
|
||||
BEGIN ::= begin BLOCK end
|
||||
BLOCK ::= EXPR*
|
||||
ASSIGN ::= (ident|INDEX) assign EXPR
|
||||
|
|
|
@ -32,14 +32,32 @@ void compiler_compile(compiler_t* self,
|
|||
|
||||
switch (node->kind)
|
||||
{
|
||||
case NODE_IF: {
|
||||
vec_t to_end;
|
||||
vec_init(&to_end);
|
||||
compiler_compile_if(self, node, prog, &to_end);
|
||||
|
||||
size_t end_point = prog->instrs.size;
|
||||
|
||||
for (size_t i=0; i<to_end.size; i++)
|
||||
{
|
||||
int const* addr = to_end.data[i];
|
||||
((instr_t*) prog->instrs.data[*addr])
|
||||
->param = end_point;
|
||||
}
|
||||
|
||||
vec_free_elements(&to_end, NULL);
|
||||
vec_free(&to_end);
|
||||
} break;
|
||||
|
||||
case NODE_BLOCK: {
|
||||
|
||||
sym_open_scope(sym);
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
compiler_compile(
|
||||
self,
|
||||
node->children.data[i],
|
||||
self,
|
||||
node->children.data[i],
|
||||
prog
|
||||
);
|
||||
}
|
||||
|
@ -92,12 +110,12 @@ void compiler_compile(compiler_t* self,
|
|||
compiler_compile(self, expr, prog);
|
||||
int status =
|
||||
sym_try_assign(
|
||||
sym,
|
||||
sym,
|
||||
target->value, self->loc_counter
|
||||
);
|
||||
|
||||
sym_entry_t* entry = sym_try_get_value(
|
||||
sym,
|
||||
sym,
|
||||
target->value
|
||||
);
|
||||
|
||||
|
@ -118,8 +136,6 @@ void compiler_compile(compiler_t* self,
|
|||
}
|
||||
|
||||
prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter);
|
||||
|
||||
self->loc_counter++;
|
||||
}
|
||||
|
||||
} break;
|
||||
|
@ -144,7 +160,7 @@ void compiler_compile(compiler_t* self,
|
|||
case NODE_IDENT: {
|
||||
char const* name = node->value;
|
||||
sym_entry_t const* entry = sym_try_get_value(
|
||||
sym,
|
||||
sym,
|
||||
name
|
||||
);
|
||||
|
||||
|
@ -425,3 +441,42 @@ void compiler_compile_and(compiler_t* self,
|
|||
|
||||
vec_free(&to_false);
|
||||
}
|
||||
|
||||
void compiler_compile_if(compiler_t* self,
|
||||
node_t* node,
|
||||
prog_t* prog,
|
||||
vec_t* to_end)
|
||||
{
|
||||
assert(self); assert(node); assert(prog);
|
||||
|
||||
if (node->kind != NODE_IF)
|
||||
{
|
||||
compiler_compile(self, node, prog);
|
||||
return;
|
||||
}
|
||||
|
||||
node_t* cond = node->children.data[0];
|
||||
node_t* block = node->children.data[1];
|
||||
node_t* next = node->children.size == 3 ?
|
||||
node->children.data[2] :
|
||||
NULL;
|
||||
|
||||
compiler_compile_if(self, cond, prog, to_end);
|
||||
int cond_point = prog_add_instr(prog, OP_BRF, 0);
|
||||
|
||||
compiler_compile_if(self, block, prog, to_end);
|
||||
int end_point = prog_add_instr(prog, OP_BR, 0); // to end
|
||||
int* addr = malloc(sizeof(int));
|
||||
*addr = end_point;
|
||||
vec_push(to_end, (void*) addr);
|
||||
|
||||
int next_pos = prog->instrs.size;
|
||||
|
||||
((instr_t*) prog->instrs.data[cond_point])->param
|
||||
= next_pos;
|
||||
|
||||
if (next)
|
||||
{
|
||||
compiler_compile_if(self, next, prog, to_end);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,4 +28,9 @@ void compiler_compile_or(compiler_t* self,
|
|||
void compiler_compile_and(compiler_t* self,
|
||||
node_t* node,
|
||||
prog_t* prog);
|
||||
|
||||
void compiler_compile_if(compiler_t* self,
|
||||
node_t* node,
|
||||
prog_t* prog,
|
||||
vec_t* to_end);
|
||||
#endif
|
||||
|
|
|
@ -171,6 +171,8 @@ node_t* lexer_try_new_next(lexer_t* self)
|
|||
}
|
||||
}
|
||||
|
||||
CCM_KEYWORD("if", NODE_IF, 0);
|
||||
CCM_KEYWORD("else", NODE_ELSE, 0);
|
||||
CCM_KEYWORD("begin", NODE_BEGIN, 0);
|
||||
CCM_KEYWORD("end", NODE_END, 0);
|
||||
CCM_KEYWORD("var", NODE_VAR, 0);
|
||||
|
|
|
@ -16,7 +16,8 @@ G(NODE_STR), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
|
|||
G(NODE_GE), G(NODE_EQ), G(NODE_NE), G(NODE_ARRAY), \
|
||||
G(NODE_VAR), G(NODE_IDENT), G(NODE_ASSIGN), \
|
||||
G(NODE_VARDECL), G(NODE_CONST), G(NODE_CONSTDECL), \
|
||||
G(NODE_BEGIN), G(NODE_BLOCK), G(NODE_END)
|
||||
G(NODE_BEGIN), G(NODE_BLOCK), G(NODE_END), G(NODE_IF), \
|
||||
G(NODE_ELSE)
|
||||
|
||||
CCM_ENUM_H(NodeKind, NODE_KIND);
|
||||
|
||||
|
|
85
lib/parser.c
85
lib/parser.c
|
@ -82,6 +82,17 @@ node_t* parser_try_new_rule(parser_t* self, rule_t rule)
|
|||
return (void*) NULL;
|
||||
}
|
||||
|
||||
int parser_consume(parser_t* self, NodeKind kind)
|
||||
{
|
||||
if (!lexer_peek_kind(self->lexer, kind, 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
lexer_consume_next(self->lexer, kind);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parser_ensure(parser_t* self, node_t* node, NodeKind kind)
|
||||
{
|
||||
assert(self);
|
||||
|
@ -152,12 +163,74 @@ node_t* parser_try_new_expr(parser_t* self)
|
|||
return CCM_TRY(parser_try_new_begin);
|
||||
}
|
||||
|
||||
if (lexer_peek_kind(self->lexer, NODE_IF, 0))
|
||||
{
|
||||
node_t* node = CCM_TRY(parser_try_new_if);
|
||||
if (!node) { return NULL; }
|
||||
lexer_consume_next(self->lexer, NODE_END);
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* assign = CCM_TRY(parser_try_new_assign);
|
||||
if (assign) { return assign; }
|
||||
|
||||
return CCM_TRY(parser_try_new_or);
|
||||
}
|
||||
|
||||
node_t* parser_try_new_if(parser_t* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
if (!parser_consume(self, NODE_IF))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
node_t* cond = CCM_TRY(parser_try_new_expr);
|
||||
if (!cond) { return NULL; }
|
||||
|
||||
node_t* block = CCM_TRY(parser_try_new_block);
|
||||
if (!block)
|
||||
{
|
||||
node_free(cond); free(cond);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, NODE_IF, "", cond->line);
|
||||
node_push_new_child(node, cond);
|
||||
node_push_new_child(node, block);
|
||||
|
||||
if (parser_consume(self, NODE_ELSE))
|
||||
{
|
||||
if (lexer_peek_kind(self->lexer, NODE_IF, 0))
|
||||
{
|
||||
node_t* next = CCM_TRY(parser_try_new_if);
|
||||
if (!next)
|
||||
{
|
||||
node_free(cond); free(cond);
|
||||
node_free(block); free(block);
|
||||
node_free(node); free(node);
|
||||
return NULL;
|
||||
}
|
||||
node_push_new_child(node, next);
|
||||
}
|
||||
else
|
||||
{
|
||||
node_t* next = CCM_TRY(parser_try_new_block);
|
||||
if (!next)
|
||||
{
|
||||
node_free(cond); free(cond);
|
||||
node_free(block); free(block);
|
||||
node_free(node); free(node);
|
||||
return NULL;
|
||||
}
|
||||
node_push_new_child(node, next);
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_begin(parser_t* self)
|
||||
{
|
||||
assert(self);
|
||||
|
@ -171,7 +244,7 @@ node_t* parser_try_new_begin(parser_t* self)
|
|||
|
||||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, NODE_BEGIN, "", self->lexer->line);
|
||||
|
||||
|
||||
node_t* block = CCM_TRY(parser_try_new_block);
|
||||
node_push_new_child(node, block);
|
||||
|
||||
|
@ -192,14 +265,14 @@ node_t* parser_try_new_block(parser_t* self)
|
|||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, NODE_BLOCK, "", self->lexer->line);
|
||||
|
||||
while (1)
|
||||
while (1)
|
||||
{
|
||||
node_t* expr = CCM_TRY(parser_try_new_expr);
|
||||
if (!expr) { break; }
|
||||
|
||||
node_push_new_child(node, expr);
|
||||
}
|
||||
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -275,7 +348,7 @@ node_t* parser_try_new_decl(parser_t* self)
|
|||
}
|
||||
|
||||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, is_const ? NODE_CONSTDECL : NODE_VARDECL,
|
||||
node_init(node, is_const ? NODE_CONSTDECL : NODE_VARDECL,
|
||||
"", self->lexer->line);
|
||||
|
||||
node_push_new_child(node, ident);
|
||||
|
@ -681,7 +754,7 @@ node_t* parser_try_new_array(parser_t* self)
|
|||
|
||||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, NODE_ARRAY, "", self->lexer->line);
|
||||
|
||||
|
||||
if (!lexer_peek_kind(self->lexer, NODE_OSQUARE, 0))
|
||||
{
|
||||
node_free(node); free(node);
|
||||
|
@ -728,7 +801,7 @@ node_t* parser_try_new_index(parser_t* self)
|
|||
assert(self);
|
||||
|
||||
node_t* target = NULL;
|
||||
|
||||
|
||||
if (lexer_peek_kind(self->lexer, NODE_STR, 0)
|
||||
|| lexer_peek_kind(self->lexer, NODE_IDENT, 0))
|
||||
{
|
||||
|
|
|
@ -21,10 +21,12 @@ void parser_free(parser_t* self);
|
|||
node_t* parser_try_new_parse(parser_t* self);
|
||||
node_t* parser_try_new_rule(parser_t* self, rule_t rule);
|
||||
node_t* parser_try_new_rule_ll1(parser_t* self, rule_ll1_t rule, node_t* node);
|
||||
int parser_consume(parser_t* self, NodeKind kind);
|
||||
int parser_ensure(parser_t* self, node_t* node, NodeKind kind);
|
||||
|
||||
node_t* parser_try_new_module(parser_t* self);
|
||||
node_t* parser_try_new_expr(parser_t* self);
|
||||
node_t* parser_try_new_if(parser_t* self);
|
||||
node_t* parser_try_new_begin(parser_t* self);
|
||||
node_t* parser_try_new_block(parser_t* self);
|
||||
node_t* parser_try_new_assign(parser_t* self);
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
# IF
|
||||
# ==
|
||||
var a = 0
|
||||
|
||||
if true
|
||||
a = 1
|
||||
end
|
||||
|
||||
assert_eq (1, a)
|
||||
|
||||
if false
|
||||
a = 2
|
||||
end
|
||||
|
||||
assert_eq (1, a)
|
||||
|
||||
# IF THEN ELSE
|
||||
# ============
|
||||
|
||||
var b = 0
|
||||
|
||||
b = 0
|
||||
|
||||
if true
|
||||
b = 1
|
||||
else if true
|
||||
b = 2
|
||||
else if true
|
||||
b = 3
|
||||
else
|
||||
b = 4
|
||||
end
|
||||
|
||||
assert_eq (1, b)
|
||||
|
||||
|
||||
b = 0
|
||||
|
||||
if false
|
||||
b = 1
|
||||
else if true
|
||||
b = 2
|
||||
else if true
|
||||
b = 3
|
||||
else
|
||||
b = 4
|
||||
end
|
||||
|
||||
assert_eq (2, b)
|
||||
|
||||
b = 0
|
||||
|
||||
if false
|
||||
b = 1
|
||||
else if false
|
||||
b = 2
|
||||
else if true
|
||||
b = 3
|
||||
else
|
||||
b = 4
|
||||
end
|
||||
|
||||
assert_eq (3, b)
|
||||
|
||||
b = 0
|
||||
|
||||
if false
|
||||
b = 1
|
||||
else if false
|
||||
b = 2
|
||||
else if false
|
||||
b = 3
|
||||
else
|
||||
b = 4
|
||||
end
|
||||
|
||||
assert_eq (4, b)
|
Loading…
Reference in New Issue