diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 2d01dbc..5c7cba0 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -5,7 +5,7 @@ EXPR ::= | DECL | ASSIGN ASSIGN ::= (ident|INDEX) assign EXPR -DECL ::= var ident assign EXPR +DECL ::= (var|const) ident assign EXPR ASSERT ::= (assert_eq|assert_ne) tuple OR ::= AND (or AND)* AND ::= EQNE (and EQNE)* diff --git a/lib/compiler.c b/lib/compiler.c index 57544fb..b80d145 100644 --- a/lib/compiler.c +++ b/lib/compiler.c @@ -44,12 +44,19 @@ void compiler_compile(compiler_t* self, ident->value ); + if (!entry) { err_push(&self->err, ident->line, "undefined array '%s'", ident->value); return; } + if (entry->is_const) { + err_push(&self->err, ident->line, + "cannot assign value to constant '%s'", + ident->value); + return; + } compiler_compile(self, expr, prog); size_t indexes_count = target->children.size - 1; @@ -66,8 +73,24 @@ void compiler_compile(compiler_t* self, } else { compiler_compile(self, expr, prog); int status = - sym_try_assign(sym, target->value, self->loc_counter); + sym_try_assign( + sym, + target->value, self->loc_counter + ); + sym_entry_t* entry = sym_try_get_value( + sym, + target->value + ); + + assert(entry); + + if (entry->is_const) { + err_push(&self->err, target->line, + "cannot assign value to constant '%s'", + target->value); + return; + } if (!status) { err_push(&self->err, target->line, @@ -83,13 +106,18 @@ void compiler_compile(compiler_t* self, } break; + case NODE_CONSTDECL: case NODE_VARDECL: { node_t const* ident = node->children.data[0]; node_t* expr = node->children.data[1]; compiler_compile(self, expr, prog); int status = - sym_declare(sym, ident->value, self->loc_counter); + sym_declare( + sym, ident->value, + self->loc_counter, + node->kind == NODE_CONSTDECL + ); assert(status); prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter); self->loc_counter++; diff --git a/lib/exec.c b/lib/exec.c index d617c24..d407025 100644 --- a/lib/exec.c +++ b/lib/exec.c @@ -71,7 +71,7 @@ void exec_instr(exec_t* self, } int line = 0; - + if (vec->size > 0) { line = ((value_t*) vec->data[0])->line; } @@ -116,7 +116,7 @@ void exec_instr(exec_t* self, int idx = ccm_from_num(ccm, ccm_idx); indexes[param - 1 - i] = idx; } - + for (int i=0; idata.array->data[indexes[i]]; @@ -124,7 +124,7 @@ void exec_instr(exec_t* self, CCM ccm_expr = ccm_pop(ccm); value_t* expr = ccm_to_value(ccm, ccm_expr); - target->data.array->data[indexes[param - 1]] + target->data.array->data[indexes[param - 1]] = expr; ccm_push(ccm, ccm_expr); self->pc++; diff --git a/lib/lexer.c b/lib/lexer.c index 641e661..fc871f3 100644 --- a/lib/lexer.c +++ b/lib/lexer.c @@ -172,6 +172,7 @@ node_t* lexer_try_new_next(lexer_t* self) } CCM_KEYWORD("var", NODE_VAR, 0); + CCM_KEYWORD("const", NODE_CONST, 0); CCM_KEYWORD("assert_eq", NODE_ASSERT_EQ, 0); CCM_KEYWORD("assert_ne", NODE_ASSERT_NE, 0); CCM_KEYWORD("true", NODE_BOOL, 1); diff --git a/lib/node.h b/lib/node.h index 136398f..47bd665 100644 --- a/lib/node.h +++ b/lib/node.h @@ -15,7 +15,7 @@ G(NODE_OSQUARE), G(NODE_CSQUARE), G(NODE_INDEX), \ 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_VARDECL), G(NODE_CONST), G(NODE_CONSTDECL) CCM_ENUM_H(NodeKind, NODE_KIND); diff --git a/lib/parser.c b/lib/parser.c index 4975df2..833a833 100644 --- a/lib/parser.c +++ b/lib/parser.c @@ -135,7 +135,8 @@ node_t* parser_try_new_expr(parser_t* self) { assert(self); - if (lexer_peek_kind(self->lexer, NODE_VAR, 0)) + if (lexer_peek_kind(self->lexer, NODE_VAR, 0) + || lexer_peek_kind(self->lexer, NODE_CONST, 0)) { return CCM_TRY(parser_try_new_decl); } @@ -191,8 +192,15 @@ node_t* parser_try_new_assign(parser_t* self) node_t* parser_try_new_decl(parser_t* self) { assert(self); - if (!lexer_consume_next(self->lexer, NODE_VAR)) - { + + int is_const = 0; + + if (lexer_peek_kind(self->lexer, NODE_VAR, 0)) { + lexer_consume_next(self->lexer, NODE_VAR); + } else if (lexer_peek_kind(self->lexer, NODE_CONST, 0)) { + lexer_consume_next(self->lexer, NODE_CONST); + is_const = 1; + } else { return NULL; } @@ -217,7 +225,8 @@ node_t* parser_try_new_decl(parser_t* self) } node_t* node = malloc(sizeof(node_t)); - node_init(node, NODE_VARDECL, "", self->lexer->line); + node_init(node, is_const ? NODE_CONSTDECL : NODE_VARDECL, + "", self->lexer->line); node_push_new_child(node, ident); node_push_new_child(node, expr); diff --git a/lib/sym.c b/lib/sym.c index 6958007..3241ee0 100644 --- a/lib/sym.c +++ b/lib/sym.c @@ -64,8 +64,9 @@ void sym_close_scope(sym_t* self) int sym_declare(sym_t* self, - char const* name, - int addr) + char const* name, + int addr, + int is_const) { assert(self); assert(self->env); @@ -79,7 +80,7 @@ int sym_declare(sym_t* self, sym_entry_t* entry = malloc(sizeof(sym_entry_t)); entry->name = strdup(name); entry->local_addr = addr; - + entry->is_const = is_const; vec_push(&self->env->entries, entry); return 1; } diff --git a/lib/sym.h b/lib/sym.h index 69b793b..3695226 100644 --- a/lib/sym.h +++ b/lib/sym.h @@ -8,6 +8,7 @@ typedef struct { char* name; int local_addr; + int is_const; } sym_entry_t; typedef struct env { @@ -27,15 +28,16 @@ void sym_open_scope(sym_t* self); void sym_close_scope(sym_t* self); int sym_declare(sym_t* self, - char const* name, - int addr); + char const* name, + int addr, + int is_const); int sym_try_assign(sym_t* self, char const* name, int addr); sym_entry_t* sym_try_get_value(sym_t* self, char const* name); -sym_entry_t* sym_try_get_env_value(sym_t* self, +sym_entry_t* sym_try_get_env_value(sym_t* self, env_t* env, char const* name);