Compare commits
3 Commits
6d34100d67
...
687236fb7d
Author | SHA1 | Date |
---|---|---|
bog | 687236fb7d | |
bog | 40b8b7f68e | |
bog | 719abe66c4 |
|
@ -5,6 +5,15 @@ EXPR ::=
|
||||||
| DECL
|
| DECL
|
||||||
| ASSIGN
|
| ASSIGN
|
||||||
| BEGIN
|
| BEGIN
|
||||||
|
| IF end
|
||||||
|
| WHILE
|
||||||
|
| FOR
|
||||||
|
| continue
|
||||||
|
| break
|
||||||
|
FOR ::= for EXPR in EXPR BLOCK end
|
||||||
|
WHILE ::= while EXPR BLOCK 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
|
||||||
|
|
|
@ -10,7 +10,7 @@ G(OP_DIV), G(OP_POW), G(OP_MOD), G(OP_MK_TUPLE), \
|
||||||
G(OP_ASSERT_EQ), G(OP_ASSERT_NE), G(OP_BRF), G(OP_BR), \
|
G(OP_ASSERT_EQ), G(OP_ASSERT_NE), G(OP_BRF), G(OP_BR), \
|
||||||
G(OP_NOT), G(OP_IN), G(OP_INDEX), G(OP_EQ), G(OP_LT), \
|
G(OP_NOT), G(OP_IN), G(OP_INDEX), G(OP_EQ), G(OP_LT), \
|
||||||
G(OP_GT), G(OP_MK_ARRAY), G(OP_LOCAL_STORE), \
|
G(OP_GT), G(OP_MK_ARRAY), G(OP_LOCAL_STORE), \
|
||||||
G(OP_LOCAL_LOAD), G(OP_ASTORE)
|
G(OP_LOCAL_LOAD), G(OP_ASTORE), G(OP_LEN)
|
||||||
|
|
||||||
CCM_ENUM_H(Opcode, OPCODES);
|
CCM_ENUM_H(Opcode, OPCODES);
|
||||||
|
|
||||||
|
|
|
@ -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++)
|
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]);
|
value_t* val = ccm_to_value(self, (CCM) self->stack.data[i]);
|
||||||
sz += value_str(val, buffer + sz, size - sz);
|
sz += value_str(val, buffer + sz, size - sz);
|
||||||
sz += snprintf(buffer + sz, size - sz, "\n");
|
sz += snprintf(buffer + sz, size - sz, "\n");
|
||||||
|
@ -261,10 +266,9 @@ char* ccm_from_str(ccm_t* self, CCM value)
|
||||||
return ccm_find_value(self, value)->data.str;
|
return ccm_find_value(self, value)->data.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
CCM ccm_to_str(ccm_t* self, char* value, int line)
|
CCM ccm_to_str(ccm_t* self, char const* value, int line)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(value);
|
|
||||||
|
|
||||||
value_t* val = malloc(sizeof(value_t));
|
value_t* val = malloc(sizeof(value_t));
|
||||||
value_init_str(val, value, line);
|
value_init_str(val, value, line);
|
||||||
|
|
|
@ -51,7 +51,7 @@ CCM ccm_to_boolean(ccm_t* self, int value, int line);
|
||||||
|
|
||||||
int ccm_is_str(ccm_t* self, CCM value);
|
int ccm_is_str(ccm_t* self, CCM value);
|
||||||
char* ccm_from_str(ccm_t* self, CCM value);
|
char* ccm_from_str(ccm_t* self, CCM value);
|
||||||
CCM ccm_to_str(ccm_t* self, char* value, int line);
|
CCM ccm_to_str(ccm_t* self, char const* value, int line);
|
||||||
|
|
||||||
int ccm_is_array(ccm_t* self, CCM value);
|
int ccm_is_array(ccm_t* self, CCM value);
|
||||||
vec_t* ccm_from_array(ccm_t* self, CCM value);
|
vec_t* ccm_from_array(ccm_t* self, CCM value);
|
||||||
|
|
233
lib/compiler.c
233
lib/compiler.c
|
@ -1,4 +1,5 @@
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
#include "prog.h"
|
||||||
|
|
||||||
void compiler_init(compiler_t* self, module_t* module)
|
void compiler_init(compiler_t* self, module_t* module)
|
||||||
{
|
{
|
||||||
|
@ -6,12 +7,15 @@ void compiler_init(compiler_t* self, module_t* module)
|
||||||
err_init(&self->err);
|
err_init(&self->err);
|
||||||
self->module = module;
|
self->module = module;
|
||||||
self->loc_counter = 0;
|
self->loc_counter = 0;
|
||||||
|
vec_init(&self->loop_infos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler_free(compiler_t* self)
|
void compiler_free(compiler_t* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
err_free(&self->err);
|
err_free(&self->err);
|
||||||
|
vec_free_elements(&self->loop_infos, NULL);
|
||||||
|
vec_free(&self->loop_infos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler_compile(compiler_t* self,
|
void compiler_compile(compiler_t* self,
|
||||||
|
@ -32,8 +36,175 @@ void compiler_compile(compiler_t* self,
|
||||||
|
|
||||||
switch (node->kind)
|
switch (node->kind)
|
||||||
{
|
{
|
||||||
case NODE_BLOCK: {
|
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_FOR: {
|
||||||
|
node_t const* ident = node->children.data[0];
|
||||||
|
node_t* expr = node->children.data[1];
|
||||||
|
node_t* block = node->children.data[2];
|
||||||
|
|
||||||
|
|
||||||
|
sym_open_scope(sym);
|
||||||
|
sym_declare(sym, "__iter",
|
||||||
|
self->loc_counter++, 0);
|
||||||
|
sym_declare(sym, ident->value,
|
||||||
|
self->loc_counter++, 0);
|
||||||
|
|
||||||
|
int var_id =
|
||||||
|
sym_try_get_value(sym, ident->value)->id;
|
||||||
|
|
||||||
|
int iter_id =
|
||||||
|
sym_try_get_value(sym, "__iter")->id;
|
||||||
|
|
||||||
|
// initialize iteration counter
|
||||||
|
value_t* value = malloc(sizeof(value_t));
|
||||||
|
value_init_num(value, -1, node->line);
|
||||||
|
|
||||||
|
prog_add_instr(prog, OP_PUSH, prog_add_new_constant(
|
||||||
|
prog,
|
||||||
|
ccm_from_value(ccm, value)
|
||||||
|
));
|
||||||
|
|
||||||
|
prog_add_instr(prog, OP_LOCAL_STORE, iter_id);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// incr iteration counter
|
||||||
|
prog_add_instr(prog, OP_LOCAL_LOAD, iter_id);
|
||||||
|
|
||||||
|
value_free(value); free(value);
|
||||||
|
value = malloc(sizeof(value_t));
|
||||||
|
value_init_num(value, 1, node->line);
|
||||||
|
|
||||||
|
prog_add_instr(prog, OP_PUSH, prog_add_new_constant(
|
||||||
|
prog,
|
||||||
|
ccm_from_value(ccm, value)
|
||||||
|
));
|
||||||
|
|
||||||
|
prog_add_instr(prog, OP_ADD, CCM_NO_PARAM);
|
||||||
|
prog_add_instr(prog, OP_LOCAL_STORE, iter_id);
|
||||||
|
|
||||||
|
// test if end is reached
|
||||||
|
prog_add_instr(prog, OP_LOCAL_LOAD, iter_id);
|
||||||
|
|
||||||
|
compiler_compile(self, expr, prog);
|
||||||
|
prog_add_instr(prog, OP_LEN, CCM_NO_PARAM);
|
||||||
|
|
||||||
|
|
||||||
|
prog_add_instr(prog, OP_LT, CCM_NO_PARAM);
|
||||||
|
int cond_point = prog_add_instr(prog, OP_BRF, 0);
|
||||||
|
|
||||||
|
// get current element
|
||||||
|
prog_add_instr(prog, OP_LOCAL_LOAD, iter_id);
|
||||||
|
compiler_compile(self, expr, prog);
|
||||||
|
prog_add_instr(prog, OP_INDEX, 1);
|
||||||
|
prog_add_instr(prog, OP_LOCAL_STORE, var_id);
|
||||||
|
|
||||||
|
// compile body
|
||||||
|
compiler_compile(self, block, prog);
|
||||||
|
|
||||||
|
// next iteration
|
||||||
|
prog_add_instr(prog, OP_BR, start);
|
||||||
|
|
||||||
|
value_free(value); free(value);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
sym_close_scope(sym);
|
||||||
|
|
||||||
|
info = vec_pop(&self->loop_infos);
|
||||||
|
vec_free(&info->to_end);
|
||||||
|
free(info);
|
||||||
|
} 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);
|
||||||
|
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);
|
sym_open_scope(sym);
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
for (size_t i=0; i<node->children.size; i++)
|
||||||
{
|
{
|
||||||
|
@ -90,17 +261,18 @@ void compiler_compile(compiler_t* self,
|
||||||
prog_add_instr(prog, OP_ASTORE, indexes_count);
|
prog_add_instr(prog, OP_ASTORE, indexes_count);
|
||||||
} else {
|
} else {
|
||||||
compiler_compile(self, expr, prog);
|
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_entry_t* entry = sym_try_get_value(
|
||||||
sym,
|
sym,
|
||||||
target->value
|
target->value
|
||||||
);
|
);
|
||||||
|
|
||||||
|
int status =
|
||||||
|
sym_try_assign(
|
||||||
|
sym,
|
||||||
|
target->value, self->loc_counter
|
||||||
|
);
|
||||||
|
|
||||||
assert(entry);
|
assert(entry);
|
||||||
|
|
||||||
if (entry->is_const) {
|
if (entry->is_const) {
|
||||||
|
@ -117,9 +289,11 @@ void compiler_compile(compiler_t* self,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter);
|
prog_add_instr(
|
||||||
|
prog,
|
||||||
self->loc_counter++;
|
OP_LOCAL_STORE,
|
||||||
|
entry->id
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
@ -154,7 +328,7 @@ void compiler_compile(compiler_t* self,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prog_add_instr(prog, OP_LOCAL_LOAD, entry->local_addr);
|
prog_add_instr(prog, OP_LOCAL_LOAD, entry->id);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_ARRAY: {
|
case NODE_ARRAY: {
|
||||||
|
@ -425,3 +599,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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,10 +8,16 @@
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int start_point;
|
||||||
|
vec_t to_end;
|
||||||
|
} loop_info_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
module_t* module;
|
module_t* module;
|
||||||
err_t err;
|
err_t err;
|
||||||
int loc_counter;
|
int loc_counter;
|
||||||
|
vec_t loop_infos;
|
||||||
} compiler_t;
|
} compiler_t;
|
||||||
|
|
||||||
void compiler_init(compiler_t* self, module_t* module);
|
void compiler_init(compiler_t* self, module_t* module);
|
||||||
|
@ -28,4 +34,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
|
||||||
|
|
27
lib/exec.c
27
lib/exec.c
|
@ -130,6 +130,31 @@ void exec_instr(exec_t* self,
|
||||||
self->pc++;
|
self->pc++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case OP_LEN: {
|
||||||
|
CCM ccm_value = ccm_pop(ccm);
|
||||||
|
value_t* value = ccm_to_value(ccm, ccm_value);
|
||||||
|
CCM ccm_res = 0;
|
||||||
|
if (value->type == TYPE_ARRAY)
|
||||||
|
{
|
||||||
|
ccm_res = ccm_to_num(
|
||||||
|
ccm,
|
||||||
|
value->data.array->size,
|
||||||
|
value->line
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (value->type == TYPE_STR)
|
||||||
|
{
|
||||||
|
ccm_res = ccm_to_num(
|
||||||
|
ccm,
|
||||||
|
strlen(value->data.str),
|
||||||
|
value->line
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ccm_push(ccm, ccm_res);
|
||||||
|
|
||||||
|
self->pc++;
|
||||||
|
} break;
|
||||||
case OP_INDEX: {
|
case OP_INDEX: {
|
||||||
CCM ccm_target = ccm_pop(ccm);
|
CCM ccm_target = ccm_pop(ccm);
|
||||||
|
|
||||||
|
@ -169,7 +194,7 @@ void exec_instr(exec_t* self,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buf[2] = {target[idx], '\0'};
|
char const buf[2] = {target[idx], '\0'};
|
||||||
ccm_push(ccm, ccm_to_str(ccm, buf, line));
|
ccm_push(ccm, ccm_to_str(ccm, buf, line));
|
||||||
}
|
}
|
||||||
else if (ccm_is_tuple(ccm, ccm_target)
|
else if (ccm_is_tuple(ccm, ccm_target)
|
||||||
|
|
14
lib/lexer.c
14
lib/lexer.c
|
@ -171,6 +171,12 @@ 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);
|
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);
|
||||||
|
@ -445,7 +451,13 @@ node_t* lexer_try_new_str(lexer_t* self)
|
||||||
cursor++;
|
cursor++;
|
||||||
self->cursor = cursor;
|
self->cursor = cursor;
|
||||||
node_t* node = malloc(sizeof(node_t));
|
node_t* node = malloc(sizeof(node_t));
|
||||||
node_init(node, NODE_STR, value.value, self->line);
|
|
||||||
|
node_init(
|
||||||
|
node,
|
||||||
|
NODE_STR,
|
||||||
|
value.size == 0 ? "" : value.value,
|
||||||
|
self->line
|
||||||
|
);
|
||||||
|
|
||||||
str_free(&value);
|
str_free(&value);
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,9 @@ 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), G(NODE_WHILE), G(NODE_FOR), G(NODE_BREAK), \
|
||||||
|
G(NODE_CONTINUE)
|
||||||
|
|
||||||
CCM_ENUM_H(NodeKind, NODE_KIND);
|
CCM_ENUM_H(NodeKind, NODE_KIND);
|
||||||
|
|
||||||
|
|
166
lib/parser.c
166
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,167 @@ 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_WHILE, 0))
|
||||||
|
{
|
||||||
|
return CCM_TRY(parser_try_new_while);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lexer_peek_kind(self->lexer, NODE_FOR, 0))
|
||||||
|
{
|
||||||
|
return CCM_TRY(parser_try_new_for);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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_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_for(parser_t* self)
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
|
||||||
|
if (!parser_consume(self, NODE_FOR))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* ident = NULL;
|
||||||
|
|
||||||
|
if (lexer_peek_kind(self->lexer, NODE_IDENT, 0))
|
||||||
|
{
|
||||||
|
ident = lexer_try_new_next(self->lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ident) { return NULL; }
|
||||||
|
|
||||||
|
if (!parser_consume(self, NODE_IN))
|
||||||
|
{
|
||||||
|
node_free(ident); free(ident);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* target = CCM_TRY(parser_try_new_expr);
|
||||||
|
|
||||||
|
if (!target)
|
||||||
|
{
|
||||||
|
node_free(ident); free(ident);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* block = CCM_TRY(parser_try_new_block);
|
||||||
|
|
||||||
|
if (!block || !parser_consume(self, NODE_END))
|
||||||
|
{
|
||||||
|
node_free(ident); free(ident);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_t* node = malloc(sizeof(node_t));
|
||||||
|
node_init(node, NODE_FOR, "", ident->line);
|
||||||
|
node_push_new_child(node, ident);
|
||||||
|
node_push_new_child(node, target);
|
||||||
|
node_push_new_child(node, block);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,14 @@ 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_for(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_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);
|
||||||
|
|
|
@ -60,7 +60,11 @@ void str_push(str_t* self, char c)
|
||||||
void str_push_cstr(str_t* self, char const* rhs)
|
void str_push_cstr(str_t* self, char const* rhs)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(rhs);
|
|
||||||
|
if (!rhs)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i=0; i<strlen(rhs); i++)
|
for (size_t i=0; i<strlen(rhs); i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@ void sym_init(sym_t* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
self->env = NULL;
|
self->env = NULL;
|
||||||
|
self->id_counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sym_free(sym_t* self)
|
void sym_free(sym_t* self)
|
||||||
|
@ -91,7 +92,9 @@ int sym_declare(sym_t* self,
|
||||||
entry->name = strdup(name);
|
entry->name = strdup(name);
|
||||||
entry->local_addr = addr;
|
entry->local_addr = addr;
|
||||||
entry->is_const = is_const;
|
entry->is_const = is_const;
|
||||||
|
entry->id = self->id_counter;
|
||||||
vec_push(&self->env->entries, entry);
|
vec_push(&self->env->entries, entry);
|
||||||
|
self->id_counter++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* name;
|
char* name;
|
||||||
|
int id;
|
||||||
int local_addr;
|
int local_addr;
|
||||||
int is_const;
|
int is_const;
|
||||||
} sym_entry_t;
|
} sym_entry_t;
|
||||||
|
@ -18,6 +19,7 @@ typedef struct env {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
env_t* env;
|
env_t* env;
|
||||||
|
int id_counter;
|
||||||
} sym_t;
|
} sym_t;
|
||||||
|
|
||||||
void sym_init(sym_t* self);
|
void sym_init(sym_t* self);
|
||||||
|
|
|
@ -28,8 +28,6 @@ void value_init_boolean(value_t* self, int boolean, int line)
|
||||||
void value_init_str(value_t* self, char const* value, int line)
|
void value_init_str(value_t* self, char const* value, int line)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(value);
|
|
||||||
|
|
||||||
self->data.str = strdup(value);
|
self->data.str = strdup(value);
|
||||||
self->type = TYPE_STR;
|
self->type = TYPE_STR;
|
||||||
self->line = line;
|
self->line = line;
|
||||||
|
@ -115,7 +113,6 @@ void value_free(value_t* self)
|
||||||
{
|
{
|
||||||
if (self->type == TYPE_ARRAY)
|
if (self->type == TYPE_ARRAY)
|
||||||
{
|
{
|
||||||
//vec_free_elements(self->data.array, (void*) value_free);
|
|
||||||
vec_free(self->data.array);
|
vec_free(self->data.array);
|
||||||
free(self->data.array);
|
free(self->data.array);
|
||||||
}
|
}
|
||||||
|
@ -127,7 +124,7 @@ void value_free(value_t* self)
|
||||||
free(self->data.tuple);
|
free(self->data.tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->type == TYPE_STR)
|
if (self->type == TYPE_STR && self->data.str)
|
||||||
{
|
{
|
||||||
free(self->data.str);
|
free(self->data.str);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
|
@ -0,0 +1,107 @@
|
||||||
|
# WHILE LOOP
|
||||||
|
# ==========
|
||||||
|
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)
|
||||||
|
|
||||||
|
# FOR LOOP
|
||||||
|
# ========
|
||||||
|
var j = 0
|
||||||
|
for k in [1, 2, 3]
|
||||||
|
j = j + k
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_eq (6, j)
|
||||||
|
|
||||||
|
var l = 0
|
||||||
|
var m = [7, 3, 1]
|
||||||
|
|
||||||
|
for n in m
|
||||||
|
l = l + n
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_eq (11, l)
|
||||||
|
|
||||||
|
var o = 0
|
||||||
|
for p in [1, 2, 3, 4, 5, 6, 7]
|
||||||
|
if p > 5
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
if p % 2 == 0
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
o = o + p
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_eq (9, o)
|
||||||
|
|
||||||
|
var q = ""
|
||||||
|
for r in "hello"
|
||||||
|
q = r + q
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_eq ("olleh", q)
|
Loading…
Reference in New Issue