ADD: while loop and break keyword.

main
bog 2023-08-26 22:45:36 +02:00
parent ba26851487
commit b9eb183319
11 changed files with 288 additions and 15 deletions

View File

@ -40,6 +40,7 @@ executable(
'src/utils.c', 'src/utils.c',
'src/opcodes.c', 'src/opcodes.c',
'src/program.c', 'src/program.c',
'src/block_info.c',
'src/value.c', 'src/value.c',
'src/array.c', 'src/array.c',

42
src/block_info.c Normal file
View File

@ -0,0 +1,42 @@
#include "block_info.h"
void block_info_init(block_info* self, int kind)
{
assert(self);
self->size = 0;
self->capacity = 1;
self->data = malloc(sizeof(info*) * self->capacity);
self->kind = kind;
}
void block_info_free(block_info* self)
{
for (size_t i=0; i<self->size; i++)
{
free(self->data[i]);
}
free(self->data);
self->size = 0;
self->capacity = 0;
self->data = NULL;
}
void block_info_push(block_info* self, size_t addr, int hint)
{
assert(self);
if (self->size >= self->capacity)
{
self->capacity *= 2;
self->data = realloc(self->data, sizeof(info*) * self->capacity);
}
self->data[self->size] = malloc(sizeof(info));
self->data[self->size]->addr = addr;
self->data[self->size]->hint = hint;
self->size++;
}

32
src/block_info.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef BLOCK_INFO_H
#define BLOCK_INFO_H
#include "commons.h"
enum BlockInfoHints {
HINT_END,
};
enum BlockInfoKind {
INFO_KIND_LOOP,
INFO_KIND_IF
};
typedef struct {
size_t addr;
int hint;
} info;
typedef struct {
size_t size;
size_t capacity;
info** data;
int kind;
} block_info;
void block_info_init(block_info* self, int kind);
void block_info_free(block_info* self);
void block_info_push(block_info* self, size_t addr, int hint);
#endif

View File

@ -7,6 +7,10 @@ void compiler_init(compiler* self)
self->sym = malloc(sizeof(symtable)); self->sym = malloc(sizeof(symtable));
symtable_init(self->sym); symtable_init(self->sym);
self->binfo.size = 0;
self->binfo.capacity = 1;
self->binfo.data = malloc(sizeof(block_info*) * self->binfo.capacity);
} }
void compiler_free(compiler* self) void compiler_free(compiler* self)
@ -16,6 +20,74 @@ void compiler_free(compiler* self)
symtable_free(self->sym); symtable_free(self->sym);
free(self->sym); free(self->sym);
self->sym = NULL; self->sym = NULL;
for (size_t i=0; i<self->binfo.size; i++)
{
block_info_free(self->binfo.data[i]);
free(self->binfo.data[i]);
}
free(self->binfo.data);
self->binfo.size = 0;
self->binfo.capacity = 0;
self->binfo.data = NULL;
}
block_info* compiler_current_info(compiler* self)
{
assert(self);
assert(self->binfo.size > 0);
return self->binfo.data[self->binfo.size - 1];
}
block_info* compiler_find_info(compiler* self, int kind)
{
assert(self);
for (size_t i=0; i<self->binfo.size; i++)
{
size_t j = self->binfo.size - 1 - i;
if (self->binfo.data[j]->kind == kind)
{
return self->binfo.data[j];
}
}
return NULL;
}
block_info* compiler_push_info(compiler* self, int kind)
{
assert(self);
if (self->binfo.size >= self->binfo.capacity)
{
self->binfo.capacity *= 2;
self->binfo.data = realloc(
self->binfo.data,
sizeof(block_info*) * self->binfo.capacity
);
}
self->binfo.data[self->binfo.size] = malloc(sizeof(block_info));
block_info_init(self->binfo.data[self->binfo.size], kind);
self->binfo.size++;
return self->binfo.data[self->binfo.size - 1];
}
void compiler_pop_info(compiler* self)
{
assert(self);
assert(self->binfo.size > 0);
block_info_free(self->binfo.data[self->binfo.size - 1]);
free(self->binfo.data[self->binfo.size - 1]);
self->binfo.size--;
} }
void compile_node(compiler* self, node* root, program* prog) void compile_node(compiler* self, node* root, program* prog)
@ -32,8 +104,52 @@ void compile_node(compiler* self, node* root, program* prog)
} }
else if (root->type == NODE_IF) else if (root->type == NODE_IF)
{ {
block_info* info = compiler_push_info(self, INFO_KIND_IF);
compile_if(self, root, prog); compile_if(self, root, prog);
program_set_mark_params(prog, prog->instrs.size);
for (size_t i=0; i<info->size; i++)
{
size_t addr = info->data[i]->addr;
int hint = info->data[i]->hint;
program_set_param(prog, addr, prog->instrs.size);
}
compiler_pop_info(self);
}
else if (root->type == NODE_WHILE)
{
block_info* bi = compiler_push_info(self, INFO_KIND_LOOP);
node* cond = root->children.data[0];
node* block = root->children.data[1];
size_t start_addr = prog->instrs.size;
compile_node(self, cond, prog);
block_info_push(bi, prog->instrs.size, HINT_END);
program_add_instr(prog, OP_BRF, 0);
compile_node(self, block, prog);
program_add_instr(prog, OP_BR, start_addr);
for (size_t i=0; i<bi->size; i++)
{
if (bi->data[i]->hint == HINT_END)
{
program_set_param(prog, bi->data[i]->addr,
prog->instrs.size);
}
}
compiler_pop_info(self);
}
else if (root->type == NODE_BREAK)
{
block_info* bi = compiler_find_info(self, INFO_KIND_LOOP);
block_info_push(bi, prog->instrs.size, HINT_END);
program_add_instr(prog, OP_BR, NO_PARAM);
} }
else if (root->type == NODE_INDEX) else if (root->type == NODE_INDEX)
{ {
@ -528,7 +644,12 @@ void compile_if(compiler* self, node* root, program* prog)
// then block // then block
node* then_block = root->children.data[1]; node* then_block = root->children.data[1];
compile_node(self, then_block, prog); compile_node(self, then_block, prog);
program_add_instr(prog, OP_BR, MARK_PARAM);
size_t to_end_addr = prog->instrs.size;
block_info* info = compiler_current_info(self);
block_info_push(info, to_end_addr, HINT_END);
program_add_instr(prog, OP_BR, NO_PARAM);
// next // next
program_set_instr(prog, cond_addr, OP_BRF, prog->instrs.size); program_set_instr(prog, cond_addr, OP_BRF, prog->instrs.size);
@ -536,7 +657,6 @@ void compile_if(compiler* self, node* root, program* prog)
if (root->children.size >= 3) if (root->children.size >= 3)
{ {
node* next_node = root->children.data[2]; node* next_node = root->children.data[2];
//char c [512]; node_str(next_node, c, 512); printf("=> %s\n", c);
compile_if(self, next_node, prog); compile_if(self, next_node, prog);
} }
} }
@ -572,3 +692,4 @@ void compile_number(compiler* self, node* root, program* prog,
cstatic_free(&cs); cstatic_free(&cs);
} }

View File

@ -5,15 +5,28 @@
#include "program.h" #include "program.h"
#include "node.h" #include "node.h"
#include "symtable.h" #include "symtable.h"
#include "block_info.h"
typedef struct { typedef struct {
symtable* sym; symtable* sym;
struct {
size_t size;
size_t capacity;
block_info** data;
} binfo;
} compiler; } compiler;
void compiler_init(compiler* self); void compiler_init(compiler* self);
void compiler_free(compiler* self); void compiler_free(compiler* self);
block_info* compiler_current_info(compiler* self);
block_info* compiler_find_info(compiler* self, int kind);
block_info* compiler_push_info(compiler* self, int kind);
void compiler_pop_info(compiler* self);
void compile_node(compiler* self, node* root, program* prog); void compile_node(compiler* self, node* root, program* prog);
void compile_children(compiler* self, node* root, program* prog); void compile_children(compiler* self, node* root, program* prog);
@ -25,4 +38,5 @@ void compile_number(compiler* self, node* root, program* prog,
void compile_if(compiler* self, node* root, program* prog); void compile_if(compiler* self, node* root, program* prog);
#endif #endif

View File

@ -25,6 +25,10 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
yylval.str = str_new(yytext); yylval.str = str_new(yytext);
return TYPE; return TYPE;
} }
"while" { return WHILE; }
"break" { return BREAK; }
"continue" { return CONTINUE; }
"if" { return IF_COND; } "if" { return IF_COND; }
"else" { return ELSE_COND; } "else" { return ELSE_COND; }
"is" { return IS; } "is" { return IS; }

View File

@ -13,7 +13,8 @@
G(NODE_ARRAY), G(NODE_INDEX), G(NODE_LT), G(NODE_LE), \ G(NODE_ARRAY), G(NODE_INDEX), G(NODE_LT), G(NODE_LE), \
G(NODE_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT), \ G(NODE_GT), G(NODE_GE), G(NODE_VARDECL), G(NODE_IDENT), \
G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO), G(NODE_IS), \ G(NODE_CONSTDECL), G(NODE_ASSIGN), G(NODE_DO), G(NODE_IS), \
G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK) G(NODE_IF), G(NODE_ELSE), G(NODE_BLOCK), \
G(NODE_WHILE), G(NODE_CONTINUE), G(NODE_BREAK)
#include "mutils.h" #include "mutils.h"

View File

@ -23,6 +23,9 @@
%token IF_COND %token IF_COND
%token ELSE_COND %token ELSE_COND
%token WHILE
%left CONTINUE
%token BREAK
%left ASSERT %left ASSERT
%token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT %token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT
%type <n_children> expr exprs prog array builtins %type <n_children> expr exprs prog array builtins
@ -82,8 +85,31 @@ exprs:
expr: expr:
BREAK {
node* n = malloc(sizeof(node));
node_init(n, NODE_BREAK, "", line);
stack_push(n);
$$ = 1;
}
| WHILE expr block END {
node* n = malloc(sizeof(node));
node_init(n, NODE_WHILE, "", line);
node* body = stack_pop();
node* condition = stack_pop();
node_add_child(n, condition);
node_add_child(n, body);
stack_push(n);
$$ = 1;
}
// TYPE OPERATORS // TYPE OPERATORS
expr IS type { | expr IS type {
node* n = malloc(sizeof(node)); node* n = malloc(sizeof(node));
node_init(n, NODE_IS, "", line); node_init(n, NODE_IS, "", line);

View File

@ -46,15 +46,12 @@ void program_set_instr(program* self, size_t index, int opcode, int param)
self->instrs.data[index]->param = param; self->instrs.data[index]->param = param;
} }
void program_set_mark_params(program* self, int param) void program_set_param(program* self, size_t index, int param)
{ {
for (size_t i=0; i<self->instrs.size; i++) assert(self);
{ assert(index < self->instrs.size);
if (self->instrs.data[i]->param == MARK_PARAM)
{ self->instrs.data[index]->param = param;
self->instrs.data[i]->param = param;
}
}
} }
size_t program_add_instr(program* self, int opcode, int param) size_t program_add_instr(program* self, int opcode, int param)

View File

@ -6,7 +6,6 @@
#include "value.h" #include "value.h"
#define NO_PARAM (-1) #define NO_PARAM (-1)
#define MARK_PARAM (-2)
typedef struct { typedef struct {
int opcode; int opcode;
@ -32,7 +31,7 @@ void program_free(program* self);
size_t program_add_instr(program* self, int opcode, int param); size_t program_add_instr(program* self, int opcode, int param);
void program_set_instr(program* self, size_t index, int opcode, int param); void program_set_instr(program* self, size_t index, int opcode, int param);
void program_set_mark_params(program* self, int param); void program_set_param(program* self, size_t index, int param);
size_t program_add_pool(program* self, value* val); size_t program_add_pool(program* self, value* val);

36
tests/test_while.wuz Normal file
View File

@ -0,0 +1,36 @@
let! a = 7
while a < 100
a = a + 1
end
assert 100 == a
let! b = 0
let! c = 0
let! d = 0
while b < 16
c = 0
while c < 16
c = c + 1
d = d + 1
end
b = b + 1
end
assert d == 256
let! e = 0
while true
e = e + 1
if e >= 17
break
end
end
assert 17 == e