✨ if-then-else expression.
parent
6d34100d67
commit
719abe66c4
|
@ -5,6 +5,9 @@ EXPR ::=
|
||||||
| DECL
|
| DECL
|
||||||
| ASSIGN
|
| ASSIGN
|
||||||
| BEGIN
|
| BEGIN
|
||||||
|
| IF end
|
||||||
|
IF ::=
|
||||||
|
| if EXPR BLOCK (else (IF | BLOCK))?
|
||||||
BEGIN ::= begin BLOCK end
|
BEGIN ::= begin BLOCK end
|
||||||
BLOCK ::= EXPR*
|
BLOCK ::= EXPR*
|
||||||
ASSIGN ::= (ident|INDEX) assign EXPR
|
ASSIGN ::= (ident|INDEX) assign EXPR
|
||||||
|
|
|
@ -32,6 +32,24 @@ void compiler_compile(compiler_t* self,
|
||||||
|
|
||||||
switch (node->kind)
|
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: {
|
case NODE_BLOCK: {
|
||||||
|
|
||||||
sym_open_scope(sym);
|
sym_open_scope(sym);
|
||||||
|
@ -118,8 +136,6 @@ void compiler_compile(compiler_t* self,
|
||||||
}
|
}
|
||||||
|
|
||||||
prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter);
|
prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter);
|
||||||
|
|
||||||
self->loc_counter++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
@ -425,3 +441,42 @@ void compiler_compile_and(compiler_t* self,
|
||||||
|
|
||||||
vec_free(&to_false);
|
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,
|
void compiler_compile_and(compiler_t* self,
|
||||||
node_t* node,
|
node_t* node,
|
||||||
prog_t* prog);
|
prog_t* prog);
|
||||||
|
|
||||||
|
void compiler_compile_if(compiler_t* self,
|
||||||
|
node_t* node,
|
||||||
|
prog_t* prog,
|
||||||
|
vec_t* to_end);
|
||||||
#endif
|
#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("begin", NODE_BEGIN, 0);
|
||||||
CCM_KEYWORD("end", NODE_END, 0);
|
CCM_KEYWORD("end", NODE_END, 0);
|
||||||
CCM_KEYWORD("var", NODE_VAR, 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_GE), G(NODE_EQ), G(NODE_NE), G(NODE_ARRAY), \
|
||||||
G(NODE_VAR), G(NODE_IDENT), G(NODE_ASSIGN), \
|
G(NODE_VAR), G(NODE_IDENT), G(NODE_ASSIGN), \
|
||||||
G(NODE_VARDECL), G(NODE_CONST), G(NODE_CONSTDECL), \
|
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);
|
CCM_ENUM_H(NodeKind, NODE_KIND);
|
||||||
|
|
||||||
|
|
73
lib/parser.c
73
lib/parser.c
|
@ -82,6 +82,17 @@ node_t* parser_try_new_rule(parser_t* self, rule_t rule)
|
||||||
return (void*) NULL;
|
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)
|
int parser_ensure(parser_t* self, node_t* node, NodeKind kind)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -152,12 +163,74 @@ node_t* parser_try_new_expr(parser_t* self)
|
||||||
return CCM_TRY(parser_try_new_begin);
|
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);
|
node_t* assign = CCM_TRY(parser_try_new_assign);
|
||||||
if (assign) { return assign; }
|
if (assign) { return assign; }
|
||||||
|
|
||||||
return CCM_TRY(parser_try_new_or);
|
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)
|
node_t* parser_try_new_begin(parser_t* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
|
|
@ -21,10 +21,12 @@ void parser_free(parser_t* self);
|
||||||
node_t* parser_try_new_parse(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(parser_t* self, rule_t rule);
|
||||||
node_t* parser_try_new_rule_ll1(parser_t* self, rule_ll1_t rule, node_t* node);
|
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);
|
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_module(parser_t* self);
|
||||||
node_t* parser_try_new_expr(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_begin(parser_t* self);
|
||||||
node_t* parser_try_new_block(parser_t* self);
|
node_t* parser_try_new_block(parser_t* self);
|
||||||
node_t* parser_try_new_assign(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