variable scope and assignment.

main
bog 2023-12-18 14:19:38 +01:00
parent bb83d39bb9
commit 400f31025a
18 changed files with 336 additions and 34 deletions

View File

@ -2,9 +2,13 @@ MOD ::= EXPR*
EXPR ::=
| ASSERT
| VARDECL
| VARSET
| BLOCK
| OR
ASSERT ::= assert EXPR
VARDECL ::= let ident assign EXPR
VARSET ::= ident assign EXPR
BLOCK ::= begin EXPR* end
OR ::= AND (or AND)*
AND ::= EQNE (and EQNE)*
EQNE ::=

View File

@ -11,7 +11,7 @@
#include <conf.h>
#include "str.h"
#define RZ_STR_LIMIT 256
#define RZ_STR_LIMIT 1024
#define RZ_STACK_LIMIT 1024
#define RZ_MAX_TYPES 256

View File

@ -18,6 +18,8 @@ void compiler_init(compiler_t* compiler,
compiler->sym = sym;
compiler->tysy = tysy;
compiler->err = err;
compiler->scope = 0;
}
void compiler_free(compiler_t* compiler)
@ -232,21 +234,69 @@ int compiler_run(compiler_t* compiler, node_t* node)
case NODE_VARDECL: {
char* name = ((node_t*) node->children.data[0])->value.data;
sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name);
node_t* block = node_try_find_parent(node, NODE_BLOCK);
sym_entry_t* entry = NULL;
entry = sym_try_find_by_name(compiler->sym, name,
compiler->scope,
SYM_PRE,
block);
if (!entry)
{
entry = sym_try_find_by_name(compiler->sym, name,
compiler->scope,
SYM_DECL,
block);
}
assert(entry);
entry->state = SYM_DECL;
int id = entry->id;
compiler_run(compiler, (node_t*) node->children.data[1]);
mod_push_instr(compiler->mod, OP_STORE, id);
} break;
case NODE_IDENT: {
char* name = node->value.data;
sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name);
case NODE_VARSET: {
char* name = ((node_t*) node->children.data[0])->value.data;
node_t* block = node_try_find_parent(node, NODE_BLOCK);
sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name,
compiler->scope,
SYM_DECL,
block);
if (!entry)
{
char msg[RZ_STR_LIMIT];
snprintf(msg, RZ_STR_LIMIT, "%s is undefined.",
snprintf(msg, RZ_STR_LIMIT,
"cannot assign value"
" to undefined variable '%s'.", name);
err_fatal(compiler->err, msg, node->line);
}
else
{
int id = entry->id;
compiler_run(compiler, (node_t*) node->children.data[1]);
mod_push_instr(compiler->mod, OP_STORE, id);
}
} break;
case NODE_IDENT: {
char* name = node->value.data;
node_t* block = node_try_find_parent(node, NODE_BLOCK);
sym_entry_t* entry = sym_try_find_by_name(compiler->sym, name,
compiler->scope,
SYM_DECL,
block);
if (!entry)
{
char msg[RZ_STR_LIMIT];
snprintf(msg, RZ_STR_LIMIT, "undefined variable '%s'.",
name);
err_fatal(compiler->err, msg, node->line);
@ -259,6 +309,16 @@ int compiler_run(compiler_t* compiler, node_t* node)
}
} break;
case NODE_BLOCK: {
compiler->scope++;
for (size_t i=0; i<node->children.size; i++)
{
compiler_run(compiler, (node_t*) node->children.data[i]);
}
compiler->scope--;
} break;
default: {
fprintf(stderr, "Cannot compile unknown node '%s'",
NodeTypeStr[node->type]);

View File

@ -13,6 +13,8 @@ typedef struct {
sym_t* sym;
tysy_t* tysy;
err_t* err;
int scope;
} compiler_t;
void compiler_init(compiler_t* compiler,

View File

@ -71,6 +71,8 @@ node_t* lexer_try_new_next(lexer_t* lexer)
// Keywords
// ========
RZ_KEYWORD("begin", NODE_BEGIN, 0);
RZ_KEYWORD("end", NODE_END, 0);
RZ_KEYWORD("let", NODE_LET, 0);
RZ_KEYWORD("and", NODE_AND, 0);
RZ_KEYWORD("or", NODE_OR, 0);

View File

@ -12,6 +12,7 @@ void node_init(node_t* node, NodeType type, char* value, int line)
str_append(&node->value, value);
node->line = line;
node->parent = NULL;
node->children.size = 0;
node->children.cap = 0;
@ -34,6 +35,20 @@ void node_free(node_t* node)
node->children.cap = 0;
}
node_t* node_try_find_parent(node_t* node, NodeType type)
{
assert(node);
node_t* itr = node;
while (itr && itr->type != type)
{
itr = (node_t*) itr->parent;
}
return itr;
}
void node_add_new_child(node_t* node, node_t* child)
{
assert(node);
@ -54,6 +69,8 @@ void node_add_new_child(node_t* node, node_t* child)
size_t sz = node->children.size;
node->children.data[sz] = (struct node_t*) child;
((node_t*) node->children.data[sz])->parent = (struct node_t*) node;
node->children.size++;
}

View File

@ -3,16 +3,17 @@
#include "commons.h"
#define NODE_TYPE(G) \
G(NODE_MOD), \
G(NODE_NUM), G(NODE_BOOL), G(NODE_STR), \
G(NODE_ASSERT), \
G(NODE_EQ), G(NODE_NE), \
G(NODE_LT), G(NODE_LE), G(NODE_GT), G(NODE_GE), \
G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), G(NODE_DIV), \
G(NODE_MODULO), G(NODE_POW), G(NODE_OPAR), G(NODE_CPAR), \
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL)
#define NODE_TYPE(G) \
G(NODE_MOD), \
G(NODE_NUM), G(NODE_BOOL), G(NODE_STR), \
G(NODE_ASSERT), \
G(NODE_EQ), G(NODE_NE), \
G(NODE_LT), G(NODE_LE), G(NODE_GT), G(NODE_GE), \
G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), G(NODE_DIV), \
G(NODE_MODULO), G(NODE_POW), G(NODE_OPAR), G(NODE_CPAR), \
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL), \
G(NODE_VARSET), G(NODE_BEGIN), G(NODE_END), G(NODE_BLOCK)
RZ_ENUM_H(NodeType, NODE_TYPE);
@ -20,6 +21,7 @@ typedef struct {
NodeType type;
str_t value;
int line;
struct node_t* parent;
struct {
struct node_t** data;
@ -31,6 +33,8 @@ typedef struct {
void node_init(node_t* node, NodeType type, char* value, int line);
void node_free(node_t* node);
node_t* node_try_find_parent(node_t* node, NodeType type);
void node_add_new_child(node_t* node, node_t* child);
node_t* node_child(node_t* node, size_t index);

View File

@ -50,23 +50,35 @@ node_t* parser_try_new_mod(parser_t* parser)
node_t* parser_try_new_expr(parser_t* parser)
{
assert(parser);
NodeType type = lexer_peek(parser->lexer, 1);
NodeType type_1 = lexer_peek(parser->lexer, 1);
NodeType type_2 = lexer_peek(parser->lexer, 2);
if (type == -1)
if (type_1 == -1)
{
return NULL;
}
if (type == NODE_ASSERT)
if (type_1 == NODE_IDENT
&& type_2 == NODE_ASSIGN)
{
return parser_try_new_varset(parser);
}
if (type_1 == NODE_ASSERT)
{
return parser_try_new_assert(parser);
}
if (type == NODE_LET)
if (type_1 == NODE_LET)
{
return parser_try_new_vardecl(parser);
}
if (type_1 == NODE_BEGIN)
{
return parser_try_new_block(parser);
}
return parser_try_new_or(parser);
}
@ -101,6 +113,48 @@ node_t* parser_try_new_vardecl(parser_t* parser)
return node;
}
node_t* parser_try_new_varset(parser_t* parser)
{
assert(parser);
node_t* node = malloc(sizeof(node_t));
node_init(node, NODE_VARSET, "", parser->lexer->line);
node_t* ident = parser_try_new_consume(parser, NODE_IDENT);
assert(ident);
parser_skip(parser, NODE_ASSIGN);
node_t* expr = parser_try_new_expr(parser);
assert(expr);
node_add_new_child(node, ident);
node_add_new_child(node, expr);
return node;
}
node_t* parser_try_new_block(parser_t* parser)
{
assert(parser);
node_t* block = malloc(sizeof(node_t));
node_init(block, NODE_BLOCK, "", parser->lexer->line);
parser_skip(parser, NODE_BEGIN);
NodeType next;
while ( (next = lexer_peek(parser->lexer, 1)) != NODE_END)
{
node_add_new_child(block, parser_try_new_expr(parser));
}
parser_skip(parser, NODE_END);
return block;
}
node_t* parser_try_new_or(parser_t* parser)
{
assert(parser);

View File

@ -18,6 +18,8 @@ node_t* parser_try_new_mod(parser_t* parser);
node_t* parser_try_new_expr(parser_t* parser);
node_t* parser_try_new_assert(parser_t* parser);
node_t* parser_try_new_vardecl(parser_t* parser);
node_t* parser_try_new_varset(parser_t* parser);
node_t* parser_try_new_block(parser_t* parser);
node_t* parser_try_new_or(parser_t* parser);
node_t* parser_try_new_and(parser_t* parser);
node_t* parser_try_new_eqne(parser_t* parser);

View File

@ -1,4 +1,5 @@
#include "prepass.h"
#include "lib/sym.h"
#include "node.h"
void prepass_init(prepass_t* prepass,
@ -14,6 +15,8 @@ void prepass_init(prepass_t* prepass,
prepass->sym = sym;
prepass->tysolver = tysolver;
prepass->err = err;
prepass->scope = 0;
}
void prepass_free(prepass_t* prepass)
@ -28,13 +31,31 @@ void prepass_run(prepass_t* prepass, node_t* node)
switch (node->type)
{
case NODE_BLOCK: {
prepass->scope++;
for (size_t i=0; i<node->children.size; i++)
{
node_t* child = (node_t*) node->children.data[i];
prepass_run(prepass, child);
}
prepass->scope--;
} break;
case NODE_VARDECL: {
char* name = ((node_t*) node->children.data[0])->value.data;
node_t* block = node_try_find_parent(node, NODE_BLOCK);
prepass_run(prepass, (node_t*) node->children.data[1]);
type_t* type = tysolver_try_solve_node(prepass->tysolver,
(node_t*) node->children.data[1]);
sym_declare(prepass->sym, name, type);
sym_declare(prepass->sym, name, type,
prepass->scope, SYM_PRE,
block);
} break;
default: {

View File

@ -11,6 +11,9 @@ typedef struct {
sym_t* sym;
tysolver_t* tysolver;
err_t* err;
int scope;
} prepass_t;
void prepass_init(prepass_t* prepass,

View File

@ -29,12 +29,23 @@ void sym_free(sym_t* sym)
sym->entries.cap = 0;
}
int sym_declare(sym_t* sym, char* name, type_t* type)
int sym_declare(sym_t* sym, char* name, type_t* type,
int scope, int state_flag, node_t* block)
{
assert(sym);
assert(name);
assert(type);
sym_entry_t* res = sym_try_find_by_name(sym,
name,
scope,
state_flag,
block);
if (res && res->block == block)
{
return res->id;
}
if (sym->entries.data == NULL)
{
sym->entries.cap = 2;
@ -57,22 +68,47 @@ int sym_declare(sym_t* sym, char* name, type_t* type)
sym->entries.data[sym->entries.size]->name = strdup(name);
sym->entries.data[sym->entries.size]->id = id;
sym->entries.data[sym->entries.size]->type = type;
sym->entries.data[sym->entries.size]->scope = scope;
sym->entries.data[sym->entries.size]->state = state_flag;
sym->entries.data[sym->entries.size]->block = block;
sym->entries.size++;
return id;
}
sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name)
sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name,
int scope, int state_flag,
node_t* block)
{
assert(sym);
sym_entry_t* res = NULL;
for (size_t i=0; i<sym->entries.size; i++)
{
if (strcmp(sym->entries.data[i]->name, name) == 0)
sym_entry_t* entry = sym->entries.data[i];
node_t* itr = block;
while (itr && itr != entry->block)
{
return sym->entries.data[i];
itr = (node_t*) itr->parent;
}
if (strcmp(entry->name, name) == 0
&& entry->scope == scope
&& (entry->state & state_flag) != 0
&& (entry->block == itr))
{
res = entry;
return res;
}
}
if (scope > 0)
{
return sym_try_find_by_name(sym, name, scope - 1, state_flag, block);
}
return NULL;
@ -87,8 +123,8 @@ size_t sym_str(sym_t* sym, char* buffer, size_t size)
for (size_t i=0; i<sym->entries.size; i++)
{
sym_entry_t* entry = sym->entries.data[i];
sz += snprintf(buffer + sz, size - sz, "(%d %s ",
entry->id, entry->name);
sz += snprintf(buffer + sz, size - sz, "(%d| %d %s ",
entry->id, entry->scope, entry->name);
sz += type_str(entry->type, buffer + sz, size - sz);

View File

@ -4,11 +4,20 @@
#include "commons.h"
#include "tysy.h"
#include "err.h"
#include "node.h"
typedef enum {
SYM_PRE = 1<<1,
SYM_DECL = 1<<2,
} sym_state_t;
typedef struct {
int id;
char* name;
type_t* type;
int scope;
sym_state_t state;
node_t* block;
} sym_entry_t;
typedef struct {
@ -26,8 +35,13 @@ typedef struct {
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err);
void sym_free(sym_t* sym);
int sym_declare(sym_t* sym, char* name, type_t* type);
sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name);
int sym_declare(sym_t* sym, char* name, type_t* type,
int scope, int state_flag,
node_t* block);
sym_entry_t* sym_try_find_by_name(sym_t* sym, char* name,
int scope, int state_flag,
node_t* block);
size_t sym_str(sym_t* sym, char* buffer, size_t size);

View File

@ -9,6 +9,7 @@ void tysolver_init(tysolver_t* tysolver, sym_t* sym, tysy_t* tysy)
tysolver->sym = sym;
tysolver->tysy = tysy;
tysolver->scope = 0;
}
void tysolver_free(tysolver_t* tysolver)
@ -28,6 +29,19 @@ type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node)
switch (node->type)
{
case NODE_BLOCK: {
tysolver->scope++;
if (node->children.size > 0)
{
size_t last = node->children.size - 1;
return tysolver_try_solve_node(tysolver,
(node_t*) node->children.data[last]);
}
tysolver->scope--;
} break;
case NODE_VARDECL: {
return tysolver_try_solve_node(tysolver,
(node_t*) node->children.data[1]);
@ -35,7 +49,12 @@ type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node)
case NODE_IDENT: {
char* name = node->value.data;
sym_entry_t* entry = sym_try_find_by_name(tysolver->sym, name);
node_t* block = node_try_find_parent(node, NODE_BLOCK);
sym_entry_t* entry = sym_try_find_by_name(tysolver->sym,
name,
tysolver->scope,
SYM_PRE | SYM_DECL,
block);
assert(entry);
return entry->type;

View File

@ -9,6 +9,8 @@
typedef struct {
sym_t* sym;
tysy_t* tysy;
int scope;
} tysolver_t;
void tysolver_init(tysolver_t* tysolver, sym_t* sym, tysy_t* tysy);

View File

@ -1,8 +1,47 @@
# VARIABLE DECLARATIONS
# =====================
# simple
let x = 35
assert x == 35
let a = 35
assert a == 35
let y = x + 2
assert y == 37
let b = a + 2
assert b == 37
# assignment
let c = 3
assert c == 3
c = 5
assert c == 5
c = "boom"
assert c == "boom"
# blocks
let d = 1
begin
assert d == 1
let d = 2
assert d == 2
begin
assert d == 2
let d = 3
assert d == 3
d = -1
assert d == -1
end
assert d == 2
end
assert d == 1
# multiple declaration
let e = 3
let e = 7
assert e == 7

View File

@ -156,3 +156,9 @@ Test(lexer, let_var) {
"ASSIGN",
"NUM[3]");
}
Test(lexer, blocks) {
test_lexer("begin end", 2,
"BEGIN",
"END");
}

View File

@ -109,3 +109,20 @@ Test(parser, var_decl) {
test_parser_ok("MOD(VARDECL(IDENT[bim],MUL(NUM[3],NUM[6])))",
" let bim = 3 * 6 ");
}
Test(parser, var_set) {
test_parser_ok("MOD(VARSET(IDENT[y],BOOL[true]))",
" y = true ");
}
Test(parser, block) {
test_parser_ok("MOD(BLOCK)",
" begin end ");
test_parser_ok("MOD(BLOCK(ADD(NUM[1],NUM[2])))",
" begin 1 + 2 end ");
test_parser_ok("MOD(BLOCK(VARSET(IDENT[y],BOOL[true])"
",VARSET(IDENT[z],BOOL[false])))",
" begin y = true z = false end ");
}