mirror of
https://github.com/sigmasternchen/macrofuck
synced 2025-03-15 07:08:56 +00:00
refactor: Change to scope based system
This commit is contained in:
parent
f0a04a6a65
commit
19ed35d535
11 changed files with 289 additions and 154 deletions
2
Makefile
2
Makefile
|
@ -11,7 +11,7 @@ LEXFLAGS =
|
|||
PLUGINS = obj/macros/numbers.o
|
||||
OBJS = obj/lex.yy.o obj/y.tab.o obj/codegen.o obj/error.o \
|
||||
obj/ast.o obj/alloc.o obj/dict.o obj/list.o obj/band.o \
|
||||
obj/plugins.o $(PLUGINS) obj/main.o
|
||||
obj/plugins.o obj/scope.o $(PLUGINS) obj/main.o
|
||||
DEPS = $(OBJS:%.o=%.d)
|
||||
|
||||
-include $(DEPS)
|
||||
|
|
25
src/band.c
25
src/band.c
|
@ -3,14 +3,12 @@
|
|||
|
||||
#include "band.h"
|
||||
#include "list.h"
|
||||
#include "dict.h"
|
||||
#include "alloc.h"
|
||||
|
||||
band_t* band_init(void) {
|
||||
band_t* band = safe_malloc(sizeof(band_t));
|
||||
band->position = 0;
|
||||
band->regions = list_new(region_t);
|
||||
band->variables = dict_new();
|
||||
band->band = list_new(region_t);
|
||||
return band;
|
||||
}
|
||||
|
@ -24,10 +22,6 @@ region_t* band_region_for_addr(band_t* band, band_addr_t addr) {
|
|||
}
|
||||
}
|
||||
|
||||
region_t* band_region_for_var(band_t* band, const char* variable) {
|
||||
return dict_get(band->variables, variable);
|
||||
}
|
||||
|
||||
band_addr_t band_find_gap(band_t* band, size_t size) {
|
||||
size_t band_size = list_size(band->band);
|
||||
|
||||
|
@ -80,24 +74,17 @@ region_t* band_allocate_region(band_t* band, size_t size) {
|
|||
return region;
|
||||
}
|
||||
|
||||
void band_make_var(band_t* band, region_t* region, const char* variable) {
|
||||
region->variable = variable;
|
||||
region->is_temp = false;
|
||||
|
||||
dict_put(band->variables, variable, region);
|
||||
}
|
||||
|
||||
region_t* band_allocate_var(band_t* band, size_t size, const char* variable) {
|
||||
region_t* band_allocate(band_t* band, size_t size) {
|
||||
region_t* region = band_allocate_region(band, size);
|
||||
band_make_var(band, region, variable);
|
||||
region->name = NULL;
|
||||
region->is_temp = false;
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
region_t* band_allocate_tmp(band_t* band, size_t size) {
|
||||
region_t* region = band_allocate_region(band, size);
|
||||
|
||||
region->variable = NULL;
|
||||
region->name = NULL;
|
||||
region->is_temp = true;
|
||||
|
||||
return region;
|
||||
|
@ -109,10 +96,6 @@ void band_region_free(band_t* band, region_t* region) {
|
|||
band->band[region->start + i] = NULL;
|
||||
}
|
||||
|
||||
if (region->variable) {
|
||||
dict_remove(band->variables, region->variable);
|
||||
}
|
||||
|
||||
free(region);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "dict.h"
|
||||
|
||||
typedef size_t band_addr_t;
|
||||
|
||||
|
@ -13,25 +12,22 @@ typedef struct {
|
|||
band_addr_t start;
|
||||
size_t index;
|
||||
size_t size;
|
||||
const char* variable;
|
||||
const char* name;
|
||||
bool is_temp;
|
||||
} region_t;
|
||||
|
||||
typedef struct {
|
||||
size_t position;
|
||||
region_t** regions;
|
||||
dict_t* variables;
|
||||
region_t** band;
|
||||
} band_t;
|
||||
|
||||
band_t* band_init(void);
|
||||
|
||||
region_t* band_region_for_addr(band_t*, band_addr_t);
|
||||
region_t* band_region_for_var(band_t*, const char*);
|
||||
|
||||
region_t* band_allocate_var(band_t*, size_t, const char*);
|
||||
region_t* band_allocate(band_t*, size_t);
|
||||
region_t* band_allocate_tmp(band_t*, size_t);
|
||||
void band_make_var(band_t*, region_t*, const char*);
|
||||
|
||||
void band_region_free(band_t*, region_t*);
|
||||
void band_region_free_raw(band_t*, band_addr_t);
|
||||
|
|
210
src/codegen.c
210
src/codegen.c
|
@ -5,28 +5,29 @@
|
|||
#include "codegen.h"
|
||||
#include "ast.h"
|
||||
#include "band.h"
|
||||
#include "scope.h"
|
||||
#include "error.h"
|
||||
#include "plugins.h"
|
||||
|
||||
|
||||
void _move_to(FILE* out, band_t* band, size_t target) {
|
||||
while (target > band->position) {
|
||||
void _move_to(FILE* out, scope_t* scope, size_t target) {
|
||||
while (target > scope->band->position) {
|
||||
next();
|
||||
band->position++;
|
||||
scope->band->position++;
|
||||
}
|
||||
while (target < band->position) {
|
||||
while (target < scope->band->position) {
|
||||
prev();
|
||||
band->position--;
|
||||
scope->band->position--;
|
||||
}
|
||||
}
|
||||
|
||||
void _copy(FILE* out, band_t* band, region_t* source, region_t* target) {
|
||||
void _copy(FILE* out, scope_t* scope, region_t* source, region_t* target) {
|
||||
size_t size = source->size;
|
||||
if (target->size < size) {
|
||||
size = target->size;
|
||||
}
|
||||
|
||||
region_t* tmp = band_allocate_tmp(band, size);
|
||||
region_t* tmp = scope_add_tmp(scope, size);
|
||||
move_to(tmp); reset();
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
|
@ -48,41 +49,41 @@ void _copy(FILE* out, band_t* band, region_t* source, region_t* target) {
|
|||
});
|
||||
}
|
||||
|
||||
band_region_free(band, tmp);
|
||||
scope_remove(scope, tmp);
|
||||
}
|
||||
|
||||
region_t* _clone(FILE* out, band_t* band, region_t* region) {
|
||||
region_t* clone = band_allocate_tmp(band, region->size);
|
||||
region_t* _clone(FILE* out, scope_t* scope, region_t* region) {
|
||||
region_t* clone = scope_add_tmp(scope, region->size);
|
||||
move_to(clone); reset();
|
||||
copy(region, clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
static void region_used(band_t* band, region_t* region) {
|
||||
static void region_used(scope_t* scope, region_t* region) {
|
||||
if (region->is_temp) {
|
||||
band_region_free(band, region);
|
||||
scope_remove(scope, region);
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_position(FILE* out, band_t* band, band_addr_t position) {
|
||||
static void reset_position(FILE* out, scope_t* scope, band_addr_t position) {
|
||||
move(position);
|
||||
reset();
|
||||
}
|
||||
|
||||
static void reset_region(FILE* out, band_t* band, region_t* region) {
|
||||
static void reset_region(FILE* out, scope_t* scope, region_t* region) {
|
||||
for (size_t i = 0; i < region->size; i++) {
|
||||
reset_position(out, band, region->start + i);
|
||||
reset_position(out, scope, region->start + i);
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_add_char(FILE* out, band_t* band, size_t position, char c) {
|
||||
void codegen_add_char(FILE* out, scope_t* scope, size_t position, char c) {
|
||||
move(position);
|
||||
reset();
|
||||
add(c);
|
||||
}
|
||||
|
||||
region_t* codegen_literal_expr(FILE* out, band_t* band, struct literal_expression expr) {
|
||||
region_t* codegen_literal_expr(FILE* out, scope_t* scope, struct literal_expression expr) {
|
||||
region_t* region = NULL;
|
||||
switch(expr.kind) {
|
||||
case NUMBER_LITERAL:
|
||||
|
@ -90,19 +91,19 @@ region_t* codegen_literal_expr(FILE* out, band_t* band, struct literal_expressio
|
|||
fprintf(stderr, "literal %lld greater than 255\n", expr.number);
|
||||
panic("number literal too big");
|
||||
}
|
||||
region = band_allocate_tmp(band, 1);
|
||||
region = scope_add_tmp(scope, 1);
|
||||
move_to(region);
|
||||
reset(); add(expr.number);
|
||||
break;
|
||||
case CHAR_LITERAL:
|
||||
region = band_allocate_tmp(band, 1);
|
||||
codegen_add_char(out, band, region->start, expr.ch);
|
||||
region = scope_add_tmp(scope, 1);
|
||||
codegen_add_char(out, scope, region->start, expr.ch);
|
||||
break;
|
||||
case STRING_LITERAL: {
|
||||
size_t l = strlen(expr.str); // don't copy \0
|
||||
region = band_allocate_tmp(band, strlen(expr.str));
|
||||
region = scope_add_tmp(scope, strlen(expr.str));
|
||||
for (size_t i = 0; i < l; i++) {
|
||||
codegen_add_char(out, band, region->start + i, expr.str[i]);
|
||||
codegen_add_char(out, scope, region->start + i, expr.str[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -113,8 +114,8 @@ region_t* codegen_literal_expr(FILE* out, band_t* band, struct literal_expressio
|
|||
return region;
|
||||
}
|
||||
|
||||
region_t* codegen_variable_expr(FILE* _, band_t* band, struct variable_expression expr) {
|
||||
region_t* region = band_region_for_var(band, expr.id);
|
||||
region_t* codegen_variable_expr(FILE* _, scope_t* scope, struct variable_expression expr) {
|
||||
region_t* region = scope_get(scope, expr.id);
|
||||
if (!region) {
|
||||
fprintf(stderr, "unknown variable: %s\n", expr.id);
|
||||
exit(1);
|
||||
|
@ -122,12 +123,12 @@ region_t* codegen_variable_expr(FILE* _, band_t* band, struct variable_expressio
|
|||
return region;
|
||||
}
|
||||
|
||||
region_t* codegen_macro_expr(FILE* out, band_t* band, struct macro_expression expr) {
|
||||
region_t* codegen_macro_expr(FILE* out, scope_t* scope, struct macro_expression expr) {
|
||||
macro_t macro = find_macro(expr.id);
|
||||
return macro(out, band, expr.argument);
|
||||
return macro(out, scope, expr.argument);
|
||||
}
|
||||
|
||||
region_t* codegen_expr(FILE*, band_t*, struct expression*);
|
||||
region_t* codegen_expr(FILE*, scope_t*, struct expression*);
|
||||
|
||||
#define swap_or_clone(result, op1, op2, allow_swap) \
|
||||
if (op1->is_temp) { \
|
||||
|
@ -147,10 +148,10 @@ region_t* codegen_expr(FILE*, band_t*, struct expression*);
|
|||
}
|
||||
|
||||
#define calc_postfix() \
|
||||
band_region_free(band, op2); \
|
||||
scope_remove(scope, op2); \
|
||||
return result;
|
||||
|
||||
region_t* codegen_addition(FILE* out, band_t* band, region_t* op1, region_t* op2) {
|
||||
region_t* codegen_addition(FILE* out, scope_t* scope, region_t* op1, region_t* op2) {
|
||||
calc_prefix(true);
|
||||
|
||||
move_to(op2);
|
||||
|
@ -162,7 +163,7 @@ region_t* codegen_addition(FILE* out, band_t* band, region_t* op1, region_t* op2
|
|||
|
||||
calc_postfix();
|
||||
}
|
||||
region_t* codegen_subtraction(FILE* out, band_t* band, region_t* op1, region_t* op2) {
|
||||
region_t* codegen_subtraction(FILE* out, scope_t* scope, region_t* op1, region_t* op2) {
|
||||
calc_prefix(false);
|
||||
|
||||
move_to(op2);
|
||||
|
@ -174,7 +175,7 @@ region_t* codegen_subtraction(FILE* out, band_t* band, region_t* op1, region_t*
|
|||
|
||||
calc_postfix();
|
||||
}
|
||||
region_t* codegen_multiplication(FILE* out, band_t* band, region_t* op1, region_t* op2) {
|
||||
region_t* codegen_multiplication(FILE* out, scope_t* scope, region_t* op1, region_t* op2) {
|
||||
calc_prefix(true);
|
||||
|
||||
// make sure to not change op1
|
||||
|
@ -198,12 +199,12 @@ region_t* codegen_multiplication(FILE* out, band_t* band, region_t* op1, region_
|
|||
move_to(op2);
|
||||
});
|
||||
|
||||
band_region_free(band, tmp);
|
||||
band_region_free(band, op1);
|
||||
scope_remove(scope, tmp);
|
||||
scope_remove(scope, op1);
|
||||
|
||||
calc_postfix();
|
||||
}
|
||||
region_t* codegen_division(FILE* out, band_t* band, region_t* op1, region_t* op2) {
|
||||
region_t* codegen_division(FILE* out, scope_t* scope, region_t* op1, region_t* op2) {
|
||||
if (!op1->is_temp) {
|
||||
op1 = clone(op1);
|
||||
}
|
||||
|
@ -211,16 +212,16 @@ region_t* codegen_division(FILE* out, band_t* band, region_t* op1, region_t* op2
|
|||
op2 = clone(op2);
|
||||
}
|
||||
|
||||
region_t* result = band_allocate_tmp(band, 1);
|
||||
region_t* result = scope_add_tmp(scope, 1);
|
||||
move_to(result); reset();
|
||||
|
||||
region_t* tmp = band_allocate_tmp(band, 1);
|
||||
region_t* tmp = scope_add_tmp(scope, 1);
|
||||
move_to(tmp); reset();
|
||||
copy(op2, tmp);
|
||||
|
||||
region_t* tmp2 = band_allocate_tmp(band, 1);
|
||||
region_t* tmp2 = scope_add_tmp(scope, 1);
|
||||
|
||||
region_t* flag = band_allocate_tmp(band, 1);
|
||||
region_t* flag = scope_add_tmp(scope, 1);
|
||||
|
||||
move_to(op1);
|
||||
loop({
|
||||
|
@ -248,14 +249,14 @@ region_t* codegen_division(FILE* out, band_t* band, region_t* op1, region_t* op2
|
|||
move_to(op1);
|
||||
});
|
||||
|
||||
band_region_free(band, flag);
|
||||
band_region_free(band, tmp2);
|
||||
band_region_free(band, tmp);
|
||||
band_region_free(band, op1);
|
||||
band_region_free(band, op2);
|
||||
scope_remove(scope, flag);
|
||||
scope_remove(scope, tmp2);
|
||||
scope_remove(scope, tmp);
|
||||
scope_remove(scope, op1);
|
||||
scope_remove(scope, op2);
|
||||
return result;
|
||||
}
|
||||
region_t* codegen_modulo(FILE* out, band_t* band, region_t* op1, region_t* op2) {
|
||||
region_t* codegen_modulo(FILE* out, scope_t* scope, region_t* op1, region_t* op2) {
|
||||
if (!op1->is_temp) {
|
||||
op1 = clone(op1);
|
||||
}
|
||||
|
@ -263,13 +264,13 @@ region_t* codegen_modulo(FILE* out, band_t* band, region_t* op1, region_t* op2)
|
|||
op2 = clone(op2);
|
||||
}
|
||||
|
||||
region_t* tmp = band_allocate_tmp(band, 1);
|
||||
region_t* tmp = scope_add_tmp(scope, 1);
|
||||
move_to(tmp); reset();
|
||||
copy(op2, tmp);
|
||||
|
||||
region_t* tmp2 = band_allocate_tmp(band, 1);
|
||||
region_t* tmp2 = scope_add_tmp(scope, 1);
|
||||
|
||||
region_t* flag = band_allocate_tmp(band, 1);
|
||||
region_t* flag = scope_add_tmp(scope, 1);
|
||||
|
||||
move_to(op1);
|
||||
loop({
|
||||
|
@ -314,34 +315,34 @@ region_t* codegen_modulo(FILE* out, band_t* band, region_t* op1, region_t* op2)
|
|||
move_to(tmp);
|
||||
});
|
||||
|
||||
band_region_free(band, flag);
|
||||
band_region_free(band, tmp2);
|
||||
band_region_free(band, tmp);
|
||||
band_region_free(band, op2);
|
||||
scope_remove(scope, flag);
|
||||
scope_remove(scope, tmp2);
|
||||
scope_remove(scope, tmp);
|
||||
scope_remove(scope, op2);
|
||||
return op1;
|
||||
}
|
||||
|
||||
region_t* codegen_calc_expr(FILE* out, band_t* band, struct calc_expression expr) {
|
||||
region_t* operand1 = codegen_expr(out, band, expr.operand1);
|
||||
region_t* operand2 = codegen_expr(out, band, expr.operand2);
|
||||
region_t* codegen_calc_expr(FILE* out, scope_t* scope, struct calc_expression expr) {
|
||||
region_t* operand1 = codegen_expr(out, scope, expr.operand1);
|
||||
region_t* operand2 = codegen_expr(out, scope, expr.operand2);
|
||||
|
||||
region_t* result;
|
||||
|
||||
switch (expr.operator) {
|
||||
case ADDITION:
|
||||
result = codegen_addition(out, band, operand1, operand2);
|
||||
result = codegen_addition(out, scope, operand1, operand2);
|
||||
break;
|
||||
case SUBTRACTION:
|
||||
result = codegen_subtraction(out, band, operand1, operand2);
|
||||
result = codegen_subtraction(out, scope, operand1, operand2);
|
||||
break;
|
||||
case MULTIPLICATION:
|
||||
result = codegen_multiplication(out, band, operand1, operand2);
|
||||
result = codegen_multiplication(out, scope, operand1, operand2);
|
||||
break;
|
||||
case DIVISION:
|
||||
result = codegen_division(out, band, operand1, operand2);
|
||||
result = codegen_division(out, scope, operand1, operand2);
|
||||
break;
|
||||
case MODULO:
|
||||
result = codegen_modulo(out, band, operand1, operand2);
|
||||
result = codegen_modulo(out, scope, operand1, operand2);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown operator: %d\n", expr.operator);
|
||||
|
@ -351,16 +352,16 @@ region_t* codegen_calc_expr(FILE* out, band_t* band, struct calc_expression expr
|
|||
return result;
|
||||
}
|
||||
|
||||
region_t* codegen_expr(FILE* out, band_t* band, struct expression* expr) {
|
||||
region_t* codegen_expr(FILE* out, scope_t* scope, struct expression* expr) {
|
||||
switch(expr->kind) {
|
||||
case LITERAL:
|
||||
return codegen_literal_expr(out, band, expr->literal);
|
||||
return codegen_literal_expr(out, scope, expr->literal);
|
||||
case VARIABLE:
|
||||
return codegen_variable_expr(out, band, expr->variable);
|
||||
return codegen_variable_expr(out, scope, expr->variable);
|
||||
case MACRO:
|
||||
return codegen_macro_expr(out, band, expr->macro);
|
||||
return codegen_macro_expr(out, scope, expr->macro);
|
||||
case CALCULATION:
|
||||
return codegen_calc_expr(out, band, expr->calc);
|
||||
return codegen_calc_expr(out, scope, expr->calc);
|
||||
default:
|
||||
fprintf(stderr, "expression kind: %d\n", expr->kind);
|
||||
panic("unknown expression kind");
|
||||
|
@ -368,8 +369,8 @@ region_t* codegen_expr(FILE* out, band_t* band, struct expression* expr) {
|
|||
}
|
||||
}
|
||||
|
||||
void codegen_print_statement(FILE* out, band_t* band, struct print_statement statement) {
|
||||
region_t* region = codegen_expr(out, band, statement.value);
|
||||
void codegen_print_statement(FILE* out, scope_t* scope, struct print_statement statement) {
|
||||
region_t* region = codegen_expr(out, scope, statement.value);
|
||||
move_to(region);
|
||||
|
||||
output();
|
||||
|
@ -377,18 +378,18 @@ void codegen_print_statement(FILE* out, band_t* band, struct print_statement sta
|
|||
next();
|
||||
output();
|
||||
}
|
||||
band->position += region->size - 1;
|
||||
scope->band->position += region->size - 1;
|
||||
|
||||
region_used(band, region);
|
||||
region_used(scope, region);
|
||||
}
|
||||
|
||||
region_t* clone_region(FILE* out, band_t* band, region_t* original) {
|
||||
region_t* tmp = band_allocate_tmp(band, 1);
|
||||
region_t* clone = band_allocate_tmp(band, original->size);
|
||||
region_t* clone_region(FILE* out, scope_t* scope, region_t* original) {
|
||||
region_t* tmp = scope_add_tmp(scope, 1);
|
||||
region_t* clone = scope_add_tmp(scope, original->size);
|
||||
|
||||
reset_position(out, band, tmp->start);
|
||||
reset_position(out, scope, tmp->start);
|
||||
for (size_t i = 0; i < original->size; i++) {
|
||||
reset_position(out, band, clone->start + i);
|
||||
reset_position(out, scope, clone->start + i);
|
||||
|
||||
move_offset(original, i);
|
||||
loop({
|
||||
|
@ -409,13 +410,13 @@ region_t* clone_region(FILE* out, band_t* band, region_t* original) {
|
|||
});
|
||||
}
|
||||
|
||||
band_region_free(band, tmp);
|
||||
scope_remove(scope, tmp);
|
||||
return clone;
|
||||
}
|
||||
|
||||
void codegen_assignment_statement(FILE* out, band_t* band, struct assignment_statement statement) {
|
||||
region_t* region = codegen_expr(out, band, statement.value);
|
||||
region_t* var = band_region_for_var(band, statement.id);
|
||||
void codegen_assignment_statement(FILE* out, scope_t* scope, struct assignment_statement statement) {
|
||||
region_t* region = codegen_expr(out, scope, statement.value);
|
||||
region_t* var = scope_get(scope, statement.id);
|
||||
if (!var) {
|
||||
fprintf(stderr, "variable not found: %s\n", statement.id);
|
||||
panic("unknown variable");
|
||||
|
@ -424,42 +425,42 @@ void codegen_assignment_statement(FILE* out, band_t* band, struct assignment_sta
|
|||
move_to(var); reset();
|
||||
copy(region, var);
|
||||
|
||||
region_used(band, region);
|
||||
region_used(scope, region);
|
||||
}
|
||||
|
||||
void codegen_decl_statement(FILE* out, band_t* band, struct assignment_statement statement) {
|
||||
if (band_region_for_var(band, statement.id)) {
|
||||
void codegen_decl_statement(FILE* out, scope_t* scope, struct assignment_statement statement) {
|
||||
if (scope_get(scope, statement.id)) {
|
||||
fprintf(stderr, "variable exists: %s\n", statement.id);
|
||||
panic("variable exists");
|
||||
}
|
||||
|
||||
region_t* region = codegen_expr(out, band, statement.value);
|
||||
region_t* region = codegen_expr(out, scope, statement.value);
|
||||
|
||||
if (!region->is_temp) {
|
||||
region = clone_region(out, band, region);
|
||||
region = clone_region(out, scope, region);
|
||||
}
|
||||
|
||||
band_make_var(band, region, statement.id);
|
||||
scope_existing(scope, region, statement.id);
|
||||
}
|
||||
|
||||
void codegen_macro_statement(FILE* out, band_t* band, struct macro_statement statement) {
|
||||
region_t* region = codegen_expr(out, band, statement.expr);
|
||||
void codegen_macro_statement(FILE* out, scope_t* scope, struct macro_statement statement) {
|
||||
region_t* region = codegen_expr(out, scope, statement.expr);
|
||||
if (region->is_temp) {
|
||||
band_region_free(band, region);
|
||||
scope_remove(scope, region);
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_block(FILE*, band_t*, struct block*);
|
||||
void codegen_block(FILE*, scope_t*, struct block*);
|
||||
|
||||
void codegen_if_statement(FILE* out, band_t* band, struct if_statement statement) {
|
||||
region_t* condition = codegen_expr(out, band, statement.condition);
|
||||
void codegen_if_statement(FILE* out, scope_t* scope, struct if_statement statement) {
|
||||
region_t* condition = codegen_expr(out, scope, statement.condition);
|
||||
if (!condition->is_temp) {
|
||||
condition = clone(condition);
|
||||
}
|
||||
|
||||
region_t *inverse_condition = NULL;
|
||||
if (statement.else_block) {
|
||||
inverse_condition = band_allocate_tmp(band, 1);
|
||||
inverse_condition = scope_add_tmp(scope, 1);
|
||||
move_to(inverse_condition); reset(); inc();
|
||||
}
|
||||
|
||||
|
@ -469,7 +470,7 @@ void codegen_if_statement(FILE* out, band_t* band, struct if_statement statement
|
|||
move_to(inverse_condition); reset();
|
||||
}
|
||||
|
||||
codegen_block(out, band, statement.if_block);
|
||||
codegen_block(out, scope, statement.if_block);
|
||||
|
||||
move_to(condition); reset();
|
||||
});
|
||||
|
@ -477,33 +478,33 @@ void codegen_if_statement(FILE* out, band_t* band, struct if_statement statement
|
|||
if (inverse_condition) {
|
||||
move_to(inverse_condition);
|
||||
loop({
|
||||
codegen_block(out, band, statement.else_block);
|
||||
codegen_block(out, scope, statement.else_block);
|
||||
|
||||
move_to(inverse_condition); reset();
|
||||
});
|
||||
|
||||
band_region_free(band, inverse_condition);
|
||||
scope_remove(scope, inverse_condition);
|
||||
}
|
||||
|
||||
band_region_free(band, condition);
|
||||
scope_remove(scope, condition);
|
||||
}
|
||||
|
||||
void codegen_statement(FILE* out, band_t* band, struct statement* statement) {
|
||||
void codegen_statement(FILE* out, scope_t* scope, struct statement* statement) {
|
||||
switch(statement->kind) {
|
||||
case PRINT_STATEMENT:
|
||||
codegen_print_statement(out, band, statement->print);
|
||||
codegen_print_statement(out, scope, statement->print);
|
||||
break;
|
||||
case DECL_STATEMENT:
|
||||
codegen_decl_statement(out, band, statement->assignment);
|
||||
codegen_decl_statement(out, scope, statement->assignment);
|
||||
break;
|
||||
case ASSIGNMENT_STATEMENT:
|
||||
codegen_assignment_statement(out, band, statement->assignment);
|
||||
codegen_assignment_statement(out, scope, statement->assignment);
|
||||
break;
|
||||
case MACRO_STATEMENT:
|
||||
codegen_macro_statement(out, band, statement->macro);
|
||||
codegen_macro_statement(out, scope, statement->macro);
|
||||
break;
|
||||
case IF_STATEMENT:
|
||||
codegen_if_statement(out, band, statement->if_else);
|
||||
codegen_if_statement(out, scope, statement->if_else);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "statement kind: %d\n", statement->kind);
|
||||
|
@ -527,26 +528,27 @@ void check_allocations(band_t* band) {
|
|||
if (region->is_temp) {
|
||||
fprintf(stderr, "[anonymous] (this is a bug in the compiler; %zu)\n", region->start);
|
||||
} else {
|
||||
fprintf(stderr, "variable %s\n", region->variable);
|
||||
fprintf(stderr, "variable %s\n", region->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_block(FILE* out, band_t* band, struct block* block) {
|
||||
void codegen_block(FILE* out, scope_t* scope, struct block* block) {
|
||||
if (block == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < block->length; i++) {
|
||||
codegen_statement(out, band, block->statements[i]);
|
||||
codegen_statement(out, scope, block->statements[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int codegen(FILE* out, struct block* program) {
|
||||
band_t* band = band_init();
|
||||
scope_t* global = scope_init(band);
|
||||
|
||||
codegen_block(out, band, program);
|
||||
codegen_block(out, global, program);
|
||||
|
||||
check_allocations(band);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "ast.h"
|
||||
#include "band.h"
|
||||
#include "scope.h"
|
||||
|
||||
#define next() fprintf(out, ">")
|
||||
#define prev() fprintf(out, "<")
|
||||
|
@ -16,16 +17,16 @@
|
|||
#define add(v) { for (int _i = 0; _i < v; _i++) inc(); }
|
||||
#define sub(v) { for (int _i = 0; _i < v; _i++) dec(); }
|
||||
|
||||
#define move(t) _move_to(out, band, t)
|
||||
#define move(t) _move_to(out, scope, t)
|
||||
#define move_to(r) move(r->start)
|
||||
#define move_offset(r, o) move(r->start + o)
|
||||
|
||||
#define copy(s, t) _copy(out, band, s, t)
|
||||
#define clone(s) _clone(out, band, s)
|
||||
#define copy(s, t) _copy(out, scope, s, t)
|
||||
#define clone(s) _clone(out, scope, s)
|
||||
|
||||
void _move_to(FILE*, band_t*, size_t);
|
||||
void _copy(FILE*, band_t*, region_t*, region_t*);
|
||||
region_t* _clone(FILE*, band_t*, region_t*);
|
||||
void _move_to(FILE*, scope_t*, size_t);
|
||||
void _copy(FILE*, scope_t*, region_t*, region_t*);
|
||||
region_t* _clone(FILE*, scope_t*, region_t*);
|
||||
|
||||
int codegen(FILE*, struct block*);
|
||||
|
||||
|
|
42
src/dict.c
42
src/dict.c
|
@ -106,3 +106,45 @@ void dict_remove(dict_t* dict, const char* key) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct dict_pair* get_next(dict_t* dict, size_t bucket, size_t index) {
|
||||
for (size_t i = bucket; i < NUMBER_OF_BUCKETS; i++) {
|
||||
size_t bucket_size = list_size(dict->buckets[i]);
|
||||
|
||||
if (i == bucket && bucket_size > index) {
|
||||
return dict->buckets[i] + index;
|
||||
} else if (bucket_size > 0) {
|
||||
return dict->buckets[i] + 0;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dict_pair* dict_iterate(dict_t* dict, struct dict_pair* last) {
|
||||
if (!last) {
|
||||
return get_next(dict, 0, 0);
|
||||
} else {
|
||||
uintptr_t last_ptr = (uintptr_t) last;
|
||||
for (size_t i = 0; i < NUMBER_OF_BUCKETS; i++) {
|
||||
uintptr_t bucket_ptr = (uintptr_t) dict->buckets[i];
|
||||
size_t bucket_size = list_size(dict->buckets[i]);
|
||||
|
||||
if (
|
||||
// probably undefined behaviour, but I'm too lazy to do it properly
|
||||
last_ptr >= bucket_ptr &&
|
||||
last_ptr < bucket_ptr + bucket_size * sizeof(struct dict_pair)
|
||||
) {
|
||||
return get_next(dict, i, (last_ptr - bucket_ptr) / sizeof(struct dict_pair));
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void dict_free(dict_t* dict) {
|
||||
for (size_t i = 0; i < NUMBER_OF_BUCKETS; i++) {
|
||||
list_free(dict->buckets[i]);
|
||||
}
|
||||
|
||||
free(dict);
|
||||
}
|
||||
|
|
|
@ -23,12 +23,19 @@ typedef struct {
|
|||
} dict_t;
|
||||
|
||||
dict_t* dict_new(void);
|
||||
|
||||
void dict_put(dict_t*, const char*, void*);
|
||||
void dict_puti(dict_t*, const char*, long long);
|
||||
|
||||
bool dict_has(dict_t*, const char*);
|
||||
|
||||
void* dict_get(dict_t*, const char*);
|
||||
long long dict_geti(dict_t*, const char*);
|
||||
|
||||
void dict_remove(dict_t*, const char*);
|
||||
|
||||
struct dict_pair* dict_iterate(dict_t*, struct dict_pair*);
|
||||
|
||||
void dict_free(dict_t*);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
#include "../band.h"
|
||||
#include "../scope.h"
|
||||
#include "../error.h"
|
||||
#include "../codegen.h"
|
||||
|
||||
extern region_t* to_str(FILE* out, band_t* band, const char* _arg) {
|
||||
region_t* arg = band_region_for_var(band, _arg);
|
||||
extern region_t* to_str(FILE* out, scope_t* scope, const char* _arg) {
|
||||
region_t* arg = scope_get(scope, _arg);
|
||||
if (!arg) {
|
||||
panic("argument has to be a variable");
|
||||
}
|
||||
|
||||
region_t* str = band_allocate_tmp(band, 3);
|
||||
region_t* str = scope_add_tmp(scope, 3);
|
||||
for (size_t i = 0; i < str->size; i++) {
|
||||
move_offset(str, i); reset();
|
||||
}
|
||||
|
||||
region_t* copy = band_allocate_tmp(band, 1);
|
||||
region_t* copy = scope_add_tmp(scope, 1);
|
||||
move_to(copy); reset();
|
||||
|
||||
region_t* ten = band_allocate_tmp(band, 1);
|
||||
region_t* ten = scope_add_tmp(scope, 1);
|
||||
move_to(ten); reset(); add(10);
|
||||
|
||||
region_t* tmp = band_allocate_tmp(band, 1);
|
||||
region_t* tmp = scope_add_tmp(scope, 1);
|
||||
move_to(tmp); reset();
|
||||
region_t* tmp2 = band_allocate_tmp(band, 1);
|
||||
region_t* tmp2 = scope_add_tmp(scope, 1);
|
||||
move_to(tmp2); reset();
|
||||
region_t* tmp3 = band_allocate_tmp(band, 1);
|
||||
region_t* tmp3 = scope_add_tmp(scope, 1);
|
||||
|
||||
move_to(arg);
|
||||
loop({
|
||||
|
@ -112,11 +112,11 @@ extern region_t* to_str(FILE* out, band_t* band, const char* _arg) {
|
|||
move_offset(str, i); add('0');
|
||||
}
|
||||
|
||||
band_region_free(band, tmp3);
|
||||
band_region_free(band, tmp2);
|
||||
band_region_free(band, tmp);
|
||||
band_region_free(band, ten);
|
||||
band_region_free(band, copy);
|
||||
scope_remove(scope, tmp3);
|
||||
scope_remove(scope, tmp2);
|
||||
scope_remove(scope, tmp);
|
||||
scope_remove(scope, ten);
|
||||
scope_remove(scope, copy);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "band.h"
|
||||
#include "scope.h"
|
||||
|
||||
typedef region_t* (*macro_t)(FILE*, band_t*, const char*);
|
||||
typedef region_t* (*macro_t)(FILE*, scope_t*, const char*);
|
||||
|
||||
void add_plugin(const char*);
|
||||
void load_plugins(void);
|
||||
|
|
79
src/scope.c
Normal file
79
src/scope.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "scope.h"
|
||||
#include "band.h"
|
||||
#include "alloc.h"
|
||||
#include "dict.h"
|
||||
|
||||
scope_t* scope_init(band_t* band) {
|
||||
scope_t* root = scope_new(NULL);
|
||||
root->band = band;
|
||||
return root;
|
||||
}
|
||||
|
||||
scope_t* scope_new(scope_t* parent) {
|
||||
scope_t* scope = safe_malloc(sizeof (scope_t));
|
||||
scope->parent = parent;
|
||||
if (parent) {
|
||||
scope->band = parent->band;
|
||||
}
|
||||
scope->variables = dict_new();
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
region_t* scope_add(scope_t* scope, const char* name, size_t size) {
|
||||
region_t* region = band_allocate(scope->band, size);
|
||||
region->name = name;
|
||||
dict_put(scope->variables, name, region);
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
region_t* scope_existing(scope_t* scope, region_t* region, const char* name) {
|
||||
region->name = name;
|
||||
region->is_temp = false;
|
||||
|
||||
dict_put(scope->variables, name, region);
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
region_t* scope_add_tmp(scope_t* scope, size_t size) {
|
||||
region_t* region = band_allocate_tmp(scope->band, size);
|
||||
return region;
|
||||
}
|
||||
|
||||
region_t* scope_get(scope_t* scope, const char* name) {
|
||||
region_t* region = dict_get(scope->variables, name);
|
||||
|
||||
if (!region) {
|
||||
if (scope->parent) {
|
||||
return scope_get(scope->parent, name);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return region;
|
||||
}
|
||||
}
|
||||
|
||||
void scope_remove(scope_t* scope, region_t* region) {
|
||||
if (region->name) {
|
||||
dict_remove(scope->variables, region->name);
|
||||
}
|
||||
|
||||
band_region_free(scope->band, region);
|
||||
}
|
||||
|
||||
void scope_free(scope_t* scope) {
|
||||
struct dict_pair* current = NULL;
|
||||
while ((current = dict_iterate(scope->variables, current)) != NULL) {
|
||||
band_region_free(scope->band, current->ptr);
|
||||
}
|
||||
|
||||
dict_free(scope->variables);
|
||||
|
||||
free(scope);
|
||||
}
|
25
src/scope.h
Normal file
25
src/scope.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef SCOPE_H
|
||||
#define SCOPE_H
|
||||
|
||||
#include "dict.h"
|
||||
#include "band.h"
|
||||
|
||||
typedef struct scope {
|
||||
struct scope* parent;
|
||||
band_t* band;
|
||||
dict_t* variables;
|
||||
} scope_t;
|
||||
|
||||
scope_t* scope_init(band_t*);
|
||||
scope_t* scope_new(scope_t*);
|
||||
|
||||
region_t* scope_add(scope_t*, const char*, size_t);
|
||||
region_t* scope_existing(scope_t*, region_t*, const char*);
|
||||
region_t* scope_add_tmp(scope_t*, size_t);
|
||||
|
||||
region_t* scope_get(scope_t*, const char*);
|
||||
|
||||
void scope_remove(scope_t*, region_t*);
|
||||
void scope_free(scope_t*);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue