From 7963d9ab628d03c5004f32899aa6b21663a78007 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Wed, 22 Dec 2021 16:30:23 +0100 Subject: Start refactoring of compiler to stack-ir --- Makefile | 7 +-- src/ir.h | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 6 ++- 3 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 src/ir.h diff --git a/Makefile b/Makefile index cdb8c93..4e31a67 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ CFLAGS += $(INC_FLAGS) NASM_FLAGS ?= -felf64 LDFLAGS := LDLIBS := -RELEASE_CFLAGS := -DNDEBUG -O2 -static +RELEASE_CFLAGS := -DNDEBUG -O2 DEBUG_CFLAGS := -DDEBUG -O0 -g .PHONY: build tests clean @@ -56,10 +56,7 @@ tests: $(BIN) # ./$(BIN) examples/variables.bdl | diff tests/variables_expected.txt - run: $(BIN) - $(BIN) example.bdl > build/example.asm - nasm $(NASM_FLAGS) build/example.asm -o build/example.o - ld build/example.o -o build/example - @./build/example + $(BIN) example.bdl # Remove build directory. clean: diff --git a/src/ir.h b/src/ir.h new file mode 100644 index 0000000..10f48fd --- /dev/null +++ b/src/ir.h @@ -0,0 +1,155 @@ +#ifndef BDL_IR_H +#define BDL_IR_H + +typedef struct LineInfo { + size_t line; + size_t col; +} LineInfo; + +typedef enum Op { + // Arithmetic ops. + // - Binary operations. + // - Arguments are passed via the stack. + OP_ADD, + OP_SUB, + OP_MUL, + OP_DIV, + OP_MOD, + // Stack ops. + // - Requires an Object to push into the stack. + OP_PUSH, + // - Discards the last value in the stack. + OP_DROP, + // Jump/conditional ops. + // - Take a label as argument. + // - For conditional jumps, the last value in the stack is used. + OP_JUMP, + OP_JUMP_IF_FALSE, + // Primitive complex commands. + // - Prints the last object in the stack. + OP_PRINT, + // Procedures. + // - Requires a function name as parameter. + OP_CALL, + // - Return position is on a know location of the stack based on the offset + // of locals, parameters, etc. + OP_RETURN, + // TODO: add remaining ops. +} Op; + +static const char* ops_str[] = { + [OP_ADD] = "OP_ADD", + [OP_SUB] = "OP_SUB", + [OP_MUL] = "OP_MUL", + [OP_DIV] = "OP_DIV", + [OP_MOD] = "OP_MOD", + [OP_PUSH] = "OP_PUSH", + [OP_DROP] = "OP_DROP", + [OP_JUMP] = "OP_JUMP", + [OP_JUMP_IF_FALSE] = "OP_JUMP_IF_FALSE", + [OP_PRINT] = "OP_PRINT", + [OP_CALL] = "OP_CALL", + [OP_RETURN] = "OP_RETURN", +}; + +typedef struct Instruction { + Op op; + Object *argument; + + // Original line/column for debugging purposes. + size_t line; + size_t col; +} Instruction; + +typedef struct Procedure { + // Procedure name. + char *name; + + // Program code. + Instruction *instructions; + + // Number of locals and parameters. + size_t n_params; + size_t n_locals; +} Procedure; + +typedef struct ProgramIr { + Procedure **procedures; + Object **constants; +} ProgramIr; + +void +print_instruction(Instruction *instruction) { + printf("%4ld:%-4ld ", instruction->line, instruction->col); + Op op = instruction->op; + switch (op) { + case OP_PUSH: { + printf("%-16s -> ", ops_str[op]); + OBJ_PRINT(instruction->argument); + } break; + default: { + printf("%s\n", ops_str[op]); + } break; + } +} + +void +print_procedure(Procedure *proc) { + printf("===== %.*s =====\n", (int)array_size(proc->name), proc->name); + printf("code:\n"); + for (size_t i = 0; i < array_size(proc->instructions); ++i) { + print_instruction(&proc->instructions[i]); + } +} + +Procedure * +proc_alloc(ProgramIr *program, StringView name) { + Procedure *proc = calloc(1, sizeof(Procedure)); + array_init(proc->name, name.n); + array_insert(proc->name, name.start, name.n); + array_init(proc->instructions, 0); + array_push(program->procedures, proc); + return proc; +} + +void +compile_object(ProgramIr *program, Procedure *proc, Object *obj) { + switch (obj->type) { + case OBJ_TYPE_NIL: + case OBJ_TYPE_TRUE: + case OBJ_TYPE_FALSE: + case OBJ_TYPE_STRING: + case OBJ_TYPE_FIXNUM: { + Instruction inst = (Instruction){OP_PUSH, obj, obj->line, obj->col}; + array_push(proc->instructions, inst); + } break; + // case OBJ_TYPE_PAIR: { compile_proc_call(obj); } break; + // case OBJ_TYPE_IF: { compile_if(obj); } break; + // case OBJ_TYPE_LAMBDA: { compile_lambda(obj); } break; + // case OBJ_TYPE_DEF: { compile_def(obj); } break; + // case OBJ_TYPE_SYMBOL: { compile_symbol(obj); } break; + default: break; + } +} + +ProgramIr +compile(Program program) { + ProgramIr program_ir = {0}; + array_init(program_ir.procedures, 0); + array_init(program_ir.constants, 0); + Procedure *main = proc_alloc(&program_ir, STRING("main")); + + for (size_t i = 0; i < array_size(program.roots); i++) { + Object *root = program.roots[i]; + compile_object(&program_ir, main, root); + } + + // DEBUG:... + for (size_t i = 0; i < array_size(program_ir.procedures); ++i) { + print_procedure(program_ir.procedures[i]); + } + + return program_ir; +} + +#endif // BDL_IR_H diff --git a/src/main.c b/src/main.c index d006d2d..30eab2b 100644 --- a/src/main.c +++ b/src/main.c @@ -8,7 +8,8 @@ #include "errors.c" #include "lexer.c" #include "parser.c" -#include "compiler.h" +#include "ir.h" +// #include "compiler.h" void init(void) { @@ -45,7 +46,8 @@ process_source(const StringView *source, const char *file_name) { // TODO: Optimization. // Compilation. - compile(program); + ProgramIr program_ir = compile(program); + (void)program_ir; // Free resources. free_objects(); -- cgit v1.2.1