diff --git a/bang/examples/rule110.bang b/bang/examples/rule110.bang index 2ed85e4..a0471cb 100644 --- a/bang/examples/rule110.bang +++ b/bang/examples/rule110.bang @@ -11,11 +11,6 @@ var state_next: i64; var display_base: ptr; -var i: i64; -var j: i64; -var cell_ptr: ptr; -var cell: u8; - proc init() { # Init lookup table table_base = heap_base; @@ -40,6 +35,7 @@ proc init() { } proc print_state_current() { + var i: u64; i = 0; while i < state_size { cell_ptr = states_base + cast(ptr, state_current * state_size + i); diff --git a/bang/src/bang.c b/bang/src/bang.c index 73a0e6c..d9f46de 100644 --- a/bang/src/bang.c +++ b/bang/src/bang.c @@ -103,15 +103,23 @@ int main(int argc, char **argv) Bang_Lexer lexer = bang_lexer_from_sv(content, input_file_path); Bang_Module module = parse_bang_module(&basm.arena, &lexer); - Bang bang = {0}; + static Bang bang = {0}; bang.write_id = basm_push_external_native(&basm, SV("write")); - compile_bang_module_into_basm(&bang, &basm, module); - bang_generate_entry_point(&bang, &basm, SV("main")); - bang_generate_heap_base(&bang, &basm, SV("heap_base")); - assert(basm.has_entry); - basm_save_to_file_as_target(&basm, output_file_path, output_target); + bang_prepare_var_stack(&bang, &basm); + + bang_push_new_scope(&bang); + { + compile_bang_module_into_basm(&bang, &basm, module); + + bang_generate_entry_point(&bang, &basm, SV("main")); + bang_generate_heap_base(&bang, &basm, SV("heap_base")); + assert(basm.has_entry); + basm_save_to_file_as_target(&basm, output_file_path, output_target); + } + bang_pop_scope(&bang); arena_free(&basm.arena); + arena_free(&bang.arena); return 0; } diff --git a/bang/src/bang_compiler.c b/bang/src/bang_compiler.c index fda42ac..d3d5160 100644 --- a/bang/src/bang_compiler.c +++ b/bang/src/bang_compiler.c @@ -2,6 +2,13 @@ // TODO(#426): bang does not support type casting +#define UNIMPLEMENTED \ + do { \ + fprintf(stderr, "%s:%d: %s is not implemented yet\n", \ + __FILE__, __LINE__, __func__); \ + abort(); \ + } while(0) + typedef struct { bool exists; Inst_Type inst; @@ -130,7 +137,7 @@ void compile_typed_write(Basm *basm, Bang_Type type) Bang_Type compile_var_read_into_basm(Bang *bang, Basm *basm, Bang_Var_Read var_read) { - Compiled_Var *var = bang_get_global_var_by_name(bang, var_read.name); + Compiled_Var *var = bang_get_compiled_var_by_name(bang, var_read.name); if (var == NULL) { fprintf(stderr, Bang_Loc_Fmt": ERROR: could not read non-existing variable `"SV_Fmt"`\n", Bang_Loc_Arg(var_read.loc), @@ -138,8 +145,18 @@ Bang_Type compile_var_read_into_basm(Bang *bang, Basm *basm, Bang_Var_Read var_r exit(1); } - basm_push_inst(basm, INST_PUSH, word_u64(var->addr)); - compile_typed_read(basm, var->type); + switch (var->storage) { + case BANG_VAR_STATIC_STORAGE: { + basm_push_inst(basm, INST_PUSH, word_u64(var->addr)); + compile_typed_read(basm, var->type); + } + break; + + case BANG_VAR_STACK_STORAGE: { + assert(false && "TODO(#454): reading stack variables is not implemented"); + } + break; + } return var->type; } @@ -236,9 +253,19 @@ Compiled_Expr compile_bang_expr_into_basm(Bang *bang, Basm *basm, Bang_Expr expr exit(1); } - Compiled_Var *var = bang_get_global_var_by_name(bang, arg.as.var_read.name); - basm_push_inst(basm, INST_PUSH, word_u64(var->addr)); - result.type = BANG_TYPE_PTR; + Compiled_Var *var = bang_get_compiled_var_by_name(bang, arg.as.var_read.name); + switch (var->storage) { + case BANG_VAR_STATIC_STORAGE: { + basm_push_inst(basm, INST_PUSH, word_u64(var->addr)); + result.type = BANG_TYPE_PTR; + } + break; + + case BANG_VAR_STACK_STORAGE: { + assert(false && "TODO(#455): Taking a pointer to stack variable is not implemented"); + } + break; + } } else if (sv_eq(funcall.name, SV("write_ptr"))) { bang_funcall_expect_arity(funcall, 2); Bang_Funcall_Arg *args = funcall.args; @@ -400,11 +427,34 @@ void compile_bang_if_into_basm(Bang *bang, Basm *basm, Bang_If eef) basm->program[else_jmp_addr].operand = word_u64(end_addr); } -Compiled_Var *bang_get_global_var_by_name(Bang *bang, String_View name) +void bang_scope_push_var(Bang_Scope *scope, Compiled_Var var) +{ + assert(scope); + assert(scope->vars_count < BANG_SCOPE_VARS_CAPACITY); + scope->vars[scope->vars_count++] = var; +} + +Compiled_Var *bang_scope_get_compiled_var_by_name(Bang_Scope *scope, String_View name) +{ + assert(scope); + + for (size_t i = 0; i < scope->vars_count; ++i) { + if (sv_eq(scope->vars[i].def.name, name)) { + return &scope->vars[i]; + } + } + + return NULL; +} + +Compiled_Var *bang_get_compiled_var_by_name(Bang *bang, String_View name) { - for (size_t i = 0; i < bang->global_vars_count; ++i) { - if (sv_eq(bang->global_vars[i].def.name, name)) { - return &bang->global_vars[i]; + for (Bang_Scope *scope = bang->scope; + scope != NULL; + scope = scope->parent) { + Compiled_Var *var = bang_scope_get_compiled_var_by_name(scope, name); + if (var != NULL) { + return var; } } return NULL; @@ -412,7 +462,7 @@ Compiled_Var *bang_get_global_var_by_name(Bang *bang, String_View name) void compile_bang_var_assign_into_basm(Bang *bang, Basm *basm, Bang_Var_Assign var_assign) { - Compiled_Var *var = bang_get_global_var_by_name(bang, var_assign.name); + Compiled_Var *var = bang_get_compiled_var_by_name(bang, var_assign.name); if (var == NULL) { fprintf(stderr, Bang_Loc_Fmt": ERROR: cannot assign non-existing variable `"SV_Fmt"`\n", Bang_Loc_Arg(var_assign.loc), @@ -420,18 +470,28 @@ void compile_bang_var_assign_into_basm(Bang *bang, Basm *basm, Bang_Var_Assign v exit(1); } - basm_push_inst(basm, INST_PUSH, word_u64(var->addr)); - Compiled_Expr expr = compile_bang_expr_into_basm(bang, basm, var_assign.value); + switch (var->storage) { + case BANG_VAR_STATIC_STORAGE: { + basm_push_inst(basm, INST_PUSH, word_u64(var->addr)); + Compiled_Expr expr = compile_bang_expr_into_basm(bang, basm, var_assign.value); + if (expr.type != var->type) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: cannot assign expression of type `%s` to a variable of type `%s`\n", + Bang_Loc_Arg(var_assign.loc), + bang_type_def(expr.type).name, + bang_type_def(var->type).name); + exit(1); + } - if (expr.type != var->type) { - fprintf(stderr, Bang_Loc_Fmt": ERROR: cannot assign expression of type `%s` to a variable of type `%s`\n", - Bang_Loc_Arg(var_assign.loc), - bang_type_def(expr.type).name, - bang_type_def(var->type).name); - exit(1); + compile_typed_write(basm, expr.type); + } + break; + + case BANG_VAR_STACK_STORAGE: { + assert(false && "TODO(#456): assigning to stack variable is not implemented"); + } + break; } - compile_typed_write(basm, expr.type); } void compile_bang_while_into_basm(Bang *bang, Basm *basm, Bang_While hwile) @@ -454,6 +514,7 @@ void compile_bang_while_into_basm(Bang *bang, Basm *basm, Bang_While hwile) basm->program[fallthrough_addr].operand = word_u64(body_end_addr); } + void compile_stmt_into_basm(Bang *bang, Basm *basm, Bang_Stmt stmt) { switch (stmt.kind) { @@ -477,6 +538,10 @@ void compile_stmt_into_basm(Bang *bang, Basm *basm, Bang_Stmt stmt) compile_bang_while_into_basm(bang, basm, stmt.as.hwile); break; + case BANG_STMT_KIND_VAR_DEF: + compile_stack_var_def_into_basm(bang, basm, stmt.as.var_def); + break; + case COUNT_BANG_STMT_KINDS: default: assert(false && "compile_stmt_into_basm: unreachable"); @@ -486,10 +551,12 @@ void compile_stmt_into_basm(Bang *bang, Basm *basm, Bang_Stmt stmt) void compile_block_into_basm(Bang *bang, Basm *basm, Bang_Block *block) { + bang_push_new_scope(bang); while (block) { compile_stmt_into_basm(bang, basm, block->stmt); block = block->next; } + bang_pop_scope(bang); } Compiled_Proc *bang_get_compiled_proc_by_name(Bang *bang, String_View name) @@ -521,6 +588,7 @@ void compile_proc_def_into_basm(Bang *bang, Basm *basm, Bang_Proc_Def proc_def) bang->procs[bang->procs_count++] = proc; compile_block_into_basm(bang, basm, proc_def.body); + basm_push_inst(basm, INST_RET, word_u64(0)); } @@ -546,42 +614,6 @@ void bang_funcall_expect_arity(Bang_Funcall funcall, size_t expected_arity) } } -void compile_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def) -{ - Bang_Type type = 0; - if (!bang_type_by_name(var_def.type_name, &type)) { - fprintf(stderr, Bang_Loc_Fmt": ERROR: type `"SV_Fmt"` does not exist\n", - Bang_Loc_Arg(var_def.loc), - SV_Arg(var_def.type_name)); - exit(1); - } - - if (type == BANG_TYPE_VOID) { - fprintf(stderr, Bang_Loc_Fmt": ERROR: defining variables with type %s is not allowed\n", - Bang_Loc_Arg(var_def.loc), - bang_type_def(type).name); - exit(1); - } - - Compiled_Var *existing_var = bang_get_global_var_by_name(bang, var_def.name); - if (existing_var) { - fprintf(stderr, Bang_Loc_Fmt": ERROR: variable `"SV_Fmt"` is already defined\n", - Bang_Loc_Arg(var_def.loc), - SV_Arg(var_def.name)); - fprintf(stderr, Bang_Loc_Fmt": NOTE: the first definition is located here\n", - Bang_Loc_Arg(existing_var->def.loc)); - exit(1); - } - - Compiled_Var new_var = {0}; - new_var.def = var_def; - new_var.addr = basm_push_byte_array_to_memory(basm, bang_type_def(type).size, 0).as_u64; - new_var.type = type; - - assert(bang->global_vars_count < BANG_GLOBAL_VARS_CAPACITY); - bang->global_vars[bang->global_vars_count++] = new_var; -} - void compile_bang_module_into_basm(Bang *bang, Basm *basm, Bang_Module module) { for (Bang_Top *top = module.tops_begin; top != NULL; top = top->next) { @@ -591,7 +623,7 @@ void compile_bang_module_into_basm(Bang *bang, Basm *basm, Bang_Module module) } break; case BANG_TOP_KIND_VAR: { - compile_var_def_into_basm(bang, basm, top->as.var); + compile_static_var_def_into_basm(bang, basm, top->as.var); } break; case COUNT_BANG_TOP_KINDS: @@ -619,9 +651,11 @@ void bang_generate_entry_point(Bang *bang, Basm *basm, String_View entry_proc_na void bang_generate_heap_base(Bang *bang, Basm *basm, String_View heap_base_var_name) { - Compiled_Var *heap_base_var = bang_get_global_var_by_name(bang, heap_base_var_name); + assert(bang->scope != NULL); + Compiled_Var *heap_base_var = bang_get_compiled_var_by_name(bang, heap_base_var_name); if (heap_base_var != NULL) { + assert(heap_base_var->storage == BANG_VAR_STATIC_STORAGE); if (heap_base_var->type != BANG_TYPE_PTR) { fprintf(stderr, Bang_Loc_Fmt": ERROR: the special `"SV_Fmt"` variable is expected to be of type `%s` but it was defined as type `%s`\n", Bang_Loc_Arg(heap_base_var->def.loc), @@ -637,3 +671,98 @@ void bang_generate_heap_base(Bang *bang, Basm *basm, String_View heap_base_var_n sizeof(heap_base_addr)); } } + +void bang_prepare_var_stack(Bang *bang, Basm *basm) +{ + basm_push_byte_array_to_memory(basm, BANG_STACK_CAPACITY, 0); + const Memory_Addr stack_start_addr = BANG_STACK_CAPACITY; + + bang->stack_top_var_addr = + basm_push_buffer_to_memory( + basm, (uint8_t*) &stack_start_addr, sizeof(stack_start_addr)).as_u64; + bang->stack_frame_var_addr = + basm_push_buffer_to_memory( + basm, (uint8_t*) &stack_start_addr, sizeof(stack_start_addr)).as_u64; +} + +void compile_static_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def) +{ + Bang_Type type = 0; + if (!bang_type_by_name(var_def.type_name, &type)) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: type `"SV_Fmt"` does not exist\n", + Bang_Loc_Arg(var_def.loc), + SV_Arg(var_def.type_name)); + exit(1); + } + + if (type == BANG_TYPE_VOID) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: defining variables with type %s is not allowed\n", + Bang_Loc_Arg(var_def.loc), + bang_type_def(type).name); + exit(1); + } + + Compiled_Var *existing_var = bang_scope_get_compiled_var_by_name(bang->scope, var_def.name); + if (existing_var) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: variable `"SV_Fmt"` is already defined\n", + Bang_Loc_Arg(var_def.loc), + SV_Arg(var_def.name)); + fprintf(stderr, Bang_Loc_Fmt": NOTE: the first definition is located here\n", + Bang_Loc_Arg(existing_var->def.loc)); + exit(1); + } + + Compiled_Var new_var = {0}; + new_var.def = var_def; + new_var.storage = BANG_VAR_STATIC_STORAGE; + new_var.addr = basm_push_byte_array_to_memory(basm, bang_type_def(type).size, 0).as_u64; + new_var.type = type; + + bang_scope_push_var(bang->scope, new_var); +} + +void compile_stack_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def) +{ + Bang_Type type = 0; + if (!bang_type_by_name(var_def.type_name, &type)) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: type `"SV_Fmt"` does not exist\n", + Bang_Loc_Arg(var_def.loc), + SV_Arg(var_def.type_name)); + exit(1); + } + + if (type == BANG_TYPE_VOID) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: defining variables with type %s is not allowed\n", + Bang_Loc_Arg(var_def.loc), + bang_type_def(type).name); + exit(1); + } + + // TODO(#457): bang compile does not warn about shadowing of the variable + + Compiled_Var *existing_var = bang_scope_get_compiled_var_by_name(bang->scope, var_def.name); + if (existing_var) { + fprintf(stderr, Bang_Loc_Fmt": ERROR: variable `"SV_Fmt"` is already defined\n", + Bang_Loc_Arg(var_def.loc), + SV_Arg(var_def.name)); + fprintf(stderr, Bang_Loc_Fmt": NOTE: the first definition is located here\n", + Bang_Loc_Arg(existing_var->def.loc)); + exit(1); + } + + (void) basm; + assert(false && "TODO(#458): compiling the stack variable is not implemented"); +} + +void bang_push_new_scope(Bang *bang) +{ + Bang_Scope *scope = arena_alloc(&bang->arena, sizeof(Bang_Scope)); + scope->parent = bang->scope; + bang->scope = scope; +} + +void bang_pop_scope(Bang *bang) +{ + assert(bang->scope != NULL); + bang->scope = bang->scope->parent; +} diff --git a/bang/src/bang_compiler.h b/bang/src/bang_compiler.h index 2091e29..239eb4f 100644 --- a/bang/src/bang_compiler.h +++ b/bang/src/bang_compiler.h @@ -6,9 +6,14 @@ #include "./bang_lexer.h" #include "./bang_parser.h" -#define BANG_GLOBAL_VARS_CAPACITY 1024 +#define BANG_SCOPE_VARS_CAPACITY 1024 #define BANG_PROCS_CAPACITY 1024 +typedef enum { + BANG_VAR_STATIC_STORAGE = 0, + BANG_VAR_STACK_STORAGE, +} Bang_Var_Storage; + // TODO(#433): there is no generic ptr type typedef enum { BANG_TYPE_VOID = 0, @@ -33,6 +38,11 @@ Bang_Type_Def bang_type_def(Bang_Type type); typedef struct { Bang_Var_Def def; Bang_Type type; + Bang_Var_Storage storage; + // when storage == BANG_VAR_STATIC_STORAGE: + // addr is absolute address of the variable in memory + // when storage == BANG_VAR_STACK_STORAGE: + // addr is an offset from the stack frame Memory_Addr addr; } Compiled_Var; @@ -41,11 +51,31 @@ typedef struct { Inst_Addr addr; } Compiled_Proc; +typedef struct Bang_Scope Bang_Scope; + +struct Bang_Scope { + Bang_Scope *parent; + Compiled_Var vars[BANG_SCOPE_VARS_CAPACITY]; + size_t vars_count; +}; + +Compiled_Var *bang_scope_get_compiled_var_by_name(Bang_Scope *scope, String_View name); +void bang_scope_push_var(Bang_Scope *scope, Compiled_Var var); + +#define BANG_STACK_CAPACITY 32 + +#define STACK_TOP_VAR_TYPE BANG_TYPE_I64 +#define STACK_FRAME_VAR_TYPE BANG_TYPE_I64 + typedef struct { + Arena arena; + Native_ID write_id; - Compiled_Var global_vars[BANG_GLOBAL_VARS_CAPACITY]; - size_t global_vars_count; + Memory_Addr stack_top_var_addr; + Memory_Addr stack_frame_var_addr; + + Bang_Scope *scope; Compiled_Proc procs[BANG_PROCS_CAPACITY]; size_t procs_count; @@ -53,9 +83,7 @@ typedef struct { Bang_Loc entry_loc; } Bang; -void compile_begin_begin(Bang *bang); - -Compiled_Var *bang_get_global_var_by_name(Bang *bang, String_View name); +Compiled_Var *bang_get_compiled_var_by_name(Bang *bang, String_View name); typedef struct { Bang_Expr ast; @@ -75,13 +103,19 @@ void compile_bang_if_into_basm(Bang *bang, Basm *basm, Bang_If eef); void compile_bang_while_into_basm(Bang *bang, Basm *basm, Bang_While hwile); void compile_bang_var_assign_into_basm(Bang *bang, Basm *basm, Bang_Var_Assign var_assign); void compile_bang_module_into_basm(Bang *bang, Basm *basm, Bang_Module module); -void compile_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def); +void compile_static_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def); +void compile_stack_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def); Bang_Type compile_var_read_into_basm(Bang *bang, Basm *basm, Bang_Var_Read var_read); Bang_Type compile_binary_op_into_basm(Bang *bang, Basm *basm, Bang_Binary_Op binary_op); +void bang_push_new_scope(Bang *bang); +void bang_pop_scope(Bang *bang); + void bang_generate_entry_point(Bang *bang, Basm *basm, String_View entry_proc_name); void bang_generate_heap_base(Bang *bang, Basm *basm, String_View heap_base_var_name); void bang_funcall_expect_arity(Bang_Funcall funcall, size_t expected_arity); +void bang_prepare_var_stack(Bang *bang, Basm *basm); + #endif // BANG_COMPILER_H_ diff --git a/bang/src/bang_parser.c b/bang/src/bang_parser.c index 7ea9aae..cf3020c 100644 --- a/bang/src/bang_parser.c +++ b/bang/src/bang_parser.c @@ -420,7 +420,7 @@ Bang_Stmt parse_bang_stmt(Arena *arena, Bang_Lexer *lexer) exit(1); } - static_assert(COUNT_BANG_STMT_KINDS == 4, "The amount of statements have changed. Please update the parse_bang_stmt function to take that into account"); + static_assert(COUNT_BANG_STMT_KINDS == 5, "The amount of statements have changed. Please update the parse_bang_stmt function to take that into account"); switch (token.kind) { case BANG_TOKEN_KIND_NAME: { @@ -434,6 +434,11 @@ Bang_Stmt parse_bang_stmt(Arena *arena, Bang_Lexer *lexer) stmt.kind = BANG_STMT_KIND_WHILE; stmt.as.hwile = parse_bang_while(arena, lexer); return stmt; + } else if (sv_eq(token.text, SV("var"))) { + Bang_Stmt stmt = {0}; + stmt.kind = BANG_STMT_KIND_VAR_DEF; + stmt.as.var_def = parse_bang_var_def(lexer); + return stmt; } else { Bang_Token next_token = {0}; if (bang_lexer_peek(lexer, &next_token, 1) && next_token.kind == BANG_TOKEN_KIND_EQ) { diff --git a/bang/src/bang_parser.h b/bang/src/bang_parser.h index 246426d..cd1df74 100644 --- a/bang/src/bang_parser.h +++ b/bang/src/bang_parser.h @@ -110,6 +110,7 @@ typedef enum { BANG_STMT_KIND_EXPR = 0, BANG_STMT_KIND_IF, BANG_STMT_KIND_VAR_ASSIGN, + BANG_STMT_KIND_VAR_DEF, BANG_STMT_KIND_WHILE, COUNT_BANG_STMT_KINDS, } Bang_Stmt_Kind; @@ -133,14 +134,21 @@ struct Bang_Var_Assign { Bang_Expr value; }; +struct Bang_Var_Def { + Bang_Loc loc; + String_View name; + String_View type_name; +}; + union Bang_Stmt_As { Bang_Expr expr; Bang_If eef; Bang_Var_Assign var_assign; Bang_While hwile; + Bang_Var_Def var_def; }; static_assert( - COUNT_BANG_STMT_KINDS == 4, + COUNT_BANG_STMT_KINDS == 5, "The amount of statement kinds has changed. " "Please update the union of those statements accordingly. " "Thanks!"); @@ -161,12 +169,6 @@ struct Bang_Proc_Def { Bang_Block *body; }; -struct Bang_Var_Def { - Bang_Loc loc; - String_View name; - String_View type_name; -}; - typedef enum { BANG_TOP_KIND_PROC = 0, BANG_TOP_KIND_VAR,