ADD: while loop and break keyword.
parent
ba26851487
commit
b9eb183319
|
@ -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',
|
||||||
|
|
|
@ -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));
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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"
|
||||||
|
|
28
src/parser.y
28
src/parser.y
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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