✨ variable scope and assignment.
parent
bb83d39bb9
commit
400f31025a
|
@ -2,9 +2,13 @@ MOD ::= EXPR*
|
||||||
EXPR ::=
|
EXPR ::=
|
||||||
| ASSERT
|
| ASSERT
|
||||||
| VARDECL
|
| VARDECL
|
||||||
|
| VARSET
|
||||||
|
| BLOCK
|
||||||
| OR
|
| OR
|
||||||
ASSERT ::= assert EXPR
|
ASSERT ::= assert EXPR
|
||||||
VARDECL ::= let ident assign EXPR
|
VARDECL ::= let ident assign EXPR
|
||||||
|
VARSET ::= ident assign EXPR
|
||||||
|
BLOCK ::= begin EXPR* end
|
||||||
OR ::= AND (or AND)*
|
OR ::= AND (or AND)*
|
||||||
AND ::= EQNE (and EQNE)*
|
AND ::= EQNE (and EQNE)*
|
||||||
EQNE ::=
|
EQNE ::=
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <conf.h>
|
#include <conf.h>
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
#define RZ_STR_LIMIT 256
|
#define RZ_STR_LIMIT 1024
|
||||||
#define RZ_STACK_LIMIT 1024
|
#define RZ_STACK_LIMIT 1024
|
||||||
#define RZ_MAX_TYPES 256
|
#define RZ_MAX_TYPES 256
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ void compiler_init(compiler_t* compiler,
|
||||||
compiler->sym = sym;
|
compiler->sym = sym;
|
||||||
compiler->tysy = tysy;
|
compiler->tysy = tysy;
|
||||||
compiler->err = err;
|
compiler->err = err;
|
||||||
|
|
||||||
|
compiler->scope = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler_free(compiler_t* compiler)
|
void compiler_free(compiler_t* compiler)
|
||||||
|
@ -232,21 +234,69 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
||||||
|
|
||||||
case NODE_VARDECL: {
|
case NODE_VARDECL: {
|
||||||
char* name = ((node_t*) node->children.data[0])->value.data;
|
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);
|
assert(entry);
|
||||||
|
entry->state = SYM_DECL;
|
||||||
|
|
||||||
int id = entry->id;
|
int id = entry->id;
|
||||||
compiler_run(compiler, (node_t*) node->children.data[1]);
|
compiler_run(compiler, (node_t*) node->children.data[1]);
|
||||||
mod_push_instr(compiler->mod, OP_STORE, id);
|
mod_push_instr(compiler->mod, OP_STORE, id);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_IDENT: {
|
case NODE_VARSET: {
|
||||||
char* name = node->value.data;
|
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 = sym_try_find_by_name(compiler->sym, name,
|
||||||
|
compiler->scope,
|
||||||
|
SYM_DECL,
|
||||||
|
block);
|
||||||
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
{
|
{
|
||||||
char msg[RZ_STR_LIMIT];
|
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);
|
name);
|
||||||
|
|
||||||
err_fatal(compiler->err, msg, node->line);
|
err_fatal(compiler->err, msg, node->line);
|
||||||
|
@ -259,6 +309,16 @@ int compiler_run(compiler_t* compiler, node_t* node)
|
||||||
}
|
}
|
||||||
} break;
|
} 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: {
|
default: {
|
||||||
fprintf(stderr, "Cannot compile unknown node '%s'",
|
fprintf(stderr, "Cannot compile unknown node '%s'",
|
||||||
NodeTypeStr[node->type]);
|
NodeTypeStr[node->type]);
|
||||||
|
|
|
@ -13,6 +13,8 @@ typedef struct {
|
||||||
sym_t* sym;
|
sym_t* sym;
|
||||||
tysy_t* tysy;
|
tysy_t* tysy;
|
||||||
err_t* err;
|
err_t* err;
|
||||||
|
|
||||||
|
int scope;
|
||||||
} compiler_t;
|
} compiler_t;
|
||||||
|
|
||||||
void compiler_init(compiler_t* compiler,
|
void compiler_init(compiler_t* compiler,
|
||||||
|
|
|
@ -71,6 +71,8 @@ node_t* lexer_try_new_next(lexer_t* lexer)
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
// ========
|
// ========
|
||||||
|
RZ_KEYWORD("begin", NODE_BEGIN, 0);
|
||||||
|
RZ_KEYWORD("end", NODE_END, 0);
|
||||||
RZ_KEYWORD("let", NODE_LET, 0);
|
RZ_KEYWORD("let", NODE_LET, 0);
|
||||||
RZ_KEYWORD("and", NODE_AND, 0);
|
RZ_KEYWORD("and", NODE_AND, 0);
|
||||||
RZ_KEYWORD("or", NODE_OR, 0);
|
RZ_KEYWORD("or", NODE_OR, 0);
|
||||||
|
|
17
lib/node.c
17
lib/node.c
|
@ -12,6 +12,7 @@ void node_init(node_t* node, NodeType type, char* value, int line)
|
||||||
str_append(&node->value, value);
|
str_append(&node->value, value);
|
||||||
|
|
||||||
node->line = line;
|
node->line = line;
|
||||||
|
node->parent = NULL;
|
||||||
|
|
||||||
node->children.size = 0;
|
node->children.size = 0;
|
||||||
node->children.cap = 0;
|
node->children.cap = 0;
|
||||||
|
@ -34,6 +35,20 @@ void node_free(node_t* node)
|
||||||
node->children.cap = 0;
|
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)
|
void node_add_new_child(node_t* node, node_t* child)
|
||||||
{
|
{
|
||||||
assert(node);
|
assert(node);
|
||||||
|
@ -54,6 +69,8 @@ void node_add_new_child(node_t* node, node_t* child)
|
||||||
|
|
||||||
size_t sz = node->children.size;
|
size_t sz = node->children.size;
|
||||||
node->children.data[sz] = (struct node_t*) child;
|
node->children.data[sz] = (struct node_t*) child;
|
||||||
|
((node_t*) node->children.data[sz])->parent = (struct node_t*) node;
|
||||||
|
|
||||||
node->children.size++;
|
node->children.size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
G(NODE_ADD), G(NODE_SUB), G(NODE_MUL), G(NODE_DIV), \
|
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_MODULO), G(NODE_POW), G(NODE_OPAR), G(NODE_CPAR), \
|
||||||
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
|
G(NODE_AND), G(NODE_OR), G(NODE_NOT), \
|
||||||
G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL)
|
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);
|
RZ_ENUM_H(NodeType, NODE_TYPE);
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ typedef struct {
|
||||||
NodeType type;
|
NodeType type;
|
||||||
str_t value;
|
str_t value;
|
||||||
int line;
|
int line;
|
||||||
|
struct node_t* parent;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct node_t** data;
|
struct node_t** data;
|
||||||
|
@ -31,6 +33,8 @@ typedef struct {
|
||||||
void node_init(node_t* node, NodeType type, char* value, int line);
|
void node_init(node_t* node, NodeType type, char* value, int line);
|
||||||
void node_free(node_t* node);
|
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);
|
void node_add_new_child(node_t* node, node_t* child);
|
||||||
node_t* node_child(node_t* node, size_t index);
|
node_t* node_child(node_t* node, size_t index);
|
||||||
|
|
||||||
|
|
62
lib/parser.c
62
lib/parser.c
|
@ -50,23 +50,35 @@ node_t* parser_try_new_mod(parser_t* parser)
|
||||||
node_t* parser_try_new_expr(parser_t* parser)
|
node_t* parser_try_new_expr(parser_t* parser)
|
||||||
{
|
{
|
||||||
assert(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;
|
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);
|
return parser_try_new_assert(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == NODE_LET)
|
if (type_1 == NODE_LET)
|
||||||
{
|
{
|
||||||
return parser_try_new_vardecl(parser);
|
return parser_try_new_vardecl(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type_1 == NODE_BEGIN)
|
||||||
|
{
|
||||||
|
return parser_try_new_block(parser);
|
||||||
|
}
|
||||||
|
|
||||||
return parser_try_new_or(parser);
|
return parser_try_new_or(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +113,48 @@ node_t* parser_try_new_vardecl(parser_t* parser)
|
||||||
return node;
|
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)
|
node_t* parser_try_new_or(parser_t* parser)
|
||||||
{
|
{
|
||||||
assert(parser);
|
assert(parser);
|
||||||
|
|
|
@ -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_expr(parser_t* parser);
|
||||||
node_t* parser_try_new_assert(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_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_or(parser_t* parser);
|
||||||
node_t* parser_try_new_and(parser_t* parser);
|
node_t* parser_try_new_and(parser_t* parser);
|
||||||
node_t* parser_try_new_eqne(parser_t* parser);
|
node_t* parser_try_new_eqne(parser_t* parser);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "prepass.h"
|
#include "prepass.h"
|
||||||
|
#include "lib/sym.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
|
||||||
void prepass_init(prepass_t* prepass,
|
void prepass_init(prepass_t* prepass,
|
||||||
|
@ -14,6 +15,8 @@ void prepass_init(prepass_t* prepass,
|
||||||
prepass->sym = sym;
|
prepass->sym = sym;
|
||||||
prepass->tysolver = tysolver;
|
prepass->tysolver = tysolver;
|
||||||
prepass->err = err;
|
prepass->err = err;
|
||||||
|
|
||||||
|
prepass->scope = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepass_free(prepass_t* prepass)
|
void prepass_free(prepass_t* prepass)
|
||||||
|
@ -28,13 +31,31 @@ void prepass_run(prepass_t* prepass, node_t* node)
|
||||||
|
|
||||||
switch (node->type)
|
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: {
|
case NODE_VARDECL: {
|
||||||
char* name = ((node_t*) node->children.data[0])->value.data;
|
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]);
|
prepass_run(prepass, (node_t*) node->children.data[1]);
|
||||||
|
|
||||||
type_t* type = tysolver_try_solve_node(prepass->tysolver,
|
type_t* type = tysolver_try_solve_node(prepass->tysolver,
|
||||||
(node_t*) node->children.data[1]);
|
(node_t*) node->children.data[1]);
|
||||||
sym_declare(prepass->sym, name, type);
|
|
||||||
|
sym_declare(prepass->sym, name, type,
|
||||||
|
prepass->scope, SYM_PRE,
|
||||||
|
block);
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
|
|
|
@ -11,6 +11,9 @@ typedef struct {
|
||||||
sym_t* sym;
|
sym_t* sym;
|
||||||
tysolver_t* tysolver;
|
tysolver_t* tysolver;
|
||||||
err_t* err;
|
err_t* err;
|
||||||
|
|
||||||
|
int scope;
|
||||||
|
|
||||||
} prepass_t;
|
} prepass_t;
|
||||||
|
|
||||||
void prepass_init(prepass_t* prepass,
|
void prepass_init(prepass_t* prepass,
|
||||||
|
|
48
lib/sym.c
48
lib/sym.c
|
@ -29,12 +29,23 @@ void sym_free(sym_t* sym)
|
||||||
sym->entries.cap = 0;
|
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(sym);
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(type);
|
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)
|
if (sym->entries.data == NULL)
|
||||||
{
|
{
|
||||||
sym->entries.cap = 2;
|
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]->name = strdup(name);
|
||||||
sym->entries.data[sym->entries.size]->id = id;
|
sym->entries.data[sym->entries.size]->id = id;
|
||||||
sym->entries.data[sym->entries.size]->type = type;
|
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++;
|
sym->entries.size++;
|
||||||
|
|
||||||
return id;
|
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);
|
assert(sym);
|
||||||
|
|
||||||
|
sym_entry_t* res = NULL;
|
||||||
|
|
||||||
for (size_t i=0; i<sym->entries.size; i++)
|
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;
|
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++)
|
for (size_t i=0; i<sym->entries.size; i++)
|
||||||
{
|
{
|
||||||
sym_entry_t* entry = sym->entries.data[i];
|
sym_entry_t* entry = sym->entries.data[i];
|
||||||
sz += snprintf(buffer + sz, size - sz, "(%d %s ",
|
sz += snprintf(buffer + sz, size - sz, "(%d| %d %s ",
|
||||||
entry->id, entry->name);
|
entry->id, entry->scope, entry->name);
|
||||||
|
|
||||||
sz += type_str(entry->type, buffer + sz, size - sz);
|
sz += type_str(entry->type, buffer + sz, size - sz);
|
||||||
|
|
||||||
|
|
18
lib/sym.h
18
lib/sym.h
|
@ -4,11 +4,20 @@
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
#include "tysy.h"
|
#include "tysy.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SYM_PRE = 1<<1,
|
||||||
|
SYM_DECL = 1<<2,
|
||||||
|
} sym_state_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int id;
|
int id;
|
||||||
char* name;
|
char* name;
|
||||||
type_t* type;
|
type_t* type;
|
||||||
|
int scope;
|
||||||
|
sym_state_t state;
|
||||||
|
node_t* block;
|
||||||
} sym_entry_t;
|
} sym_entry_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -26,8 +35,13 @@ typedef struct {
|
||||||
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err);
|
void sym_init(sym_t* sym, tysy_t* tysy, err_t* err);
|
||||||
void sym_free(sym_t* sym);
|
void sym_free(sym_t* sym);
|
||||||
|
|
||||||
int sym_declare(sym_t* sym, char* name, type_t* type);
|
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 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);
|
size_t sym_str(sym_t* sym, char* buffer, size_t size);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ void tysolver_init(tysolver_t* tysolver, sym_t* sym, tysy_t* tysy)
|
||||||
|
|
||||||
tysolver->sym = sym;
|
tysolver->sym = sym;
|
||||||
tysolver->tysy = tysy;
|
tysolver->tysy = tysy;
|
||||||
|
tysolver->scope = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tysolver_free(tysolver_t* tysolver)
|
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)
|
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: {
|
case NODE_VARDECL: {
|
||||||
return tysolver_try_solve_node(tysolver,
|
return tysolver_try_solve_node(tysolver,
|
||||||
(node_t*) node->children.data[1]);
|
(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: {
|
case NODE_IDENT: {
|
||||||
char* name = node->value.data;
|
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);
|
assert(entry);
|
||||||
|
|
||||||
return entry->type;
|
return entry->type;
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sym_t* sym;
|
sym_t* sym;
|
||||||
tysy_t* tysy;
|
tysy_t* tysy;
|
||||||
|
|
||||||
|
int scope;
|
||||||
} tysolver_t;
|
} tysolver_t;
|
||||||
|
|
||||||
void tysolver_init(tysolver_t* tysolver, sym_t* sym, tysy_t* tysy);
|
void tysolver_init(tysolver_t* tysolver, sym_t* sym, tysy_t* tysy);
|
||||||
|
|
|
@ -1,8 +1,47 @@
|
||||||
# VARIABLE DECLARATIONS
|
# VARIABLE DECLARATIONS
|
||||||
# =====================
|
# =====================
|
||||||
# simple
|
# simple
|
||||||
let x = 35
|
let a = 35
|
||||||
assert x == 35
|
assert a == 35
|
||||||
|
|
||||||
let y = x + 2
|
let b = a + 2
|
||||||
assert y == 37
|
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
|
|
@ -156,3 +156,9 @@ Test(lexer, let_var) {
|
||||||
"ASSIGN",
|
"ASSIGN",
|
||||||
"NUM[3]");
|
"NUM[3]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(lexer, blocks) {
|
||||||
|
test_lexer("begin end", 2,
|
||||||
|
"BEGIN",
|
||||||
|
"END");
|
||||||
|
}
|
||||||
|
|
|
@ -109,3 +109,20 @@ Test(parser, var_decl) {
|
||||||
test_parser_ok("MOD(VARDECL(IDENT[bim],MUL(NUM[3],NUM[6])))",
|
test_parser_ok("MOD(VARDECL(IDENT[bim],MUL(NUM[3],NUM[6])))",
|
||||||
" let bim = 3 * 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 ");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue