ADD: while loop and break keyword.
parent
ba26851487
commit
b9eb183319
|
@ -40,6 +40,7 @@ executable(
|
|||
'src/utils.c',
|
||||
'src/opcodes.c',
|
||||
'src/program.c',
|
||||
'src/block_info.c',
|
||||
|
||||
'src/value.c',
|
||||
'src/array.c',
|
||||
|
|
|
@ -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++;
|
||||
}
|
|
@ -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
|
127
src/compiler.c
127
src/compiler.c
|
@ -7,6 +7,10 @@ void compiler_init(compiler* self)
|
|||
self->sym = malloc(sizeof(symtable));
|
||||
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)
|
||||
|
@ -16,6 +20,74 @@ void compiler_free(compiler* self)
|
|||
symtable_free(self->sym);
|
||||
free(self->sym);
|
||||
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)
|
||||
|
@ -32,8 +104,52 @@ void compile_node(compiler* self, node* root, program* prog)
|
|||
}
|
||||
else if (root->type == NODE_IF)
|
||||
{
|
||||
block_info* info = compiler_push_info(self, INFO_KIND_IF);
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -528,7 +644,12 @@ void compile_if(compiler* self, node* root, program* prog)
|
|||
// then block
|
||||
node* then_block = root->children.data[1];
|
||||
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
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -572,3 +692,4 @@ void compile_number(compiler* self, node* root, program* prog,
|
|||
|
||||
cstatic_free(&cs);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,15 +5,28 @@
|
|||
#include "program.h"
|
||||
#include "node.h"
|
||||
#include "symtable.h"
|
||||
#include "block_info.h"
|
||||
|
||||
typedef struct {
|
||||
symtable* sym;
|
||||
|
||||
struct {
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
block_info** data;
|
||||
} binfo;
|
||||
|
||||
} compiler;
|
||||
|
||||
void compiler_init(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_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);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,10 @@ IDENT [_A-Za-z][_A-Za-z0-9]*
|
|||
yylval.str = str_new(yytext);
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
"while" { return WHILE; }
|
||||
"break" { return BREAK; }
|
||||
"continue" { return CONTINUE; }
|
||||
"if" { return IF_COND; }
|
||||
"else" { return ELSE_COND; }
|
||||
"is" { return IS; }
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
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_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"
|
||||
|
|
28
src/parser.y
28
src/parser.y
|
@ -23,6 +23,9 @@
|
|||
|
||||
%token IF_COND
|
||||
%token ELSE_COND
|
||||
%token WHILE
|
||||
%left CONTINUE
|
||||
%token BREAK
|
||||
%left ASSERT
|
||||
%token <str> TYPE BOOLEAN INTEGER FLOAT STRING IDENT
|
||||
%type <n_children> expr exprs prog array builtins
|
||||
|
@ -82,8 +85,31 @@ exprs:
|
|||
|
||||
|
||||
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
|
||||
expr IS type {
|
||||
| expr IS type {
|
||||
node* n = malloc(sizeof(node));
|
||||
node_init(n, NODE_IS, "", line);
|
||||
|
||||
|
|
|
@ -46,15 +46,12 @@ void program_set_instr(program* self, size_t index, int opcode, int 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++)
|
||||
{
|
||||
if (self->instrs.data[i]->param == MARK_PARAM)
|
||||
{
|
||||
self->instrs.data[i]->param = param;
|
||||
}
|
||||
}
|
||||
assert(self);
|
||||
assert(index < self->instrs.size);
|
||||
|
||||
self->instrs.data[index]->param = param;
|
||||
}
|
||||
|
||||
size_t program_add_instr(program* self, int opcode, int param)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "value.h"
|
||||
|
||||
#define NO_PARAM (-1)
|
||||
#define MARK_PARAM (-2)
|
||||
|
||||
typedef struct {
|
||||
int opcode;
|
||||
|
@ -32,7 +31,7 @@ void program_free(program* self);
|
|||
|
||||
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_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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue