✨ while expression.
parent
719abe66c4
commit
40b8b7f68e
|
@ -6,6 +6,10 @@ EXPR ::=
|
|||
| ASSIGN
|
||||
| BEGIN
|
||||
| IF end
|
||||
| WHILE
|
||||
| continue
|
||||
| break
|
||||
WHILE ::= while EXPR BLOCK end
|
||||
IF ::=
|
||||
| if EXPR BLOCK (else (IF | BLOCK))?
|
||||
BEGIN ::= begin BLOCK end
|
||||
|
|
|
@ -40,6 +40,11 @@ size_t ccm_str(ccm_t* self, char* buffer, size_t size)
|
|||
|
||||
for (size_t i=0; i<self->stack.size; i++)
|
||||
{
|
||||
if (sz >= size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
value_t* val = ccm_to_value(self, (CCM) self->stack.data[i]);
|
||||
sz += value_str(val, buffer + sz, size - sz);
|
||||
sz += snprintf(buffer + sz, size - sz, "\n");
|
||||
|
|
|
@ -6,12 +6,15 @@ void compiler_init(compiler_t* self, module_t* module)
|
|||
err_init(&self->err);
|
||||
self->module = module;
|
||||
self->loc_counter = 0;
|
||||
vec_init(&self->loop_infos);
|
||||
}
|
||||
|
||||
void compiler_free(compiler_t* self)
|
||||
{
|
||||
assert(self);
|
||||
err_free(&self->err);
|
||||
vec_free_elements(&self->loop_infos, NULL);
|
||||
vec_free(&self->loop_infos);
|
||||
}
|
||||
|
||||
void compiler_compile(compiler_t* self,
|
||||
|
@ -32,6 +35,63 @@ void compiler_compile(compiler_t* self,
|
|||
|
||||
switch (node->kind)
|
||||
{
|
||||
case NODE_CONTINUE: {
|
||||
assert(self->loop_infos.size > 0);
|
||||
|
||||
loop_info_t const* info
|
||||
= self->loop_infos.data[
|
||||
self->loop_infos.size - 1
|
||||
];
|
||||
|
||||
prog_add_instr(prog, OP_BR, info->start_point);
|
||||
|
||||
} break;
|
||||
|
||||
case NODE_BREAK: {
|
||||
assert(self->loop_infos.size > 0);
|
||||
|
||||
loop_info_t* info
|
||||
= self->loop_infos.data[
|
||||
self->loop_infos.size - 1
|
||||
];
|
||||
|
||||
size_t point = prog_add_instr(prog, OP_BR, 0);
|
||||
vec_push(&info->to_end, (void*) point);
|
||||
|
||||
} break;
|
||||
case NODE_WHILE: {
|
||||
node_t* expr = node->children.data[0];
|
||||
node_t* block = node->children.data[1];
|
||||
|
||||
int start = prog->instrs.size;
|
||||
loop_info_t* info = malloc(sizeof(loop_info_t));
|
||||
info->start_point = start;
|
||||
vec_init(&info->to_end);
|
||||
|
||||
vec_push(&self->loop_infos, info);
|
||||
|
||||
compiler_compile(self, expr, prog);
|
||||
int cond_point = prog_add_instr(prog, OP_BRF, 0);
|
||||
|
||||
compiler_compile(self, block, prog);
|
||||
prog_add_instr(prog, OP_BR, start);
|
||||
|
||||
int end_point = prog->instrs.size;
|
||||
((instr_t*)prog->instrs.data[cond_point])->param
|
||||
= end_point;
|
||||
|
||||
for (size_t i=0; i<info->to_end.size; i++)
|
||||
{
|
||||
int addr = (size_t)info->to_end.data[i];
|
||||
instr_t* instr = prog->instrs.data[addr];
|
||||
instr->param = end_point;
|
||||
}
|
||||
|
||||
info = vec_pop(&self->loop_infos);
|
||||
vec_free(&info->to_end);
|
||||
free(info);
|
||||
} break;
|
||||
|
||||
case NODE_IF: {
|
||||
vec_t to_end;
|
||||
vec_init(&to_end);
|
||||
|
@ -51,7 +111,6 @@ void compiler_compile(compiler_t* self,
|
|||
} break;
|
||||
|
||||
case NODE_BLOCK: {
|
||||
|
||||
sym_open_scope(sym);
|
||||
for (size_t i=0; i<node->children.size; i++)
|
||||
{
|
||||
|
@ -108,17 +167,18 @@ void compiler_compile(compiler_t* self,
|
|||
prog_add_instr(prog, OP_ASTORE, indexes_count);
|
||||
} else {
|
||||
compiler_compile(self, expr, prog);
|
||||
int status =
|
||||
sym_try_assign(
|
||||
sym,
|
||||
target->value, self->loc_counter
|
||||
);
|
||||
|
||||
sym_entry_t* entry = sym_try_get_value(
|
||||
sym,
|
||||
target->value
|
||||
);
|
||||
|
||||
int status =
|
||||
sym_try_assign(
|
||||
sym,
|
||||
target->value, self->loc_counter
|
||||
);
|
||||
|
||||
assert(entry);
|
||||
|
||||
if (entry->is_const) {
|
||||
|
@ -135,7 +195,11 @@ void compiler_compile(compiler_t* self,
|
|||
return;
|
||||
}
|
||||
|
||||
prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter);
|
||||
prog_add_instr(
|
||||
prog,
|
||||
OP_LOCAL_STORE,
|
||||
entry->id
|
||||
);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
@ -170,7 +234,7 @@ void compiler_compile(compiler_t* self,
|
|||
return;
|
||||
}
|
||||
|
||||
prog_add_instr(prog, OP_LOCAL_LOAD, entry->local_addr);
|
||||
prog_add_instr(prog, OP_LOCAL_LOAD, entry->id);
|
||||
} break;
|
||||
|
||||
case NODE_ARRAY: {
|
||||
|
|
|
@ -8,10 +8,16 @@
|
|||
#include "err.h"
|
||||
#include "module.h"
|
||||
|
||||
typedef struct {
|
||||
int start_point;
|
||||
vec_t to_end;
|
||||
} loop_info_t;
|
||||
|
||||
typedef struct {
|
||||
module_t* module;
|
||||
err_t err;
|
||||
int loc_counter;
|
||||
vec_t loop_infos;
|
||||
} compiler_t;
|
||||
|
||||
void compiler_init(compiler_t* self, module_t* module);
|
||||
|
|
|
@ -171,6 +171,10 @@ node_t* lexer_try_new_next(lexer_t* self)
|
|||
}
|
||||
}
|
||||
|
||||
CCM_KEYWORD("break", NODE_BREAK, 0);
|
||||
CCM_KEYWORD("continue", NODE_CONTINUE, 0);
|
||||
CCM_KEYWORD("for", NODE_FOR, 0);
|
||||
CCM_KEYWORD("while", NODE_WHILE, 0);
|
||||
CCM_KEYWORD("if", NODE_IF, 0);
|
||||
CCM_KEYWORD("else", NODE_ELSE, 0);
|
||||
CCM_KEYWORD("begin", NODE_BEGIN, 0);
|
||||
|
|
|
@ -17,7 +17,8 @@ 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_IF), \
|
||||
G(NODE_ELSE)
|
||||
G(NODE_ELSE), G(NODE_WHILE), G(NODE_FOR), G(NODE_BREAK), \
|
||||
G(NODE_CONTINUE)
|
||||
|
||||
CCM_ENUM_H(NodeKind, NODE_KIND);
|
||||
|
||||
|
|
39
lib/parser.c
39
lib/parser.c
|
@ -163,6 +163,17 @@ node_t* parser_try_new_expr(parser_t* self)
|
|||
return CCM_TRY(parser_try_new_begin);
|
||||
}
|
||||
|
||||
if (lexer_peek_kind(self->lexer, NODE_WHILE, 0))
|
||||
{
|
||||
return CCM_TRY(parser_try_new_while);
|
||||
}
|
||||
|
||||
if (lexer_peek_kind(self->lexer, NODE_CONTINUE, 0)
|
||||
|| lexer_peek_kind(self->lexer, NODE_BREAK, 0))
|
||||
{
|
||||
return lexer_try_new_next(self->lexer);
|
||||
}
|
||||
|
||||
if (lexer_peek_kind(self->lexer, NODE_IF, 0))
|
||||
{
|
||||
node_t* node = CCM_TRY(parser_try_new_if);
|
||||
|
@ -177,6 +188,34 @@ node_t* parser_try_new_expr(parser_t* self)
|
|||
return CCM_TRY(parser_try_new_or);
|
||||
}
|
||||
|
||||
node_t* parser_try_new_while(parser_t* self)
|
||||
{
|
||||
assert(self);
|
||||
|
||||
if (!parser_consume(self, NODE_WHILE))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node_t* expr = CCM_TRY(parser_try_new_expr);
|
||||
if (!expr) { return NULL; }
|
||||
|
||||
node_t* block = CCM_TRY(parser_try_new_block);
|
||||
|
||||
if (!block || !parser_consume(self, NODE_END))
|
||||
{
|
||||
node_free(expr); free(expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node_t* node = malloc(sizeof(node_t));
|
||||
node_init(node, NODE_WHILE, "", expr->line);
|
||||
node_push_new_child(node, expr);
|
||||
node_push_new_child(node, block);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
node_t* parser_try_new_if(parser_t* self)
|
||||
{
|
||||
assert(self);
|
||||
|
|
|
@ -26,6 +26,7 @@ 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_while(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);
|
||||
|
|
|
@ -4,6 +4,7 @@ void sym_init(sym_t* self)
|
|||
{
|
||||
assert(self);
|
||||
self->env = NULL;
|
||||
self->id_counter = 0;
|
||||
}
|
||||
|
||||
void sym_free(sym_t* self)
|
||||
|
@ -91,7 +92,9 @@ int sym_declare(sym_t* self,
|
|||
entry->name = strdup(name);
|
||||
entry->local_addr = addr;
|
||||
entry->is_const = is_const;
|
||||
entry->id = self->id_counter;
|
||||
vec_push(&self->env->entries, entry);
|
||||
self->id_counter++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
typedef struct {
|
||||
char* name;
|
||||
int id;
|
||||
int local_addr;
|
||||
int is_const;
|
||||
} sym_entry_t;
|
||||
|
@ -18,6 +19,7 @@ typedef struct env {
|
|||
|
||||
typedef struct {
|
||||
env_t* env;
|
||||
int id_counter;
|
||||
} sym_t;
|
||||
|
||||
void sym_init(sym_t* self);
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
var a = 0
|
||||
|
||||
while a < 100
|
||||
a = a + 1
|
||||
end
|
||||
|
||||
assert_eq (100, a)
|
||||
|
||||
var b = 0
|
||||
var c = 0
|
||||
var d = 0
|
||||
|
||||
while b < 6
|
||||
c = 0
|
||||
while c < 7
|
||||
d = d + 1
|
||||
c = c + 1
|
||||
end
|
||||
|
||||
b = b + 1
|
||||
end
|
||||
|
||||
assert_eq (d, 42)
|
||||
|
||||
var e = 0
|
||||
var f = 0
|
||||
|
||||
while e < 128
|
||||
e = e + 1
|
||||
if e % 2 == 0
|
||||
continue
|
||||
end
|
||||
|
||||
f = f + 1
|
||||
end
|
||||
|
||||
assert_eq (64, f)
|
||||
|
||||
var g = 0
|
||||
var h = 0
|
||||
var i = 0
|
||||
|
||||
while g < 100
|
||||
h = 0
|
||||
|
||||
if g >= 7
|
||||
break
|
||||
end
|
||||
|
||||
while h < 100
|
||||
if h >= 6
|
||||
break
|
||||
end
|
||||
|
||||
h = h + 1
|
||||
if h % 2 == 0
|
||||
continue
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
g = g + 1
|
||||
end
|
||||
|
||||
assert_eq (21, i)
|
Loading…
Reference in New Issue