if-then-else expression.

main
bog 2024-03-22 16:33:41 +01:00
parent 6d34100d67
commit 719abe66c4
8 changed files with 232 additions and 14 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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))
{

View File

@ -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);

77
tests/cond.ccm Normal file
View File

@ -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)