Compare commits

...

4 Commits

Author SHA1 Message Date
bog 789ad9657f begin blocks. 2024-03-22 08:57:44 +01:00
bog 73b051f6cc constant declaration. 2024-03-22 08:20:31 +01:00
bog d67466cad6 vars assignment. 2024-03-22 08:01:21 +01:00
bog a19071bf1d vars declaration. 2024-03-21 12:00:20 +01:00
23 changed files with 817 additions and 42 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@
*\#*
build
doc/build
vgcore.*

View File

@ -11,9 +11,10 @@ int main(int argc, char** argv)
module_t module;
module_init(&module);
module_load(&module, argv[1]);
status = module_load(&module, argv[1]);
if (!err_is_ok(&module.err))
if (status != 0 || !err_is_ok(&module.err))
{
err_print_stack_trace(&module.err);
status = 1;

View File

@ -2,6 +2,13 @@ MODULE ::= EXPR*
EXPR ::=
| OR
| ASSERT
| DECL
| ASSIGN
| BEGIN
BEGIN ::= begin BLOCK end
BLOCK ::= EXPR*
ASSIGN ::= (ident|INDEX) assign EXPR
DECL ::= (var|const) ident assign EXPR
ASSERT ::= (assert_eq|assert_ne) tuple
OR ::= AND (or AND)*
AND ::= EQNE (and EQNE)*
@ -21,7 +28,7 @@ LITERAL ::=
| opar EXPR cpar
ARRAY ::= osquare (EXPR (comma EXPR)*)? csquare
INDEX ::=
| (TUPLE|str|ARRAY) osquare (EXPR (comma EXPR)*)? csquare
| (TUPLE|str|ident|ARRAY) osquare (EXPR (comma EXPR)*)? csquare
TUPLE ::=
| opar EXPR+ cpar
BUILTIN ::= num | bool | str
BUILTIN ::= num | bool | str | ident

View File

@ -17,6 +17,7 @@ add_library(ccm_lib
prog.c
compiler.c
exec.c
sym.c
)
set_property(TARGET ccm_lib PROPERTY C_STANDARD 99)

View File

@ -9,7 +9,8 @@ G(OP_ADD), G(OP_SUB), G(OP_USUB), G(OP_MUL), \
G(OP_DIV), G(OP_POW), G(OP_MOD), G(OP_MK_TUPLE), \
G(OP_ASSERT_EQ), G(OP_ASSERT_NE), G(OP_BRF), G(OP_BR), \
G(OP_NOT), G(OP_IN), G(OP_INDEX), G(OP_EQ), G(OP_LT), \
G(OP_GT), G(OP_MK_ARRAY)
G(OP_GT), G(OP_MK_ARRAY), G(OP_LOCAL_STORE), \
G(OP_LOCAL_LOAD), G(OP_ASTORE)
CCM_ENUM_H(Opcode, OPCODES);

View File

@ -4,11 +4,14 @@
void ccm_init(ccm_t* self)
{
assert(self);
sym_init(&self->sym);
vec_init(&self->values);
vec_init(&self->stack);
vec_init(&self->globals);
err_init(&self->err);
self->id_counter = 0;
sym_open_scope(&self->sym);
}
void ccm_entry_free(ccm_entry_t* self)
@ -20,6 +23,7 @@ void ccm_entry_free(ccm_entry_t* self)
void ccm_free(ccm_t* self)
{
assert(self);
sym_free(&self->sym);
err_free(&self->err);
vec_free_elements(&self->values, (void*) ccm_entry_free);
vec_free(&self->values);
@ -332,6 +336,26 @@ CCM ccm_top(ccm_t* self, int depth)
return (CCM) self->stack.data[self->stack.size - 1 - depth];
}
void ccm_set(ccm_t* self, CCM value, int addr)
{
assert(self);
while (addr >= (ssize_t) self->stack.size)
{
ccm_push(self, 0);
}
self->stack.data[addr] = (void*) value;
}
CCM ccm_get(ccm_t* self, int addr)
{
assert(self);
assert(addr < (ssize_t) self->stack.size);
assert(addr >= 0);
return (CCM) self->stack.data[addr];
}
void ccm_in(ccm_t* self)
{
assert(self);

View File

@ -5,6 +5,7 @@
#include "vec.h"
#include "value.h"
#include "err.h"
#include "sym.h"
typedef size_t CCM;
@ -14,6 +15,7 @@ typedef struct {
} ccm_entry_t;
typedef struct {
sym_t sym;
err_t err;
vec_t values;
vec_t stack;
@ -62,6 +64,8 @@ CCM ccm_to_ref(ccm_t* self, size_t value, int line);
void ccm_push(ccm_t* self, CCM value);
CCM ccm_pop(ccm_t* self);
CCM ccm_top(ccm_t* self, int depth);
void ccm_set(ccm_t* self, CCM value, int addr);
CCM ccm_get(ccm_t* self, int addr);
void ccm_in(ccm_t* self);
void ccm_add(ccm_t* self);
@ -80,4 +84,4 @@ void ccm_le(ccm_t* self);
void ccm_gt(ccm_t* self);
void ccm_ge(ccm_t* self);
#endif
#endif

View File

@ -9,7 +9,7 @@
#include <ctype.h>
#include <assert.h>
#define CCM_STRLEN 256
#define CCM_STRLEN 4096
#define CCM_ENUM_ENUM(X) X
#define CCM_ENUM_STR(X) #X

View File

@ -5,6 +5,7 @@ void compiler_init(compiler_t* self, module_t* module)
assert(self);
err_init(&self->err);
self->module = module;
self->loc_counter = 0;
}
void compiler_free(compiler_t* self)
@ -27,9 +28,135 @@ void compiler_compile(compiler_t* self,
}
ccm_t* ccm = &self->module->ccm;
sym_t* sym = &self->module->sym;
switch (node->kind)
{
case NODE_BLOCK: {
sym_open_scope(sym);
for (size_t i=0; i<node->children.size; i++)
{
compiler_compile(
self,
node->children.data[i],
prog
);
}
sym_close_scope(sym);
} break;
case NODE_BEGIN: {
compiler_compile(self, node->children.data[0], prog);
} break;
case NODE_ASSIGN: {
node_t* target = node->children.data[0];
node_t* expr = node->children.data[1];
if (target->kind == NODE_INDEX) {
node_t* ident = target->children.data[0];
sym_entry_t const* entry = sym_try_get_value(
sym,
ident->value
);
if (!entry) {
err_push(&self->err, ident->line,
"undefined array '%s'", ident->value);
return;
}
if (entry->is_const) {
err_push(&self->err, ident->line,
"cannot assign value to constant '%s'",
ident->value);
return;
}
compiler_compile(self, expr, prog);
size_t indexes_count = target->children.size - 1;
for (size_t i=1; i<target->children.size; i++) {
compiler_compile(
self,
target->children.data[i],
prog
);
}
prog_add_instr(prog, OP_PUSH, entry->local_addr);
prog_add_instr(prog, OP_ASTORE, indexes_count);
} else {
compiler_compile(self, expr, prog);
int status =
sym_try_assign(
sym,
target->value, self->loc_counter
);
sym_entry_t* entry = sym_try_get_value(
sym,
target->value
);
assert(entry);
if (entry->is_const) {
err_push(&self->err, target->line,
"cannot assign value to constant '%s'",
target->value);
return;
}
if (!status)
{
err_push(&self->err, target->line,
"cannot assign value to '%s'",
target->value);
return;
}
prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter);
self->loc_counter++;
}
} break;
case NODE_CONSTDECL:
case NODE_VARDECL: {
node_t const* ident = node->children.data[0];
node_t* expr = node->children.data[1];
compiler_compile(self, expr, prog);
int status =
sym_declare(
sym, ident->value,
self->loc_counter,
node->kind == NODE_CONSTDECL
);
assert(status);
prog_add_instr(prog, OP_LOCAL_STORE, self->loc_counter);
self->loc_counter++;
} break;
case NODE_IDENT: {
char const* name = node->value;
sym_entry_t const* entry = sym_try_get_value(
sym,
name
);
if (!entry) {
err_push(&self->err, node->line,
"undefined '%s'", name);
return;
}
prog_add_instr(prog, OP_LOCAL_LOAD, entry->local_addr);
} break;
case NODE_ARRAY: {
for (size_t i=0; i<node->children.size; i++)
{

View File

@ -11,6 +11,7 @@
typedef struct {
module_t* module;
err_t err;
int loc_counter;
} compiler_t;
void compiler_init(compiler_t* self, module_t* module);

View File

@ -44,6 +44,22 @@ void exec_instr(exec_t* self,
switch (op)
{
case OP_LOCAL_STORE: {
CCM value = ccm_pop(ccm);
int addr = param;
ccm_set(ccm, value, addr);
ccm_push(ccm, value);
self->pc++;
} break;
case OP_LOCAL_LOAD: {
int addr = param;
CCM value = ccm_get(ccm, addr);
ccm_push(ccm, value);
self->pc++;
} break;
case OP_MK_ARRAY: {
vec_t* vec = malloc(sizeof(vec_t));
vec_init(vec);
@ -54,7 +70,11 @@ void exec_instr(exec_t* self,
vec_push(vec, ccm_to_value(ccm, element));
}
int line = ((value_t*) vec->data[0])->line;
int line = 0;
if (vec->size > 0) {
line = ((value_t*) vec->data[0])->line;
}
size_t addr = ccm_store_global(
ccm,
@ -80,6 +100,36 @@ void exec_instr(exec_t* self,
self->pc++;
} break;
case OP_ASTORE: {
int addr = ccm_pop(ccm);
CCM ccm_gaddr = ccm_get(ccm, addr);
int gaddr = ccm_from_ref(ccm, ccm_gaddr);
CCM ccm_target = ccm_load_global(ccm, gaddr);
value_t* target = ccm_to_value(ccm, ccm_target);
int indexes[param];
memset(indexes, 0, param * sizeof(int));
for (int i=0; i<param; i++) {
CCM ccm_idx = ccm_pop(ccm);
int idx = ccm_from_num(ccm, ccm_idx);
indexes[param - 1 - i] = idx;
}
for (int i=0; i<param-1; i++)
{
target = target->data.array->data[indexes[i]];
}
CCM ccm_expr = ccm_pop(ccm);
value_t* expr = ccm_to_value(ccm, ccm_expr);
target->data.array->data[indexes[param - 1]]
= expr;
ccm_push(ccm, ccm_expr);
self->pc++;
} break;
case OP_INDEX: {
CCM ccm_target = ccm_pop(ccm);
@ -165,16 +215,21 @@ void exec_instr(exec_t* self,
CCM ccm_result = ccm_from_value(ccm, result);
if (ccm_is_array(ccm, ccm_result)) {
CCM ref = ccm_to_ref(ccm,
ccm_store_global(ccm, ccm_result),
result->line);
CCM ref = ccm_to_ref(
ccm,
ccm_store_global(ccm, ccm_result),
result->line
);
ccm_push(ccm, ref);
} else {
ccm_push(ccm, ccm_result);
}
} else {
assert(0);
value_t const* val = ccm_to_value(ccm, ccm_target);
err_push(&self->err, val->line,
"not an array");
return;
}
self->pc++;
@ -210,9 +265,6 @@ void exec_instr(exec_t* self,
case OP_ASSERT_NE:
case OP_ASSERT_EQ: {
// TODO: bug here
// [1] == [1] -> OK
// assert_eq ([1], [1]) -> Failed
CCM val = ccm_pop(ccm);
vec_t* values = ccm_from_tuple(ccm, val);
assert(values->size == 2);
@ -255,6 +307,13 @@ void exec_instr(exec_t* self,
"assertion failed: <%s> %s <%s>",
lhs, operator, rhs
);
} else {
ccm_push(ccm,
ccm_to_boolean(
ccm, 1,
((value_t*) values->data[0])->line
)
);
}
self->pc++;

View File

@ -32,6 +32,7 @@ void lexer_init(lexer_t* self)
lexer_add_text(self, "%", NODE_MOD);
lexer_add_text(self, "[", NODE_OSQUARE);
lexer_add_text(self, "]", NODE_CSQUARE);
lexer_add_text(self, "=", NODE_ASSIGN);
}
void lexer_free(lexer_t* self)
@ -170,6 +171,10 @@ node_t* lexer_try_new_next(lexer_t* self)
}
}
CCM_KEYWORD("begin", NODE_BEGIN, 0);
CCM_KEYWORD("end", NODE_END, 0);
CCM_KEYWORD("var", NODE_VAR, 0);
CCM_KEYWORD("const", NODE_CONST, 0);
CCM_KEYWORD("assert_eq", NODE_ASSERT_EQ, 0);
CCM_KEYWORD("assert_ne", NODE_ASSERT_NE, 0);
CCM_KEYWORD("true", NODE_BOOL, 1);
@ -179,7 +184,13 @@ node_t* lexer_try_new_next(lexer_t* self)
CCM_KEYWORD("not", NODE_NOT, 0);
CCM_KEYWORD("in", NODE_IN, 0);
if ( (node = lexer_try_new_ident(self)) )
{
return node;
}
if (self->cursor < (ssize_t) strlen(self->source))
{
str_t s;
str_init(&s);
@ -441,3 +452,47 @@ node_t* lexer_try_new_str(lexer_t* self)
return node;
}
node_t* lexer_try_new_ident(lexer_t* self)
{
int cursor = self->cursor;
str_t value;
str_init(&value);
if (cursor >= (ssize_t) strlen(self->source)
|| !lexer_is_ident_start(self, self->source[cursor]))
{
return NULL;
}
str_push(&value, self->source[cursor]);
cursor++;
while (cursor < (ssize_t) strlen(self->source)
&& lexer_is_ident(self, self->source[cursor]))
{
str_push(&value, self->source[cursor]);
cursor++;
}
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_IDENT, value.value, self->line);
str_free(&value);
self->cursor = cursor;
return node;
}
int lexer_is_ident_start(lexer_t* lexer, char c)
{
assert(lexer);
return isalpha(c)
|| c == '_'
|| c == '?'
|| c == '!';
}
int lexer_is_ident(lexer_t* lexer, char c)
{
return isdigit(c)
|| lexer_is_ident_start(lexer, c);
}

View File

@ -54,4 +54,8 @@ node_t* lexer_try_new_text(lexer_t* self,
node_t* lexer_try_new_num(lexer_t* self);
node_t* lexer_try_new_str(lexer_t* self);
node_t* lexer_try_new_ident(lexer_t* self);
int lexer_is_ident_start(lexer_t* lexer, char c);
int lexer_is_ident(lexer_t* lexer, char c);
#endif

View File

@ -10,11 +10,15 @@ void module_init(module_t* self)
prog_init(&self->prog);
err_init(&self->err);
ccm_init(&self->ccm);
sym_init(&self->sym);
sym_open_scope(&self->sym);
}
void module_free(module_t* self)
{
assert(self);
sym_free(&self->sym);
if (self->source)
{
@ -30,6 +34,7 @@ int module_load(module_t* self, char const* path)
{
assert(self);
assert(path);
int status = 0;
if (module_load_source(self, path) != 0)
{
@ -45,25 +50,33 @@ int module_load(module_t* self, char const* path)
parser_init(&parser, &lexer);
node_t* ast = parser_try_new_parse(&parser);
if (!err_is_ok(&lexer.err) || !err_is_ok(&parser.err))
{
err_print_stack_trace(&lexer.err);
err_print_stack_trace(&parser.err);
err_push(&self->err, lexer.line, "invalid module");
status = 1;
goto free_parser;
}
if (!ast)
{
status = 1;
goto free_parser;
}
compiler_t compiler;
compiler_init(&compiler, self);
compiler_compile(&compiler, ast, &self->prog);
if (!err_is_ok(&compiler.err))
{
err_print_stack_trace(&compiler.err);
status = 1;
goto free_compiler;
}
free_compiler:
compiler_free(&compiler);
node_free(ast);
free(ast);
@ -71,7 +84,7 @@ free_parser:
parser_free(&parser);
lexer_free(&lexer);
return 0;
return status;
}
int module_load_source(module_t* self, char const* path)

View File

@ -5,12 +5,14 @@
#include "prog.h"
#include "err.h"
#include "ccm.h"
#include "sym.h"
typedef struct {
err_t err;
char* source;
prog_t prog;
ccm_t ccm;
sym_t sym;
} module_t;
void module_init(module_t* self);

View File

@ -13,7 +13,10 @@ G(NODE_ASSERT_EQ), G(NODE_ASSERT_NE), G(NODE_BOOL), \
G(NODE_AND), G(NODE_OR), G(NODE_NOT), G(NODE_IN), \
G(NODE_OSQUARE), G(NODE_CSQUARE), G(NODE_INDEX), \
G(NODE_STR), G(NODE_LT), G(NODE_LE), G(NODE_GT), \
G(NODE_GE), G(NODE_EQ), G(NODE_NE), G(NODE_ARRAY)
G(NODE_GE), G(NODE_EQ), G(NODE_NE), G(NODE_ARRAY), \
G(NODE_VAR), G(NODE_IDENT), G(NODE_ASSIGN), \
G(NODE_VARDECL), G(NODE_CONST), G(NODE_CONSTDECL), \
G(NODE_BEGIN), G(NODE_BLOCK), G(NODE_END)
CCM_ENUM_H(NodeKind, NODE_KIND);

View File

@ -26,7 +26,21 @@ node_t* parser_try_new_parse(parser_t* self)
if (self->lexer->cursor < (ssize_t)strlen(self->lexer->source))
{
err_push(&self->err, res ? res->line : 0, "unexpected end");
str_t s;
str_init(&s);
while (self->lexer->cursor
< (ssize_t)strlen(self->lexer->source)
&& !isspace(self->lexer->source[self->lexer->cursor]))
{
str_push(&s, self->lexer->source[self->lexer->cursor]);
self->lexer->cursor++;
}
err_push(&self->err, res ? res->line : 0,
"unexpected end after '%s'", s.value);
str_free(&s);
}
return res;
@ -121,15 +135,155 @@ node_t* parser_try_new_expr(parser_t* self)
{
assert(self);
if (lexer_peek_kind(self->lexer, NODE_VAR, 0)
|| lexer_peek_kind(self->lexer, NODE_CONST, 0))
{
return CCM_TRY(parser_try_new_decl);
}
if (lexer_peek_kind(self->lexer, NODE_ASSERT_EQ, 0)
|| lexer_peek_kind(self->lexer, NODE_ASSERT_NE, 0))
{
return CCM_TRY(parser_try_new_assert);
}
if (lexer_peek_kind(self->lexer, NODE_BEGIN, 0))
{
return CCM_TRY(parser_try_new_begin);
}
node_t* assign = CCM_TRY(parser_try_new_assign);
if (assign) { return assign; }
return CCM_TRY(parser_try_new_or);
}
node_t* parser_try_new_begin(parser_t* self)
{
assert(self);
if (!lexer_peek_kind(self->lexer, NODE_BEGIN, 0))
{
return NULL;
}
lexer_consume_next(self->lexer, NODE_BEGIN);
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_BEGIN, "", self->lexer->line);
node_t* block = CCM_TRY(parser_try_new_block);
node_push_new_child(node, block);
if (!block || !lexer_peek_kind(self->lexer, NODE_END, 0))
{
node_free(node); free(node);
return NULL;
}
lexer_consume_next(self->lexer, NODE_END);
return node;
}
node_t* parser_try_new_block(parser_t* self)
{
assert(self);
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_BLOCK, "", self->lexer->line);
while (1)
{
node_t* expr = CCM_TRY(parser_try_new_expr);
if (!expr) { break; }
node_push_new_child(node, expr);
}
return node;
}
node_t* parser_try_new_assign(parser_t* self)
{
assert(self);
node_t* target = CCM_TRY(parser_try_new_index);
if (!target && lexer_peek_kind(self->lexer, NODE_IDENT, 0)) {
target = lexer_try_new_next(self->lexer);
}
if (target == NULL) {
return NULL;
}
if (!lexer_peek_kind(self->lexer, NODE_ASSIGN, 0))
{
node_free(target); free(target);
return NULL;
}
lexer_consume_next(self->lexer, NODE_ASSIGN);
node_t* expr = CCM_TRY(parser_try_new_expr);
if (!expr)
{
node_free(target); free(target);
return NULL;
}
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_ASSIGN, "", self->lexer->line);
node_push_new_child(node, target);
node_push_new_child(node, expr);
return node;
}
node_t* parser_try_new_decl(parser_t* self)
{
assert(self);
int is_const = 0;
if (lexer_peek_kind(self->lexer, NODE_VAR, 0)) {
lexer_consume_next(self->lexer, NODE_VAR);
} else if (lexer_peek_kind(self->lexer, NODE_CONST, 0)) {
lexer_consume_next(self->lexer, NODE_CONST);
is_const = 1;
} else {
return NULL;
}
if (!lexer_peek_kind(self->lexer, NODE_IDENT, 0))
{
return NULL;
}
node_t* ident = lexer_try_new_next(self->lexer);
if (!lexer_consume_next(self->lexer, NODE_ASSIGN))
{
node_free(ident); free(ident);
return NULL;
}
node_t* expr = CCM_TRY(parser_try_new_expr);
if (!expr)
{
node_free(ident); free(ident);
return NULL;
}
node_t* node = malloc(sizeof(node_t));
node_init(node, is_const ? NODE_CONSTDECL : NODE_VARDECL,
"", self->lexer->line);
node_push_new_child(node, ident);
node_push_new_child(node, expr);
return node;
}
node_t* parser_try_new_assert(parser_t* self)
{
assert(self);
@ -478,15 +632,12 @@ node_t* parser_try_new_literal(parser_t* self)
{
assert(self);
node_t* index = CCM_TRY(parser_try_new_index);
if (index) { return index; }
if (lexer_peek_kind(self->lexer, NODE_OSQUARE, 0))
{
node_t* array = CCM_TRY(parser_try_new_array);
if (lexer_peek_kind(self->lexer, NODE_OSQUARE, 0))
{
return CCM_TRY_LL1(parser_try_new_index, array);
}
return array;
}
@ -496,11 +647,6 @@ node_t* parser_try_new_literal(parser_t* self)
if (tuple)
{
if (lexer_peek_kind(self->lexer, NODE_OSQUARE, 0))
{
return CCM_TRY_LL1(parser_try_new_index, tuple);
}
return tuple;
}
@ -526,13 +672,6 @@ node_t* parser_try_new_literal(parser_t* self)
return expr;
}
if (lexer_peek_kind(self->lexer, NODE_STR, 0)
&& lexer_peek_kind(self->lexer, NODE_OSQUARE, 1))
{
node_t* target = CCM_TRY(parser_try_new_builtin);
return CCM_TRY_LL1(parser_try_new_index, target);
}
return CCM_TRY(parser_try_new_builtin);
}
@ -542,6 +681,12 @@ node_t* parser_try_new_array(parser_t* self)
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_ARRAY, "", self->lexer->line);
if (!lexer_peek_kind(self->lexer, NODE_OSQUARE, 0))
{
node_free(node); free(node);
return NULL;
}
lexer_consume_next(self->lexer, NODE_OSQUARE);
@ -567,15 +712,50 @@ node_t* parser_try_new_array(parser_t* self)
first = 0;
}
if (!lexer_peek_kind(self->lexer, NODE_CSQUARE, 0))
{
node_free(node); free(node);
return NULL;
}
lexer_consume_next(self->lexer, NODE_CSQUARE);
return node;
}
node_t* parser_try_new_index(parser_t* self, node_t* target)
node_t* parser_try_new_index(parser_t* self)
{
assert(self);
node_t* target = NULL;
if (lexer_peek_kind(self->lexer, NODE_STR, 0)
|| lexer_peek_kind(self->lexer, NODE_IDENT, 0))
{
target = lexer_try_new_next(self->lexer);
}
if (!target)
{
target = CCM_TRY(parser_try_new_tuple);
}
if (!target)
{
target = CCM_TRY(parser_try_new_array);
}
if (target == NULL)
{
return NULL;
}
if (!lexer_peek_kind(self->lexer, NODE_OSQUARE, 0))
{
node_free(target); free(target);
return NULL;
}
lexer_consume_next(self->lexer, NODE_OSQUARE);
node_t* node = malloc(sizeof(node_t));
@ -589,6 +769,7 @@ node_t* parser_try_new_index(parser_t* self, node_t* target)
if (!element)
{
node_free(node); free(node);
node_free(target); free(target);
return NULL;
}
@ -600,6 +781,13 @@ node_t* parser_try_new_index(parser_t* self, node_t* target)
}
}
if (!lexer_peek_kind(self->lexer, NODE_CSQUARE, 0))
{
node_free(node); free(node);
node_free(target); free(target);
return NULL;
}
lexer_consume_next(self->lexer, NODE_CSQUARE);
return node;
@ -611,13 +799,15 @@ node_t* parser_try_new_tuple(parser_t* self)
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_TUPLE, "", self->lexer->line);
if (!lexer_consume_next(self->lexer, NODE_OPAR))
if (!lexer_peek_kind(self->lexer, NODE_OPAR, 0))
{
node_free(node);
free(node);
return NULL;
}
lexer_consume_next(self->lexer, NODE_OPAR);
node_t* lhs = CCM_TRY(parser_try_new_expr);
if (!lhs)
@ -648,6 +838,13 @@ node_t* parser_try_new_tuple(parser_t* self)
contains_more_than_one_expr = 1;
}
if (!lexer_peek_kind(self->lexer, NODE_CPAR, 0))
{
node_free(node);
free(node);
return NULL;
}
lexer_consume_next(self->lexer, NODE_CPAR);
if (!contains_more_than_one_expr)
@ -671,6 +868,7 @@ node_t* parser_try_new_builtin(parser_t* self)
node->kind == NODE_NUM
|| node->kind == NODE_BOOL
|| node->kind == NODE_STR
|| node->kind == NODE_IDENT
)
)
{

View File

@ -25,6 +25,10 @@ int parser_ensure(parser_t* self, node_t* node, NodeKind kind);
node_t* parser_try_new_module(parser_t* self);
node_t* parser_try_new_expr(parser_t* self);
node_t* parser_try_new_begin(parser_t* self);
node_t* parser_try_new_block(parser_t* self);
node_t* parser_try_new_assign(parser_t* self);
node_t* parser_try_new_decl(parser_t* self);
node_t* parser_try_new_assert(parser_t* self);
node_t* parser_try_new_or(parser_t* self);
node_t* parser_try_new_and(parser_t* self);
@ -38,7 +42,7 @@ node_t* parser_try_new_pow(parser_t* self);
node_t* parser_try_new_in(parser_t* self);
node_t* parser_try_new_literal(parser_t* self);
node_t* parser_try_new_array(parser_t* self);
node_t* parser_try_new_index(parser_t* self, node_t* target);
node_t* parser_try_new_index(parser_t* self);
node_t* parser_try_new_tuple(parser_t* self);
node_t* parser_try_new_builtin(parser_t* self);

157
lib/sym.c Normal file
View File

@ -0,0 +1,157 @@
#include "sym.h"
void sym_init(sym_t* self)
{
assert(self);
self->env = NULL;
}
void sym_free(sym_t* self)
{
assert(self);
if (self->env)
{
sym_free_env(self, self->env);
free(self->env);
}
}
void sym_free_env(sym_t* self, env_t* env)
{
assert(self);
assert(env);
if (env->parent)
{
sym_free_env(self, env->parent);
free(env->parent);
}
for (size_t i=0; i<env->entries.size; i++)
{
sym_entry_t* entry = env->entries.data[i];
free(entry->name);
free(entry);
}
vec_free(&env->entries);
}
void sym_open_scope(sym_t* self)
{
assert(self);
env_t* env = malloc(sizeof(env_t));
env->parent = NULL;
vec_init(&env->entries);
if (self->env == NULL) {
self->env = env;
} else {
env->parent = self->env;
self->env = env;
}
}
void sym_close_scope(sym_t* self)
{
assert(self);
assert(self->env);
for (size_t i=0; i<self->env->entries.size; i++)
{
sym_entry_t* entry = self->env->entries.data[i];
free(entry->name);
free(entry);
}
vec_free(&self->env->entries);
env_t* parent = self->env->parent;
free(self->env);
self->env = parent;
}
int sym_declare(sym_t* self,
char const* name,
int addr,
int is_const)
{
assert(self);
assert(self->env);
assert(name);
if (sym_try_get_env_value(self,self->env, name) != NULL)
{
return 0;
}
sym_entry_t* entry = malloc(sizeof(sym_entry_t));
entry->name = strdup(name);
entry->local_addr = addr;
entry->is_const = is_const;
vec_push(&self->env->entries, entry);
return 1;
}
int sym_try_assign(sym_t* self,
char const* name,
int addr)
{
assert(self);
assert(name);
sym_entry_t* entry = sym_try_get_value(self, name);
if (!entry) { return 0; }
entry->local_addr = addr;
return 1;
}
sym_entry_t* sym_try_get_value(sym_t* self, char const* name)
{
assert(self);
assert(name);
env_t* env = self->env;
while (env)
{
sym_entry_t* entry = sym_try_get_env_value(
self,
env,
name
);
if (entry)
{
return entry;
}
env = env->parent;
}
return NULL;
}
sym_entry_t* sym_try_get_env_value(sym_t* self,
env_t* env,
char const* name)
{
assert(self); assert(env); assert(name);
for (size_t i=0; i<env->entries.size; i++)
{
sym_entry_t const* entry =
((sym_entry_t*) env->entries.data[i]);
if (strcmp(entry->name, name) == 0)
{
return env->entries.data[i];
}
}
return NULL;
}

44
lib/sym.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef CCM_SYM_H
#define CCM_SYM_H
#include "commons.h"
#include "vec.h"
#include "value.h"
typedef struct {
char* name;
int local_addr;
int is_const;
} sym_entry_t;
typedef struct env {
vec_t entries;
struct env* parent;
} env_t;
typedef struct {
env_t* env;
} sym_t;
void sym_init(sym_t* self);
void sym_free(sym_t* self);
void sym_free_env(sym_t* self, env_t* env);
void sym_open_scope(sym_t* self);
void sym_close_scope(sym_t* self);
int sym_declare(sym_t* self,
char const* name,
int addr,
int is_const);
int sym_try_assign(sym_t* self,
char const* name,
int addr);
sym_entry_t* sym_try_get_value(sym_t* self, char const* name);
sym_entry_t* sym_try_get_env_value(sym_t* self,
env_t* env,
char const* name);
#endif

36
tests/block.ccm Normal file
View File

@ -0,0 +1,36 @@
var a = 12
begin
a = 32
end
assert_eq (32, a)
# SHADOWING
# =========
var b = 34
begin
var b = "bim"
assert_eq ("bim", b)
end
assert_eq(34, b)
# NESTED BLOCKS
# =============
var c = "hello"
begin
var c = "world"
begin
var c = "pizza"
c = "cat"
assert_eq ("cat", c)
end
assert_eq ("world", c)
end
assert_eq ("hello", c)

View File

@ -18,7 +18,7 @@ assert_eq ("hello"[-1], "o")
# BINOPS
# ======
assert_eq (
"hello world", "hello "
"hello world", "hello "
+ "world"
)

33
tests/var.ccm Normal file
View File

@ -0,0 +1,33 @@
# DECLARATION
# ===========
var a = 32
assert_eq (32, a)
var b = a + 1
assert_eq(33, b)
var c = (var d = 3)
assert_eq(3, c)
assert_eq(3, d)
var e = [1, 2]
assert_eq (2, e[-1])
var f = [2, 3]
var g = 1
assert_eq (3, f[g])
# ASSIGN
# ======
var h = 34
h = 37
assert_eq (37, h)
var i = [2, 3, 4]
i[2] = 7
assert_eq ([2, 3, 7], i)
var j = [[1, 2], [3, 4]]
j[1, 0] = 99
assert_eq ([[1, 2], [99, 4]], j)