From 75987d97806cbdfa52877bb7d53a69445aa4301d Mon Sep 17 00:00:00 2001 From: bog Date: Mon, 12 Feb 2024 20:21:05 +0100 Subject: [PATCH] :sparkles: var and const declaration, assignment and blocks. --- bc/src/compiler.c | 105 +++++++++++++++++--- bc/src/compiler.h | 6 +- bc/src/opcodes.h | 10 +- bc/src/program.c | 17 +++- doc/gux.bnf | 21 +++- guxi/src/main.c | 22 ++++- lang/CMakeLists.txt | 2 + lang/src/lexer.c | 105 ++++++++++++++++---- lang/src/lexer.h | 5 + lang/src/node.c | 75 ++++++++++++++ lang/src/node.h | 13 ++- lang/src/parser.c | 182 ++++++++++++++++++++++++++++++++-- lang/src/parser.h | 8 ++ lang/src/syms.c | 191 ++++++++++++++++++++++++++++++++++++ lang/src/syms.h | 49 ++++++++++ lang/src/type_checker.c | 199 +++++++++++++++++++++++++++++++++++++- lang/src/type_checker.h | 8 +- lang/src/type_resolver.c | 43 +++++++- lang/src/type_resolver.h | 4 +- lang/tests/lexer.c | 20 +++- lang/tests/parser.c | 24 +++++ lang/tests/syms.c | 20 ++++ lang/tests/type_checker.c | 22 ++++- lib/src/commons.h | 1 + tests/run.sh | 2 +- tests/vars_and_consts.gux | 47 +++++++++ vm/src/vm.c | 60 ++++++++++++ vm/src/vm.h | 9 ++ 28 files changed, 1204 insertions(+), 66 deletions(-) create mode 100644 lang/src/syms.c create mode 100644 lang/src/syms.h create mode 100644 lang/tests/syms.c create mode 100644 tests/vars_and_consts.gux diff --git a/bc/src/compiler.c b/bc/src/compiler.c index 4b7bd8c..e846b81 100644 --- a/bc/src/compiler.c +++ b/bc/src/compiler.c @@ -2,12 +2,15 @@ #include "commons.h" #include "node.h" #include "opcodes.h" +#include "syms.h" #include "value.h" #include "vec.h" -void compiler_init(struct compiler* self) +void compiler_init(struct compiler* self, struct syms* syms) { assert(self); + self->syms = syms; + memset(self->error_msg, 0, GUX_STR_SIZE); } void compiler_free(struct compiler* self) @@ -25,6 +28,56 @@ int compiler_compile(struct compiler* self, switch (node->type) { + case NODE_ASSIGN: { + struct node* ident = node->children.data[0]; + struct node* expr = node->children.data[1]; + struct syms_entry* entry = syms_try_get(self->syms, ident->value, + node); + assert(entry); + + if (compiler_compile(self, expr, program) != 0) + { + return 1; + } + + program_push_instr(program, OP_STORE, entry->addr); + } break; + + case NODE_IDENT: { + struct syms_entry* entry = syms_try_get(self->syms, + node->value, + node); + + if (!entry) + { + snprintf(self->error_msg, GUX_STR_SIZE, + "%s is not defined", node->value); + self->error_line = node->line; + return 1; + } + + program_push_instr(program, OP_LOAD, entry->addr); + } break; + + case NODE_CONSTDECL: + case NODE_VARDECL: { + int err = compiler_compile(self, node->children.size == 1 + ? node->children.data[0] + : node->children.data[1], + program); + + if (err != 0) + { + return 1; + } + + struct syms_entry* entry = syms_try_get(self->syms, + node->value, + node); + assert(entry); + + program_push_instr(program, OP_STORE, entry->addr); + } break; case NODE_BOOL: { struct value* val = malloc(sizeof(struct value)); value_init_bool(val, @@ -56,7 +109,11 @@ int compiler_compile(struct compiler* self, } break; case NODE_ASSERT: { - compiler_compile(self, node->children.data[0], program); + if (compiler_compile(self, node->children.data[0], program) != 0) + { + return 1; + } + size_t brt = program_push_instr(program, OP_BRT, NO_PARAM); program_push_instr(program, OP_PUSH, GUX_RET_ASSERT); size_t halt = program_push_instr(program, OP_HALT, node->line); @@ -77,20 +134,34 @@ int compiler_compile(struct compiler* self, } break; case NODE_EQ: { - compiler_compile(self, node->children.data[0], program); - compiler_compile(self, node->children.data[1], program); + int err = compiler_compile(self, node->children.data[0], program); + int err2 = compiler_compile(self, node->children.data[1], program); + if (err != 0 || err2 != 0) + { + return 1; + } program_push_instr(program, OP_EQ, NO_PARAM); } break; case NODE_NE: { - compiler_compile(self, node->children.data[0], program); - compiler_compile(self, node->children.data[1], program); + int err = compiler_compile(self, node->children.data[0], program); + int err2 = compiler_compile(self, node->children.data[1], program); + + if (err != 0 || err2 != 0) + { + return 1; + } + program_push_instr(program, OP_EQ, NO_PARAM); program_push_instr(program, OP_NOT, NO_PARAM); } break; case NODE_NOT: { - compiler_compile(self, node->children.data[0], program); + if (compiler_compile(self, node->children.data[0], program) != 0) + { + return 1; + } + program_push_instr(program, OP_NOT, NO_PARAM); } break; @@ -100,7 +171,10 @@ int compiler_compile(struct compiler* self, for (size_t i=0; ichildren.size; i++) { - compiler_compile(self, node->children.data[i], program); + if (compiler_compile(self, node->children.data[i], program) != 0) + { + return 1; + } size_t* addr = malloc(sizeof(size_t)); *addr = program_push_instr(program, OP_BRF, NO_PARAM); // to pivot @@ -149,7 +223,10 @@ int compiler_compile(struct compiler* self, for (size_t i=0; ichildren.size; i++) { - compiler_compile(self, node->children.data[i], program); + if (compiler_compile(self, node->children.data[i], program) != 0) + { + return 1; + } size_t* addr = malloc(sizeof(size_t)); *addr = program_push_instr(program, OP_BRT, NO_PARAM); // to pivot @@ -206,7 +283,10 @@ int compiler_compile(struct compiler* self, for (size_t i=0; ichildren.size; i++) { - compiler_compile(self, node->children.data[i], program); + if (compiler_compile(self, node->children.data[i], program) != 0) + { + return 1; + } } switch (node->type) @@ -229,7 +309,10 @@ int compiler_compile(struct compiler* self, default: { for (size_t i=0; ichildren.size; i++) { - compiler_compile(self, node->children.data[i], program); + if (compiler_compile(self, node->children.data[i], program) != 0) + { + return 1; + } } } break; diff --git a/bc/src/compiler.h b/bc/src/compiler.h index 0dc531b..a530d38 100644 --- a/bc/src/compiler.h +++ b/bc/src/compiler.h @@ -4,13 +4,15 @@ #include #include #include "program.h" +#include "syms.h" struct compiler { - char* error_msg; + char error_msg[GUX_STR_SIZE]; + struct syms* syms; int error_line; }; -void compiler_init(struct compiler* self); +void compiler_init(struct compiler* self, struct syms* syms); void compiler_free(struct compiler* self); int compiler_compile(struct compiler* self, diff --git a/bc/src/opcodes.h b/bc/src/opcodes.h index fb64900..8b6d3b5 100644 --- a/bc/src/opcodes.h +++ b/bc/src/opcodes.h @@ -1,11 +1,11 @@ #ifndef OPCODES_H #define OPCODES_H -#define OPCODES(G) \ - G(OP_PUSH), G(OP_POP), G(OP_BRF), G(OP_BR), G(OP_HALT), \ - G(OP_BRT), G(OP_NOP), G(OP_NOT), G(OP_EQ), \ - G(OP_ADD), G(OP_SUB), G(OP_MUL), G(OP_DIV), G(OP_MOD), G(OP_POW), \ - G(OP_LT), G(OP_LE), G(OP_GT),G(OP_GE), +#define OPCODES(G) \ + G(OP_PUSH), G(OP_POP), G(OP_BRF), G(OP_BR), G(OP_HALT), \ + G(OP_BRT), G(OP_NOP), G(OP_NOT), G(OP_EQ), \ + G(OP_ADD), G(OP_SUB), G(OP_MUL), G(OP_DIV), G(OP_MOD), G(OP_POW), \ + G(OP_LT), G(OP_LE), G(OP_GT),G(OP_GE), G(OP_LOAD), G(OP_STORE) #include diff --git a/bc/src/program.c b/bc/src/program.c index f60f783..f751e50 100644 --- a/bc/src/program.c +++ b/bc/src/program.c @@ -67,10 +67,19 @@ size_t program_str(struct program* self, char* buffer, size_t size) struct instruction* instr = (struct instruction*) self->instructions.data[i]; - sz += snprintf(buffer + sz, size - sz, "\t%ld: %s %d\n", - i, - OpcodesStr[instr->opcode] + strlen("OP_"), - instr->param); + if (instr->param != NO_PARAM) + { + sz += snprintf(buffer + sz, size - sz, "\t%ld: %s %d\n", + i, + OpcodesStr[instr->opcode] + strlen("OP_"), + instr->param); + } + else + { + sz += snprintf(buffer + sz, size - sz, "\t%ld: %s\n", + i, + OpcodesStr[instr->opcode] + strlen("OP_")); + } } return sz; diff --git a/doc/gux.bnf b/doc/gux.bnf index 1ceca80..9bcc89a 100644 --- a/doc/gux.bnf +++ b/doc/gux.bnf @@ -1,11 +1,24 @@ -ROOT ::= EXPR* +ROOT ::= INSTR* INSTR ::= -| EXPR semicolon +| LEXPR semicolon +| BEXPR -EXPR ::= +EXPR ::= LEXPR | BEXPR + +LEXPR ::= | OR | ASSERT EXPR +| VARDECL +| CONSTDECL +| ASSIGN + +BEXPR ::= BLOCK + +BLOCK ::= obrace INSTR* cbrace +VARDECL ::= var ident colon type? assign EXPR +CONSTDECL ::= ident colon type? assign EXPR +ASSIGN ::= ident assign EXPR OR ::= AND (or AND)* AND ::= EQNE (and EQNE)* @@ -16,5 +29,5 @@ FACTOR ::= POW ((mul|div|mod) POW)* POW ::= NOT (pow NOT)? NOT ::= not* LITERAL -LITERAL ::= BUILTIN | opar EXPR cpar +LITERAL ::= ident | BUILTIN | opar EXPR cpar BUILTIN ::= bool | int | float | string diff --git a/guxi/src/main.c b/guxi/src/main.c index 06ccb8c..1589ce8 100644 --- a/guxi/src/main.c +++ b/guxi/src/main.c @@ -5,6 +5,7 @@ #include #include #include +#include char* load_new_source(char const* path) { @@ -49,6 +50,7 @@ int main(int argc, char** argv) static int show_ast = 0; static int show_bytecodes = 0; static int show_stack = 0; + static int show_syms = 0; int c; @@ -59,6 +61,7 @@ int main(int argc, char** argv) {"ast", no_argument, &show_ast, 1}, {"bytecodes", no_argument, &show_bytecodes, 1}, {"stack", no_argument, &show_stack, 1}, + {"symbols", no_argument, &show_syms, 1}, {"help", no_argument, 0, 'h'} }; @@ -156,8 +159,11 @@ int main(int argc, char** argv) printf("%s\n", msg); } + struct syms syms; + syms_init(&syms); + struct type_checker checker; - type_checker_init(&checker); + type_checker_init(&checker, &syms); if (type_checker_check(&checker, ast) != 0) { @@ -166,6 +172,7 @@ int main(int argc, char** argv) checker.error_line, checker.error_msg); + syms_free(&syms); type_checker_free(&checker); if (ast) @@ -193,7 +200,7 @@ int main(int argc, char** argv) program_init(&program); struct compiler compiler; - compiler_init(&compiler); + compiler_init(&compiler, &syms); if (compiler_compile(&compiler, ast, &program) != 0) { @@ -204,6 +211,7 @@ int main(int argc, char** argv) compiler_free(&compiler); program_free(&program); + syms_free(&syms); type_checker_free(&checker); if (ast) @@ -234,6 +242,13 @@ int main(int argc, char** argv) printf("%s\n", buffer); } + if (show_syms) + { + char buffer[GUX_STR_SIZE]; + syms_str(&syms, buffer, GUX_STR_SIZE); + printf("%s\n", buffer); + } + struct vm vm; vm_init(&vm); @@ -246,9 +261,11 @@ int main(int argc, char** argv) vm.error_line, vm.error_msg); + vm_free(&vm); compiler_free(&compiler); program_free(&program); + syms_free(&syms); type_checker_free(&checker); if (ast) @@ -284,6 +301,7 @@ int main(int argc, char** argv) vm_free(&vm); compiler_free(&compiler); program_free(&program); + syms_free(&syms); type_checker_free(&checker); if (ast) diff --git a/lang/CMakeLists.txt b/lang/CMakeLists.txt index 6c70ae6..fe5eb50 100644 --- a/lang/CMakeLists.txt +++ b/lang/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(gux-lang OBJECT src/value.c src/type_resolver.c src/type_checker.c + src/syms.c ) set_property(TARGET gux-lang PROPERTY C_STANDARD 99) @@ -41,6 +42,7 @@ add_executable(gux-lang-tests tests/type.c tests/value.c tests/type_checker.c + tests/syms.c ) set_property(TARGET gux-lang-tests PROPERTY C_STANDARD 99) diff --git a/lang/src/lexer.c b/lang/src/lexer.c index c902019..5e81778 100644 --- a/lang/src/lexer.c +++ b/lang/src/lexer.c @@ -12,27 +12,39 @@ void lexer_init(struct lexer* self, char const* source) vec_init(&self->toks, 1); - lexer_add_tok(self, "<", NODE_LT, 0); - lexer_add_tok(self, "<=", NODE_LE, 0); - lexer_add_tok(self, ">", NODE_GT, 0); - lexer_add_tok(self, ">=", NODE_GE, 0); + lexer_add_tok(self, "var", NODE_VAR, "", 1); - lexer_add_tok(self, "+", NODE_ADD, 0); - lexer_add_tok(self, "-", NODE_SUB, 0); - lexer_add_tok(self, "*", NODE_MUL, 0); - lexer_add_tok(self, "/", NODE_DIV, 0); - lexer_add_tok(self, "%", NODE_MOD, 0); - lexer_add_tok(self, "**", NODE_POW, 0); + lexer_add_tok(self, "int", NODE_TYPE, "int", 1); + lexer_add_tok(self, "float", NODE_TYPE, "float", 1); + lexer_add_tok(self, "bool", NODE_TYPE, "bool", 1); + lexer_add_tok(self, "string", NODE_TYPE, "string", 1); - lexer_add_tok(self, "==", NODE_EQ, 0); - lexer_add_tok(self, "!=", NODE_NE, 0); - lexer_add_tok(self, "&&", NODE_AND, 0); + lexer_add_tok(self, "{", NODE_OBRACE, "", 0); + lexer_add_tok(self, "}", NODE_CBRACE, "", 0); + lexer_add_tok(self, ":", NODE_COLON, "", 0); + lexer_add_tok(self, "=", NODE_ASSIGN, "", 0); - lexer_add_tok(self, "||", NODE_OR, 0); - lexer_add_tok(self, "!", NODE_NOT, 0); - lexer_add_tok(self, "(", NODE_OPAR, 0); - lexer_add_tok(self, ")", NODE_CPAR, 0); - lexer_add_tok(self, ";", NODE_SEMICOLON, 0); + lexer_add_tok(self, "<", NODE_LT, "", 0); + lexer_add_tok(self, "<=", NODE_LE, "", 0); + lexer_add_tok(self, ">", NODE_GT, "", 0); + lexer_add_tok(self, ">=", NODE_GE, "", 0); + + lexer_add_tok(self, "+", NODE_ADD, "", 0); + lexer_add_tok(self, "-", NODE_SUB, "", 0); + lexer_add_tok(self, "*", NODE_MUL, "", 0); + lexer_add_tok(self, "/", NODE_DIV, "", 0); + lexer_add_tok(self, "%", NODE_MOD, "", 0); + lexer_add_tok(self, "**", NODE_POW, "", 0); + + lexer_add_tok(self, "==", NODE_EQ, "", 0); + lexer_add_tok(self, "!=", NODE_NE, "", 0); + lexer_add_tok(self, "&&", NODE_AND, "", 0); + + lexer_add_tok(self, "||", NODE_OR, "", 0); + lexer_add_tok(self, "!", NODE_NOT, "", 0); + lexer_add_tok(self, "(", NODE_OPAR, "", 0); + lexer_add_tok(self, ")", NODE_CPAR, "", 0); + lexer_add_tok(self, ";", NODE_SEMICOLON, "", 0); } void lexer_free(struct lexer* self) @@ -111,12 +123,13 @@ struct node* lexer_next_new(struct lexer* self) { struct tok* tok = self->toks.data[i]; - if (lexer_scan_text(self, tok->sym, &info)) + if ((tok->is_keyword && lexer_scan_keyword(self, tok->sym, &info)) + || (!tok->is_keyword && lexer_scan_text(self, tok->sym, &info))) { if (best == NULL || info.position > pos) { struct node* node = malloc(sizeof(struct node)); - node_init(node, tok->type, "", self->line); + node_init(node, tok->type, tok->value, self->line); if (best) { @@ -161,6 +174,14 @@ struct node* lexer_next_new(struct lexer* self) return node; } + if (lexer_scan_ident(self, &info)) + { + struct node* node = malloc(sizeof(struct node)); + node_init(node, info.type, info.value, self->line); + self->cursor = info.position; + return node; + } + return NULL; } @@ -411,16 +432,60 @@ int lexer_scan_string(struct lexer* self, return 0; } +int lexer_scan_ident(struct lexer* self, + struct token_info* info) +{ + assert(self); + assert(info); + + char value[GUX_STR_SIZE]; + size_t size = 0; + size_t cursor = self->cursor; + + while (cursor < strlen(self->source)) + { + char c = self->source[cursor]; + + if (isalpha(c) + || c == '_' + || c == '!' + || c == '?' + || (size > 0 && isdigit(c))) + { + value[size] = c; + size++; + cursor++; + } + else + { + break; + } + } + + if (size > 0) + { + info->position = cursor; + memcpy(info->value, value, size); + info->value[size] = '\0'; + info->type = NODE_IDENT; + return 1; + } + + return 0; +} + void lexer_add_tok(struct lexer* self, char* sym, enum NodeType type, + char* value, int is_keyword) { (void) self; struct tok* tok = malloc(sizeof(struct tok)); tok->sym = sym; tok->type = type; + memcpy(tok->value, value, GUX_STR_SIZE); tok->is_keyword = is_keyword; vec_push(&self->toks, tok); diff --git a/lang/src/lexer.h b/lang/src/lexer.h index d8400c2..b0b1c9d 100644 --- a/lang/src/lexer.h +++ b/lang/src/lexer.h @@ -9,6 +9,7 @@ struct tok { char* sym; enum NodeType type; int is_keyword; + char value[GUX_STR_SIZE]; }; struct lexer { @@ -52,9 +53,13 @@ int lexer_scan_float(struct lexer* self, int lexer_scan_string(struct lexer* self, struct token_info* info); +int lexer_scan_ident(struct lexer* self, + struct token_info* info); + void lexer_add_tok(struct lexer* self, char* sym, enum NodeType type, + char* value, int is_keyword); #endif diff --git a/lang/src/node.c b/lang/src/node.c index 5c14946..fdb3899 100644 --- a/lang/src/node.c +++ b/lang/src/node.c @@ -11,6 +11,7 @@ void node_init(struct node* self, enum NodeType type, self->value = strdup(value); vec_init(&self->children, 1); self->line = line; + self->parent = NULL; } void node_free(struct node* self) @@ -43,6 +44,7 @@ struct node* node_add_child(struct node* self, struct node* child) { assert(self); vec_push(&self->children, child); + child->parent = self; return child; } @@ -81,3 +83,76 @@ size_t node_str(struct node* self, char* buffer, size_t size) return sz; } + +int node_depth(struct node* self) +{ + assert(self); + struct node* itr = self; + int depth = 0; + + while (itr != NULL) + { + if (itr->type == NODE_BLOCK) + { + depth++; + } + + itr = itr->parent; + } + + return depth; +} + +struct node* node_try_find_parent(struct node* self, enum NodeType type) +{ + assert(self); + + struct node* p = self; + + while (p != NULL && p->type != type) + { + p = p->parent; + } + + return p; +} + +size_t node_parent_index(struct node* self) +{ + assert(self); + + struct node* parent = self->parent; + + if (parent == NULL) + { + return 0; + } + + for (size_t i=0; ichildren.size; i++) + { + if (parent->children.data[i] == self) + { + return i; + } + } + + return 0; +} + +size_t node_block_index(struct node* self) +{ + assert(self); + struct node* block = node_try_find_parent(self, NODE_BLOCK); + + if (block == NULL) + { + return 0; + } + + if (self->parent == block) + { + return node_parent_index(self); + } + + return node_block_index(self->parent); +} diff --git a/lang/src/node.h b/lang/src/node.h index 4df1a63..86ba439 100644 --- a/lang/src/node.h +++ b/lang/src/node.h @@ -11,14 +11,17 @@ G(NODE_CPAR), G(NODE_AND), G(NODE_OR), G(NODE_NOT), \ G(NODE_EQ), G(NODE_NE), G(NODE_INT), G(NODE_FLOAT), \ G(NODE_STRING), G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), G(NODE_DIV), \ - G(NODE_MOD), G(NODE_POW), G(NODE_LT), G(NODE_LE), G(NODE_GT), \ - G(NODE_GE) + G(NODE_MOD), G(NODE_POW), G(NODE_LT), G(NODE_LE), G(NODE_GT), \ + G(NODE_GE), G(NODE_COLON), G(NODE_ASSIGN), G(NODE_IDENT), \ + G(NODE_TYPE), G(NODE_VARDECL), G(NODE_CONSTDECL), G(NODE_VAR), \ + G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_BLOCK) GUX_ENUM_H(NodeType, NODE_TYPE); struct node { enum NodeType type; char* value; + struct node* parent; struct vec children; int line; }; @@ -34,4 +37,10 @@ struct node* node_add_child(struct node* self, struct node* child); size_t node_str(struct node* self, char* buffer, size_t size); +int node_depth(struct node* self); +struct node* node_try_find_parent(struct node* self, enum NodeType type); +size_t node_parent_index(struct node* self); + +size_t node_block_index(struct node* self); + #endif diff --git a/lang/src/parser.c b/lang/src/parser.c index 1ec7fa4..6bf024b 100644 --- a/lang/src/parser.c +++ b/lang/src/parser.c @@ -127,6 +127,14 @@ int parser_try_consume(struct parser* self, enum NodeType type) return 0; } +int parser_start_bexpr(struct parser* self) +{ + assert(self); + struct node* tok = self->tokens.data[self->cursor]; + + return tok->type == NODE_OBRACE; +} + struct node* parser_try_new_root(struct parser* self, char const* source) { assert(self); @@ -163,22 +171,42 @@ struct node* parser_try_new_root(struct parser* self, char const* source) struct node* parser_try_new_instr(struct parser* self) { assert(self); - struct node* node = parser_try_new_expr(self); - if (parser_ensure(self, NODE_SEMICOLON) != 0) + if (parser_start_bexpr(self)) { - node_free(node); - free(node); - return NULL; + return parser_try_new_bexpr(self); } + else + { + struct node* node = parser_try_new_lexpr(self); - return node; + if (parser_ensure(self, NODE_SEMICOLON) != 0) + { + node_free(node); + free(node); + return NULL; + } + + return node; + } } struct node* parser_try_new_expr(struct parser* self) { assert(self); + if (parser_start_bexpr(self)) + { + return parser_try_new_bexpr(self); + } + + return parser_try_new_lexpr(self); +} + +struct node* parser_try_new_lexpr(struct parser* self) +{ + assert(self); + if (parser_type_is(self, NODE_ASSERT, 0)) { struct node* node = malloc(sizeof(struct node)); @@ -198,6 +226,20 @@ struct node* parser_try_new_expr(struct parser* self) return node; } + else if (parser_type_is(self, NODE_VAR, 0)) + { + return parser_try_new_vardecl(self); + } + else if (parser_type_is(self, NODE_IDENT, 0) + && parser_type_is(self, NODE_COLON, 1)) + { + return parser_try_new_constdecl(self); + } + else if (parser_type_is(self, NODE_IDENT, 0) + && parser_type_is(self, NODE_ASSIGN, 1)) + { + return parser_try_new_assign(self); + } struct node* node = parser_try_new_or(self); @@ -209,6 +251,129 @@ struct node* parser_try_new_expr(struct parser* self) return node; } +struct node* parser_try_new_bexpr(struct parser* self) +{ + assert(self); + return parser_try_new_block(self); +} + +struct node* parser_try_new_block(struct parser* self) +{ + + parser_try_consume(self, NODE_OBRACE); + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_BLOCK, "", parser_current_line(self)); + + while (!parser_type_is(self, NODE_CBRACE, 0)) + { + node_add_child(node, parser_try_new_instr(self)); + } + + if (parser_try_consume(self, NODE_CBRACE) != 0) + { + node_free(node); + free(node); + + return NULL; + } + + return node; +} + +struct node* parser_try_new_assign(struct parser* self) +{ + assert(self); + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_ASSIGN, "", parser_current_line(self)); + + node_add_child(node, parser_try_consume_new(self, NODE_IDENT)); + self->cursor++; // assign + node_add_child(node, parser_try_new_expr(self)); + + return node; +} + +struct node* parser_try_new_vardecl(struct parser* self) +{ + assert(self); + self->cursor++; // var + struct node* current = self->tokens.data[self->cursor]; + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_VARDECL, current->value, parser_current_line(self)); + + self->cursor++; // ident + + if (parser_try_consume(self, NODE_COLON) != 0) + { + node_free(node); + free(node); + return NULL; + } + + if (parser_type_is(self, NODE_TYPE, 0)) + { + current = self->tokens.data[self->cursor]; + struct node* ty = malloc(sizeof(struct node)); + node_init(ty, NODE_TYPE, current->value, parser_current_line(self)); + + node_add_child(node, ty); + self->cursor++; + } + + if (parser_try_consume(self, NODE_ASSIGN) != 0) + { + node_free(node); + free(node); + return NULL; + } + + node_add_child(node, parser_try_new_expr(self)); + + return node; +} + +struct node* parser_try_new_constdecl(struct parser* self) +{ + assert(self); + struct node* current = self->tokens.data[self->cursor]; + + struct node* node = malloc(sizeof(struct node)); + node_init(node, NODE_CONSTDECL, current->value, parser_current_line(self)); + + self->cursor++; // ident + + if (parser_try_consume(self, NODE_COLON) != 0) + { + node_free(node); + free(node); + return NULL; + } + + if (parser_type_is(self, NODE_TYPE, 0)) + { + current = self->tokens.data[self->cursor]; + struct node* ty = malloc(sizeof(struct node)); + node_init(ty, NODE_TYPE, current->value, parser_current_line(self)); + + node_add_child(node, ty); + self->cursor++; + } + + if (parser_try_consume(self, NODE_ASSIGN) != 0) + { + node_free(node); + free(node); + return NULL; + } + + struct node* expr = parser_try_new_expr(self); + assert(expr); + node_add_child(node, expr); + + return node; +} + struct node* parser_try_new_or(struct parser* self) { struct node* lhs = parser_try_new_and(self); @@ -388,6 +553,11 @@ struct node* parser_try_new_literal(struct parser* self) return node; } + if (parser_type_is(self, NODE_IDENT, 0)) + { + return parser_try_consume_new(self, NODE_IDENT); + } + return parser_try_new_builtin(self); } diff --git a/lang/src/parser.h b/lang/src/parser.h index 0028e11..bb392a8 100644 --- a/lang/src/parser.h +++ b/lang/src/parser.h @@ -24,9 +24,17 @@ struct node* parser_try_consume_new(struct parser* self, enum NodeType type); int parser_try_consume(struct parser* self, enum NodeType type); int parser_ensure(struct parser* self, enum NodeType type); +int parser_start_bexpr(struct parser* self); + struct node* parser_try_new_root(struct parser* self, char const* source); struct node* parser_try_new_instr(struct parser* self); struct node* parser_try_new_expr(struct parser* self); +struct node* parser_try_new_lexpr(struct parser* self); +struct node* parser_try_new_bexpr(struct parser* self); +struct node* parser_try_new_block(struct parser* self); +struct node* parser_try_new_assign(struct parser* self); +struct node* parser_try_new_vardecl(struct parser* self); +struct node* parser_try_new_constdecl(struct parser* self); struct node* parser_try_new_or(struct parser* self); struct node* parser_try_new_and(struct parser* self); struct node* parser_try_new_eqne(struct parser* self); diff --git a/lang/src/syms.c b/lang/src/syms.c new file mode 100644 index 0000000..052a3ed --- /dev/null +++ b/lang/src/syms.c @@ -0,0 +1,191 @@ +#include "syms.h" +#include "commons.h" +#include "type.h" +#include "node.h" + +void syms_init(struct syms* self) +{ + assert(self); + vec_init(&self->types, 1); + vec_init(&self->entries, 1); + self->addr_counter = 0; + size_t k = 0; + syms_add_type(self, k++, TYPE_INT, 0); + syms_add_type(self, k++, TYPE_FLOAT, 0); + syms_add_type(self, k++, TYPE_BOOL, 0); + syms_add_type(self, k++, TYPE_STRING, 0); +} + +void syms_free(struct syms* self) +{ + assert(self); + + for (size_t i=0; itypes.size; i++) + { + struct syms_type* st = self->types.data[i]; + type_free(&st->type); + } + + vec_free_elements(&self->types); + vec_free(&self->types); + + vec_free_elements(&self->entries); + vec_free(&self->entries); +} + +void syms_add_type(struct syms* self, size_t id, enum TypeKind type, + int count, ...) +{ + va_list va; + va_start(va, count); + + struct syms_type* ty = malloc(sizeof(struct syms_type)); + ty->id = id; + type_init(&ty->type, type); + + for (int i=0; itype, va_arg(va, enum TypeKind)); + } + + vec_push(&self->types, ty); + va_end(va); +} + +size_t syms_type_id(struct syms* self, enum TypeKind type) +{ + assert(self); + + for (size_t i=0; itypes.size; i++) + { + struct syms_type* ty = self->types.data[i]; + + if (ty->type.kind == type) + { + return ty->id; + } + } + + fprintf(stderr, "type not found\n"); + abort(); +} + +struct type* syms_try_type(struct syms* self, size_t id) +{ + for (size_t i=0; itypes.size; i++) + { + struct syms_type* ty = self->types.data[i]; + + if (ty->id == id) + { + return &ty->type; + } + } + + return NULL; +} + +void syms_declare(struct syms* self, char* name, + size_t type, int is_var, + struct node* node) +{ + assert(self); + struct syms_entry* entry = malloc(sizeof(struct syms_entry)); + size_t sz = strlen(name); + + if (sz > GUX_STR_SIZE) + { + sz = GUX_STR_SIZE; + } + + memset(entry->name, 0, GUX_STR_SIZE); + memcpy(entry->name, name, sz); + + entry->type = type; + entry->addr = self->addr_counter++; + entry->is_var = is_var; + entry->node = node; + + entry->depth = 0; + struct node* itr = entry->node; + + while (itr != NULL) + { + if (itr->type == NODE_BLOCK) + { + entry->depth++; + } + + itr = itr->parent; + } + + vec_push(&self->entries, entry); +} + +struct syms_entry* syms_try_get(struct syms* self, char* name, + struct node* node) +{ + assert(self); + + struct syms_entry* res = NULL; + int max_depth = -1; + int depth = node ? node_depth(node) : 0; + + for (size_t i=0; ientries.size; i++) + { + struct syms_entry* entry = self->entries.data[i]; + + if (strcmp(entry->name, name) == 0 && entry->depth > max_depth + && entry->depth <= depth) + { + if (node && entry->node && entry->depth == depth) + { + struct node* node_block = + node_try_find_parent(node, NODE_BLOCK); + struct node* entry_block = + node_try_find_parent(entry->node, NODE_BLOCK); + + if (node_block == entry_block) + { + int node_index = node_block_index(node); + int entry_index = node_block_index(entry->node); + + if (entry_index > node_index) + { + continue; + } + } + else + { + continue; + } + } + + max_depth = entry->depth; + res = entry; + } + } + + return res; +} + +size_t syms_str(struct syms* self, char* buffer, size_t size) +{ + assert(self); + assert(buffer); + + size_t sz = 0; + + for (size_t i=0; ientries.size; i++) + { + struct syms_entry* entry = self->entries.data[i]; + struct type* type = syms_try_type(self, entry->type); + sz += snprintf(buffer + sz, size - sz, "[%zu] ", entry->addr); + sz += type_str(type, buffer + sz, size - sz); + sz += snprintf(buffer + sz, size - sz, " %s, ", entry->name); + sz += snprintf(buffer + sz, size - sz, " depth=%d, ", entry->depth); + sz += snprintf(buffer + sz, size - sz, " block=%p\n", entry->node); + } + + return sz; +} diff --git a/lang/src/syms.h b/lang/src/syms.h new file mode 100644 index 0000000..2f679f2 --- /dev/null +++ b/lang/src/syms.h @@ -0,0 +1,49 @@ +#ifndef SYMS_H +#define SYMS_H + +#include +#include +#include + +#define SYM_IS_VAR 1 +#define SYM_IS_CONST 0 + +struct syms_type { + size_t id; + struct type type; +}; + +struct syms_entry { + char name[GUX_STR_SIZE]; + size_t type; + size_t addr; + int is_var; + int depth; + struct node* node; +}; + +struct syms { + struct vec types; + struct vec entries; + size_t addr_counter; +}; + +void syms_init(struct syms* self); +void syms_free(struct syms* self); + +void syms_add_type(struct syms* self, size_t id, enum TypeKind type, + int count, ...); + +size_t syms_type_id(struct syms* self, enum TypeKind type); +struct type* syms_try_type(struct syms* self, size_t id); + +void syms_declare(struct syms* self, char* name, + size_t type, int is_var, + struct node* node); + +struct syms_entry* syms_try_get(struct syms* self, char* name, + struct node* node); + +size_t syms_str(struct syms* self, char* buffer, size_t size); + +#endif diff --git a/lang/src/type_checker.c b/lang/src/type_checker.c index 33a5e4b..74b5f31 100644 --- a/lang/src/type_checker.c +++ b/lang/src/type_checker.c @@ -3,11 +3,13 @@ #include "node.h" #include "type.h" #include "type_resolver.h" +#include "syms.h" -void type_checker_init(struct type_checker* self) +void type_checker_init(struct type_checker* self, struct syms* syms) { assert(self); - type_resolver_init(&self->resolver); + self->syms = syms; + type_resolver_init(&self->resolver, self->syms); memset(self->error_msg, 0, GUX_STR_SIZE); } @@ -25,6 +27,161 @@ int type_checker_check(struct type_checker* self, switch (node->type) { + case NODE_ASSIGN: { + struct node* ident = node->children.data[0]; + struct node* expr = node->children.data[1]; + + struct syms_entry* entry = syms_try_get(self->syms, ident->value, + node); + + if (!entry) + { + snprintf(self->error_msg, GUX_STR_SIZE, "<%s> is not declared", + ident->value); + self->error_line = ident->line; + + return 1; + } + + if (!entry->is_var) + { + snprintf(self->error_msg, GUX_STR_SIZE, "<%s> is not mutable", + ident->value); + self->error_line = ident->line; + + return 1; + } + + struct type* var_type = syms_try_type(self->syms, entry->type); + + struct type expr_type; + type_init(&expr_type, TYPE_VOID); + + type_resolver_resolve(&self->resolver, expr, &expr_type); + + if (!type_equals(var_type, &expr_type)) + { + type_checker_error_msg(self, node, var_type, &expr_type); + type_free(&expr_type); + return 1; + } + + type_free(&expr_type); + } return 0; + + case NODE_VARDECL: + case NODE_CONSTDECL:{ + struct syms_entry* entry = syms_try_get(self->syms, + node->value, + node); + + if (entry && entry->depth == node_depth(node)) + { + snprintf(self->error_msg, GUX_STR_SIZE, + "%s is already defined", node->value); + self->error_line = node->line; + + return 1; + } + + char* type_name = NULL; + struct node* expr = NULL; + int is_var = node->type == NODE_VARDECL; + + for (size_t i=0; ichildren.size; i++) + { + type_checker_check(self, node->children.data[i]); + } + + if (node->children.size == 1) + { + expr = node->children.data[0]; + + struct type ty; + type_init(&ty, TYPE_VOID); + if (type_resolver_resolve(&self->resolver, expr, &ty) != 0) + { + type_free(&ty); + return 1; + } + + syms_declare(self->syms, node->value, + syms_type_id(self->syms, ty.kind), is_var, + node); + + type_free(&ty); + } + else if (node->children.size == 2) + { + expr = node->children.data[1]; + + type_name = ((struct node*) node->children.data[0])->value; + struct type ty; + + if (strcmp(type_name, "int") == 0) + { + type_init(&ty, TYPE_INT); + } + else if (strcmp(type_name, "float") == 0) + { + type_init(&ty, TYPE_FLOAT); + } + else if (strcmp(type_name, "bool") == 0) + { + type_init(&ty, TYPE_BOOL); + } + else if (strcmp(type_name, "string") == 0) + { + type_init(&ty, TYPE_STRING); + } + else + { + snprintf(self->error_msg, GUX_STR_SIZE, + "unknown type <%s>", + type_name); + + self->error_line = node->line; + + return 1; + } + + struct type expr_ty; + type_init(&expr_ty, TYPE_VOID); + if (type_resolver_resolve(&self->resolver, expr, &expr_ty) != 0) + { + type_free(&expr_ty); + type_free(&ty); + return 1; + } + + if (!type_equals(&ty, &expr_ty)) + { + char ty0[GUX_STR_SIZE / 3]; + type_str(&expr_ty, ty0, GUX_STR_SIZE/3); + + char ty1[GUX_STR_SIZE / 3]; + type_str(&ty, ty1, GUX_STR_SIZE/3); + + snprintf(self->error_msg, GUX_STR_SIZE, + "mismatch type: expected <%s>, got <%s>", + ty1, + ty0); + + self->error_line = node->line; + + type_free(&ty); + type_free(&expr_ty); + + return 1; + } + + syms_declare(self->syms, node->value, + syms_type_id(self->syms, ty.kind), is_var, node); + + type_free(&ty); + type_free(&expr_ty); + } + } return 0; case NODE_LT: case NODE_LE: case NODE_GT: @@ -163,6 +320,18 @@ int type_checker_check(struct type_checker* self, if (type_resolver_resolve(&self->resolver, node, &type) != 0) { + struct type lhs; + type_init(&lhs, TYPE_VOID); + type_resolver_resolve(&self->resolver, node->children.data[0], &lhs); + + struct type rhs; + type_init(&rhs, TYPE_VOID); + type_resolver_resolve(&self->resolver, node->children.data[1], &rhs); + + type_checker_error_msg(self, node, &lhs, &rhs); + + type_free(&rhs); + type_free(&lhs); type_free(&type); return 1; } @@ -211,3 +380,29 @@ int type_checker_ensure_kind(struct type_checker* self, type_free(&type); return 0; } + +void type_checker_error_msg(struct type_checker* self, + struct node* node, + struct type* want, + struct type* have) +{ + assert(self); + assert(node); + assert(want); + assert(have); + + size_t const sz = GUX_STR_SIZE / 3; + + char w[sz]; + type_str(want, w, sz); + + char h[sz]; + type_str(have, h, sz); + + snprintf(self->error_msg, GUX_STR_SIZE, + "type mismatch: expected <%s>, got <%s>", + w, + h); + + self->error_line = node->line; +} diff --git a/lang/src/type_checker.h b/lang/src/type_checker.h index 8f48a9b..701a733 100644 --- a/lang/src/type_checker.h +++ b/lang/src/type_checker.h @@ -7,12 +7,13 @@ #include struct type_checker { + struct syms* syms; struct type_resolver resolver; char error_msg[GUX_STR_SIZE]; int error_line; }; -void type_checker_init(struct type_checker* self); +void type_checker_init(struct type_checker* self, struct syms* syms); void type_checker_free(struct type_checker* self); int type_checker_check(struct type_checker* self, @@ -22,4 +23,9 @@ int type_checker_ensure_kind(struct type_checker* self, struct node* node, enum TypeKind kind); +void type_checker_error_msg(struct type_checker* self, + struct node* node, + struct type* want, + struct type* have); + #endif diff --git a/lang/src/type_resolver.c b/lang/src/type_resolver.c index ee8ee91..f053354 100644 --- a/lang/src/type_resolver.c +++ b/lang/src/type_resolver.c @@ -1,10 +1,12 @@ #include "type_resolver.h" #include "node.h" +#include "syms.h" #include "type.h" -void type_resolver_init(struct type_resolver* self) +void type_resolver_init(struct type_resolver* self, struct syms* syms) { assert(self); + self->syms = syms; } void type_resolver_free(struct type_resolver* self) @@ -24,6 +26,45 @@ int type_resolver_resolve(struct type_resolver* self, switch (node->type) { + + case NODE_ASSIGN: { + return type_resolver_resolve(self, node->children.data[1], type); + } return 0; + + + case NODE_BLOCK: { + size_t last = node->children.size - 1; + return type_resolver_resolve(self, node->children.data[last], type); + } return 0; + + case NODE_VARDECL: + case NODE_CONSTDECL: { + if (node->children.size == 1) + { + type_resolver_resolve(self, node->children.data[0], type); + } + else + { + type_resolver_resolve(self, node->children.data[1], type); + } + + } return 0; + + case NODE_IDENT: { + struct syms_entry* entry = syms_try_get(self->syms, + node->value, + node_depth(node)); + + if (!entry) + { + return 1; + } + + struct type* ty = syms_try_type(self->syms, entry->type); + + type->kind = ty->kind; + } return 0; + case NODE_EQ: case NODE_NE: case NODE_ASSERT: diff --git a/lang/src/type_resolver.h b/lang/src/type_resolver.h index c048c4d..c50691e 100644 --- a/lang/src/type_resolver.h +++ b/lang/src/type_resolver.h @@ -6,10 +6,10 @@ #include struct type_resolver { - + struct syms* syms; }; -void type_resolver_init(struct type_resolver* self); +void type_resolver_init(struct type_resolver* self, struct syms* syms); void type_resolver_free(struct type_resolver* self); int type_resolver_resolve(struct type_resolver* self, diff --git a/lang/tests/lexer.c b/lang/tests/lexer.c index 423a29b..3a33f2a 100644 --- a/lang/tests/lexer.c +++ b/lang/tests/lexer.c @@ -105,5 +105,23 @@ Test(lexer, comparisons) { "GE", "LT", "LE"); - +} + +Test(lexer, var_decl) { + test_lexer(":=var", 3, "COLON", "ASSIGN", "VAR"); +} + +Test(lexer, ident) { + test_lexer("atrue salut! coucou32 az_za?", 4, + "IDENT[atrue]", "IDENT[salut!]", + "IDENT[coucou32]", "IDENT[az_za?]"); +} + +Test(lexer, var_types) { + test_lexer("int float bool string", 4, + "TYPE[int]", "TYPE[float]", "TYPE[bool]", "TYPE[string]"); +} + +Test(lexer, blocks) { + test_lexer("{}", 2, "OBRACE", "CBRACE"); } diff --git a/lang/tests/parser.c b/lang/tests/parser.c index 366aebd..bcc82e0 100644 --- a/lang/tests/parser.c +++ b/lang/tests/parser.c @@ -108,3 +108,27 @@ Test(parser, cmp) { test_parser("ROOT(AND(LE(INT[0],INT[2]),GE(FLOAT[5.0],FLOAT[1.0])))", "0 <= 2 && 5.0 >= 1.0;"); } + +Test(parser, vardecl) { + test_parser("ROOT(CONSTDECL[x](INT[3]))", + "x := 3;"); + + test_parser("ROOT(CONSTDECL[x](TYPE[string],STRING[bim]))", + "x : string = 'bim';"); + + test_parser("ROOT(VARDECL[x](INT[3]))", + "var x := 3;"); + + test_parser("ROOT(VARDECL[x](TYPE[string],STRING[bim]))", + "var x : string = 'bim';"); +} + +Test(parser, assign) { + test_parser("ROOT(ASSIGN(IDENT[x],INT[45]))", + "x = 45;"); +} + +Test(parser, block) { + test_parser("ROOT(BLOCK(ASSIGN(IDENT[x],INT[2]),ADD(INT[1],INT[1])))", + "{ x = 2; 1 + 1;}"); +} diff --git a/lang/tests/syms.c b/lang/tests/syms.c new file mode 100644 index 0000000..130ac7d --- /dev/null +++ b/lang/tests/syms.c @@ -0,0 +1,20 @@ +#include +#include + +Test(syms, register_var) { + struct syms syms; + syms_init(&syms); + + syms_declare(&syms, "name", syms_try_type(&syms, TYPE_INT)->kind, + SYM_IS_VAR, NULL); + + struct syms_entry* entry = syms_try_get(&syms, "nope", NULL); + cr_assert_eq(entry, NULL); + + entry = syms_try_get(&syms, "name", NULL); + cr_assert_neq(entry, NULL); + + cr_assert_eq(entry->type, syms_try_type(&syms, TYPE_INT)->kind); + + syms_free(&syms); +} diff --git a/lang/tests/type_checker.c b/lang/tests/type_checker.c index b91596d..77c733a 100644 --- a/lang/tests/type_checker.c +++ b/lang/tests/type_checker.c @@ -3,6 +3,7 @@ #include #include #include +#include static void test_check_ok(char const* source) { @@ -12,8 +13,11 @@ static void test_check_ok(char const* source) struct node* ast = parser_try_new_root(&parser, source); cr_assert_neq(ast, NULL); + struct syms syms; + syms_init(&syms); + struct type_checker tc; - type_checker_init(&tc); + type_checker_init(&tc, &syms); char buf[GUX_STR_SIZE]; node_str(ast, buf, GUX_STR_SIZE); @@ -22,6 +26,7 @@ static void test_check_ok(char const* source) "type checker failed: %s", buf); type_checker_free(&tc); + syms_free(&syms); node_free(ast); free(ast); @@ -36,11 +41,15 @@ static void test_check_ko(char const* source) struct node* ast = parser_try_new_root(&parser, source); cr_assert_neq(ast, NULL, "NULL: %s", source); + struct syms syms; + syms_init(&syms); + struct type_checker tc; - type_checker_init(&tc); + type_checker_init(&tc, &syms); cr_assert_neq(type_checker_check(&tc, ast), 0, "%s == null", source); + syms_free(&syms); type_checker_free(&tc); node_free(ast); @@ -153,3 +162,12 @@ Test(type_checker, cmp) { test_check_ok("5 <= 5;"); test_check_ok("5.1 <= 5.2;"); } + +Test(type_checker, assign) { + test_check_ok("var x := 3; x = 4;"); + test_check_ko("var x := 3; x = 4.0;"); + test_check_ko("var x := 3; x = true;"); + test_check_ko("var x := 3; x = 'salut';"); + test_check_ko("x := 3; x = 4;"); + test_check_ko("z = 4;"); +} diff --git a/lib/src/commons.h b/lib/src/commons.h index 4287e7c..2e80f15 100644 --- a/lib/src/commons.h +++ b/lib/src/commons.h @@ -7,6 +7,7 @@ #include #include #include +#include #define GUX_STR_SIZE 256 #define GUX_ENUM_IDENT(X) X diff --git a/tests/run.sh b/tests/run.sh index c73de16..50f704c 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -8,7 +8,7 @@ do MSG=$(guxi $file 2>&1) RET=$? - echo -en "$file...\t" + echo -en "$file -> " if [ $RET -eq 0 ] then echo -e "\e[32mpass\e[0m" diff --git a/tests/vars_and_consts.gux b/tests/vars_and_consts.gux new file mode 100644 index 0000000..bd3c889 --- /dev/null +++ b/tests/vars_and_consts.gux @@ -0,0 +1,47 @@ +var x : int = 4; +var y := 3.2; + +assert x == 4; +assert x != 5; +assert y == 3.2; +assert y != 3.1; + +var a := (b := (c := 4)); +assert a == 4; +assert b == 4; +assert c == 4; + +a = 9; +assert a == 9; + +var u := 0; +var v := 0; + +u = (v = 17); +assert u == 17; +assert v == 17; + +# SCOPES +# ====== + +var a0 := 42; + +{ + assert a0 == 42; + var a0 := 3; + assert a0 == 3; + + { + var a0 := 777; + assert a0 == 777; + } + + { + var a0 := 19; + assert a0 == 19; + } + + assert a0 == 3; +} + +assert a0 == 42; diff --git a/vm/src/vm.c b/vm/src/vm.c index f27a33f..e9a3c6e 100644 --- a/vm/src/vm.c +++ b/vm/src/vm.c @@ -3,6 +3,7 @@ #include "program.h" #include "type.h" #include "value.h" +#include "vec.h" void vm_init(struct vm* self) { @@ -32,6 +33,8 @@ void vm_add_frame(struct vm* self) assert(self); self->stack[self->fp] = malloc(sizeof(struct frame)); self->stack[self->fp]->sp = 0; + vec_init(&self->stack[self->fp]->locals, 1); + self->fp++; } @@ -40,6 +43,9 @@ void vm_remove_frame(struct vm* self) assert(self); assert(self->fp > 0); + vec_free_elements(&self->stack[self->fp - 1]->locals); + vec_free(&self->stack[self->fp - 1]->locals); + free(self->stack[self->fp - 1]); self->fp--; } @@ -52,6 +58,48 @@ void vm_push(struct vm* self, int param) frame->sp++; } +int vm_load(struct vm* self, int addr) +{ + assert(self); + struct frame* frame = self->stack[self->fp - 1]; + + for (size_t i=0; ilocals.size; i++) + { + struct local* loc = frame->locals.data[i]; + + if (loc->addr == addr) + { + return loc->stack_addr; + } + } + + assert(0); +} + +void vm_store(struct vm* self, int addr) +{ + assert(self); + + struct frame* frame = self->stack[self->fp - 1]; + + for (size_t i=0; ilocals.size; i++) + { + struct local* loc = frame->locals.data[i]; + + if (loc->addr == addr) + { + loc->stack_addr = frame->sp - 1; + return; + } + } + + struct local* loc = malloc(sizeof(struct local)); + loc->addr = addr; + loc->stack_addr = frame->sp - 1; + + vec_push(&frame->locals, loc); +} + int vm_pop(struct vm* self) { assert(self); @@ -76,6 +124,18 @@ int vm_exec(struct vm* self, struct program* program) switch (opcode) { + case OP_LOAD: { + int stack_addr = vm_load(self, param); + struct frame* myframe = self->stack[self->fp - 1]; + vm_push(self, myframe->stack[stack_addr]); + self->pc++; + } break; + + case OP_STORE: { + vm_store(self, param); + self->pc++; + } break; + case OP_PUSH: { vm_push(self, param); self->pc++; diff --git a/vm/src/vm.h b/vm/src/vm.h index 5de094b..7ef7a2e 100644 --- a/vm/src/vm.h +++ b/vm/src/vm.h @@ -7,9 +7,15 @@ #define FRAME_DEPTH 256 #define STACK_DEPTH 256 +struct local { + int addr; + int stack_addr; +}; + struct frame { int stack[STACK_DEPTH]; size_t sp; + struct vec locals; }; struct vm { @@ -28,6 +34,9 @@ void vm_remove_frame(struct vm* self); void vm_push(struct vm* self, int param); int vm_pop(struct vm* self); +int vm_load(struct vm* self, int addr); +void vm_store(struct vm* self, int addr); + int vm_exec(struct vm* self, struct program* program); size_t vm_str(struct vm* self, struct program* program,