From 14edad9a88787b0fec63e34ea31235f2b05731be Mon Sep 17 00:00:00 2001 From: overflowerror Date: Thu, 2 May 2024 14:28:08 +0200 Subject: [PATCH] feat: Add support for array subscripts --- compiler/src/ast.c | 14 ++++++ compiler/src/ast.h | 4 ++ compiler/src/band.c | 49 ++++++++++++++++--- compiler/src/band.h | 7 ++- compiler/src/codegen_expr.c | 10 ++++ compiler/src/parser.y | 16 +++--- compiler/src/scope.c | 8 +++ compiler/src/scope.h | 1 + .../test/cases/020c-print-array-offset.in | 4 ++ .../test/cases/020c-print-array-offset.out | 3 ++ 10 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 compiler/test/cases/020c-print-array-offset.in create mode 100644 compiler/test/cases/020c-print-array-offset.out diff --git a/compiler/src/ast.c b/compiler/src/ast.c index b2d3ef3..fd1346a 100644 --- a/compiler/src/ast.c +++ b/compiler/src/ast.c @@ -135,11 +135,25 @@ struct expression* literal_expression_array_new(size_t length, struct expression } struct expression* variable_expression_new(char* id) { + _new(expr, expression); + expr->kind = VARIABLE; + expr->type = UNKNOWN_TYPE; + expr->variable = (struct variable_expression) { + .id = id, + .is_offset = false, + .offset = 0, + }; + return expr; +} + +struct expression* variable_expression_new_offset(char* id, size_t offset) { _new(expr, expression); expr->kind = VARIABLE; expr->type = UNKNOWN_TYPE; expr->variable = (struct variable_expression) { .id = id, + .is_offset = true, + .offset = offset, }; return expr; } diff --git a/compiler/src/ast.h b/compiler/src/ast.h index abd0f38..ad212eb 100644 --- a/compiler/src/ast.h +++ b/compiler/src/ast.h @@ -2,6 +2,7 @@ #define AST_H #include +#include enum literal_kind { NUMBER_LITERAL, @@ -50,6 +51,8 @@ struct literal_expression { struct variable_expression { char* id; + bool is_offset; + size_t offset; }; struct macro_expression { @@ -147,6 +150,7 @@ struct expression* literal_expression_str_new(char*); struct expression* literal_expression_num_new(long long); struct expression* literal_expression_array_new(size_t, struct expression**); struct expression* variable_expression_new(char*); +struct expression* variable_expression_new_offset(char*, size_t); struct expression* macro_expression_new(char*, char*); struct expression* builtin_call_expression_new(void); void builtin_call_expression_add_argument(struct expression*, struct expression*); diff --git a/compiler/src/band.c b/compiler/src/band.c index b2a8384..6ffdd0f 100644 --- a/compiler/src/band.c +++ b/compiler/src/band.c @@ -60,12 +60,20 @@ size_t band_find_empty_region_index(band_t* band) { region_t* band_allocate_region(band_t* band, size_t size) { region_t* region = safe_malloc(sizeof(region_t)); - band_addr_t addr = band_find_gap(band, size); - size_t regions_index = band_find_empty_region_index(band); + size_t regions_index = band_find_empty_region_index(band); + + band_addr_t addr; + if (size != 0) { + addr = band_find_gap(band, size); + } else { + addr = 0; + } region->start = addr; region->size = size; region->index = regions_index; + region->ref_count = 1; + region->parent = NULL; band->regions[regions_index] = region; for (size_t i = 0; i < size; i++) { @@ -91,13 +99,38 @@ region_t* band_allocate_tmp(band_t* band, size_t size) { return region; } -void band_region_free(band_t* band, region_t* region) { - band->regions[region->index] = NULL; - for (size_t i = 0; i < region->size; i++) { - band->band[region->start + i] = NULL; - } +region_t* band_allocate_ref(band_t* band, region_t* parent) { + region_t* region = band_allocate_region(band, 0); + region->name = NULL; + region->is_temp = true; - free(region); + parent->ref_count++; + region->parent = parent; + + region->size = parent->size; + region->start = parent->start; + + return region; +} + +void band_region_free(band_t* band, region_t* region) { + region->ref_count--; + + if (region->ref_count == 0) { + if (region->parent == NULL) { + band->regions[region->index] = NULL; + for (size_t i = 0; i < region->size; i++) { + band->band[region->start + i] = NULL; + } + + free(region); + } else { + band_region_free(band, region->parent); + + band->regions[region->index] = NULL; + free(region); + } + } } void band_region_free_raw(band_t* band, band_addr_t addr) { diff --git a/compiler/src/band.h b/compiler/src/band.h index b1bcd3e..5b1c568 100644 --- a/compiler/src/band.h +++ b/compiler/src/band.h @@ -8,12 +8,14 @@ typedef size_t band_addr_t; -typedef struct { +typedef struct region { band_addr_t start; size_t index; size_t size; const char* name; - bool is_temp; + bool is_temp; + size_t ref_count; + struct region* parent; } region_t; typedef struct { @@ -28,6 +30,7 @@ region_t* band_region_for_addr(band_t*, band_addr_t); region_t* band_allocate(band_t*, size_t); region_t* band_allocate_tmp(band_t*, size_t); +region_t* band_allocate_ref(band_t*, region_t*); void band_region_free(band_t*, region_t*); void band_region_free_raw(band_t*, band_addr_t); diff --git a/compiler/src/codegen_expr.c b/compiler/src/codegen_expr.c index a485d40..8c21bbc 100644 --- a/compiler/src/codegen_expr.c +++ b/compiler/src/codegen_expr.c @@ -67,6 +67,16 @@ static region_t* codegen_variable_expr(FILE* _, scope_t* scope, struct variable_ fprintf(stderr, "unknown variable: %s\n", expr.id); exit(1); } + + if (expr.is_offset) { + if (expr.offset >= region->size) { + fprintf(stderr, "index out of bounds (%zu >= %zu)\n", expr.offset, region->size); + exit(1); + } + + region = scope_add_ref(scope, region, expr.offset, 1); + } + return region; } diff --git a/compiler/src/parser.y b/compiler/src/parser.y index e72811e..8c6aa42 100644 --- a/compiler/src/parser.y +++ b/compiler/src/parser.y @@ -260,6 +260,16 @@ literal: NUM | arrayliteral ; +variable: ID + { + $$ = variable_expression_new($1); + } + | ID OPENING_SQ_BRACKETS NUM CLOSING_SQ_BRACKETS + { + $$ = variable_expression_new_offset($1, $3); + } +; + arrayliteral: OPENING_SQ_BRACKETS NUM CLOSING_SQ_BRACKETS { $$ = literal_expression_array_new($2, NULL); @@ -273,12 +283,6 @@ arrayliteral: OPENING_SQ_BRACKETS NUM CLOSING_SQ_BRACKETS } ; -variable: ID - { - $$ = variable_expression_new($1); - } -; - macroexpr: ID MACRO_CONTENT { $$ = macro_expression_new($1, $2); diff --git a/compiler/src/scope.c b/compiler/src/scope.c index aa6c486..1ebbc25 100644 --- a/compiler/src/scope.c +++ b/compiler/src/scope.c @@ -46,6 +46,14 @@ region_t* scope_add_tmp(scope_t* scope, size_t size) { return region; } +region_t* scope_add_ref(scope_t* scope, region_t* parent, size_t offset, size_t size) { + region_t* region = band_allocate_ref(scope->band, parent); + region->start += offset; + region->size = size; + + return region; +} + region_t* scope_get(scope_t* scope, const char* name) { region_t* region = dict_get(scope->variables, name); diff --git a/compiler/src/scope.h b/compiler/src/scope.h index 73bc397..ad7c1b5 100644 --- a/compiler/src/scope.h +++ b/compiler/src/scope.h @@ -17,6 +17,7 @@ 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_add_ref(scope_t*, region_t*, size_t, size_t); region_t* scope_get(scope_t*, const char*); diff --git a/compiler/test/cases/020c-print-array-offset.in b/compiler/test/cases/020c-print-array-offset.in new file mode 100644 index 0000000..a6b1897 --- /dev/null +++ b/compiler/test/cases/020c-print-array-offset.in @@ -0,0 +1,4 @@ +var a = []{'a', 'b', 'c'}; + +print(a[0], '\n'); +print(a[1], '\n'); \ No newline at end of file diff --git a/compiler/test/cases/020c-print-array-offset.out b/compiler/test/cases/020c-print-array-offset.out new file mode 100644 index 0000000..e703ff4 --- /dev/null +++ b/compiler/test/cases/020c-print-array-offset.out @@ -0,0 +1,3 @@ +>>>[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]<[-<<<+>>>>+<]>[-<+>]<[-]++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]<[-<<+>>>+<]>[-<+>]<[-]+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>[-]<[-<+>>+<]>[-<+>] +<[-]++++++++++<<<.>>>. +[-]++++++++++<<.>>.