From 8e9b6f956d034dda210ecbefba12ae078e9750ff Mon Sep 17 00:00:00 2001 From: bog Date: Tue, 2 Apr 2024 17:33:31 +0200 Subject: [PATCH] :sparkles: variables and constants. --- doc/grammar.bnf | 9 ++ features/vars.sk | 20 +++++ lib/CMakeLists.txt | 2 + lib/include/compiler.h | 15 ++-- lib/include/lexer.h | 3 + lib/include/module.h | 2 + lib/include/node.h | 4 +- lib/include/parser.h | 4 + lib/include/prog.h | 2 +- lib/include/state.h | 27 ++++-- lib/include/sym.h | 48 +++++++++++ lib/include/token.h | 10 ++- lib/src/compiler.c | 126 +++++++++++++++++++++------ lib/src/exec.c | 10 +++ lib/src/lexer.c | 81 +++++++++++++++++- lib/src/module.c | 4 +- lib/src/parser.c | 190 +++++++++++++++++++++++++++++++++++++++++ lib/src/state.c | 84 +++++++++++++++--- lib/src/sym.c | 122 ++++++++++++++++++++++++++ tests/lexer.h | 20 +++++ tests/parser.h | 30 +++++++ 21 files changed, 757 insertions(+), 56 deletions(-) create mode 100644 features/vars.sk create mode 100644 lib/include/sym.h create mode 100644 lib/src/sym.c diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 644be89..5e966d2 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -2,6 +2,14 @@ ROOT ::= EXPR* EXPR ::= | OR | ASSERT +| VAR_DECL +| CONST_DECL +| ASSIGN +| BLOCK +BLOCK ::= begin EXPR* end +ASSIGN ::= ident assign EXPR +VAR_DECL ::= var ident assign EXPR +CONST_DECL ::= const ident assign EXPR ASSERT ::= assert EXPR eq EXPR OR ::= AND (or AND)* AND ::= EQ (and EQ)* @@ -15,6 +23,7 @@ POW ::= LITERAL (pow LITERAL)? LITERAL ::= | BUILTIN | opar EXPR cpar +| ident BUILTIN ::= | int | bool diff --git a/features/vars.sk b/features/vars.sk new file mode 100644 index 0000000..007aa0b --- /dev/null +++ b/features/vars.sk @@ -0,0 +1,20 @@ +var a = 32 +assert a eq 32 + +a = 7 +2 +assert a eq 7 + +a = a + 1 +assert a eq 8 + +begin + assert a eq 8 + a = 9 + var a = "hop" + assert a eq "hop" + a = 27 + assert a eq 27 +end + +assert a eq 9 diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index cce0a2d..aff007d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -22,6 +22,8 @@ add_library(skopy-lib SHARED src/module.c src/errors.c + + src/sym.c ) file(GLOB_RECURSE diff --git a/lib/include/compiler.h b/lib/include/compiler.h index 7db4ae3..95da880 100644 --- a/lib/include/compiler.h +++ b/lib/include/compiler.h @@ -3,6 +3,7 @@ #include "commons.h" #include "prog.h" +#include "sym.h" struct compiler { @@ -13,11 +14,13 @@ void compiler_free(struct compiler* self); void compiler_compile(struct compiler* self, struct node* node, - struct prog* prog); + struct prog* prog, + struct sym* sym); void compiler_compile_children(struct compiler* self, struct node* node, - struct prog* prog); + struct prog* prog, + struct sym* sym); void compiler_compile_value(struct compiler* self, struct node* node, @@ -27,10 +30,12 @@ void compiler_compile_value(struct compiler* self, void compiler_compile_and(struct compiler* self, struct node* node, - struct prog* prog); + struct prog* prog, + struct sym* sym); void compiler_compile_or(struct compiler* self, - struct node* node, - struct prog* prog); + struct node* node, + struct prog* prog, + struct sym* sym); #endif diff --git a/lib/include/lexer.h b/lib/include/lexer.h index 03500ff..3371b9e 100644 --- a/lib/include/lexer.h +++ b/lib/include/lexer.h @@ -26,12 +26,15 @@ void lexer_skip_comments(struct lexer* self); bool lexer_is_sep(struct lexer* self, size_t index); bool lexer_next_is(struct lexer* self, TokenKind kind); +bool lexer_next_nth_is(struct lexer* self, TokenKind kind, int nth); void lexer_consume_next(struct lexer* self); struct token* lexer_try_new_next(struct lexer* self); struct token* lexer_try_scan_int(struct lexer* self); struct token* lexer_try_scan_float(struct lexer* self); struct token* lexer_try_scan_string(struct lexer* self); +struct token* lexer_try_scan_ident(struct lexer* self); +bool lexer_is_ident(struct lexer* self, size_t index); struct token* lexer_try_scan_text(struct lexer* self, char const* text, TokenKind kind); diff --git a/lib/include/module.h b/lib/include/module.h index 41eff89..2fd08fe 100644 --- a/lib/include/module.h +++ b/lib/include/module.h @@ -3,11 +3,13 @@ #include "commons.h" #include "prog.h" +#include "sym.h" struct module { struct str source; struct prog prog; + struct sym sym; }; void module_init(struct module* self); diff --git a/lib/include/node.h b/lib/include/node.h index 081aa75..6efe52f 100644 --- a/lib/include/node.h +++ b/lib/include/node.h @@ -12,7 +12,9 @@ G(NODE_USUB), G(NODE_ASSERT_EQ), \ G(NODE_BOOL), G(NODE_AND), G(NODE_OR), \ G(NODE_NOT), G(NODE_FLOAT), G(NODE_STRING), \ G(NODE_LT), G(NODE_LE), G(NODE_GT), G(NODE_GE), \ -G(NODE_EQUAL), G(NODE_NOT_EQUAL) +G(NODE_EQUAL), G(NODE_NOT_EQUAL), G(NODE_VAR_DECL), \ +G(NODE_CONST_DECL), G(NODE_IDENT), G(NODE_ASSIGN), \ +G(NODE_BLOCK) SK_ENUM_H(NodeKind, NODE_KIND); diff --git a/lib/include/parser.h b/lib/include/parser.h index 31614de..d12f5b8 100644 --- a/lib/include/parser.h +++ b/lib/include/parser.h @@ -19,6 +19,10 @@ struct node* parser_try(struct parser* self, struct node* parser_try_parse(struct parser* self); struct node* parser_try_root(struct parser* self); struct node* parser_try_expr(struct parser* self); +struct node* parser_try_block(struct parser* self); +struct node* parser_try_assign(struct parser* self); +struct node* parser_try_var_decl(struct parser* self); +struct node* parser_try_const_decl(struct parser* self); struct node* parser_try_assert(struct parser* self); struct node* parser_try_or(struct parser* self); struct node* parser_try_and(struct parser* self); diff --git a/lib/include/prog.h b/lib/include/prog.h index 7fb64f9..b2f720b 100644 --- a/lib/include/prog.h +++ b/lib/include/prog.h @@ -12,7 +12,7 @@ G(OP_DIV), G(OP_MOD), G(OP_POW), \ G(OP_USUB), G(OP_ASSERT_EQ), \ G(OP_NOT), G(OP_AND), G(OP_OR), \ G(OP_BR), G(OP_BRF), G(OP_LT), G(OP_GT), \ -G(OP_EQUAL) +G(OP_EQUAL), G(OP_LOCAL_STORE), G(OP_LOCAL_LOAD) SK_ENUM_H(Opcode, OPCODE); diff --git a/lib/include/state.h b/lib/include/state.h index 12ad993..15d0e6d 100644 --- a/lib/include/state.h +++ b/lib/include/state.h @@ -3,9 +3,17 @@ #include "commons.h" #include "value.h" + #define SK size_t +#define SK_NO_ID (-1) struct local +{ + int id; + size_t addr; +}; + +struct stack_value { size_t addr; struct value* value; @@ -13,6 +21,7 @@ struct local struct frame { + struct vec stack_values; struct vec locals; struct vec stack; }; @@ -23,11 +32,11 @@ struct state size_t addr; }; -void local_init(struct local* self, +void stack_value_init(struct stack_value* self, size_t addr, struct value* new_value); -void local_free(struct local* self); +void stack_value_free(struct stack_value* self); void frame_init(struct frame* self); void frame_free(struct frame* self); @@ -44,9 +53,9 @@ struct value* state_try_get_value(struct state* self, SK value); SK state_pop(struct state* self); -SK state_push(struct state* self, - TypeKind type, - union val val, +SK state_push(struct state* self, + TypeKind type, + union val val, int line); SK state_push_int(struct state* self, int integer, int line); @@ -54,6 +63,14 @@ SK state_push_bool(struct state* self, bool boolean, int line); SK state_push_float(struct state* self, double real, int line); SK state_push_string(struct state* self, char const* str, int line); +struct local* state_try_get_local(struct state* self, int id); + +SK state_local_store(struct state* self, + int id); + +void state_local_load(struct state* self, + int id); + TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs); TypeKind state_type(struct state* self, SK value); double state_as_real(struct state* self, SK lhs); diff --git a/lib/include/sym.h b/lib/include/sym.h new file mode 100644 index 0000000..ac94eae --- /dev/null +++ b/lib/include/sym.h @@ -0,0 +1,48 @@ +#ifndef SK_SYM_H +#define SK_SYM_H + +#include "commons.h" + +struct symbol +{ + int id; + char* name; + bool is_const; + struct env* env; +}; + +struct env +{ + struct vec symbols; + struct env* parent; +}; + +struct sym +{ + int id_counter; + struct env* env; +}; + +void env_init(struct env* self); +void env_free(struct env* self); +struct symbol* env_try_get(struct env* self, char const* name); + +void symbol_init(struct symbol* self, + int id, + char const* name, + struct env* env); + +void symbol_free(struct symbol* self); + +void sym_init(struct sym* self); +void sym_free(struct sym* self); + +int sym_decl_var(struct sym* self, char const* name); +int sym_decl_const(struct sym* self, char const* name); + +void sym_open_scope(struct sym* self); +void sym_close_scope(struct sym* self); + +struct symbol* sym_try_get(struct sym* self, char const* name); + +#endif diff --git a/lib/include/token.h b/lib/include/token.h index ee0d311..59d7f63 100644 --- a/lib/include/token.h +++ b/lib/include/token.h @@ -13,7 +13,9 @@ G(TOKEN_ASSERT), G(TOKEN_ASSERT_EQ), \ G(TOKEN_BOOL), G(TOKEN_AND), G(TOKEN_OR), \ G(TOKEN_NOT), G(TOKEN_FLOAT), G(TOKEN_STRING), \ G(TOKEN_LT), G(TOKEN_LE), G(TOKEN_GT), G(TOKEN_GE), \ -G(TOKEN_EQUAL), G(TOKEN_NOT_EQUAL) +G(TOKEN_EQUAL), G(TOKEN_NOT_EQUAL), G(TOKEN_VAR), \ +G(TOKEN_CONST), G(TOKEN_ASSIGN), G(TOKEN_IDENT), \ +G(TOKEN_BEGIN), G(TOKEN_END) SK_ENUM_H(TokenKind, TOKEN_KIND); @@ -24,9 +26,9 @@ struct token int line; }; -void token_init(struct token* self, - TokenKind kind, - char const* value, +void token_init(struct token* self, + TokenKind kind, + char const* value, int line); void token_free(struct token* self); diff --git a/lib/src/compiler.c b/lib/src/compiler.c index 7617d17..0231de4 100644 --- a/lib/src/compiler.c +++ b/lib/src/compiler.c @@ -13,7 +13,8 @@ void compiler_free(struct compiler* self) void compiler_compile(struct compiler* self, struct node* node, - struct prog* prog) + struct prog* prog, + struct sym* sym) { assert(self); assert(node); @@ -25,28 +26,97 @@ void compiler_compile(struct compiler* self, for (size_t i=0; ichildren.size; i++) { compiler_compile(self, node->children.data[i], - prog); + prog, sym); } } break; + case NODE_BLOCK: { + sym_open_scope(sym); + for (size_t i=0; ichildren.size; i++) + { + compiler_compile(self, node->children.data[i], + prog, sym); + } + sym_close_scope(sym); + } break; + case NODE_NOT: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_NOT, SK_NO_PARAM); } break; case NODE_AND: { - compiler_compile_and(self, node, prog); + compiler_compile_and(self, node, prog, sym); } break; case NODE_OR: { - compiler_compile_or(self, node, prog); + compiler_compile_or(self, node, prog, sym); } break; case NODE_ASSERT_EQ: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_ASSERT_EQ, SK_NO_PARAM); } break; + case NODE_VAR_DECL: { + struct node* ident = node->children.data[0]; + struct symbol const* s = sym_try_get(sym, ident->token->value); + + if (s && s->env == sym->env) + { + errors_push(node->token->line, "'%s' is already defined", + ident->token->value); + } + + struct node* expr = node->children.data[1]; + compiler_compile(self, expr, prog, sym); + int id = sym_decl_var(sym, ident->token->value); + prog_add_instr(prog, OP_LOCAL_STORE, id); + } break; + + case NODE_CONST_DECL: { + struct node* ident = node->children.data[0]; + struct symbol const* s = sym_try_get(sym, ident->token->value); + if (s && s->env == sym->env) + { + errors_push(node->token->line, "'%s' is already defined", + ident->token->value); + } + struct node* expr = node->children.data[1]; + compiler_compile(self, expr, prog, sym); + int id = sym_decl_const(sym, ident->token->value); + prog_add_instr(prog, OP_LOCAL_STORE, id); + } break; + + case NODE_ASSIGN: { + struct node* ident = node->children.data[0]; + struct node* expr = node->children.data[1]; + struct symbol* symbol = sym_try_get(sym, ident->token->value); + + if (!symbol) + { + errors_push(ident->token->line, "'%s' is not defined", + ident->token->value); + break; + } + + if (symbol->is_const) + { + errors_push(ident->token->line, "'%s' is not mutable", + ident->token->value); + break; + } + + compiler_compile(self, expr, prog, sym); + prog_add_instr(prog, OP_LOCAL_STORE, symbol->id); + } break; + + case NODE_IDENT: { + struct symbol* symbol = sym_try_get(sym, + node->token->value); + assert(symbol); + prog_add_instr(prog, OP_LOCAL_LOAD, symbol->id); + } break; case NODE_BOOL: { union val val; val.boolean = @@ -77,70 +147,70 @@ void compiler_compile(struct compiler* self, } break; case NODE_LT: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_LT, SK_NO_PARAM); } break; case NODE_LE: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_GT, SK_NO_PARAM); prog_add_instr(prog, OP_NOT, SK_NO_PARAM); } break; case NODE_GT: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_GT, SK_NO_PARAM); } break; case NODE_GE: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_LT, SK_NO_PARAM); prog_add_instr(prog, OP_NOT, SK_NO_PARAM); } break; case NODE_EQUAL: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_EQUAL, SK_NO_PARAM); } break; case NODE_NOT_EQUAL: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_EQUAL, SK_NO_PARAM); prog_add_instr(prog, OP_NOT, SK_NO_PARAM); } break; case NODE_ADD: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_ADD, SK_NO_PARAM); } break; case NODE_SUB: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_SUB, SK_NO_PARAM); } break; case NODE_MUL: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_MUL, SK_NO_PARAM); } break; case NODE_DIV: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_DIV, SK_NO_PARAM); } break; case NODE_MOD: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_MOD, SK_NO_PARAM); } break; case NODE_POW: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_POW, SK_NO_PARAM); } break; case NODE_USUB: { - compiler_compile_children(self, node, prog); + compiler_compile_children(self, node, prog, sym); prog_add_instr(prog, OP_USUB, SK_NO_PARAM); } break; @@ -154,7 +224,8 @@ void compiler_compile(struct compiler* self, void compiler_compile_children(struct compiler* self, struct node* node, - struct prog* prog) + struct prog* prog, + struct sym* sym) { assert(self); assert(node); @@ -163,7 +234,7 @@ void compiler_compile_children(struct compiler* self, for (size_t i=0; ichildren.size; i++) { struct node* child = node->children.data[i]; - compiler_compile(self, child, prog); + compiler_compile(self, child, prog, sym); } } @@ -184,11 +255,13 @@ void compiler_compile_value(struct compiler* self, void compiler_compile_and(struct compiler* self, struct node* node, - struct prog* prog) + struct prog* prog, + struct sym* sym) { assert(self); assert(node); assert(prog); + assert(sym); struct vec to_false; vec_init(&to_false); @@ -196,7 +269,7 @@ void compiler_compile_and(struct compiler* self, for (size_t i =0; ichildren.size; i++) { struct node* child = node->children.data[i]; - compiler_compile(self, child, prog); + compiler_compile(self, child, prog, sym); size_t brf = prog_add_instr(prog, OP_BRF, 0); // to false vec_push(&to_false, (void*) brf); } @@ -225,19 +298,20 @@ void compiler_compile_and(struct compiler* self, void compiler_compile_or(struct compiler* self, struct node* node, - struct prog* prog) + struct prog* prog, + struct sym* sym) { assert(self); assert(node); assert(prog); - + assert(sym); struct vec to_true; vec_init(&to_true); for (size_t i =0; ichildren.size; i++) { struct node* child = node->children.data[i]; - compiler_compile(self, child, prog); + compiler_compile(self, child, prog, sym); prog_add_instr(prog, OP_NOT, 0); size_t brf = prog_add_instr(prog, OP_BRF, 0); // to true vec_push(&to_true, (void*) brf); diff --git a/lib/src/exec.c b/lib/src/exec.c index 34dbe13..33adeec 100644 --- a/lib/src/exec.c +++ b/lib/src/exec.c @@ -27,6 +27,16 @@ void exec_execute(struct exec* self, switch (opcode) { + case OP_LOCAL_STORE: { + state_local_store(state, param); + self->pc++; + } break; + + case OP_LOCAL_LOAD: { + state_local_load(state, param); + self->pc++; + } break; + case OP_ASSERT_EQ: { SK rhs = state_pop(state); SK lhs = state_pop(state); diff --git a/lib/src/lexer.c b/lib/src/lexer.c index cc66efa..470553d 100644 --- a/lib/src/lexer.c +++ b/lib/src/lexer.c @@ -92,6 +92,34 @@ bool lexer_is_sep(struct lexer* self, size_t index) || c == '='; } +bool lexer_next_nth_is(struct lexer* self, TokenKind kind, int nth) +{ + assert(self); + + struct context ctx = self->context; + + bool res = false; + + for (int i=0; i<=nth; i++) + { + struct token* tok = lexer_try_new_next(self); + + if (!tok) + { + self->context = ctx; + return false; + } + + res = tok->kind == kind; + token_free(tok); + free(tok); + } + + self->context = ctx; + + return res; +} + bool lexer_next_is(struct lexer* self, TokenKind kind) { struct context ctx = self->context; @@ -100,6 +128,7 @@ bool lexer_next_is(struct lexer* self, TokenKind kind) if (!tok) { + self->context = ctx; return false; } @@ -108,7 +137,6 @@ bool lexer_next_is(struct lexer* self, TokenKind kind) free(tok); self->context = ctx; - return res; } @@ -164,6 +192,11 @@ struct token* lexer_try_new_next(struct lexer* self) SK_SCAN_TEXT(")", TOKEN_CPAR); SK_SCAN_TEXT(">", TOKEN_GT); SK_SCAN_TEXT("<", TOKEN_LT); + SK_SCAN_TEXT("=", TOKEN_ASSIGN); + SK_SCAN_KEYWORD("begin", TOKEN_BEGIN, NULL); + SK_SCAN_KEYWORD("end", TOKEN_END, NULL); + SK_SCAN_KEYWORD("var", TOKEN_VAR, NULL); + SK_SCAN_KEYWORD("const", TOKEN_CONST, NULL); SK_SCAN_KEYWORD("assert", TOKEN_ASSERT, NULL); SK_SCAN_KEYWORD("eq", TOKEN_ASSERT_EQ, NULL); SK_SCAN_KEYWORD("true", TOKEN_BOOL, "true"); @@ -173,6 +206,11 @@ struct token* lexer_try_new_next(struct lexer* self) SK_SCAN_KEYWORD("not", TOKEN_NOT, NULL); + if ( (tok=lexer_try_scan_ident(self)) ) + { + return tok; + } + if (self->context.cursor < self->len) { struct str str; @@ -352,6 +390,47 @@ struct token* lexer_try_scan_string(struct lexer* self) return tok; } +struct token* lexer_try_scan_ident(struct lexer* self) +{ + assert(self); + size_t cursor = self->context.cursor; + struct str value; + str_init(&value); + + while (cursor < self->len + && lexer_is_ident(self, cursor)) + { + str_push(&value, self->source[cursor]); + cursor++; + } + + struct token* tok = NULL; + + if (value.size > 0 && !isdigit(value.value[0])) + { + tok = malloc(sizeof(struct token)); + token_init(tok, TOKEN_IDENT, + value.value, self->context.line); + + self->context.cursor = cursor; + } + + str_free(&value); + return tok; +} + +bool lexer_is_ident(struct lexer* self, size_t index) +{ + assert(self); + if (index >= self->len) { return false; } + + char c = self->source[index]; + return isalnum(c) + || c == '_' + || c == '!' + || c == '?'; +} + struct token* lexer_try_scan_text(struct lexer* self, char const* text, TokenKind kind) diff --git a/lib/src/module.c b/lib/src/module.c index d9b34d7..9b39e5e 100644 --- a/lib/src/module.c +++ b/lib/src/module.c @@ -9,6 +9,7 @@ void module_init(struct module* self) assert(self); str_init(&self->source); prog_init(&self->prog); + sym_init(&self->sym); } void module_free(struct module* self) @@ -16,6 +17,7 @@ void module_free(struct module* self) assert(self); str_free(&self->source); prog_free(&self->prog); + sym_free(&self->sym); } void module_load_source(struct module* self, @@ -52,7 +54,7 @@ int module_compile(struct module* self) struct compiler compiler; compiler_init(&compiler); - compiler_compile(&compiler, root, &self->prog); + compiler_compile(&compiler, root, &self->prog, &self->sym); struct exec exec; exec_init(&exec); diff --git a/lib/src/parser.c b/lib/src/parser.c index 6a06c2b..447286f 100644 --- a/lib/src/parser.c +++ b/lib/src/parser.c @@ -94,9 +94,188 @@ struct node* parser_try_expr(struct parser* self) return SK_TRY(parser_try_assert); } + if (lexer_next_is(&self->lexer, TOKEN_CONST)) + { + return SK_TRY(parser_try_const_decl); + } + + if (lexer_next_is(&self->lexer, TOKEN_IDENT) + && lexer_next_nth_is(&self->lexer, TOKEN_ASSIGN, 1)) + { + return SK_TRY(parser_try_assign); + } + + if (lexer_next_is(&self->lexer, TOKEN_VAR)) + { + return SK_TRY(parser_try_var_decl); + } + + if (lexer_next_is(&self->lexer, TOKEN_BEGIN)) + { + return SK_TRY(parser_try_block); + } + return SK_TRY(parser_try_or); } +struct node* parser_try_block(struct parser* self) +{ + assert(self); + + if (!lexer_next_is(&self->lexer, TOKEN_BEGIN)) + { + return NULL; + } + + struct token* tok = lexer_try_new_next(&self->lexer); + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_BLOCK, tok); + + while (true) + { + struct node* child = SK_TRY(parser_try_expr); + + if (!child) + { + break; + } + + node_push_new_child(node, child); + } + + if (!lexer_next_is(&self->lexer, TOKEN_END)) + { + node_free(node); free(node); + return NULL; + } + + lexer_consume_next(&self->lexer); + return node; +} + +struct node* parser_try_assign(struct parser* self) +{ + assert(self); + + if (!lexer_next_is(&self->lexer, TOKEN_IDENT)) + { + return NULL; + } + + struct node* ident = malloc(sizeof(struct node)); + node_init(ident, NODE_IDENT, lexer_try_new_next(&self->lexer)); + + if (!lexer_next_is(&self->lexer, TOKEN_ASSIGN)) + { + node_free(ident); free(ident); + return NULL; + } + + struct token* tok = lexer_try_new_next(&self->lexer); + + struct node* expr = SK_TRY(parser_try_expr); + + if (!expr) + { + node_free(ident); free(ident); + return NULL; + } + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_ASSIGN, tok); + node_push_new_child(node, ident); + node_push_new_child(node, expr); + + return node; +} + +struct node* parser_try_var_decl(struct parser* self) +{ + assert(self); + + if (!lexer_next_is(&self->lexer, TOKEN_VAR)) + { + return NULL; + } + + lexer_consume_next(&self->lexer); + + if (!lexer_next_is(&self->lexer, TOKEN_IDENT)) + { + return NULL; + } + + struct node* ident = malloc(sizeof(struct node)); + node_init(ident, NODE_IDENT, lexer_try_new_next(&self->lexer)); + + if (!lexer_next_is(&self->lexer, TOKEN_ASSIGN)) + { + node_free(ident); free(ident); + return NULL; + } + + struct token* tok = lexer_try_new_next(&self->lexer); + + struct node* expr = SK_TRY(parser_try_expr); + + if (!expr) + { + node_free(ident); free(ident); + return NULL; + } + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_VAR_DECL, tok); + node_push_new_child(node, ident); + node_push_new_child(node, expr); + + return node; +} + +struct node* parser_try_const_decl(struct parser* self) +{ + assert(self); + + if (!lexer_next_is(&self->lexer, TOKEN_CONST)) + { + return NULL; + } + + lexer_consume_next(&self->lexer); + + if (!lexer_next_is(&self->lexer, TOKEN_IDENT)) + { + return NULL; + } + + struct node* ident = malloc(sizeof(struct node)); + node_init(ident, NODE_IDENT, lexer_try_new_next(&self->lexer)); + + if (!lexer_next_is(&self->lexer, TOKEN_ASSIGN)) + { + node_free(ident); free(ident); + return NULL; + } + + struct token* tok = lexer_try_new_next(&self->lexer); + + struct node* expr = SK_TRY(parser_try_expr); + + if (!expr) + { + node_free(ident); free(ident); + return NULL; + } + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_CONST_DECL, tok); + node_push_new_child(node, ident); + node_push_new_child(node, expr); + + return node; +} + struct node* parser_try_assert(struct parser* self) { assert(self); @@ -530,6 +709,17 @@ struct node* parser_try_literal(struct parser* self) return node; } + if (lexer_next_is(&self->lexer, TOKEN_IDENT)) + { + struct node* node = malloc(sizeof(struct node)); + + node_init(node, + NODE_IDENT, + lexer_try_new_next(&self->lexer)); + + return node; + } + return SK_TRY(parser_try_builtin); } diff --git a/lib/src/state.c b/lib/src/state.c index 5ec9e27..2cc43c9 100644 --- a/lib/src/state.c +++ b/lib/src/state.c @@ -1,8 +1,8 @@ #include "state.h" -void local_init(struct local* self, - size_t addr, - struct value* new_value) +void stack_value_init(struct stack_value* self, + size_t addr, + struct value* new_value) { assert(self); assert(new_value); @@ -11,7 +11,7 @@ void local_init(struct local* self, self->value = new_value; } -void local_free(struct local* self) +void stack_value_free(struct stack_value* self) { value_free(self->value); free(self->value); @@ -20,13 +20,16 @@ void local_free(struct local* self) void frame_init(struct frame* self) { + vec_init(&self->stack_values); vec_init(&self->locals); vec_init(&self->stack); } void frame_free(struct frame* self) { - vec_free_elements(&self->locals, (void*) local_free); + vec_free_elements(&self->stack_values, (void*) stack_value_free); + vec_free(&self->stack_values); + vec_free_elements(&self->locals, NULL); vec_free(&self->locals); vec_free(&self->stack); } @@ -83,13 +86,13 @@ struct value* state_try_get_value(struct state* self, SK value) assert(self); struct frame* frame = state_frame(self); - for (size_t i=0; ilocals.size; i++) + for (size_t i=0; istack_values.size; i++) { - struct local* local = frame->locals.data[i]; + struct stack_value* stack_value = frame->stack_values.data[i]; - if (local->addr == value) + if (stack_value->addr == value) { - return local->value; + return stack_value->value; } } @@ -118,10 +121,10 @@ SK state_push(struct state* self, value_init(value, type, val, line); struct frame* frame = state_frame(self); - struct local* local = malloc(sizeof(struct local)); - local_init(local, self->addr, value); + struct stack_value* stack_value = malloc(sizeof(struct stack_value)); + stack_value_init(stack_value, self->addr, value); - vec_push(&frame->locals, local); + vec_push(&frame->stack_values, stack_value); vec_push(&frame->stack, (void*) self->addr); self->addr++; @@ -162,6 +165,63 @@ SK state_push_string(struct state* self, char const* str, int line) return state_push(self, TYPE_STRING, val ,line); } +struct local* state_try_get_local(struct state* self, int id) +{ + struct frame* frame = state_frame(self); + + for (size_t i=0; ilocals.size; i++) + { + struct local* local = frame->locals.data[i]; + + if (local->id == id) + { + return local; + } + } + + return NULL; +} + +SK state_local_store(struct state* self, + int id) +{ + struct local* local = state_try_get_local(self, id); + + if (local) + { + local->addr = state_pop(self); + return local->addr; + } + + local = malloc(sizeof(struct local)); + local->id = id; + local->addr = state_top(self); + + struct frame* frame = state_frame(self); + vec_push(&frame->locals, local); + + return local->addr; +} + +void state_local_load(struct state* self, + int id) +{ + struct frame* frame = state_frame(self); + + for (size_t i=0; ilocals.size; i++) + { + struct local* local = frame->locals.data[i]; + + if (local->id == id) + { + vec_push(&frame->stack, (void*) local->addr); + return; + } + } + + assert(0); +} + TypeKind state_common_num_type(struct state* self, SK lhs, SK rhs) { assert(self); diff --git a/lib/src/sym.c b/lib/src/sym.c new file mode 100644 index 0000000..2e9ca8f --- /dev/null +++ b/lib/src/sym.c @@ -0,0 +1,122 @@ +#include "sym.h" + +void env_init(struct env* self) +{ + assert(self); + vec_init(&self->symbols); + self->parent = NULL; +} + +void env_free(struct env* self) +{ + assert(self); + vec_free_elements(&self->symbols, (void*) symbol_free); + vec_free(&self->symbols); +} + +struct symbol* env_try_get(struct env* self, char const* name) +{ + assert(self); + assert(name); + + for (size_t i=0; isymbols.size; i++) + { + struct symbol* symbol = self->symbols.data[i]; + + if (strcmp(symbol->name, name) == 0) + { + return symbol; + } + } + + if (self->parent) + { + return env_try_get(self->parent, name); + } + + return NULL; +} + +void symbol_init(struct symbol* self, + int id, + char const* name, + struct env* env) +{ + assert(self); + self->id = id; + self->name = strdup(name); + self->is_const = false; + self->env = env; +} + +void symbol_free(struct symbol* self) +{ + assert(self); + free(self->name); +} + +void sym_init(struct sym* self) +{ + assert(self); + self->id_counter = 1; + self->env = malloc(sizeof(struct env)); + env_init(self->env); +} + +void sym_free(struct sym* self) +{ + assert(self); + env_free(self->env); + free(self->env); + self->env = NULL; +} + +int sym_decl_var(struct sym* self, char const* name) +{ + assert(self); + assert(name); + struct symbol* symbol = malloc(sizeof(struct symbol)); + symbol_init(symbol, self->id_counter, name, self->env); + + vec_push(&self->env->symbols, symbol); + + self->id_counter++; + return self->id_counter - 1; +} + +int sym_decl_const(struct sym* self, char const* name) +{ + assert(self); + assert(name); + struct symbol* symbol = malloc(sizeof(struct symbol)); + symbol_init(symbol, self->id_counter, name, self->env); + symbol->is_const = true; + vec_push(&self->env->symbols, symbol); + + self->id_counter++; + return self->id_counter - 1; +} + +void sym_open_scope(struct sym* self) +{ + assert(self); + struct env* env = malloc(sizeof(struct env)); + env_init(env); + env->parent = self->env; + self->env = env; +} + +void sym_close_scope(struct sym* self) +{ + assert(self); + struct env* env = self->env; + self->env = env->parent; + + env_free(env); + free(env); +} + +struct symbol* sym_try_get(struct sym* self, char const* name) +{ + return env_try_get(self->env, name); +} diff --git a/tests/lexer.h b/tests/lexer.h index 4a6602b..8ec51f2 100644 --- a/tests/lexer.h +++ b/tests/lexer.h @@ -75,6 +75,16 @@ static void test_lexer_bool() ); } +static void test_lexer_decl() +{ + test_lexer(" var const = x ", 4, + "VAR", + "CONST", + "ASSIGN", + "IDENT[x]" + ); +} + static void test_lexer_float() { test_lexer(".4 7. 2.3 6.12", 4, @@ -109,6 +119,14 @@ static void test_lexer_cmp() ); } +static void test_lexer_block() +{ + test_lexer("begin end", 2, + "BEGIN", + "END" + ); +} + void register_lexer() { CU_pSuite suite = CU_add_suite("Lexer", 0, 0); @@ -118,6 +136,8 @@ void register_lexer() CU_add_test(suite, "Floats", test_lexer_float); CU_add_test(suite, "Strings", test_lexer_string); CU_add_test(suite, "Comparisons", test_lexer_cmp); + CU_add_test(suite, "Var Declarations", test_lexer_decl); + CU_add_test(suite, "Blocks", test_lexer_block); } #endif diff --git a/tests/parser.h b/tests/parser.h index 33a5484..f2ccbcb 100644 --- a/tests/parser.h +++ b/tests/parser.h @@ -87,6 +87,33 @@ static void test_parser_cmp() "5<>3"); } +static void test_parser_decl() +{ + test_parser("ROOT(IDENT[bim!])", + "bim!"); + + test_parser("ROOT(VAR_DECL(IDENT[x],INT[37]))", + "var x = 37"); + + test_parser("ROOT(CONST_DECL(IDENT[x],MUL(FLOAT[2.2],INT[3])))", + "const x = 2.2 * 3"); +} + +static void test_parser_assign() +{ + test_parser("ROOT(ASSIGN(IDENT[hello],BOOL[false]))", + "hello = false"); +} + +static void test_parser_block() +{ + test_parser("ROOT(BLOCK)", + "begin end"); + + test_parser("ROOT(BLOCK(INT[1],INT[2]))", + "begin 1 2 end"); +} + void register_parser() { CU_pSuite suite = CU_add_suite("Parser", 0, 0); @@ -95,6 +122,9 @@ void register_parser() CU_add_test(suite, "Booleans", test_parser_bool); CU_add_test(suite, "Strings", test_parser_string); CU_add_test(suite, "Comparisons", test_parser_cmp); + CU_add_test(suite, "Declarations", test_parser_decl); + CU_add_test(suite, "Assignments", test_parser_assign); + CU_add_test(suite, "Blocks", test_parser_block); } #endif