diff --git a/ccm/main.c b/ccm/main.c index 6a4f73c..a6dae7d 100644 --- a/ccm/main.c +++ b/ccm/main.c @@ -11,9 +11,10 @@ int main(int argc, char** argv) module_t module; module_init(&module); - module_load(&module, argv[1]); + status = module_load(&module, argv[1]); - if (!err_is_ok(&module.err)) + + if (status != 0 || !err_is_ok(&module.err)) { err_print_stack_trace(&module.err); status = 1; diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 89533b3..2d01dbc 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -3,6 +3,8 @@ EXPR ::= | OR | ASSERT | DECL +| ASSIGN +ASSIGN ::= (ident|INDEX) assign EXPR DECL ::= var ident assign EXPR ASSERT ::= (assert_eq|assert_ne) tuple OR ::= AND (or AND)* diff --git a/lib/bytecode.h b/lib/bytecode.h index 5b401b4..7b6759b 100644 --- a/lib/bytecode.h +++ b/lib/bytecode.h @@ -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_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_LOCAL_LOAD) +G(OP_LOCAL_LOAD), G(OP_ASTORE) CCM_ENUM_H(Opcode, OPCODES); diff --git a/lib/commons.h b/lib/commons.h index 08a67a7..3eeff48 100644 --- a/lib/commons.h +++ b/lib/commons.h @@ -9,7 +9,7 @@ #include #include -#define CCM_STRLEN 256 +#define CCM_STRLEN 4096 #define CCM_ENUM_ENUM(X) X #define CCM_ENUM_STR(X) #X diff --git a/lib/compiler.c b/lib/compiler.c index 2a092c4..57544fb 100644 --- a/lib/compiler.c +++ b/lib/compiler.c @@ -32,6 +32,57 @@ void compiler_compile(compiler_t* self, switch (node->kind) { + case NODE_ASSIGN: { + node_t* target = node->children.data[0]; + node_t* expr = node->children.data[1]; + + if (target->kind == NODE_INDEX) { + node_t* ident = target->children.data[0]; + + sym_entry_t const* entry = sym_try_get_value( + sym, + ident->value + ); + + if (!entry) { + err_push(&self->err, ident->line, + "undefined array '%s'", ident->value); + return; + } + + compiler_compile(self, expr, prog); + size_t indexes_count = target->children.size - 1; + + for (size_t i=1; ichildren.size; i++) { + compiler_compile( + self, + target->children.data[i], + prog + ); + } + + prog_add_instr(prog, OP_PUSH, entry->local_addr); + 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); + + if (!status) + { + err_push(&self->err, target->line, + "cannot assign value to '%s'", + target->value); + return; + } + + prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter); + + self->loc_counter++; + } + + } break; + case NODE_VARDECL: { node_t const* ident = node->children.data[0]; node_t* expr = node->children.data[1]; diff --git a/lib/exec.c b/lib/exec.c index 41c3448..d617c24 100644 --- a/lib/exec.c +++ b/lib/exec.c @@ -70,7 +70,11 @@ void exec_instr(exec_t* self, vec_push(vec, ccm_to_value(ccm, element)); } - int line = ((value_t*) vec->data[0])->line; + int line = 0; + + if (vec->size > 0) { + line = ((value_t*) vec->data[0])->line; + } size_t addr = ccm_store_global( ccm, @@ -96,6 +100,36 @@ void exec_instr(exec_t* self, self->pc++; } break; + case OP_ASTORE: { + int addr = ccm_pop(ccm); + CCM ccm_gaddr = ccm_get(ccm, addr); + int gaddr = ccm_from_ref(ccm, ccm_gaddr); + + CCM ccm_target = ccm_load_global(ccm, gaddr); + value_t* target = ccm_to_value(ccm, ccm_target); + + int indexes[param]; + memset(indexes, 0, param * sizeof(int)); + + for (int i=0; idata.array->data[indexes[i]]; + } + + CCM ccm_expr = ccm_pop(ccm); + value_t* expr = ccm_to_value(ccm, ccm_expr); + target->data.array->data[indexes[param - 1]] + = expr; + ccm_push(ccm, ccm_expr); + self->pc++; + } break; + case OP_INDEX: { CCM ccm_target = ccm_pop(ccm); @@ -192,7 +226,10 @@ void exec_instr(exec_t* self, } } else { - assert(0); + value_t const* val = ccm_to_value(ccm, ccm_target); + err_push(&self->err, val->line, + "not an array"); + return; } self->pc++; diff --git a/lib/module.c b/lib/module.c index 70dff67..e79b50d 100644 --- a/lib/module.c +++ b/lib/module.c @@ -34,6 +34,7 @@ int module_load(module_t* self, char const* path) { assert(self); assert(path); + int status = 0; if (module_load_source(self, path) != 0) { @@ -54,19 +55,28 @@ int module_load(module_t* self, char const* path) err_print_stack_trace(&lexer.err); err_print_stack_trace(&parser.err); err_push(&self->err, lexer.line, "invalid module"); + status = 1; goto free_parser; } if (!ast) { + status = 1; goto free_parser; } compiler_t compiler; compiler_init(&compiler, self); - compiler_compile(&compiler, ast, &self->prog); + + if (!err_is_ok(&compiler.err)) + { + err_print_stack_trace(&compiler.err); + status = 1; + goto free_compiler; + } +free_compiler: compiler_free(&compiler); node_free(ast); free(ast); @@ -74,7 +84,7 @@ free_parser: parser_free(&parser); lexer_free(&lexer); - return 0; + return status; } int module_load_source(module_t* self, char const* path) diff --git a/lib/parser.c b/lib/parser.c index 971c8a0..4975df2 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -146,9 +146,48 @@ node_t* parser_try_new_expr(parser_t* self) return CCM_TRY(parser_try_new_assert); } + 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_assign(parser_t* self) +{ + assert(self); + node_t* target = CCM_TRY(parser_try_new_index); + + if (!target && lexer_peek_kind(self->lexer, NODE_IDENT, 0)) { + target = lexer_try_new_next(self->lexer); + } + + if (target == NULL) { + return NULL; + } + + if (!lexer_peek_kind(self->lexer, NODE_ASSIGN, 0)) + { + node_free(target); free(target); + return NULL; + } + + lexer_consume_next(self->lexer, NODE_ASSIGN); + node_t* expr = CCM_TRY(parser_try_new_expr); + + if (!expr) + { + node_free(target); free(target); + return NULL; + } + + node_t* node = malloc(sizeof(node_t)); + node_init(node, NODE_ASSIGN, "", self->lexer->line); + node_push_new_child(node, target); + node_push_new_child(node, expr); + + return node; +} + node_t* parser_try_new_decl(parser_t* self) { assert(self); @@ -534,15 +573,12 @@ node_t* parser_try_new_literal(parser_t* self) { assert(self); + node_t* index = CCM_TRY(parser_try_new_index); + if (index) { return index; } + if (lexer_peek_kind(self->lexer, NODE_OSQUARE, 0)) { node_t* array = CCM_TRY(parser_try_new_array); - - if (lexer_peek_kind(self->lexer, NODE_OSQUARE, 0)) - { - return CCM_TRY_LL1(parser_try_new_index, array); - } - return array; } @@ -552,11 +588,6 @@ node_t* parser_try_new_literal(parser_t* self) if (tuple) { - if (lexer_peek_kind(self->lexer, NODE_OSQUARE, 0)) - { - return CCM_TRY_LL1(parser_try_new_index, tuple); - } - return tuple; } @@ -582,14 +613,6 @@ node_t* parser_try_new_literal(parser_t* self) return expr; } - if ((lexer_peek_kind(self->lexer, NODE_STR, 0) - || lexer_peek_kind(self->lexer, NODE_IDENT, 0)) - && lexer_peek_kind(self->lexer, NODE_OSQUARE, 1)) - { - node_t* target = CCM_TRY(parser_try_new_builtin); - return CCM_TRY_LL1(parser_try_new_index, target); - } - return CCM_TRY(parser_try_new_builtin); } @@ -599,6 +622,12 @@ 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); + return NULL; + } lexer_consume_next(self->lexer, NODE_OSQUARE); @@ -624,15 +653,50 @@ node_t* parser_try_new_array(parser_t* self) first = 0; } + if (!lexer_peek_kind(self->lexer, NODE_CSQUARE, 0)) + { + node_free(node); free(node); + return NULL; + } + lexer_consume_next(self->lexer, NODE_CSQUARE); return node; } -node_t* parser_try_new_index(parser_t* self, node_t* target) +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)) + { + target = lexer_try_new_next(self->lexer); + } + + if (!target) + { + target = CCM_TRY(parser_try_new_tuple); + } + + if (!target) + { + target = CCM_TRY(parser_try_new_array); + } + + if (target == NULL) + { + return NULL; + } + + if (!lexer_peek_kind(self->lexer, NODE_OSQUARE, 0)) + { + node_free(target); free(target); + return NULL; + } + lexer_consume_next(self->lexer, NODE_OSQUARE); node_t* node = malloc(sizeof(node_t)); @@ -646,6 +710,7 @@ node_t* parser_try_new_index(parser_t* self, node_t* target) if (!element) { node_free(node); free(node); + node_free(target); free(target); return NULL; } @@ -657,6 +722,13 @@ node_t* parser_try_new_index(parser_t* self, node_t* target) } } + if (!lexer_peek_kind(self->lexer, NODE_CSQUARE, 0)) + { + node_free(node); free(node); + node_free(target); free(target); + return NULL; + } + lexer_consume_next(self->lexer, NODE_CSQUARE); return node; @@ -668,13 +740,15 @@ node_t* parser_try_new_tuple(parser_t* self) node_t* node = malloc(sizeof(node_t)); node_init(node, NODE_TUPLE, "", self->lexer->line); - if (!lexer_consume_next(self->lexer, NODE_OPAR)) + if (!lexer_peek_kind(self->lexer, NODE_OPAR, 0)) { node_free(node); free(node); return NULL; } + lexer_consume_next(self->lexer, NODE_OPAR); + node_t* lhs = CCM_TRY(parser_try_new_expr); if (!lhs) @@ -705,6 +779,13 @@ node_t* parser_try_new_tuple(parser_t* self) contains_more_than_one_expr = 1; } + if (!lexer_peek_kind(self->lexer, NODE_CPAR, 0)) + { + node_free(node); + free(node); + return NULL; + } + lexer_consume_next(self->lexer, NODE_CPAR); if (!contains_more_than_one_expr) diff --git a/lib/parser.h b/lib/parser.h index 9fb50ba..ea13765 100644 --- a/lib/parser.h +++ b/lib/parser.h @@ -25,6 +25,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_assign(parser_t* self); node_t* parser_try_new_decl(parser_t* self); node_t* parser_try_new_assert(parser_t* self); node_t* parser_try_new_or(parser_t* self); @@ -39,7 +40,7 @@ node_t* parser_try_new_pow(parser_t* self); node_t* parser_try_new_in(parser_t* self); node_t* parser_try_new_literal(parser_t* self); node_t* parser_try_new_array(parser_t* self); -node_t* parser_try_new_index(parser_t* self, node_t* target); +node_t* parser_try_new_index(parser_t* self); node_t* parser_try_new_tuple(parser_t* self); node_t* parser_try_new_builtin(parser_t* self); diff --git a/tests/var.ccm b/tests/var.ccm index 9eb1265..722a939 100644 --- a/tests/var.ccm +++ b/tests/var.ccm @@ -17,3 +17,17 @@ var f = [2, 3] var g = 1 assert_eq (3, f[g]) + +# ASSIGN +# ====== +var h = 34 +h = 37 +assert_eq (37, h) + +var i = [2, 3, 4] +i[2] = 7 +assert_eq ([2, 3, 7], i) + +var j = [[1, 2], [3, 4]] +j[1, 0] = 99 +assert_eq ([[1, 2], [99, 4]], j)