var and const declaration, assignment and blocks.

main
bog 2024-02-12 20:21:05 +01:00
parent dd5c65b448
commit 75987d9780
28 changed files with 1204 additions and 66 deletions

View File

@ -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; i<node->children.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; i<node->children.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; i<node->children.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; i<node->children.size; i++)
{
compiler_compile(self, node->children.data[i], program);
if (compiler_compile(self, node->children.data[i], program) != 0)
{
return 1;
}
}
} break;

View File

@ -4,13 +4,15 @@
#include <commons.h>
#include <node.h>
#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,

View File

@ -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 <commons.h>

View File

@ -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;

View File

@ -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

View File

@ -5,6 +5,7 @@
#include <type_checker.h>
#include <compiler.h>
#include <vm.h>
#include <syms.h>
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)

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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; i<parent->children.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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);

191
lang/src/syms.c Normal file
View File

@ -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; i<self->types.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; i<count; i++)
{
type_add_subtype(&ty->type, 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; i<self->types.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; i<self->types.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; i<self->entries.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; i<self->entries.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;
}

49
lang/src/syms.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef SYMS_H
#define SYMS_H
#include <commons.h>
#include <vec.h>
#include <type.h>
#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

View File

@ -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; i<node->children.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;
}

View File

@ -7,12 +7,13 @@
#include <type_resolver.h>
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

View File

@ -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:

View File

@ -6,10 +6,10 @@
#include <type.h>
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,

View File

@ -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");
}

View File

@ -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;}");
}

20
lang/tests/syms.c Normal file
View File

@ -0,0 +1,20 @@
#include <criterion/criterion.h>
#include <syms.h>
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);
}

View File

@ -3,6 +3,7 @@
#include <parser.h>
#include <parser.h>
#include <type_checker.h>
#include <syms.h>
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;");
}

View File

@ -7,6 +7,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#define GUX_STR_SIZE 256
#define GUX_ENUM_IDENT(X) X

View File

@ -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"

47
tests/vars_and_consts.gux Normal file
View File

@ -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;

View File

@ -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; i<frame->locals.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; i<frame->locals.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++;

View File

@ -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,