✨ var and const declaration, assignment and blocks.
parent
dd5c65b448
commit
75987d9780
|
@ -2,12 +2,15 @@
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
|
#include "syms.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
|
|
||||||
void compiler_init(struct compiler* self)
|
void compiler_init(struct compiler* self, struct syms* syms)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
self->syms = syms;
|
||||||
|
memset(self->error_msg, 0, GUX_STR_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler_free(struct compiler* self)
|
void compiler_free(struct compiler* self)
|
||||||
|
@ -25,6 +28,56 @@ int compiler_compile(struct compiler* self,
|
||||||
|
|
||||||
switch (node->type)
|
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: {
|
case NODE_BOOL: {
|
||||||
struct value* val = malloc(sizeof(struct value));
|
struct value* val = malloc(sizeof(struct value));
|
||||||
value_init_bool(val,
|
value_init_bool(val,
|
||||||
|
@ -56,7 +109,11 @@ int compiler_compile(struct compiler* self,
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_ASSERT: {
|
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);
|
size_t brt = program_push_instr(program, OP_BRT, NO_PARAM);
|
||||||
program_push_instr(program, OP_PUSH, GUX_RET_ASSERT);
|
program_push_instr(program, OP_PUSH, GUX_RET_ASSERT);
|
||||||
size_t halt = program_push_instr(program, OP_HALT, node->line);
|
size_t halt = program_push_instr(program, OP_HALT, node->line);
|
||||||
|
@ -77,20 +134,34 @@ int compiler_compile(struct compiler* self,
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_EQ: {
|
case NODE_EQ: {
|
||||||
compiler_compile(self, node->children.data[0], program);
|
int err = compiler_compile(self, node->children.data[0], program);
|
||||||
compiler_compile(self, node->children.data[1], 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_EQ, NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_NE: {
|
case NODE_NE: {
|
||||||
compiler_compile(self, node->children.data[0], program);
|
int err = compiler_compile(self, node->children.data[0], program);
|
||||||
compiler_compile(self, node->children.data[1], 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_EQ, NO_PARAM);
|
||||||
program_push_instr(program, OP_NOT, NO_PARAM);
|
program_push_instr(program, OP_NOT, NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_NOT: {
|
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);
|
program_push_instr(program, OP_NOT, NO_PARAM);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -100,7 +171,10 @@ int compiler_compile(struct compiler* self,
|
||||||
|
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
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));
|
size_t* addr = malloc(sizeof(size_t));
|
||||||
*addr = program_push_instr(program, OP_BRF, NO_PARAM); // to pivot
|
*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++)
|
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));
|
size_t* addr = malloc(sizeof(size_t));
|
||||||
*addr = program_push_instr(program, OP_BRT, NO_PARAM); // to pivot
|
*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++)
|
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)
|
switch (node->type)
|
||||||
|
@ -229,7 +309,10 @@ int compiler_compile(struct compiler* self,
|
||||||
default: {
|
default: {
|
||||||
for (size_t i=0; i<node->children.size; i++)
|
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;
|
} break;
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,15 @@
|
||||||
#include <commons.h>
|
#include <commons.h>
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
#include "program.h"
|
#include "program.h"
|
||||||
|
#include "syms.h"
|
||||||
|
|
||||||
struct compiler {
|
struct compiler {
|
||||||
char* error_msg;
|
char error_msg[GUX_STR_SIZE];
|
||||||
|
struct syms* syms;
|
||||||
int error_line;
|
int error_line;
|
||||||
};
|
};
|
||||||
|
|
||||||
void compiler_init(struct compiler* self);
|
void compiler_init(struct compiler* self, struct syms* syms);
|
||||||
void compiler_free(struct compiler* self);
|
void compiler_free(struct compiler* self);
|
||||||
|
|
||||||
int compiler_compile(struct compiler* self,
|
int compiler_compile(struct compiler* self,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
G(OP_PUSH), G(OP_POP), G(OP_BRF), G(OP_BR), G(OP_HALT), \
|
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_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_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_LT), G(OP_LE), G(OP_GT),G(OP_GE), G(OP_LOAD), G(OP_STORE)
|
||||||
|
|
||||||
#include <commons.h>
|
#include <commons.h>
|
||||||
|
|
||||||
|
|
|
@ -67,11 +67,20 @@ size_t program_str(struct program* self, char* buffer, size_t size)
|
||||||
struct instruction* instr = (struct instruction*)
|
struct instruction* instr = (struct instruction*)
|
||||||
self->instructions.data[i];
|
self->instructions.data[i];
|
||||||
|
|
||||||
|
if (instr->param != NO_PARAM)
|
||||||
|
{
|
||||||
sz += snprintf(buffer + sz, size - sz, "\t%ld: %s %d\n",
|
sz += snprintf(buffer + sz, size - sz, "\t%ld: %s %d\n",
|
||||||
i,
|
i,
|
||||||
OpcodesStr[instr->opcode] + strlen("OP_"),
|
OpcodesStr[instr->opcode] + strlen("OP_"),
|
||||||
instr->param);
|
instr->param);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sz += snprintf(buffer + sz, size - sz, "\t%ld: %s\n",
|
||||||
|
i,
|
||||||
|
OpcodesStr[instr->opcode] + strlen("OP_"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
21
doc/gux.bnf
21
doc/gux.bnf
|
@ -1,11 +1,24 @@
|
||||||
ROOT ::= EXPR*
|
ROOT ::= INSTR*
|
||||||
|
|
||||||
INSTR ::=
|
INSTR ::=
|
||||||
| EXPR semicolon
|
| LEXPR semicolon
|
||||||
|
| BEXPR
|
||||||
|
|
||||||
EXPR ::=
|
EXPR ::= LEXPR | BEXPR
|
||||||
|
|
||||||
|
LEXPR ::=
|
||||||
| OR
|
| OR
|
||||||
| ASSERT EXPR
|
| 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)*
|
OR ::= AND (or AND)*
|
||||||
AND ::= EQNE (and EQNE)*
|
AND ::= EQNE (and EQNE)*
|
||||||
|
@ -16,5 +29,5 @@ FACTOR ::= POW ((mul|div|mod) POW)*
|
||||||
POW ::= NOT (pow NOT)?
|
POW ::= NOT (pow NOT)?
|
||||||
|
|
||||||
NOT ::= not* LITERAL
|
NOT ::= not* LITERAL
|
||||||
LITERAL ::= BUILTIN | opar EXPR cpar
|
LITERAL ::= ident | BUILTIN | opar EXPR cpar
|
||||||
BUILTIN ::= bool | int | float | string
|
BUILTIN ::= bool | int | float | string
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <type_checker.h>
|
#include <type_checker.h>
|
||||||
#include <compiler.h>
|
#include <compiler.h>
|
||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
|
#include <syms.h>
|
||||||
|
|
||||||
char* load_new_source(char const* path)
|
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_ast = 0;
|
||||||
static int show_bytecodes = 0;
|
static int show_bytecodes = 0;
|
||||||
static int show_stack = 0;
|
static int show_stack = 0;
|
||||||
|
static int show_syms = 0;
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
@ -59,6 +61,7 @@ int main(int argc, char** argv)
|
||||||
{"ast", no_argument, &show_ast, 1},
|
{"ast", no_argument, &show_ast, 1},
|
||||||
{"bytecodes", no_argument, &show_bytecodes, 1},
|
{"bytecodes", no_argument, &show_bytecodes, 1},
|
||||||
{"stack", no_argument, &show_stack, 1},
|
{"stack", no_argument, &show_stack, 1},
|
||||||
|
{"symbols", no_argument, &show_syms, 1},
|
||||||
{"help", no_argument, 0, 'h'}
|
{"help", no_argument, 0, 'h'}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -156,8 +159,11 @@ int main(int argc, char** argv)
|
||||||
printf("%s\n", msg);
|
printf("%s\n", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct syms syms;
|
||||||
|
syms_init(&syms);
|
||||||
|
|
||||||
struct type_checker checker;
|
struct type_checker checker;
|
||||||
type_checker_init(&checker);
|
type_checker_init(&checker, &syms);
|
||||||
|
|
||||||
if (type_checker_check(&checker, ast) != 0)
|
if (type_checker_check(&checker, ast) != 0)
|
||||||
{
|
{
|
||||||
|
@ -166,6 +172,7 @@ int main(int argc, char** argv)
|
||||||
checker.error_line,
|
checker.error_line,
|
||||||
checker.error_msg);
|
checker.error_msg);
|
||||||
|
|
||||||
|
syms_free(&syms);
|
||||||
type_checker_free(&checker);
|
type_checker_free(&checker);
|
||||||
|
|
||||||
if (ast)
|
if (ast)
|
||||||
|
@ -193,7 +200,7 @@ int main(int argc, char** argv)
|
||||||
program_init(&program);
|
program_init(&program);
|
||||||
|
|
||||||
struct compiler compiler;
|
struct compiler compiler;
|
||||||
compiler_init(&compiler);
|
compiler_init(&compiler, &syms);
|
||||||
|
|
||||||
if (compiler_compile(&compiler, ast, &program) != 0)
|
if (compiler_compile(&compiler, ast, &program) != 0)
|
||||||
{
|
{
|
||||||
|
@ -204,6 +211,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
compiler_free(&compiler);
|
compiler_free(&compiler);
|
||||||
program_free(&program);
|
program_free(&program);
|
||||||
|
syms_free(&syms);
|
||||||
type_checker_free(&checker);
|
type_checker_free(&checker);
|
||||||
|
|
||||||
if (ast)
|
if (ast)
|
||||||
|
@ -234,6 +242,13 @@ int main(int argc, char** argv)
|
||||||
printf("%s\n", buffer);
|
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;
|
struct vm vm;
|
||||||
vm_init(&vm);
|
vm_init(&vm);
|
||||||
|
|
||||||
|
@ -246,9 +261,11 @@ int main(int argc, char** argv)
|
||||||
vm.error_line,
|
vm.error_line,
|
||||||
vm.error_msg);
|
vm.error_msg);
|
||||||
|
|
||||||
|
|
||||||
vm_free(&vm);
|
vm_free(&vm);
|
||||||
compiler_free(&compiler);
|
compiler_free(&compiler);
|
||||||
program_free(&program);
|
program_free(&program);
|
||||||
|
syms_free(&syms);
|
||||||
type_checker_free(&checker);
|
type_checker_free(&checker);
|
||||||
|
|
||||||
if (ast)
|
if (ast)
|
||||||
|
@ -284,6 +301,7 @@ int main(int argc, char** argv)
|
||||||
vm_free(&vm);
|
vm_free(&vm);
|
||||||
compiler_free(&compiler);
|
compiler_free(&compiler);
|
||||||
program_free(&program);
|
program_free(&program);
|
||||||
|
syms_free(&syms);
|
||||||
type_checker_free(&checker);
|
type_checker_free(&checker);
|
||||||
|
|
||||||
if (ast)
|
if (ast)
|
||||||
|
|
|
@ -12,6 +12,7 @@ add_library(gux-lang OBJECT
|
||||||
src/value.c
|
src/value.c
|
||||||
src/type_resolver.c
|
src/type_resolver.c
|
||||||
src/type_checker.c
|
src/type_checker.c
|
||||||
|
src/syms.c
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET gux-lang PROPERTY C_STANDARD 99)
|
set_property(TARGET gux-lang PROPERTY C_STANDARD 99)
|
||||||
|
@ -41,6 +42,7 @@ add_executable(gux-lang-tests
|
||||||
tests/type.c
|
tests/type.c
|
||||||
tests/value.c
|
tests/value.c
|
||||||
tests/type_checker.c
|
tests/type_checker.c
|
||||||
|
tests/syms.c
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET gux-lang-tests PROPERTY C_STANDARD 99)
|
set_property(TARGET gux-lang-tests PROPERTY C_STANDARD 99)
|
||||||
|
|
105
lang/src/lexer.c
105
lang/src/lexer.c
|
@ -12,27 +12,39 @@ void lexer_init(struct lexer* self, char const* source)
|
||||||
|
|
||||||
vec_init(&self->toks, 1);
|
vec_init(&self->toks, 1);
|
||||||
|
|
||||||
lexer_add_tok(self, "<", NODE_LT, 0);
|
lexer_add_tok(self, "var", NODE_VAR, "", 1);
|
||||||
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, "int", NODE_TYPE, "int", 1);
|
||||||
lexer_add_tok(self, "-", NODE_SUB, 0);
|
lexer_add_tok(self, "float", NODE_TYPE, "float", 1);
|
||||||
lexer_add_tok(self, "*", NODE_MUL, 0);
|
lexer_add_tok(self, "bool", NODE_TYPE, "bool", 1);
|
||||||
lexer_add_tok(self, "/", NODE_DIV, 0);
|
lexer_add_tok(self, "string", NODE_TYPE, "string", 1);
|
||||||
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_OBRACE, "", 0);
|
||||||
lexer_add_tok(self, "!=", NODE_NE, 0);
|
lexer_add_tok(self, "}", NODE_CBRACE, "", 0);
|
||||||
lexer_add_tok(self, "&&", NODE_AND, 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_LT, "", 0);
|
||||||
lexer_add_tok(self, "!", NODE_NOT, 0);
|
lexer_add_tok(self, "<=", NODE_LE, "", 0);
|
||||||
lexer_add_tok(self, "(", NODE_OPAR, 0);
|
lexer_add_tok(self, ">", NODE_GT, "", 0);
|
||||||
lexer_add_tok(self, ")", NODE_CPAR, 0);
|
lexer_add_tok(self, ">=", NODE_GE, "", 0);
|
||||||
lexer_add_tok(self, ";", NODE_SEMICOLON, 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)
|
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];
|
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)
|
if (best == NULL || info.position > pos)
|
||||||
{
|
{
|
||||||
struct node* node = malloc(sizeof(struct node));
|
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)
|
if (best)
|
||||||
{
|
{
|
||||||
|
@ -161,6 +174,14 @@ struct node* lexer_next_new(struct lexer* self)
|
||||||
return node;
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,16 +432,60 @@ int lexer_scan_string(struct lexer* self,
|
||||||
return 0;
|
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,
|
void lexer_add_tok(struct lexer* self,
|
||||||
char* sym,
|
char* sym,
|
||||||
enum NodeType type,
|
enum NodeType type,
|
||||||
|
char* value,
|
||||||
int is_keyword)
|
int is_keyword)
|
||||||
{
|
{
|
||||||
(void) self;
|
(void) self;
|
||||||
struct tok* tok = malloc(sizeof(struct tok));
|
struct tok* tok = malloc(sizeof(struct tok));
|
||||||
tok->sym = sym;
|
tok->sym = sym;
|
||||||
tok->type = type;
|
tok->type = type;
|
||||||
|
memcpy(tok->value, value, GUX_STR_SIZE);
|
||||||
tok->is_keyword = is_keyword;
|
tok->is_keyword = is_keyword;
|
||||||
|
|
||||||
vec_push(&self->toks, tok);
|
vec_push(&self->toks, tok);
|
||||||
|
|
|
@ -9,6 +9,7 @@ struct tok {
|
||||||
char* sym;
|
char* sym;
|
||||||
enum NodeType type;
|
enum NodeType type;
|
||||||
int is_keyword;
|
int is_keyword;
|
||||||
|
char value[GUX_STR_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lexer {
|
struct lexer {
|
||||||
|
@ -52,9 +53,13 @@ int lexer_scan_float(struct lexer* self,
|
||||||
int lexer_scan_string(struct lexer* self,
|
int lexer_scan_string(struct lexer* self,
|
||||||
struct token_info* info);
|
struct token_info* info);
|
||||||
|
|
||||||
|
int lexer_scan_ident(struct lexer* self,
|
||||||
|
struct token_info* info);
|
||||||
|
|
||||||
void lexer_add_tok(struct lexer* self,
|
void lexer_add_tok(struct lexer* self,
|
||||||
char* sym,
|
char* sym,
|
||||||
enum NodeType type,
|
enum NodeType type,
|
||||||
|
char* value,
|
||||||
int is_keyword);
|
int is_keyword);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,7 @@ void node_init(struct node* self, enum NodeType type,
|
||||||
self->value = strdup(value);
|
self->value = strdup(value);
|
||||||
vec_init(&self->children, 1);
|
vec_init(&self->children, 1);
|
||||||
self->line = line;
|
self->line = line;
|
||||||
|
self->parent = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void node_free(struct node* self)
|
void node_free(struct node* self)
|
||||||
|
@ -43,6 +44,7 @@ struct node* node_add_child(struct node* self, struct node* child)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
vec_push(&self->children, child);
|
vec_push(&self->children, child);
|
||||||
|
child->parent = self;
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,3 +83,76 @@ size_t node_str(struct node* self, char* buffer, size_t size)
|
||||||
|
|
||||||
return sz;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -12,13 +12,16 @@
|
||||||
G(NODE_EQ), G(NODE_NE), G(NODE_INT), G(NODE_FLOAT), \
|
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_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_MOD), G(NODE_POW), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
|
||||||
G(NODE_GE)
|
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);
|
GUX_ENUM_H(NodeType, NODE_TYPE);
|
||||||
|
|
||||||
struct node {
|
struct node {
|
||||||
enum NodeType type;
|
enum NodeType type;
|
||||||
char* value;
|
char* value;
|
||||||
|
struct node* parent;
|
||||||
struct vec children;
|
struct vec children;
|
||||||
int line;
|
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);
|
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
|
#endif
|
||||||
|
|
|
@ -127,6 +127,14 @@ int parser_try_consume(struct parser* self, enum NodeType type)
|
||||||
return 0;
|
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)
|
struct node* parser_try_new_root(struct parser* self, char const* source)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -163,7 +171,14 @@ 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_instr(struct parser* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
struct node* node = parser_try_new_expr(self);
|
|
||||||
|
if (parser_start_bexpr(self))
|
||||||
|
{
|
||||||
|
return parser_try_new_bexpr(self);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct node* node = parser_try_new_lexpr(self);
|
||||||
|
|
||||||
if (parser_ensure(self, NODE_SEMICOLON) != 0)
|
if (parser_ensure(self, NODE_SEMICOLON) != 0)
|
||||||
{
|
{
|
||||||
|
@ -174,11 +189,24 @@ struct node* parser_try_new_instr(struct parser* self)
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct node* parser_try_new_expr(struct parser* self)
|
struct node* parser_try_new_expr(struct parser* self)
|
||||||
{
|
{
|
||||||
assert(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))
|
if (parser_type_is(self, NODE_ASSERT, 0))
|
||||||
{
|
{
|
||||||
struct node* node = malloc(sizeof(struct node));
|
struct node* node = malloc(sizeof(struct node));
|
||||||
|
@ -198,6 +226,20 @@ struct node* parser_try_new_expr(struct parser* self)
|
||||||
|
|
||||||
return node;
|
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);
|
struct node* node = parser_try_new_or(self);
|
||||||
|
|
||||||
|
@ -209,6 +251,129 @@ struct node* parser_try_new_expr(struct parser* self)
|
||||||
return node;
|
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* parser_try_new_or(struct parser* self)
|
||||||
{
|
{
|
||||||
struct node* lhs = parser_try_new_and(self);
|
struct node* lhs = parser_try_new_and(self);
|
||||||
|
@ -388,6 +553,11 @@ struct node* parser_try_new_literal(struct parser* self)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parser_type_is(self, NODE_IDENT, 0))
|
||||||
|
{
|
||||||
|
return parser_try_consume_new(self, NODE_IDENT);
|
||||||
|
}
|
||||||
|
|
||||||
return parser_try_new_builtin(self);
|
return parser_try_new_builtin(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_try_consume(struct parser* self, enum NodeType type);
|
||||||
int parser_ensure(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_root(struct parser* self, char const* source);
|
||||||
struct node* parser_try_new_instr(struct parser* self);
|
struct node* parser_try_new_instr(struct parser* self);
|
||||||
struct node* parser_try_new_expr(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_or(struct parser* self);
|
||||||
struct node* parser_try_new_and(struct parser* self);
|
struct node* parser_try_new_and(struct parser* self);
|
||||||
struct node* parser_try_new_eqne(struct parser* self);
|
struct node* parser_try_new_eqne(struct parser* self);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -3,11 +3,13 @@
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "type_resolver.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);
|
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);
|
memset(self->error_msg, 0, GUX_STR_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +27,161 @@ int type_checker_check(struct type_checker* self,
|
||||||
|
|
||||||
switch (node->type)
|
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_LT:
|
||||||
case NODE_LE:
|
case NODE_LE:
|
||||||
case NODE_GT:
|
case NODE_GT:
|
||||||
|
@ -163,6 +320,18 @@ int type_checker_check(struct type_checker* self,
|
||||||
|
|
||||||
if (type_resolver_resolve(&self->resolver, node, &type) != 0)
|
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);
|
type_free(&type);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -211,3 +380,29 @@ int type_checker_ensure_kind(struct type_checker* self,
|
||||||
type_free(&type);
|
type_free(&type);
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -7,12 +7,13 @@
|
||||||
#include <type_resolver.h>
|
#include <type_resolver.h>
|
||||||
|
|
||||||
struct type_checker {
|
struct type_checker {
|
||||||
|
struct syms* syms;
|
||||||
struct type_resolver resolver;
|
struct type_resolver resolver;
|
||||||
char error_msg[GUX_STR_SIZE];
|
char error_msg[GUX_STR_SIZE];
|
||||||
int error_line;
|
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);
|
void type_checker_free(struct type_checker* self);
|
||||||
|
|
||||||
int type_checker_check(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,
|
struct node* node,
|
||||||
enum TypeKind kind);
|
enum TypeKind kind);
|
||||||
|
|
||||||
|
void type_checker_error_msg(struct type_checker* self,
|
||||||
|
struct node* node,
|
||||||
|
struct type* want,
|
||||||
|
struct type* have);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include "type_resolver.h"
|
#include "type_resolver.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
#include "syms.h"
|
||||||
#include "type.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);
|
assert(self);
|
||||||
|
self->syms = syms;
|
||||||
}
|
}
|
||||||
|
|
||||||
void type_resolver_free(struct type_resolver* self)
|
void type_resolver_free(struct type_resolver* self)
|
||||||
|
@ -24,6 +26,45 @@ int type_resolver_resolve(struct type_resolver* self,
|
||||||
|
|
||||||
switch (node->type)
|
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_EQ:
|
||||||
case NODE_NE:
|
case NODE_NE:
|
||||||
case NODE_ASSERT:
|
case NODE_ASSERT:
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
#include <type.h>
|
#include <type.h>
|
||||||
|
|
||||||
struct type_resolver {
|
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);
|
void type_resolver_free(struct type_resolver* self);
|
||||||
|
|
||||||
int type_resolver_resolve(struct type_resolver* self,
|
int type_resolver_resolve(struct type_resolver* self,
|
||||||
|
|
|
@ -105,5 +105,23 @@ Test(lexer, comparisons) {
|
||||||
"GE",
|
"GE",
|
||||||
"LT",
|
"LT",
|
||||||
"LE");
|
"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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,3 +108,27 @@ Test(parser, cmp) {
|
||||||
test_parser("ROOT(AND(LE(INT[0],INT[2]),GE(FLOAT[5.0],FLOAT[1.0])))",
|
test_parser("ROOT(AND(LE(INT[0],INT[2]),GE(FLOAT[5.0],FLOAT[1.0])))",
|
||||||
"0 <= 2 && 5.0 >= 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;}");
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
#include <parser.h>
|
#include <parser.h>
|
||||||
#include <parser.h>
|
#include <parser.h>
|
||||||
#include <type_checker.h>
|
#include <type_checker.h>
|
||||||
|
#include <syms.h>
|
||||||
|
|
||||||
static void test_check_ok(char const* source)
|
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);
|
struct node* ast = parser_try_new_root(&parser, source);
|
||||||
cr_assert_neq(ast, NULL);
|
cr_assert_neq(ast, NULL);
|
||||||
|
|
||||||
|
struct syms syms;
|
||||||
|
syms_init(&syms);
|
||||||
|
|
||||||
struct type_checker tc;
|
struct type_checker tc;
|
||||||
type_checker_init(&tc);
|
type_checker_init(&tc, &syms);
|
||||||
|
|
||||||
char buf[GUX_STR_SIZE];
|
char buf[GUX_STR_SIZE];
|
||||||
node_str(ast, 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 failed: %s", buf);
|
||||||
|
|
||||||
type_checker_free(&tc);
|
type_checker_free(&tc);
|
||||||
|
syms_free(&syms);
|
||||||
|
|
||||||
node_free(ast);
|
node_free(ast);
|
||||||
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);
|
struct node* ast = parser_try_new_root(&parser, source);
|
||||||
cr_assert_neq(ast, NULL, "NULL: %s", source);
|
cr_assert_neq(ast, NULL, "NULL: %s", source);
|
||||||
|
|
||||||
|
struct syms syms;
|
||||||
|
syms_init(&syms);
|
||||||
|
|
||||||
struct type_checker tc;
|
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);
|
cr_assert_neq(type_checker_check(&tc, ast), 0, "%s == null", source);
|
||||||
|
|
||||||
|
syms_free(&syms);
|
||||||
type_checker_free(&tc);
|
type_checker_free(&tc);
|
||||||
|
|
||||||
node_free(ast);
|
node_free(ast);
|
||||||
|
@ -153,3 +162,12 @@ Test(type_checker, cmp) {
|
||||||
test_check_ok("5 <= 5;");
|
test_check_ok("5 <= 5;");
|
||||||
test_check_ok("5.1 <= 5.2;");
|
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;");
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#define GUX_STR_SIZE 256
|
#define GUX_STR_SIZE 256
|
||||||
#define GUX_ENUM_IDENT(X) X
|
#define GUX_ENUM_IDENT(X) X
|
||||||
|
|
|
@ -8,7 +8,7 @@ do
|
||||||
MSG=$(guxi $file 2>&1)
|
MSG=$(guxi $file 2>&1)
|
||||||
RET=$?
|
RET=$?
|
||||||
|
|
||||||
echo -en "$file...\t"
|
echo -en "$file -> "
|
||||||
if [ $RET -eq 0 ]
|
if [ $RET -eq 0 ]
|
||||||
then
|
then
|
||||||
echo -e "\e[32mpass\e[0m"
|
echo -e "\e[32mpass\e[0m"
|
||||||
|
|
|
@ -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;
|
60
vm/src/vm.c
60
vm/src/vm.c
|
@ -3,6 +3,7 @@
|
||||||
#include "program.h"
|
#include "program.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include "vec.h"
|
||||||
|
|
||||||
void vm_init(struct vm* self)
|
void vm_init(struct vm* self)
|
||||||
{
|
{
|
||||||
|
@ -32,6 +33,8 @@ void vm_add_frame(struct vm* self)
|
||||||
assert(self);
|
assert(self);
|
||||||
self->stack[self->fp] = malloc(sizeof(struct frame));
|
self->stack[self->fp] = malloc(sizeof(struct frame));
|
||||||
self->stack[self->fp]->sp = 0;
|
self->stack[self->fp]->sp = 0;
|
||||||
|
vec_init(&self->stack[self->fp]->locals, 1);
|
||||||
|
|
||||||
self->fp++;
|
self->fp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +43,9 @@ void vm_remove_frame(struct vm* self)
|
||||||
assert(self);
|
assert(self);
|
||||||
assert(self->fp > 0);
|
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]);
|
free(self->stack[self->fp - 1]);
|
||||||
self->fp--;
|
self->fp--;
|
||||||
}
|
}
|
||||||
|
@ -52,6 +58,48 @@ void vm_push(struct vm* self, int param)
|
||||||
frame->sp++;
|
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)
|
int vm_pop(struct vm* self)
|
||||||
{
|
{
|
||||||
assert(self);
|
assert(self);
|
||||||
|
@ -76,6 +124,18 @@ int vm_exec(struct vm* self, struct program* program)
|
||||||
|
|
||||||
switch (opcode)
|
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: {
|
case OP_PUSH: {
|
||||||
vm_push(self, param);
|
vm_push(self, param);
|
||||||
self->pc++;
|
self->pc++;
|
||||||
|
|
|
@ -7,9 +7,15 @@
|
||||||
#define FRAME_DEPTH 256
|
#define FRAME_DEPTH 256
|
||||||
#define STACK_DEPTH 256
|
#define STACK_DEPTH 256
|
||||||
|
|
||||||
|
struct local {
|
||||||
|
int addr;
|
||||||
|
int stack_addr;
|
||||||
|
};
|
||||||
|
|
||||||
struct frame {
|
struct frame {
|
||||||
int stack[STACK_DEPTH];
|
int stack[STACK_DEPTH];
|
||||||
size_t sp;
|
size_t sp;
|
||||||
|
struct vec locals;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vm {
|
struct vm {
|
||||||
|
@ -28,6 +34,9 @@ void vm_remove_frame(struct vm* self);
|
||||||
void vm_push(struct vm* self, int param);
|
void vm_push(struct vm* self, int param);
|
||||||
int vm_pop(struct vm* self);
|
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);
|
int vm_exec(struct vm* self, struct program* program);
|
||||||
|
|
||||||
size_t vm_str(struct vm* self, struct program* program,
|
size_t vm_str(struct vm* self, struct program* program,
|
||||||
|
|
Loading…
Reference in New Issue