From ed0ad1d095f90cfa25c4f79f43856cb90bf87da5 Mon Sep 17 00:00:00 2001 From: Lorenzo Torres Date: Wed, 14 Jan 2026 18:36:27 +0100 Subject: [PATCH 1/3] codegen --- Makefile | 4 +- codegen.c | 736 ++++++++++++++++++++++++++++++++++++++++++++ codegen.h | 8 + ir.c | 812 ------------------------------------------------- ir.h | 65 ---- lc.c | 6 +- sema.c | 36 ++- test | Bin 0 -> 20192 bytes test.l | 20 +- test.s | 20 ++ test_control | Bin 0 -> 21712 bytes test_control.l | 23 ++ test_simple | Bin 0 -> 21712 bytes test_simple.l | 13 + 14 files changed, 846 insertions(+), 897 deletions(-) create mode 100644 codegen.c create mode 100644 codegen.h delete mode 100644 ir.c delete mode 100644 ir.h create mode 100755 test create mode 100644 test.s create mode 100755 test_control create mode 100644 test_control.l create mode 100755 test_simple create mode 100644 test_simple.l diff --git a/Makefile b/Makefile index 203633a..7b960e9 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ include config.mk -SRC = lc.c utils.c lexer.c parser.c sema.c ir.c -HDR = config.def.h utils.h lexer.h parser.h sema.h ir.h +SRC = lc.c utils.c lexer.c parser.c sema.c codegen.c +HDR = config.def.h utils.h lexer.h parser.h sema.h codegen.h OBJ = ${SRC:.c=.o} all: options lc diff --git a/codegen.c b/codegen.c new file mode 100644 index 0000000..7220d49 --- /dev/null +++ b/codegen.c @@ -0,0 +1,736 @@ +#include +#include +#include +#include "codegen.h" +#include "sema.h" + +#include "stb_ds.h" + +typedef struct { + char *key; + int value; +} var_map; + +static var_map *variables = NULL; +static int stack_offset = 0; +static int label_counter = 0; +static int *break_stack = NULL; + +void gen_expr(FILE *fp, ast_node *expr); +void gen_unary(FILE *fp, ast_node *expr); +void gen_statement_list(FILE *fp, ast_node *stmt); +int get_var_offset(char *name, usize name_len); +int get_var_offset_sized(char *name, usize name_len, usize size); + +void gen_binary(FILE *fp, ast_node *expr) +{ + switch (expr->expr.binary.operator) { + case OP_PLUS: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "add %%rcx, %%rax\n"); + break; + case OP_MINUS: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "sub %%rax, %%rcx\n"); + fprintf(fp, "mov %%rcx, %%rax\n"); + break; + case OP_MUL: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "imul %%rcx, %%rax\n"); + break; + case OP_DIV: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "mov %%rax, %%rbx\n"); + fprintf(fp, "mov %%rcx, %%rax\n"); + fprintf(fp, "cqo\n"); + fprintf(fp, "idiv %%rbx\n"); + break; + case OP_MOD: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "mov %%rax, %%rbx\n"); + fprintf(fp, "mov %%rcx, %%rax\n"); + fprintf(fp, "cqo\n"); + fprintf(fp, "idiv %%rbx\n"); + fprintf(fp, "mov %%rdx, %%rax\n"); + break; + case OP_BOR: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "or %%rcx, %%rax\n"); + break; + case OP_BAND: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "and %%rcx, %%rax\n"); + break; + case OP_BXOR: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "xor %%rcx, %%rax\n"); + break; + case OP_EQ: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "cmp %%rax, %%rcx\n"); + fprintf(fp, "sete %%al\n"); + fprintf(fp, "movzx %%al, %%rax\n"); + break; + case OP_NEQ: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "cmp %%rax, %%rcx\n"); + fprintf(fp, "setne %%al\n"); + fprintf(fp, "movzx %%al, %%rax\n"); + break; + case OP_LT: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "cmp %%rax, %%rcx\n"); + fprintf(fp, "setl %%al\n"); + fprintf(fp, "movzx %%al, %%rax\n"); + break; + case OP_GT: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "cmp %%rax, %%rcx\n"); + fprintf(fp, "setg %%al\n"); + fprintf(fp, "movzx %%al, %%rax\n"); + break; + case OP_LE: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "cmp %%rax, %%rcx\n"); + fprintf(fp, "setle %%al\n"); + fprintf(fp, "movzx %%al, %%rax\n"); + break; + case OP_GE: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "mov %%rax, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "cmp %%rax, %%rcx\n"); + fprintf(fp, "setge %%al\n"); + fprintf(fp, "movzx %%al, %%rax\n"); + break; + case OP_AND: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "test %%rax, %%rax\n"); + fprintf(fp, "setne %%al\n"); + fprintf(fp, "movzx %%al, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "test %%rax, %%rax\n"); + fprintf(fp, "setne %%al\n"); + fprintf(fp, "movzx %%al, %%rax\n"); + fprintf(fp, "and %%rcx, %%rax\n"); + break; + case OP_OR: + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "test %%rax, %%rax\n"); + fprintf(fp, "setne %%al\n"); + fprintf(fp, "movzx %%al, %%rcx\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "test %%rax, %%rax\n"); + fprintf(fp, "setne %%al\n"); + fprintf(fp, "movzx %%al, %%rax\n"); + fprintf(fp, "or %%rcx, %%rax\n"); + break; + case OP_ASSIGN: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + gen_expr(fp, expr->expr.binary.right); + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + case OP_ASSIGN_PTR: { + gen_expr(fp, expr->expr.binary.left); + fprintf(fp, "push %%rax\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "pop %%rcx\n"); + fprintf(fp, "mov %%rax, (%%rcx)\n"); + break; + } + case OP_PLUS_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", offset); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "add %%rcx, %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + case OP_MINUS_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", offset); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "sub %%rax, %%rcx\n"); + fprintf(fp, "mov %%rcx, %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + case OP_MUL_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", offset); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "imul %%rcx, %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + case OP_DIV_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", offset); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "mov %%rax, %%rbx\n"); + fprintf(fp, "mov %%rcx, %%rax\n"); + fprintf(fp, "cqo\n"); + fprintf(fp, "idiv %%rbx\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + case OP_MOD_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", offset); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "mov %%rax, %%rbx\n"); + fprintf(fp, "mov %%rcx, %%rax\n"); + fprintf(fp, "cqo\n"); + fprintf(fp, "idiv %%rbx\n"); + fprintf(fp, "mov %%rdx, -%d(%%rbp)\n", offset); + break; + } + case OP_BOR_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", offset); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "or %%rcx, %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + case OP_BAND_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", offset); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "and %%rcx, %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + case OP_BXOR_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", offset); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "xor %%rcx, %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + case OP_RSHIFT_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rax\n", offset); + fprintf(fp, "push %%rax\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "mov %%rax, %%rcx\n"); + fprintf(fp, "pop %%rax\n"); + fprintf(fp, "sar %%cl, %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + case OP_LSHIFT_EQ: { + if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + break; + } + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rax\n", offset); + fprintf(fp, "push %%rax\n"); + gen_expr(fp, expr->expr.binary.right); + fprintf(fp, "mov %%rax, %%rcx\n"); + fprintf(fp, "pop %%rax\n"); + fprintf(fp, "shl %%cl, %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; + } + } +} + +int get_var_offset(char *name, usize name_len) +{ + char *var_name = strndup(name, name_len); + ptrdiff_t idx = shgeti(variables, var_name); + + if (idx >= 0) { + free(var_name); + return variables[idx].value; + } + + stack_offset += 8; + shput(variables, var_name, stack_offset); + return stack_offset; +} + +int get_var_offset_sized(char *name, usize name_len, usize size) +{ + char *var_name = strndup(name, name_len); + ptrdiff_t idx = shgeti(variables, var_name); + + if (idx >= 0) { + free(var_name); + return variables[idx].value; + } + + usize aligned_size = (size + 7) & ~7; + stack_offset += aligned_size; + shput(variables, var_name, stack_offset); + return stack_offset; +} + +void gen_statement_list(FILE *fp, ast_node *stmt) +{ + if (!stmt) return; + + if (stmt->type == NODE_UNIT) { + ast_node *current = stmt; + while (current && current->type == NODE_UNIT) { + if (current->expr.unit_node.expr) { + gen_expr(fp, current->expr.unit_node.expr); + } + current = current->expr.unit_node.next; + } + } else { + gen_expr(fp, stmt); + } +} + +void gen_unary(FILE *fp, ast_node *expr) +{ + switch (expr->expr.unary.operator) { + case UOP_MINUS: + gen_expr(fp, expr->expr.unary.right); + fprintf(fp, "neg %%rax\n"); + break; + case UOP_NOT: + gen_expr(fp, expr->expr.unary.right); + fprintf(fp, "test %%rax, %%rax\n"); + fprintf(fp, "sete %%al\n"); + fprintf(fp, "movzx %%al, %%rax\n"); + break; + case UOP_INCR: + if (expr->expr.unary.right->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: increment requires identifier\n"); + break; + } + int offset_incr = get_var_offset(expr->expr.unary.right->expr.string.start, + expr->expr.unary.right->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rax\n", offset_incr); + fprintf(fp, "inc %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset_incr); + break; + case UOP_DECR: + if (expr->expr.unary.right->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: decrement requires identifier\n"); + break; + } + int offset_decr = get_var_offset(expr->expr.unary.right->expr.string.start, + expr->expr.unary.right->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rax\n", offset_decr); + fprintf(fp, "dec %%rax\n"); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset_decr); + break; + case UOP_REF: + if (expr->expr.unary.right->type != NODE_IDENTIFIER) { + fprintf(fp, "# ERROR: address-of requires identifier\n"); + break; + } + int offset_ref = get_var_offset(expr->expr.unary.right->expr.string.start, + expr->expr.unary.right->expr.string.len); + fprintf(fp, "lea -%d(%%rbp), %%rax\n", offset_ref); + break; + case UOP_DEREF: + gen_expr(fp, expr->expr.unary.right); + fprintf(fp, "mov (%%rax), %%rax\n"); + break; + } +} + +void gen_expr(FILE *fp, ast_node *expr) +{ + switch (expr->type) { + case NODE_INTEGER: + fprintf(fp, "mov $%lu, %%rax\n", expr->expr.integer); + break; + case NODE_FLOAT: { + // TODO: do not truncate + i64 int_val = (i64)expr->expr.flt; + fprintf(fp, "mov $%ld, %%rax\n", int_val); + break; + } + case NODE_CHAR: + fprintf(fp, "mov $%d, %%rax\n", (int)(unsigned char)expr->expr.ch); + break; + case NODE_BOOL: + fprintf(fp, "mov $%d, %%rax\n", expr->expr.boolean ? 1 : 0); + break; + case NODE_IDENTIFIER: { + int offset = get_var_offset(expr->expr.string.start, expr->expr.string.len); + fprintf(fp, "mov -%d(%%rbp), %%rax\n", offset); + break; + } + case NODE_BINARY: + gen_binary(fp, expr); + break; + case NODE_UNARY: + gen_unary(fp, expr); + break; + case NODE_CAST: + gen_expr(fp, expr->expr.cast.value); + break; + case NODE_VAR_DECL: { + int offset; + if (expr->expr.var_decl.type && expr->expr.var_decl.type->expr_type) { + usize var_size = expr->expr.var_decl.type->expr_type->size; + offset = get_var_offset_sized(expr->expr.var_decl.name, + expr->expr.var_decl.name_len, var_size); + } else { + offset = get_var_offset(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + } + + if (expr->expr.var_decl.value) { + if (expr->expr.var_decl.value->type == NODE_STRUCT_INIT) { + ast_node *member_list = expr->expr.var_decl.value->expr.struct_init.members; + ast_node *current = member_list; + + type *struct_type = expr->expr_type; + if (!struct_type && expr->expr.var_decl.type) { + struct_type = expr->expr.var_decl.type->expr_type; + } + + while (current && current->type == NODE_UNIT) { + ast_node *assignment = current->expr.unit_node.expr; + if (assignment && assignment->type == NODE_BINARY && + assignment->expr.binary.operator == OP_ASSIGN) { + ast_node *field = assignment->expr.binary.left; + ast_node *value = assignment->expr.binary.right; + + if (field->type == NODE_IDENTIFIER && struct_type && + struct_type->tag == TYPE_STRUCT) { + char *field_name = strndup(field->expr.string.start, + field->expr.string.len); + + member *m = struct_type->data.structure.members; + int field_offset = -1; + while (m) { + if (m->name_len == field->expr.string.len && + strncmp(m->name, field->expr.string.start, m->name_len) == 0) { + field_offset = m->offset; + break; + } + m = m->next; + } + + if (field_offset >= 0) { + gen_expr(fp, value); + + type *field_type = shget(struct_type->data.structure.member_types, field_name); + + if (field_type && field_type->size == 4) { + fprintf(fp, "mov %%eax, -%d(%%rbp)\n", offset + field_offset); + } else if (field_type && field_type->size == 2) { + fprintf(fp, "mov %%ax, -%d(%%rbp)\n", offset + field_offset); + } else if (field_type && field_type->size == 1) { + fprintf(fp, "mov %%al, -%d(%%rbp)\n", offset + field_offset); + } else { + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset + field_offset); + } + } + + free(field_name); + } + } + current = current->expr.unit_node.next; + } + } else { + gen_expr(fp, expr->expr.var_decl.value); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + } + } + break; + } + case NODE_RETURN: { + if (expr->expr.ret.value) { + gen_expr(fp, expr->expr.ret.value); + } + fprintf(fp, "mov %%rbp, %%rsp\n"); + fprintf(fp, "pop %%rbp\n"); + fprintf(fp, "ret\n"); + break; + } + case NODE_IF: { + int label_else = label_counter++; + int label_end = label_counter++; + + gen_expr(fp, expr->expr.if_stmt.condition); + fprintf(fp, "test %%rax, %%rax\n"); + + if (expr->expr.if_stmt.otherwise) { + fprintf(fp, "jz .L%d\n", label_else); + } else { + fprintf(fp, "jz .L%d\n", label_end); + } + + gen_statement_list(fp, expr->expr.if_stmt.body); + + if (expr->expr.if_stmt.otherwise) { + fprintf(fp, "jmp .L%d\n", label_end); + fprintf(fp, ".L%d:\n", label_else); + gen_statement_list(fp, expr->expr.if_stmt.otherwise); + } + + fprintf(fp, ".L%d:\n", label_end); + break; + } + case NODE_WHILE: { + int label_start = label_counter++; + int label_end = label_counter++; + + fprintf(fp, ".L%d:\n", label_start); + + gen_expr(fp, expr->expr.whle.condition); + fprintf(fp, "test %%rax, %%rax\n"); + fprintf(fp, "jz .L%d\n", label_end); + + arrput(break_stack, label_end); + + gen_statement_list(fp, expr->expr.whle.body); + + arrpop(break_stack); + + fprintf(fp, "jmp .L%d\n", label_start); + + fprintf(fp, ".L%d:\n", label_end); + break; + } + case NODE_LABEL: { + char *label_name = strndup(expr->expr.label.name, expr->expr.label.name_len); + fprintf(fp, ".L_%s:\n", label_name); + free(label_name); + break; + } + case NODE_GOTO: { + char *label_name = strndup(expr->expr.label.name, expr->expr.label.name_len); + fprintf(fp, "jmp .L_%s\n", label_name); + free(label_name); + break; + } + case NODE_BREAK: { + if (arrlen(break_stack) > 0) { + int loop_end = break_stack[arrlen(break_stack) - 1]; + fprintf(fp, "jmp .L%d\n", loop_end); + } else { + fprintf(fp, "# ERROR: break outside of loop\n"); + } + break; + } + case NODE_ACCESS: { + ast_node *base = expr->expr.access.expr; + ast_node *member_node = expr->expr.access.member; + + if (base->type == NODE_IDENTIFIER) { + int base_offset = get_var_offset(base->expr.string.start, base->expr.string.len); + + type *struct_type = base->expr_type; + + if (member_node->type == NODE_IDENTIFIER && struct_type && + struct_type->tag == TYPE_STRUCT) { + member *m = struct_type->data.structure.members; + int field_offset = -1; + while (m) { + if (m->name_len == member_node->expr.string.len && + strncmp(m->name, member_node->expr.string.start, m->name_len) == 0) { + field_offset = m->offset; + break; + } + m = m->next; + } + + if (field_offset >= 0) { + fprintf(fp, "mov -%d(%%rbp), %%rax\n", base_offset + field_offset); + } else { + fprintf(fp, "# ERROR: field not found\n"); + } + } else { + fprintf(fp, "# ERROR: not a struct type\n"); + } + } else { + fprintf(fp, "# ERROR: complex struct access not implemented\n"); + } + break; + } + case NODE_STRUCT_INIT: { + fprintf(fp, "# ERROR: struct init outside of variable declaration\n"); + break; + } + case NODE_CALL: { + const char *arg_regs[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"}; + + int param_count = 0; + ast_node *param = expr->expr.call.parameters; + while (param && param->type == NODE_UNIT) { + param_count++; + param = param->expr.unit_node.next; + } + + param = expr->expr.call.parameters; + int i = 0; + while (param && param->type == NODE_UNIT) { + if (param->expr.unit_node.expr) { + gen_expr(fp, param->expr.unit_node.expr); + fprintf(fp, "push %%rax\n"); + } + param = param->expr.unit_node.next; + i++; + } + + for (int j = param_count - 1; j >= 0; j--) { + if (j < 6) { + fprintf(fp, "pop %s\n", arg_regs[j]); + } else { + // TODO: handle more than 6 arguments properly + fprintf(fp, "pop %%rax\n"); + fprintf(fp, "push %%rax\n"); + } + } + + fprintf(fp, "call %.*s\n", (int)expr->expr.call.name_len, expr->expr.call.name); + + if (param_count > 6) { + int stack_args = param_count - 6; + fprintf(fp, "add $%d, %%rsp\n", stack_args * 8); + } + + break; + } + } +} + +void gen_function(FILE *fp, ast_node *fn) +{ + ast_node *current = fn->expr.function.body; + + stack_offset = 0; + label_counter = 0; + shfree(variables); + variables = NULL; + arrfree(break_stack); + break_stack = NULL; + + fprintf(fp, ".global %s\n%s:\n", fn->expr.function.name, fn->expr.function.name); + + fprintf(fp, "push %%rbp\n"); + fprintf(fp, "mov %%rsp, %%rbp\n"); + fprintf(fp, "sub $256, %%rsp\n"); + + const char *param_regs[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"}; + member *param = fn->expr.function.parameters; + int param_idx = 0; + while (param && param_idx < 6) { + int offset = get_var_offset(param->name, param->name_len); + fprintf(fp, "mov %s, -%d(%%rbp)\n", param_regs[param_idx], offset); + param = param->next; + param_idx++; + } + + while (current && current->type == NODE_UNIT) { + if (current->expr.unit_node.expr) { + gen_expr(fp, current->expr.unit_node.expr); + } + current = current->expr.unit_node.next; + } + + fprintf(fp, "mov %%rbp, %%rsp\n"); + fprintf(fp, "pop %%rbp\n"); + fprintf(fp, "ret\n"); +} + +void generate(ast_node *node) +{ + FILE *fp = fopen("test.s", "w"); + + ast_node *current = node; + + fprintf(fp, ".section .text\n"); + while (current && current->type == NODE_UNIT) { + if (current->expr.unit_node.expr && current->expr.unit_node.expr->type == NODE_FUNCTION) { + gen_function(fp, current->expr.unit_node.expr); + } + current = current->expr.unit_node.next; + } + + fclose(fp); + + shfree(variables); + variables = NULL; + arrfree(break_stack); + break_stack = NULL; +} diff --git a/codegen.h b/codegen.h new file mode 100644 index 0000000..8e87114 --- /dev/null +++ b/codegen.h @@ -0,0 +1,8 @@ +#ifndef CODEGEN_H +#define CODEGEN_H + +#include "parser.h" + +void generate(ast_node *node); + +#endif diff --git a/ir.c b/ir.c deleted file mode 100644 index 61da14a..0000000 --- a/ir.c +++ /dev/null @@ -1,812 +0,0 @@ -#include "ir.h" -#include -#include -#include "stb_ds.h" -#include "sema.h" - -struct { ir_node key; ir_node *value; } *global_hash = NULL; -static ir_node *graph; -static ir_node *current_memory; -static ir_node *current_control; -static usize current_stack = 0; - -static ir_node *current_scope = NULL; - -static ir_node *build_expression(ast_node *node); - -static struct { - ir_node **return_controls; - ir_node **return_memories; - ir_node **return_values; -} current_func = {0}; - -static void node_name(ir_node *node) -{ - if (!node) { - printf("null [label=\"NULL\", style=filled, fillcolor=red]\n"); - return; - } - printf("%ld ", node->id); - switch (node->code) { - case OC_START: - printf("[label=\"%s\", style=filled, color=orange]\n", node->data.start_name); - break; - case OC_RETURN: - printf("[label=\"return\", style=filled, color=orange]\n"); - break; - case OC_ADD: - printf("[label=\"+\"]\n"); - break; - case OC_NEG: - case OC_SUB: - printf("[label=\"-\"]\n"); - break; - case OC_DIV: - printf("[label=\"/\"]\n"); - break; - case OC_MUL: - printf("[label=\"*\"]\n"); - break; - case OC_MOD: - printf("[label=\"%%\"]\n"); - break; - case OC_BAND: - printf("[label=\"&\"]\n"); - break; - case OC_BOR: - printf("[label=\"|\"]\n"); - break; - case OC_BXOR: - printf("[label=\"^\"]\n"); - break; - case OC_EQ: - printf("[label=\"==\"]\n"); - break; - case OC_CONST_INT: - printf("[label=\"%ld\"]\n", node->data.const_int); - break; - case OC_CONST_FLOAT: - printf("[label=\"%f\"]\n", node->data.const_float); - break; - case OC_FRAME_PTR: - printf("[label=\"frame_ptr\"]\n"); - break; - case OC_STORE: - printf("[label=\"store\", shape=box]\n"); - break; - case OC_LOAD: - printf("[label=\"load\", shape=box]\n"); - break; - case OC_ADDR: - printf("[label=\"addr\"]\n"); - break; - case OC_REGION: - printf("[label=\"region\", shape=diamond, style=filled, color=green]\n"); - break; - case OC_PHI: - printf("[label=\"phi\", shape=triangle]\n"); - break; - case OC_IF: - printf("[label=\"if\", shape=diamond, style=filled, color=lightblue]\n"); - break; - case OC_PROJ: - printf("[label=\"proj\", shape=diamond, style=filled, color=cyan]\n"); - break; - default: - printf("[label=\"%d\"]\n", node->code); - break; - } -} - -static void print_graph(ir_node *node) -{ - for (int i = 0; i < hmlen(global_hash); i++) { - ir_node *node = global_hash[i].value; - node_name(node); - - for (int j = 0; j < arrlen(node->out); j++) { - if (node->out[j]) { - node_name(node->out[j]); - printf("%ld->%ld\n", node->out[j]->id, node->id); - } - } - } -} - -static void push_scope(void) -{ - arrput(current_scope->data.symbol_tables, NULL); -} - -static struct symbol_def *get_def(char *name) -{ - for (int i = arrlen(current_scope->data.symbol_tables) - 1; i >= 0; i--) { - struct symbol_def *def = shget(current_scope->data.symbol_tables[i], name); - if (def) return def; - } - return NULL; -} - -static void set_def(char *name, ir_node *node, bool lvalue) -{ - for (int i = arrlen(current_scope->data.symbol_tables) - 1; i >= 0; i--) { - if (shget(current_scope->data.symbol_tables[i], name)) { - struct symbol_def *def = calloc(1, sizeof(struct symbol_def)); - def->is_lvalue = lvalue; - def->node = node; - shput(current_scope->data.symbol_tables[i], name, def); - return; - } - } - int index = arrlen(current_scope->data.symbol_tables) - 1; - struct symbol_def *def = calloc(1, sizeof(struct symbol_def)); - def->is_lvalue = lvalue; - def->node = node; - shput(current_scope->data.symbol_tables[index], name, def); -} - -static ir_node *copy_scope(ir_node *src) -{ - ir_node *dst = calloc(1, sizeof(ir_node)); - dst->code = OC_SCOPE; - - for (int i=0; i < arrlen(src->data.symbol_tables); i++) { - arrput(dst->data.symbol_tables, NULL); - symbol_table *src_table = src->data.symbol_tables[i]; - for (int j=0; j < shlen(src_table); j++) { - shput(dst->data.symbol_tables[i], src_table[j].key, src_table[j].value); - } - } - return dst; -} - -static void const_fold(ir_node *binary) -{ - ir_node *left = binary->out[0]; - ir_node *right = binary->out[1]; - - if (left->code == OC_CONST_INT && right->code == OC_CONST_INT) { - switch (binary->code) { - case OC_ADD: - binary->data.const_int = left->data.const_int + right->data.const_int; - break; - case OC_SUB: - binary->data.const_int = left->data.const_int - right->data.const_int; - break; - case OC_MUL: - binary->data.const_int = left->data.const_int * right->data.const_int; - break; - case OC_DIV: - if (right->data.const_int != 0) - binary->data.const_int = left->data.const_int / right->data.const_int; - break; - case OC_MOD: - if (right->data.const_int != 0) - binary->data.const_int = left->data.const_int % right->data.const_int; - break; - case OC_BOR: - binary->data.const_int = left->data.const_int | right->data.const_int; - break; - case OC_BAND: - binary->data.const_int = left->data.const_int & right->data.const_int; - break; - case OC_BXOR: - binary->data.const_int = left->data.const_int ^ right->data.const_int; - break; - case OC_EQ: - binary->data.const_int = left->data.const_int == right->data.const_int; - break; - default: - return; - } - binary->code = OC_CONST_INT; - arrfree(binary->out); binary->out = NULL; - arrfree(binary->in); binary->in = NULL; - binary->id = stbds_hash_bytes(binary, sizeof(ir_node), 0xcafebabe); - } - - if (left->code == OC_CONST_FLOAT && right->code == OC_CONST_FLOAT) { - switch (binary->code) { - case OC_ADD: - binary->data.const_float = left->data.const_float + right->data.const_float; - break; - case OC_SUB: - binary->data.const_float = left->data.const_float - right->data.const_float; - break; - case OC_MUL: - binary->data.const_float = left->data.const_float * right->data.const_float; - break; - case OC_DIV: - if (right->data.const_float != 0.0f) - binary->data.const_float = left->data.const_float / right->data.const_float; - break; - default: - return; - } - binary->code = OC_CONST_FLOAT; - arrfree(binary->out); binary->out = NULL; - arrfree(binary->in); binary->in = NULL; - binary->id = stbds_hash_bytes(binary, sizeof(ir_node), 0xcafebabe); - } -} - -static ir_node *build_address(usize base, usize offset) { - ir_node *addr = calloc(1, sizeof(ir_node)); - addr->code = OC_ADDR; - - ir_node *base_node = calloc(1, sizeof(ir_node)); - if (base == -1) { - base_node->code = OC_FRAME_PTR; - base_node->id = stbds_hash_bytes(base_node, sizeof(ir_node), 0xcafebabe); - } else { - base_node->code = OC_CONST_INT; - base_node->data.const_int = base; - base_node->id = stbds_hash_bytes(base_node, sizeof(ir_node), 0xcafebabe); - } - - ir_node *offset_node = calloc(1, sizeof(ir_node)); - offset_node->code = OC_CONST_INT; - offset_node->data.const_int = offset; - offset_node->id = stbds_hash_bytes(offset_node, sizeof(ir_node), 0xcafebabe); - - arrput(addr->out, base_node); - arrput(addr->out, offset_node); - - addr->id = stbds_hash_bytes(addr, sizeof(ir_node), 0xcafebabe); - ir_node *tmp = hmget(global_hash, *addr); - if (tmp) { - free(addr); - return tmp; - } - - return addr; -} - -static ir_node *build_assign_ptr(ast_node *binary) -{ - ir_node *val_node = build_expression(binary->expr.binary.right); - - char *var_name = binary->expr.binary.left->expr.string.start; - - ir_node *existing_def = get_def(var_name)->node; - - ir_node *store = calloc(1, sizeof(ir_node)); - store->code = OC_STORE; - - arrput(store->out, current_control); - - arrput(store->out, current_memory); - arrput(store->out, existing_def); - arrput(store->out, val_node); - - store->id = stbds_hash_bytes(store, sizeof(ir_node), 0xcafebabe); - hmput(global_hash, *store, store); - - current_memory = store; - - return val_node; -} - -static ir_node *build_assign(ast_node *binary) -{ - ir_node *val_node = build_expression(binary->expr.binary.right); - - char *var_name = binary->expr.binary.left->expr.string.start; - - struct symbol_def *def = get_def(var_name); - - if (def && def->is_lvalue) { - ir_node *existing_def = def->node; - ir_node *store = calloc(1, sizeof(ir_node)); - store->code = OC_STORE; - - arrput(store->out, current_control); - - arrput(store->out, current_memory); - arrput(store->out, existing_def); - arrput(store->out, val_node); - - store->id = stbds_hash_bytes(store, sizeof(ir_node), 0xcafebabe); - hmput(global_hash, *store, store); - - current_memory = store; - - return val_node; - } - - set_def(var_name, val_node, false); - return val_node; -} - -static ir_node *build_binary(ast_node *node) -{ - ir_node *n = calloc(1, sizeof(ir_node)); - switch (node->expr.binary.operator) { - case OP_ASSIGN: - free(n); - return build_assign(node); - case OP_ASSIGN_PTR: - free(n); - return build_assign_ptr(node); - case OP_PLUS: - n->code = OC_ADD; - break; - case OP_MINUS: - n->code = OC_SUB; - break; - case OP_DIV: - n->code = OC_DIV; - break; - case OP_MUL: - n->code = OC_MUL; - break; - case OP_MOD: - n->code = OC_MOD; - break; - case OP_BOR: - n->code = OC_BOR; - break; - case OP_BAND: - n->code = OC_BAND; - break; - case OP_BXOR: - n->code = OC_BXOR; - break; - case OP_EQ: - n->code = OC_EQ; - break; - default: - break; - } - arrput(n->out, build_expression(node->expr.binary.left)); - arrput(n->out, build_expression(node->expr.binary.right)); - n->id = stbds_hash_bytes(n, sizeof(ir_node), 0xcafebabe); - const_fold(n); - ir_node *tmp = hmget(global_hash, *n); - if (tmp) { - free(n); - return tmp; - } - - return n; -} - -static ir_node *build_load(ast_node *node) -{ - ir_node *n = calloc(1, sizeof(ir_node)); - n->code = OC_LOAD; - - arrput(n->out, current_memory); - arrput(n->out, build_expression(node)); - n->id = stbds_hash_bytes(n, sizeof(ir_node), 0xcafebabebabecafe); - - ir_node *tmp = hmget(global_hash, *n); - if (tmp) { - free(n); - return tmp; - } - - return n; -} - -static ir_node *build_unary(ast_node *node) -{ - ir_node *n = calloc(1, sizeof(ir_node)); - switch (node->expr.unary.operator) { - case UOP_MINUS: - n->code = OC_NEG; - arrput(n->out, build_expression(node->expr.unary.right)); - break; - case UOP_REF: - free(n); - - if (node->expr.unary.right->type == NODE_IDENTIFIER) { - struct symbol_def *def = get_def(node->expr.unary.right->expr.string.start); - if (def) { - return def->node; - } - } - - return build_expression(node->expr.unary.right); - case UOP_DEREF: - free(n); - return build_load(node->expr.unary.right); - default: - break; - } - - if (n->out && n->out[0]->code == OC_CONST_INT) { - switch (n->code) { - case OC_NEG: - n->data.const_int = -(n->out[0]->data.const_int); - break; - default: - break; - } - n->code = OC_CONST_INT; - arrfree(n->out); n->out = NULL; - } else if (n->out && n->out[0]->code == OC_CONST_FLOAT) { - switch (n->code) { - case OC_NEG: - n->data.const_float = -(n->out[0]->data.const_float); - break; - default: - break; - } - n->code = OC_CONST_FLOAT; - arrfree(n->out); n->out = NULL; - } - - n->id = stbds_hash_bytes(n, sizeof(ir_node), 0xcafebabe); - ir_node *tmp = hmget(global_hash, *n); - if (tmp) { - free(n); - return tmp; - } - - return n; -} - -static ir_node *build_if(ast_node *node) -{ - ir_node *condition = build_expression(node->expr.if_stmt.condition); - - ir_node *if_node = calloc(1, sizeof(ir_node)); - if_node->code = OC_IF; - arrput(if_node->out, condition); - arrput(if_node->out, current_control); - if_node->id = stbds_hash_bytes(if_node, sizeof(ir_node), 0xcafebabe); - hmput(global_hash, *if_node, if_node); - - ir_node *proj_true = calloc(1, sizeof(ir_node)); - proj_true->code = OC_PROJ; - arrput(proj_true->out, if_node); - proj_true->id = stbds_hash_bytes(proj_true, sizeof(ir_node), 0xcafebabe); - hmput(global_hash, *proj_true, proj_true); - - ir_node *proj_false = calloc(1, sizeof(ir_node)); - proj_false->code = OC_PROJ; - arrput(proj_false->out, if_node); - proj_false->id = stbds_hash_bytes(proj_false, sizeof(ir_node), 0xcafebabe); - hmput(global_hash, *proj_false, proj_false); - - ir_node *base_scope = copy_scope(current_scope); - ir_node *base_mem = current_memory; - - current_control = proj_true; - - ast_node *current = node->expr.if_stmt.body; - while (current && current->type == NODE_UNIT) { - if (current->expr.unit_node.expr) { - build_expression(current->expr.unit_node.expr); - } - current = current->expr.unit_node.next; - } - ir_node *then_scope = current_scope; - ir_node *then_mem = current_memory; - ir_node *then_control = current_control; - - current_scope = copy_scope(base_scope); - current_memory = base_mem; - - current_control = proj_false; - current = node->expr.if_stmt.otherwise; - while (current && current->type == NODE_UNIT) { - if (current->expr.unit_node.expr) { - build_expression(current->expr.unit_node.expr); - } - current = current->expr.unit_node.next; - } - ir_node *else_scope = current_scope; - ir_node *else_mem = current_memory; - ir_node *else_control = current_control; - - ir_node *region = calloc(1, sizeof(ir_node)); - region->code = OC_REGION; - arrput(region->out, then_control); - arrput(region->out, else_control); - region->id = stbds_hash_bytes(region, sizeof(ir_node), 0xcafebabe); - hmput(global_hash, *region, region); - - if (then_mem->id != else_mem->id) { - ir_node *phi = calloc(1, sizeof(ir_node)); - phi->code = OC_PHI; - arrput(phi->out, region); - arrput(phi->out, then_mem); - arrput(phi->out, else_mem); - phi->id = stbds_hash_bytes(phi, sizeof(ir_node), 0xcafebabe); - - hmput(global_hash, *phi, phi); - - current_memory = phi; - } else { - current_memory = then_mem; - } - - current_scope = base_scope; - - for (int i = 0; i < arrlen(current_scope->data.symbol_tables); i++) { - symbol_table *base_table = current_scope->data.symbol_tables[i]; - for (int j = 0; j < shlen(base_table); j++) { - char *key = base_table[j].key; - - ir_node *found_then = NULL; - symbol_table *t_table = then_scope->data.symbol_tables[i]; - if (shget(t_table, key)->node) found_then = shget(t_table, key)->node; - else found_then = base_table[j].value->node; - - ir_node *found_else = NULL; - symbol_table *e_table = else_scope->data.symbol_tables[i]; - if (shget(e_table, key)->node) found_else = shget(e_table, key)->node; - else found_else = base_table[j].value->node; - - if (found_then->id != found_else->id) { - ir_node *phi = calloc(1, sizeof(ir_node)); - phi->code = OC_PHI; - arrput(phi->out, region); - arrput(phi->out, found_then); - arrput(phi->out, found_else); - phi->id = stbds_hash_bytes(phi, sizeof(ir_node), 0xcafebabe); - struct symbol_def *def = calloc(1, sizeof(struct symbol_def)); - def->node = phi; - def->is_lvalue = false; - shput(current_scope->data.symbol_tables[i], key, def); - hmput(global_hash, *phi, phi); - } else { - struct symbol_def *def = calloc(1, sizeof(struct symbol_def)); - def->node = found_then; - def->is_lvalue = false; - shput(current_scope->data.symbol_tables[i], key, def); - } - } - } - - current_control = region; - - return region; -} - -static void build_return(ast_node *node) -{ - ir_node *val = NULL; - - if (node->expr.ret.value) { - val = build_expression(node->expr.ret.value); - } else { - val = calloc(1, sizeof(ir_node)); - val->code = OC_VOID; - val->id = stbds_hash_bytes(val, sizeof(ir_node), 0xcafebabe); - } - - arrput(current_func.return_controls, current_control); - arrput(current_func.return_memories, current_memory); - arrput(current_func.return_values, val); - - current_control = NULL; -} - -static void finalize_function(void) -{ - int count = arrlen(current_func.return_controls); - - if (count == 0) { - return; - } - - ir_node *final_ctrl = NULL; - ir_node *final_mem = NULL; - ir_node *final_val = NULL; - - if (count == 1) { - final_ctrl = current_func.return_controls[0]; - final_mem = current_func.return_memories[0]; - final_val = current_func.return_values[0]; - } - else { - ir_node *region = calloc(1, sizeof(ir_node)); - region->code = OC_REGION; - for (int i=0; iout, current_func.return_controls[i]); - } - hmput(global_hash, *region, region); - final_ctrl = region; - - ir_node *mem_phi = calloc(1, sizeof(ir_node)); - mem_phi->code = OC_PHI; - arrput(mem_phi->out, region); - for (int i=0; iout, current_func.return_memories[i]); - } - hmput(global_hash, *mem_phi, mem_phi); - mem_phi->id = stbds_hash_bytes(mem_phi, sizeof(ir_node), 0xcafebabe); - final_mem = mem_phi; - - ir_node *val_phi = calloc(1, sizeof(ir_node)); - val_phi->code = OC_PHI; - //arrput(val_phi->out, region); - for (int i=0; iout, current_func.return_values[i]); - } - val_phi->id = stbds_hash_bytes(val_phi, sizeof(ir_node), 0xcafebabe); - hmput(global_hash, *val_phi, val_phi); - final_val = val_phi; - - region->id = stbds_hash_bytes(region, sizeof(ir_node), 0xcafebabe); - } - - ir_node *ret = calloc(1, sizeof(ir_node)); - ret->code = OC_RETURN; - arrput(ret->out, final_ctrl); - arrput(ret->out, final_mem); - arrput(ret->out, final_val); - ret->id = stbds_hash_bytes(ret, sizeof(ir_node), 0xcafebabe); - - hmput(global_hash, *ret, ret); -} - -static ir_node *build_function(ast_node *node) -{ - memset(¤t_func, 0x0, sizeof(current_func)); - ast_node *current = node->expr.function.body; - - ir_node *func = calloc(1, sizeof(ir_node)); - func->code = OC_START; - func->id = stbds_hash_bytes(func, sizeof(ir_node), 0xcafebabe); - func->data.start_name = node->expr.function.name; - - ir_node *start_ctrl = calloc(1, sizeof(ir_node)); - start_ctrl->code = OC_PROJ; - start_ctrl->id = stbds_hash_bytes(&start_ctrl, sizeof(usize), 0xcafebabe); - arrput(start_ctrl->out, func); - hmput(global_hash, *start_ctrl, start_ctrl); - - current_control = start_ctrl; - - ir_node *start_mem = calloc(1, sizeof(ir_node)); - start_mem->code = OC_PROJ; - start_mem->id = stbds_hash_bytes(&start_mem, sizeof(usize), 0xcafebabe); - arrput(start_mem->out, func); - hmput(global_hash, *start_mem, start_mem); - - current_memory = start_mem; - - current_scope = calloc(1, sizeof(ir_node)); - current_scope->code = OC_SCOPE; - - push_scope(); - - member *m = node->expr.function.parameters; - while (m) { - ir_node *proj_param = calloc(1, sizeof(ir_node)); - proj_param->code = OC_PROJ; - arrput(proj_param->out, func); - proj_param->id = stbds_hash_bytes(proj_param, sizeof(ir_node), 0xcafebabe); - set_def(m->name, proj_param, false); - hmput(global_hash, *proj_param, proj_param); - - m = m->next; - } - - while (current && current->type == NODE_UNIT) { - if (current->expr.unit_node.expr) { - build_expression(current->expr.unit_node.expr); - } - current = current->expr.unit_node.next; - } - - func->id = stbds_hash_bytes(func, sizeof(ir_node), 0xcafebabe); - - finalize_function(); - - return func; -} - -static ir_node *build_expression(ast_node *node) -{ - ir_node *n = NULL; - ir_node *tmp = NULL; - switch (node->type) { - case NODE_UNARY: - n = build_unary(node); - break; - case NODE_BINARY: - n = build_binary(node); - break; - case NODE_INTEGER: - n = calloc(1, sizeof(ir_node)); - n->code = OC_CONST_INT; - n->data.const_int = node->expr.integer; - n->id = stbds_hash_bytes(n, sizeof(ir_node), 0xcafebabe); - tmp = hmget(global_hash, *n); - if (tmp) { - free(n); - return tmp; - } - break; - case NODE_VAR_DECL: - n = calloc(1, sizeof(ir_node)); - if (node->address_taken) { - n->code = OC_STORE; - - arrput(n->out, current_memory); - arrput(n->out, build_address(-1, current_stack)); - arrput(n->out, build_expression(node->expr.var_decl.value)); - current_memory = n; - current_stack += node->expr_type->size; - n->id = stbds_hash_bytes(n, sizeof(ir_node), 0xcafebabe); - hmput(global_hash, *n, n); - n = n->out[1]; - set_def(node->expr.var_decl.name, n, true); - } else { - n = build_expression(node->expr.var_decl.value); - set_def(node->expr.var_decl.name, n, false); - } - - return n; - case NODE_IDENTIFIER: - struct symbol_def *def = get_def(node->expr.string.start); - n = def->node; - - if (n && def->is_lvalue) { - ir_node *addr_node = n; - - n = calloc(1, sizeof(ir_node)); - n->code = OC_LOAD; - - arrput(n->out, current_memory); - arrput(n->out, addr_node); - - n->id = stbds_hash_bytes(n, sizeof(ir_node), 0xcafebabe); - - ir_node *tmp = hmget(global_hash, *n); - if (tmp) { - free(n); - n = tmp; - } else { - hmput(global_hash, *n, n); - } - } - break; - case NODE_IF: - n = build_if(node); - break; - case NODE_RETURN: - build_return(node); - break; - default: - break; - } - - if (n) hmput(global_hash, *n, n); - return n; -} - -void ir_build(ast_node *ast) -{ - ast_node *current = ast; - - graph = calloc(1, sizeof(ir_node)); - graph->code = OC_START; - graph->id = stbds_hash_bytes(graph, sizeof(ir_node), 0xcafebabe); - graph->data.start_name = "program"; - - current_memory = calloc(1, sizeof(ir_node)); - current_memory->code = OC_FRAME_PTR; - current_memory->id = stbds_hash_bytes(current_memory, sizeof(ir_node), 0xcafebabe); - - current_scope = calloc(1, sizeof(ir_node)); - current_scope->code = OC_SCOPE; - push_scope(); - - while (current && current->type == NODE_UNIT) { - if (current->expr.unit_node.expr && current->expr.unit_node.expr->type == NODE_FUNCTION) { - ir_node *expr = build_function(current->expr.unit_node.expr); - arrput(graph->out, expr); - hmput(global_hash, *expr, expr); - } - current = current->expr.unit_node.next; - } - printf("digraph G {\n"); - print_graph(graph); - printf("}\n"); -} diff --git a/ir.h b/ir.h deleted file mode 100644 index bfd684f..0000000 --- a/ir.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef IR_H -#define IR_H - -#include "utils.h" -#include "parser.h" - -struct _ir_node; -struct symbol_def { - struct _ir_node *node; - bool is_lvalue; -}; - -typedef struct { char *key; struct symbol_def *value; } symbol_table; - -typedef enum { - OC_START, - OC_ADD, - OC_SUB, - OC_MUL, - OC_DIV, - OC_MOD, - OC_BAND, - OC_BOR, - OC_BXOR, - OC_NEG, - OC_EQ, - - OC_CONST_INT, - OC_CONST_FLOAT, - OC_VOID, - - OC_FRAME_PTR, - OC_ADDR, - - OC_STORE, - OC_LOAD, - - OC_REGION, - OC_PHI, - - OC_IF, - OC_PROJ, - - OC_STOP, - OC_RETURN, - - OC_SCOPE, -} opcode; - -typedef struct _ir_node { - opcode code; - usize id; - struct _ir_node **in; - struct _ir_node **out; - union { - i64 const_int; - f64 const_float; - symbol_table **symbol_tables; - char *start_name; - } data; -} ir_node; - -void ir_build(ast_node *ast); - -#endif diff --git a/lc.c b/lc.c index 0d0ddbb..ad01157 100644 --- a/lc.c +++ b/lc.c @@ -4,7 +4,7 @@ #include "lexer.h" #include "parser.h" #include "sema.h" -#include "ir.h" +#include "codegen.h" void print_indent(int depth) { for (int i = 0; i < depth; i++) printf(" "); @@ -230,10 +230,10 @@ int main(void) arena a = arena_init(0x1000 * 0x1000 * 64); lexer *l = lexer_init(src, size, &a); parser *p = parser_init(l, &a); - //print_ast(p->ast, 0); + print_ast(p->ast, 0); sema_init(p, &a); - ir_build(p->ast); + generate(p->ast); arena_deinit(a); diff --git a/sema.c b/sema.c index 9f2033d..f116912 100644 --- a/sema.c +++ b/sema.c @@ -26,9 +26,11 @@ static type *const_int = NULL; static type *const_float = NULL; static bool in_loop = false; +static bool has_errors = false; static void error(ast_node *n, char *msg) { + has_errors = true; if (n) { printf("\x1b[31m\x1b[1merror\x1b[0m\x1b[1m:%ld:%ld:\x1b[0m %s\n", n->position.row, n->position.column, msg); } else { @@ -133,6 +135,16 @@ static type *get_type(sema *s, ast_node *n) char *name = NULL; type *t = NULL; switch (n->type) { + case NODE_ACCESS: + t = get_type(s, n->expr.access.expr); + name = intern_string(s, n->expr.access.member->expr.string.start, n->expr.access.member->expr.string.len); + if (t->tag != TYPE_STRUCT) { + error(n->expr.access.expr, "expected structure."); + return NULL; + } + t = shget(t->data.structure.member_types, name); + + return t; case NODE_IDENTIFIER: name = intern_string(s, n->expr.string.start, n->expr.string.len); t = shget(type_reg, name); @@ -433,7 +445,8 @@ static bool can_cast(type *source, type *dest) switch (dest->tag) { case TYPE_INTEGER: case TYPE_UINTEGER: - return source->tag == TYPE_INTEGER_CONST; + case TYPE_INTEGER_CONST: + return source->tag == TYPE_INTEGER_CONST || source->tag == TYPE_INTEGER || source->tag == TYPE_UINTEGER; case TYPE_FLOAT: return source->tag == TYPE_FLOAT_CONST; default: @@ -558,11 +571,20 @@ static type *get_expression_type(sema *s, ast_node *node) node->expr_type = t; return t; case NODE_CALL: - prot = shget(prototypes, intern_string(s, node->expr.call.name, node->expr.call.name_len)); + node->expr.call.name = intern_string(s, node->expr.call.name, node->expr.call.name_len); + prot = shget(prototypes, node->expr.call.name); if (!prot) { error(node, "unknown function."); return NULL; } + // Process call arguments + ast_node *arg = node->expr.call.parameters; + while (arg && arg->type == NODE_UNIT) { + if (arg->expr.unit_node.expr) { + get_expression_type(s, arg->expr.unit_node.expr); + } + arg = arg->expr.unit_node.next; + } t = prot->type; node->expr_type = t; return t; @@ -709,8 +731,9 @@ static void check_statement(sema *s, ast_node *node) error(node, "redeclaration of variable."); break; } - if (!can_cast(get_expression_type(s, node->expr.var_decl.value), t) && !match(t, get_expression_type(s, node->expr.var_decl.value))) { - error(node, "type mismatch."); + if (t->tag == TYPE_STRUCT) { + } else if (!can_cast(get_expression_type(s, node->expr.var_decl.value), t) && !match(t, get_expression_type(s, node->expr.var_decl.value))) { + error(node, "type mismatch (decl)."); } shput(current_scope->defs, name, node); break; @@ -815,4 +838,9 @@ void sema_init(parser *p, arena *a) const_float->data.flt = 0; analyze_unit(s, s->ast); + + if (has_errors) { + printf("Compilation failed.\n"); + exit(1); + } } diff --git a/test b/test new file mode 100755 index 0000000000000000000000000000000000000000..2fd1a557d42dcbcf3a1a56613ba75f0bfc91cf33 GIT binary patch literal 20192 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 literal 0 HcmV?d00001 diff --git a/test.l b/test.l index 6c3aec2..1aac346 100644 --- a/test.l +++ b/test.l @@ -1,12 +1,10 @@ -u32 main(u32 b) -{ - u32 a = 4; - //return a; - if (b == 3) { - return 3; - } else { - return 4; - } - - return a; +struct point { + i32 x, + i32 y +} + +i32 main() +{ + point result = .{ x = 2, y = 1 }; + return (result.y) + 2; } diff --git a/test.s b/test.s new file mode 100644 index 0000000..9d3b3f4 --- /dev/null +++ b/test.s @@ -0,0 +1,20 @@ +.section .text +.global main +main: +push %rbp +mov %rsp, %rbp +sub $256, %rsp +mov $2, %rax +mov %eax, -8(%rbp) +mov $1, %rax +mov %eax, -12(%rbp) +mov -12(%rbp), %rax +mov %rax, %rcx +mov $2, %rax +add %rcx, %rax +mov %rbp, %rsp +pop %rbp +ret +mov %rbp, %rsp +pop %rbp +ret diff --git a/test_control b/test_control new file mode 100755 index 0000000000000000000000000000000000000000..d9550eee03315872647ea0586c219e355182dbcf GIT binary patch literal 21712 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±U*cV@>Hk^n|E%_J^v&hg+kf8Q;;K{ge_rdK*ZL{#EC@*7MxPH` zSU!M*qQ<{@pFOAt%Ij%;@%BH1M!tJC`sRJ}l-8$T7Sn$tXCNPd^If)~&HLAEz~&Wgw#NH2VD zpATp2i)PnY+&9$go9pJ`b|unOlT?V;{};4=?b;nnD#4fnUU@?s_?Hl)e-l5mU+`;v zv;LGd6>EbNK8&MYKc@Z1Vr*3pf)u7|6Mw^d3`qU?XZD46#*~Bxia>4pZ5U4j!E;i% zhRHMgEb~8VUVnx*kdK}4B(|n+_H{`rr|}PEi;8=hG;(`iFa! z!g0?D=rJeOFQWhIwMzeXb7E=#Uj5CB=%iQgfadNUZYK`2p3J)D h^q93L6-_mwkOw>tJtXcW7S?~@50rkvqu?RM{{V1A{rUg^ literal 0 HcmV?d00001 diff --git a/test_control.l b/test_control.l new file mode 100644 index 0000000..d8576a2 --- /dev/null +++ b/test_control.l @@ -0,0 +1,23 @@ +i32 main() +{ + i32 x = 0; + i32 i = 0; + + // Test while loop with break + while (i < 10) { + i = i + 1; + if (i == 5) { + break; + } + x = x + i; + } + + // Test goto and label + if (x == 10) { + goto skip; + } + x = 999; + + skip: + return x; +} diff --git a/test_simple b/test_simple new file mode 100755 index 0000000000000000000000000000000000000000..d9550eee03315872647ea0586c219e355182dbcf GIT binary patch literal 21712 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±U*cV@>Hk^n|E%_J^v&hg+kf8Q;;K{ge_rdK*ZL{#EC@*7MxPH` zSU!M*qQ<{@pFOAt%Ij%;@%BH1M!tJC`sRJ}l-8$T7Sn$tXCNPd^If)~&HLAEz~&Wgw#NH2VD zpATp2i)PnY+&9$go9pJ`b|unOlT?V;{};4=?b;nnD#4fnUU@?s_?Hl)e-l5mU+`;v zv;LGd6>EbNK8&MYKc@Z1Vr*3pf)u7|6Mw^d3`qU?XZD46#*~Bxia>4pZ5U4j!E;i% zhRHMgEb~8VUVnx*kdK}4B(|n+_H{`rr|}PEi;8=hG;(`iFa! z!g0?D=rJeOFQWhIwMzeXb7E=#Uj5CB=%iQgfadNUZYK`2p3J)D h^q93L6-_mwkOw>tJtXcW7S?~@50rkvqu?RM{{V1A{rUg^ literal 0 HcmV?d00001 diff --git a/test_simple.l b/test_simple.l new file mode 100644 index 0000000..61dc5fb --- /dev/null +++ b/test_simple.l @@ -0,0 +1,13 @@ +i32 main() +{ + i32 x = 0; + + while (x < 10) { + x = x + 1; + if (x == 5) { + break; + } + } + + return x; +} From 870cf8f0b41251b59e602cabb236749155f40d4a Mon Sep 17 00:00:00 2001 From: Lorenzo Torres Date: Fri, 16 Jan 2026 23:26:28 +0100 Subject: [PATCH 2/3] codegen almost finished --- codegen.c | 430 +++++++++++++++++++++++++++++++++++++++++++------ done.txt | 0 parser.c | 47 +++++- parser.h | 1 + report.txt | 0 sema.c | 90 ++++++++++- test | Bin 20192 -> 0 bytes test.l | 22 ++- test.s | 20 --- test_control | Bin 21712 -> 0 bytes test_control.l | 23 --- test_simple | Bin 21712 -> 0 bytes test_simple.l | 13 -- todo.cfg | 2 - todo.txt | 1 - 15 files changed, 523 insertions(+), 126 deletions(-) delete mode 100644 done.txt delete mode 100644 report.txt delete mode 100755 test delete mode 100644 test.s delete mode 100755 test_control delete mode 100644 test_control.l delete mode 100755 test_simple delete mode 100644 test_simple.l delete mode 100644 todo.cfg delete mode 100644 todo.txt diff --git a/codegen.c b/codegen.c index 7220d49..552bb77 100644 --- a/codegen.c +++ b/codegen.c @@ -447,72 +447,240 @@ void gen_expr(FILE *fp, ast_node *expr) gen_expr(fp, expr->expr.cast.value); break; case NODE_VAR_DECL: { - int offset; - if (expr->expr.var_decl.type && expr->expr.var_decl.type->expr_type) { - usize var_size = expr->expr.var_decl.type->expr_type->size; - offset = get_var_offset_sized(expr->expr.var_decl.name, - expr->expr.var_decl.name_len, var_size); - } else { - offset = get_var_offset(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + int offset = 0; + type *var_type = expr->expr_type; + if (!var_type && expr->expr.var_decl.type) { + var_type = expr->expr.var_decl.type->expr_type; + } + + bool is_inline_slice = false; + if (var_type && var_type->tag == TYPE_SLICE && expr->expr.var_decl.value && + (expr->expr.var_decl.value->type == NODE_STRUCT_INIT || + expr->expr.var_decl.value->type == NODE_RANGE)) { + is_inline_slice = true; + } + + if (!is_inline_slice) { + if (var_type && var_type->size > 0) { + offset = get_var_offset_sized(expr->expr.var_decl.name, + expr->expr.var_decl.name_len, var_type->size); + } else { + offset = get_var_offset(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + } } if (expr->expr.var_decl.value) { - if (expr->expr.var_decl.value->type == NODE_STRUCT_INIT) { + if (expr->expr.var_decl.value->type == NODE_RANGE && var_type && var_type->tag == TYPE_SLICE) { + ast_node *range = expr->expr.var_decl.value; + if (range->expr.binary.left->type == NODE_INTEGER && + range->expr.binary.right->type == NODE_INTEGER) { + i64 start = range->expr.binary.left->expr.integer; + i64 end = range->expr.binary.right->expr.integer; + i64 count = end - start + 1; + + type *element_type = var_type->data.slice.child; + usize element_size = element_type ? element_type->size : 8; + + usize data_size = count * element_size; + usize aligned_data_size = (data_size + 7) & ~7; + stack_offset += aligned_data_size; + int data_offset = stack_offset; + + stack_offset += 16; + offset = stack_offset; + + char *var_name = strndup(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + shput(variables, var_name, offset); + + for (i64 i = 0; i < count; i++) { + i64 value = start + i; + int element_offset = data_offset - (i * element_size); + fprintf(fp, "mov $%ld, %%rax\n", value); + if (element_size == 4) { + fprintf(fp, "mov %%eax, -%d(%%rbp)\n", element_offset); + } else if (element_size == 2) { + fprintf(fp, "mov %%ax, -%d(%%rbp)\n", element_offset); + } else if (element_size == 1) { + fprintf(fp, "mov %%al, -%d(%%rbp)\n", element_offset); + } else { + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", element_offset); + } + } + + fprintf(fp, "lea -%d(%%rbp), %%rax\n", data_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + fprintf(fp, "mov $%ld, %%rax\n", count); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset - 8); + } + } else if (expr->expr.var_decl.value->type == NODE_STRING && var_type && var_type->tag == TYPE_SLICE) { + ast_node *str = expr->expr.var_decl.value; + usize str_len = str->expr.string.len; + char *str_data = str->expr.string.start; + + usize aligned_data_size = (str_len + 7) & ~7; + stack_offset += aligned_data_size; + int data_offset = stack_offset; + + stack_offset += 16; + offset = stack_offset; + + char *var_name = strndup(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + shput(variables, var_name, offset); + + for (usize i = 0; i < str_len; i++) { + int byte_offset = data_offset - i; + if ((unsigned char)str_data[i] == '\\' && (unsigned char)str_data[i+1] == 'n') { + fprintf(fp, "movb $%d, -%d(%%rbp)\n", (unsigned char)'\n', byte_offset); + i += 1; + } else { + fprintf(fp, "movb $%d, -%d(%%rbp)\n", (unsigned char)str_data[i], byte_offset); + } + } + + fprintf(fp, "lea -%d(%%rbp), %%rax\n", data_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + fprintf(fp, "mov $%lu, %%rax\n", str_len); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset - 8); + } else if (expr->expr.var_decl.value->type == NODE_STRUCT_INIT) { ast_node *member_list = expr->expr.var_decl.value->expr.struct_init.members; ast_node *current = member_list; - type *struct_type = expr->expr_type; - if (!struct_type && expr->expr.var_decl.type) { - struct_type = expr->expr.var_decl.type->expr_type; - } + if (var_type && var_type->tag == TYPE_STRUCT) { + while (current && current->type == NODE_UNIT) { + ast_node *assignment = current->expr.unit_node.expr; + if (assignment && assignment->type == NODE_BINARY && + assignment->expr.binary.operator == OP_ASSIGN) { + ast_node *field = assignment->expr.binary.left; + ast_node *value = assignment->expr.binary.right; - while (current && current->type == NODE_UNIT) { - ast_node *assignment = current->expr.unit_node.expr; - if (assignment && assignment->type == NODE_BINARY && - assignment->expr.binary.operator == OP_ASSIGN) { - ast_node *field = assignment->expr.binary.left; - ast_node *value = assignment->expr.binary.right; + if (field->type == NODE_IDENTIFIER) { + char *field_name = strndup(field->expr.string.start, + field->expr.string.len); - if (field->type == NODE_IDENTIFIER && struct_type && - struct_type->tag == TYPE_STRUCT) { - char *field_name = strndup(field->expr.string.start, - field->expr.string.len); - - member *m = struct_type->data.structure.members; - int field_offset = -1; - while (m) { - if (m->name_len == field->expr.string.len && - strncmp(m->name, field->expr.string.start, m->name_len) == 0) { - field_offset = m->offset; - break; + member *m = var_type->data.structure.members; + int field_offset = -1; + while (m) { + if (m->name_len == field->expr.string.len && + strncmp(m->name, field->expr.string.start, m->name_len) == 0) { + field_offset = m->offset; + break; + } + m = m->next; } - m = m->next; - } - if (field_offset >= 0) { + if (field_offset >= 0) { + gen_expr(fp, value); + + type *field_type = shget(var_type->data.structure.member_types, field_name); + + if (field_type && field_type->size == 4) { + fprintf(fp, "mov %%eax, -%d(%%rbp)\n", offset + field_offset); + } else if (field_type && field_type->size == 2) { + fprintf(fp, "mov %%ax, -%d(%%rbp)\n", offset + field_offset); + } else if (field_type && field_type->size == 1) { + fprintf(fp, "mov %%al, -%d(%%rbp)\n", offset + field_offset); + } else { + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset + field_offset); + } + } + + free(field_name); + } + } + current = current->expr.unit_node.next; + } + } + else if (var_type && (var_type->tag == TYPE_PTR || var_type->tag == TYPE_SLICE)) { + usize element_size = 8; + type *element_type = NULL; + + if (var_type->tag == TYPE_PTR && var_type->data.ptr.child) { + element_type = var_type->data.ptr.child; + element_size = element_type->size; + } else if (var_type->tag == TYPE_SLICE && var_type->data.slice.child) { + element_type = var_type->data.slice.child; + element_size = element_type->size; + } + + int element_count = 0; + ast_node *count_node = current; + while (count_node && count_node->type == NODE_UNIT) { + element_count++; + count_node = count_node->expr.unit_node.next; + } + if (var_type->tag == TYPE_SLICE) { + usize data_size = element_count * element_size; + usize aligned_data_size = (data_size + 7) & ~7; + stack_offset += aligned_data_size; + int data_offset = stack_offset; + stack_offset += 16; + offset = stack_offset; + + char *var_name = strndup(expr->expr.var_decl.name, expr->expr.var_decl.name_len); + shput(variables, var_name, offset); + + int index = 0; + while (current && current->type == NODE_UNIT) { + ast_node *value = current->expr.unit_node.expr; + if (value) { gen_expr(fp, value); - type *field_type = shget(struct_type->data.structure.member_types, field_name); + int element_offset = data_offset - (index * element_size); - if (field_type && field_type->size == 4) { - fprintf(fp, "mov %%eax, -%d(%%rbp)\n", offset + field_offset); - } else if (field_type && field_type->size == 2) { - fprintf(fp, "mov %%ax, -%d(%%rbp)\n", offset + field_offset); - } else if (field_type && field_type->size == 1) { - fprintf(fp, "mov %%al, -%d(%%rbp)\n", offset + field_offset); + if (element_type && element_type->size == 4) { + fprintf(fp, "mov %%eax, -%d(%%rbp)\n", element_offset); + } else if (element_type && element_type->size == 2) { + fprintf(fp, "mov %%ax, -%d(%%rbp)\n", element_offset); + } else if (element_type && element_type->size == 1) { + fprintf(fp, "mov %%al, -%d(%%rbp)\n", element_offset); } else { - fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset + field_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", element_offset); } } + index++; + current = current->expr.unit_node.next; + } - free(field_name); + fprintf(fp, "lea -%d(%%rbp), %%rax\n", data_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + fprintf(fp, "mov $%d, %%rax\n", element_count); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset - 8); + } else { + int index = 0; + while (current && current->type == NODE_UNIT) { + ast_node *value = current->expr.unit_node.expr; + if (value) { + gen_expr(fp, value); + + int element_offset = offset + (index * element_size); + + if (element_type && element_type->size == 4) { + fprintf(fp, "mov %%eax, -%d(%%rbp)\n", element_offset); + } else if (element_type && element_type->size == 2) { + fprintf(fp, "mov %%ax, -%d(%%rbp)\n", element_offset); + } else if (element_type && element_type->size == 1) { + fprintf(fp, "mov %%al, -%d(%%rbp)\n", element_offset); + } else { + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", element_offset); + } + } + index++; + current = current->expr.unit_node.next; } } - current = current->expr.unit_node.next; } } else { gen_expr(fp, expr->expr.var_decl.value); - fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + + // If assigning a slice value, copy the 16-byte structure + if (var_type && var_type->tag == TYPE_SLICE) { + fprintf(fp, "mov (%%rax), %%rcx\n"); // Load ptr field + fprintf(fp, "mov 8(%%rax), %%rdx\n"); // Load len field + fprintf(fp, "mov %%rcx, -%d(%%rbp)\n", offset); // Store ptr + fprintf(fp, "mov %%rdx, -%d(%%rbp)\n", offset - 8); // Store len + } else { + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + } } } break; @@ -598,12 +766,24 @@ void gen_expr(FILE *fp, ast_node *expr) if (base->type == NODE_IDENTIFIER) { int base_offset = get_var_offset(base->expr.string.start, base->expr.string.len); + type *base_type = base->expr_type; - type *struct_type = base->expr_type; + if (base_type && base_type->tag == TYPE_SLICE && member_node->type == NODE_IDENTIFIER) { + char *field_name = strndup(member_node->expr.string.start, member_node->expr.string.len); - if (member_node->type == NODE_IDENTIFIER && struct_type && - struct_type->tag == TYPE_STRUCT) { - member *m = struct_type->data.structure.members; + if (strcmp(field_name, "ptr") == 0) { + fprintf(fp, "mov -%d(%%rbp), %%rax\n", base_offset); + } else if (strcmp(field_name, "len") == 0) { + fprintf(fp, "mov -%d(%%rbp), %%rax\n", base_offset - 8); + } else { + fprintf(fp, "# ERROR: slice field '%s' not found\n", field_name); + } + + free(field_name); + } + else if (member_node->type == NODE_IDENTIFIER && base_type && + base_type->tag == TYPE_STRUCT) { + member *m = base_type->data.structure.members; int field_offset = -1; while (m) { if (m->name_len == member_node->expr.string.len && @@ -620,17 +800,165 @@ void gen_expr(FILE *fp, ast_node *expr) fprintf(fp, "# ERROR: field not found\n"); } } else { - fprintf(fp, "# ERROR: not a struct type\n"); + fprintf(fp, "# ERROR: not a struct or slice type\n"); } } else { fprintf(fp, "# ERROR: complex struct access not implemented\n"); } break; } + case NODE_RANGE: { + if (expr->expr.binary.left->type == NODE_INTEGER && + expr->expr.binary.right->type == NODE_INTEGER) { + i64 start = expr->expr.binary.left->expr.integer; + i64 end = expr->expr.binary.right->expr.integer; + i64 count = end - start + 1; + + usize element_size = 8; + usize data_size = count * element_size; + usize aligned_data_size = (data_size + 7) & ~7; + stack_offset += aligned_data_size; + int data_offset = stack_offset; + + for (i64 i = 0; i < count; i++) { + i64 value = start + i; + int element_offset = data_offset - (i * element_size); + fprintf(fp, "mov $%ld, %%rax\n", value); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", element_offset); + } + + stack_offset += 16; + int slice_offset = stack_offset; + + fprintf(fp, "lea -%d(%%rbp), %%rax\n", data_offset); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", slice_offset); + fprintf(fp, "mov $%ld, %%rax\n", count); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", slice_offset - 8); + + fprintf(fp, "lea -%d(%%rbp), %%rax\n", slice_offset); + } else { + fprintf(fp, "# ERROR: range expression requires constant bounds\n"); + } + break; + } case NODE_STRUCT_INIT: { fprintf(fp, "# ERROR: struct init outside of variable declaration\n"); break; } + case NODE_ARRAY_SUBSCRIPT: { + usize element_size = 8; + type *base_type = expr->expr.subscript.expr->expr_type; + bool is_slice = false; + + if (base_type) { + if (base_type->tag == TYPE_PTR && base_type->data.ptr.child) { + element_size = base_type->data.ptr.child->size; + } else if (base_type->tag == TYPE_SLICE && base_type->data.slice.child) { + element_size = base_type->data.slice.child->size; + is_slice = true; + } + } + + if (expr->expr.subscript.index->type == NODE_RANGE) { + if (expr->expr.subscript.expr->type == NODE_IDENTIFIER) { + int base_offset = get_var_offset(expr->expr.subscript.expr->expr.string.start, + expr->expr.subscript.expr->expr.string.len); + + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", base_offset); + + gen_expr(fp, expr->expr.subscript.index->expr.binary.left); + fprintf(fp, "push %%rax\n"); + + gen_expr(fp, expr->expr.subscript.index->expr.binary.right); + fprintf(fp, "mov %%rax, %%rdx\n"); // rdx = end + fprintf(fp, "pop %%rax\n"); // rax = start + fprintf(fp, "mov %%rdx, %%r8\n"); + fprintf(fp, "sub %%rax, %%r8\n"); + fprintf(fp, "inc %%r8\n"); // r8 = new length + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + fprintf(fp, "add %%rcx, %%rax\n"); // rax = new ptr + + // Allocate temporary slice struct (16 bytes) + stack_offset += 16; + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", stack_offset); // Store ptr + fprintf(fp, "mov %%r8, -%d(%%rbp)\n", stack_offset - 8); // Store len + fprintf(fp, "lea -%d(%%rbp), %%rax\n", stack_offset); // Return address of temp slice + } + } + else if (expr->expr.subscript.expr->type == NODE_IDENTIFIER && is_slice) { + int base_offset = get_var_offset(expr->expr.subscript.expr->expr.string.start, + expr->expr.subscript.expr->expr.string.len); + + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", base_offset); + + gen_expr(fp, expr->expr.subscript.index); + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + + fprintf(fp, "add %%rcx, %%rax\n"); + + if (expr->expr_type && expr->expr_type->size == 4) { + fprintf(fp, "movl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 2) { + fprintf(fp, "movzwl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 1) { + fprintf(fp, "movzbl (%%rax), %%eax\n"); + } else { + fprintf(fp, "mov (%%rax), %%rax\n"); + } + } else if (expr->expr.subscript.expr->type == NODE_IDENTIFIER) { + int base_offset = get_var_offset(expr->expr.subscript.expr->expr.string.start, + expr->expr.subscript.expr->expr.string.len); + + gen_expr(fp, expr->expr.subscript.index); + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + + fprintf(fp, "add $%d, %%rax\n", base_offset); + fprintf(fp, "neg %%rax\n"); + fprintf(fp, "add %%rbp, %%rax\n"); + + if (expr->expr_type && expr->expr_type->size == 4) { + fprintf(fp, "movl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 2) { + fprintf(fp, "movzwl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 1) { + fprintf(fp, "movzbl (%%rax), %%eax\n"); + } else { + fprintf(fp, "mov (%%rax), %%rax\n"); + } + } else { + gen_expr(fp, expr->expr.subscript.expr); + fprintf(fp, "push %%rax\n"); + + gen_expr(fp, expr->expr.subscript.index); + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + + fprintf(fp, "pop %%rcx\n"); + fprintf(fp, "add %%rcx, %%rax\n"); + + if (expr->expr_type && expr->expr_type->size == 4) { + fprintf(fp, "movl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 2) { + fprintf(fp, "movzwl (%%rax), %%eax\n"); + } else if (expr->expr_type && expr->expr_type->size == 1) { + fprintf(fp, "movzbl (%%rax), %%eax\n"); + } else { + fprintf(fp, "mov (%%rax), %%rax\n"); + } + } + break; + } case NODE_CALL: { const char *arg_regs[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"}; @@ -676,6 +1004,10 @@ void gen_expr(FILE *fp, ast_node *expr) void gen_function(FILE *fp, ast_node *fn) { + if (fn->expr.function.is_extern || fn->expr.function.body == NULL) { + return; + } + ast_node *current = fn->expr.function.body; stack_offset = 0; diff --git a/done.txt b/done.txt deleted file mode 100644 index e69de29..0000000 diff --git a/parser.c b/parser.c index 8061fc1..4fd7c65 100644 --- a/parser.c +++ b/parser.c @@ -1089,6 +1089,7 @@ static ast_node *parse_function(parser *p) { ast_node *fn = arena_alloc(p->allocator, sizeof(ast_node)); fn->type = NODE_FUNCTION; + fn->expr.function.is_extern = false; fn->expr.function.type = parse_type(p); fn->expr.function.name = peek(p)->lexeme; fn->expr.function.name_len = peek(p)->lexeme_len; @@ -1097,7 +1098,14 @@ static ast_node *parse_function(parser *p) advance(p); if (match(p, TOKEN_RPAREN)) { - fn->expr.function.body = parse_compound(p);; + // Check if this is an extern declaration (semicolon) or definition (body) + if (match_peek(p, TOKEN_SEMICOLON)) { + // Extern function - no body, just consume semicolon + advance(p); + fn->expr.function.body = NULL; + } else { + fn->expr.function.body = parse_compound(p); + } fn->expr.function.parameters = NULL; fn->expr.function.parameters_len = 0; return fn; @@ -1111,7 +1119,13 @@ static ast_node *parse_function(parser *p) error(p, "expected `,`."); return NULL; } else { - fn->expr.function.body = parse_compound(p); + // Check if this is an extern declaration (semicolon) or definition (body) + if (match_peek(p, TOKEN_SEMICOLON)) { + advance(p); + fn->expr.function.body = NULL; + } else { + fn->expr.function.body = parse_compound(p); + } return fn; } } @@ -1132,7 +1146,14 @@ static ast_node *parse_function(parser *p) prev = current; } - fn->expr.function.body = parse_compound(p); + + // Check if this is an extern declaration (semicolon) or definition (body) + if (match_peek(p, TOKEN_SEMICOLON)) { + advance(p); + fn->expr.function.body = NULL; + } else { + fn->expr.function.body = parse_compound(p); + } return fn; } @@ -1140,6 +1161,13 @@ static ast_node *parse_function(parser *p) static ast_node *parse_statement(parser *p) { token *cur = peek(p); + + /* Check for extern function declaration */ + bool is_extern = false; + if (match(p, TOKEN_EXTERN)) { + is_extern = true; + } + ast_node *type = parse_type(p); if (type && type->type == NODE_STRUCT && type->expr.structure.name_len > 0) { goto skip_struct; @@ -1148,9 +1176,20 @@ static ast_node *parse_statement(parser *p) if (p->tokens->next && p->tokens->next->type == TOKEN_LPAREN) { /* Function definition. */ p->tokens = cur; - return parse_function(p); + if (is_extern) { + advance(p); // Skip TOKEN_EXTERN + } + ast_node *fn = parse_function(p); + if (fn && is_extern) { + fn->expr.function.is_extern = true; + fn->expr.function.body = NULL; + } + return fn; } p->tokens = cur; + if (is_extern) { + advance(p); // Skip TOKEN_EXTERN for non-function case + } /* Variable declaration. */ ast_node *node = arena_alloc(p->allocator, sizeof(ast_node)); node->type = NODE_VAR_DECL; diff --git a/parser.h b/parser.h index dced7ec..bbe3d0c 100644 --- a/parser.h +++ b/parser.h @@ -230,6 +230,7 @@ typedef struct _ast_node { usize name_len; struct _ast_node *type; struct _ast_node *body; + bool is_extern; } function; struct { variant *variants; diff --git a/report.txt b/report.txt deleted file mode 100644 index e69de29..0000000 diff --git a/sema.c b/sema.c index f116912..4e87625 100644 --- a/sema.c +++ b/sema.c @@ -152,17 +152,18 @@ static type *get_type(sema *s, ast_node *n) return t; case NODE_PTR_TYPE: t = malloc(sizeof(type)); - t->size = sizeof(usize); t->alignment = sizeof(usize); if (n->expr.ptr_type.flags & PTR_RAW) { t->name = "ptr"; t->tag = TYPE_PTR; + t->size = sizeof(usize); t->data.ptr.child = get_type(s, n->expr.ptr_type.type); t->data.ptr.is_const = (n->expr.ptr_type.flags & PTR_CONST) != 0; t->data.ptr.is_volatile = (n->expr.ptr_type.flags & PTR_VOLATILE) != 0; } else { t->name = "slice"; t->tag = TYPE_SLICE; + t->size = sizeof(usize) * 2; // ptr + len = 16 bytes t->data.slice.child = get_type(s, n->expr.ptr_type.type); t->data.slice.is_const = (n->expr.ptr_type.flags & PTR_CONST) != 0; t->data.slice.is_volatile = (n->expr.ptr_type.flags & PTR_VOLATILE) != 0; @@ -377,8 +378,8 @@ static ast_node *get_def(sema *s, char *name) static type *get_string_type(sema *s, ast_node *node) { type *string_type = arena_alloc(s->allocator, sizeof(type)); - string_type->tag = TYPE_PTR; - string_type->size = sizeof(usize); + string_type->tag = TYPE_SLICE; + string_type->size = sizeof(usize) * 2; // ptr + len = 16 bytes string_type->alignment = sizeof(usize); string_type->name = "slice"; string_type->data.slice.child = shget(type_reg, "u8"); @@ -409,6 +410,33 @@ static type *get_access_type(sema *s, ast_node *node) ast_node *member = node->expr.access.member; char *name_start = member->expr.string.start; usize name_len = member->expr.string.len; + + // Handle slice field access + if (t && t->tag == TYPE_SLICE) { + char *name = intern_string(s, name_start, name_len); + if (strcmp(name, "ptr") == 0) { + // Return pointer to element type + type *ptr_type = arena_alloc(s->allocator, sizeof(type)); + ptr_type->tag = TYPE_PTR; + ptr_type->size = 8; + ptr_type->alignment = 8; + ptr_type->name = "ptr"; + ptr_type->data.ptr.child = t->data.slice.child; + ptr_type->data.ptr.is_const = t->data.slice.is_const; + ptr_type->data.ptr.is_volatile = t->data.slice.is_volatile; + free(name); + return ptr_type; + } else if (strcmp(name, "len") == 0) { + // Return usize type + free(name); + return shget(type_reg, "usize"); + } else { + error(node, "slice doesn't have that field"); + free(name); + return NULL; + } + } + if (!t || (t->tag != TYPE_STRUCT && t->tag != TYPE_UNION)) { error(node, "invalid expression."); return NULL; @@ -557,6 +585,36 @@ static type *get_expression_type(sema *s, ast_node *node) return t; case NODE_ARRAY_SUBSCRIPT: t = get_expression_type(s, node->expr.subscript.expr); + + // Check if this is range subscripting (creates a slice) + if (node->expr.subscript.index && node->expr.subscript.index->type == NODE_RANGE) { + type *element_type = NULL; + switch (t->tag) { + case TYPE_SLICE: + element_type = t->data.slice.child; + break; + case TYPE_PTR: + element_type = t->data.ptr.child; + break; + default: + error(node, "only pointers and slices can be indexed."); + return NULL; + } + + // Return a slice type + type *slice_type = arena_alloc(s->allocator, sizeof(type)); + slice_type->tag = TYPE_SLICE; + slice_type->size = sizeof(usize) * 2; + slice_type->alignment = sizeof(usize); + slice_type->data.slice.child = element_type; + slice_type->data.slice.is_const = false; + slice_type->data.slice.len = 0; + + node->expr_type = slice_type; + return slice_type; + } + + // Regular subscript - return element type switch (t->tag) { case TYPE_SLICE: t = t->data.slice.child; @@ -732,6 +790,18 @@ static void check_statement(sema *s, ast_node *node) break; } if (t->tag == TYPE_STRUCT) { + // Struct initialization with NODE_STRUCT_INIT is allowed + } else if (node->expr.var_decl.value && node->expr.var_decl.value->type == NODE_STRUCT_INIT && + (t->tag == TYPE_SLICE || t->tag == TYPE_PTR)) { + // Array/slice initialization with NODE_STRUCT_INIT is allowed + } else if (node->expr.var_decl.value && node->expr.var_decl.value->type == NODE_RANGE && + t->tag == TYPE_SLICE) { + // Range initialization for slices is allowed + get_expression_type(s, node->expr.var_decl.value); + } else if (node->expr.var_decl.value && node->expr.var_decl.value->type == NODE_STRING && + t->tag == TYPE_SLICE) { + // String literal can be assigned to slice + get_expression_type(s, node->expr.var_decl.value); } else if (!can_cast(get_expression_type(s, node->expr.var_decl.value), t) && !match(t, get_expression_type(s, node->expr.var_decl.value))) { error(node, "type mismatch (decl)."); } @@ -758,15 +828,18 @@ static void check_function(sema *s, ast_node *f) param_node->expr_type = p_type; param_node->address_taken = false; param_node->expr.var_decl.name = t_name; - + shput(current_scope->defs, t_name, param_node); param = param->next; } - ast_node *current = f->expr.function.body; - while (current && current->type == NODE_UNIT) { - check_statement(s, current->expr.unit_node.expr); - current = current->expr.unit_node.next; + // Skip body checking for extern functions + if (!f->expr.function.is_extern && f->expr.function.body) { + ast_node *current = f->expr.function.body; + while (current && current->type == NODE_UNIT) { + check_statement(s, current->expr.unit_node.expr); + current = current->expr.unit_node.next; + } } pop_scope(s); @@ -820,6 +893,7 @@ void sema_init(parser *p, arena *a) register_type(s, "u16", create_integer(s, "u16", 16, false)); register_type(s, "u32", create_integer(s, "u32", 32, false)); register_type(s, "u64", create_integer(s, "u64", 64, false)); + register_type(s, "usize", create_integer(s, "usize", 64, false)); register_type(s, "i8", create_integer(s, "i8", 8, true)); register_type(s, "i16", create_integer(s, "i16", 16, true)); register_type(s, "i32", create_integer(s, "i32", 32, true)); diff --git a/test b/test deleted file mode 100755 index 2fd1a557d42dcbcf3a1a56613ba75f0bfc91cf33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20192 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 diff --git a/test.l b/test.l index 1aac346..2763f97 100644 --- a/test.l +++ b/test.l @@ -1,10 +1,20 @@ -struct point { - i32 x, - i32 y -} +extern i64 write(i32 fd, *u8 buf, u64 count); +extern void exit(i32 code); +extern *u8 malloc(usize size); i32 main() { - point result = .{ x = 2, y = 1 }; - return (result.y) + 2; + [u8] message = "Hello world!\n"; + *u8 message_heap = malloc(message.len); + [u8] new_message = message_heap[0..13]; + u32 i = 0; + + loop while i < message.len { + new_message[i] = message[i]; + i = i + 1; + } + + write(1, new_message.ptr, new_message.len); + + return 0; } diff --git a/test.s b/test.s deleted file mode 100644 index 9d3b3f4..0000000 --- a/test.s +++ /dev/null @@ -1,20 +0,0 @@ -.section .text -.global main -main: -push %rbp -mov %rsp, %rbp -sub $256, %rsp -mov $2, %rax -mov %eax, -8(%rbp) -mov $1, %rax -mov %eax, -12(%rbp) -mov -12(%rbp), %rax -mov %rax, %rcx -mov $2, %rax -add %rcx, %rax -mov %rbp, %rsp -pop %rbp -ret -mov %rbp, %rsp -pop %rbp -ret diff --git a/test_control b/test_control deleted file mode 100755 index d9550eee03315872647ea0586c219e355182dbcf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21712 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±U*cV@>Hk^n|E%_J^v&hg+kf8Q;;K{ge_rdK*ZL{#EC@*7MxPH` zSU!M*qQ<{@pFOAt%Ij%;@%BH1M!tJC`sRJ}l-8$T7Sn$tXCNPd^If)~&HLAEz~&Wgw#NH2VD zpATp2i)PnY+&9$go9pJ`b|unOlT?V;{};4=?b;nnD#4fnUU@?s_?Hl)e-l5mU+`;v zv;LGd6>EbNK8&MYKc@Z1Vr*3pf)u7|6Mw^d3`qU?XZD46#*~Bxia>4pZ5U4j!E;i% zhRHMgEb~8VUVnx*kdK}4B(|n+_H{`rr|}PEi;8=hG;(`iFa! z!g0?D=rJeOFQWhIwMzeXb7E=#Uj5CB=%iQgfadNUZYK`2p3J)D h^q93L6-_mwkOw>tJtXcW7S?~@50rkvqu?RM{{V1A{rUg^ diff --git a/test_control.l b/test_control.l deleted file mode 100644 index d8576a2..0000000 --- a/test_control.l +++ /dev/null @@ -1,23 +0,0 @@ -i32 main() -{ - i32 x = 0; - i32 i = 0; - - // Test while loop with break - while (i < 10) { - i = i + 1; - if (i == 5) { - break; - } - x = x + i; - } - - // Test goto and label - if (x == 10) { - goto skip; - } - x = 999; - - skip: - return x; -} diff --git a/test_simple b/test_simple deleted file mode 100755 index d9550eee03315872647ea0586c219e355182dbcf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21712 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±U*cV@>Hk^n|E%_J^v&hg+kf8Q;;K{ge_rdK*ZL{#EC@*7MxPH` zSU!M*qQ<{@pFOAt%Ij%;@%BH1M!tJC`sRJ}l-8$T7Sn$tXCNPd^If)~&HLAEz~&Wgw#NH2VD zpATp2i)PnY+&9$go9pJ`b|unOlT?V;{};4=?b;nnD#4fnUU@?s_?Hl)e-l5mU+`;v zv;LGd6>EbNK8&MYKc@Z1Vr*3pf)u7|6Mw^d3`qU?XZD46#*~Bxia>4pZ5U4j!E;i% zhRHMgEb~8VUVnx*kdK}4B(|n+_H{`rr|}PEi;8=hG;(`iFa! z!g0?D=rJeOFQWhIwMzeXb7E=#Uj5CB=%iQgfadNUZYK`2p3J)D h^q93L6-_mwkOw>tJtXcW7S?~@50rkvqu?RM{{V1A{rUg^ diff --git a/test_simple.l b/test_simple.l deleted file mode 100644 index 61dc5fb..0000000 --- a/test_simple.l +++ /dev/null @@ -1,13 +0,0 @@ -i32 main() -{ - i32 x = 0; - - while (x < 10) { - x = x + 1; - if (x == 5) { - break; - } - } - - return x; -} diff --git a/todo.cfg b/todo.cfg deleted file mode 100644 index 5e35825..0000000 --- a/todo.cfg +++ /dev/null @@ -1,2 +0,0 @@ -export TODO_DIR="." -export TODO_FILE="$TODO_DIR/todo.txt" diff --git a/todo.txt b/todo.txt deleted file mode 100644 index c023562..0000000 --- a/todo.txt +++ /dev/null @@ -1 +0,0 @@ -implement dominator tree for control flow From 667769d1c0d963114ca9c026a7ed039734de10e2 Mon Sep 17 00:00:00 2001 From: Lorenzo Torres Date: Sat, 17 Jan 2026 10:33:19 +0100 Subject: [PATCH 3/3] implement array subscript for assignment in codegen --- codegen.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++--- test | Bin 0 -> 20368 bytes test.s | 90 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 5 deletions(-) create mode 100755 test create mode 100644 test.s diff --git a/codegen.c b/codegen.c index 552bb77..d1c58fd 100644 --- a/codegen.c +++ b/codegen.c @@ -152,14 +152,114 @@ void gen_binary(FILE *fp, ast_node *expr) fprintf(fp, "or %%rcx, %%rax\n"); break; case OP_ASSIGN: { - if (expr->expr.binary.left->type != NODE_IDENTIFIER) { + if (expr->expr.binary.left->type == NODE_IDENTIFIER) { + gen_expr(fp, expr->expr.binary.right); + int offset = get_var_offset(expr->expr.binary.left->expr.string.start, + expr->expr.binary.left->expr.string.len); + fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + } else if (expr->expr.binary.left->type == NODE_ARRAY_SUBSCRIPT) { + ast_node *subscript = expr->expr.binary.left; + usize element_size = 8; + type *base_type = subscript->expr.subscript.expr->expr_type; + bool is_slice = false; + + if (base_type) { + if (base_type->tag == TYPE_PTR && base_type->data.ptr.child) { + element_size = base_type->data.ptr.child->size; + } else if (base_type->tag == TYPE_SLICE && base_type->data.slice.child) { + element_size = base_type->data.slice.child->size; + is_slice = true; + } + } + + if (subscript->expr.subscript.expr->type == NODE_IDENTIFIER && is_slice) { + int base_offset = get_var_offset(subscript->expr.subscript.expr->expr.string.start, + subscript->expr.subscript.expr->expr.string.len); + + fprintf(fp, "mov -%d(%%rbp), %%rcx\n", base_offset); + gen_expr(fp, subscript->expr.subscript.index); + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + + fprintf(fp, "add %%rcx, %%rax\n"); + fprintf(fp, "push %%rax\n"); + + gen_expr(fp, expr->expr.binary.right); + + fprintf(fp, "pop %%rcx\n"); + + if (subscript->expr_type && subscript->expr_type->size == 4) { + fprintf(fp, "mov %%eax, (%%rcx)\n"); + } else if (subscript->expr_type && subscript->expr_type->size == 2) { + fprintf(fp, "mov %%ax, (%%rcx)\n"); + } else if (subscript->expr_type && subscript->expr_type->size == 1) { + fprintf(fp, "mov %%al, (%%rcx)\n"); + } else { + fprintf(fp, "mov %%rax, (%%rcx)\n"); + } + } else if (subscript->expr.subscript.expr->type == NODE_IDENTIFIER) { + int base_offset = get_var_offset(subscript->expr.subscript.expr->expr.string.start, + subscript->expr.subscript.expr->expr.string.len); + + gen_expr(fp, subscript->expr.subscript.index); + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + + fprintf(fp, "add $%d, %%rax\n", base_offset); + fprintf(fp, "neg %%rax\n"); + fprintf(fp, "add %%rbp, %%rax\n"); + fprintf(fp, "push %%rax\n"); + + gen_expr(fp, expr->expr.binary.right); + + fprintf(fp, "pop %%rcx\n"); + + if (subscript->expr_type && subscript->expr_type->size == 4) { + fprintf(fp, "mov %%eax, (%%rcx)\n"); + } else if (subscript->expr_type && subscript->expr_type->size == 2) { + fprintf(fp, "mov %%ax, (%%rcx)\n"); + } else if (subscript->expr_type && subscript->expr_type->size == 1) { + fprintf(fp, "mov %%al, (%%rcx)\n"); + } else { + fprintf(fp, "mov %%rax, (%%rcx)\n"); + } + } else { + gen_expr(fp, subscript->expr.subscript.expr); + fprintf(fp, "push %%rax\n"); + + gen_expr(fp, subscript->expr.subscript.index); + + if (element_size != 1) { + fprintf(fp, "imul $%lu, %%rax\n", element_size); + } + + fprintf(fp, "pop %%rcx\n"); + fprintf(fp, "add %%rcx, %%rax\n"); + fprintf(fp, "push %%rax\n"); + + gen_expr(fp, expr->expr.binary.right); + + fprintf(fp, "pop %%rcx\n"); + + if (subscript->expr_type && subscript->expr_type->size == 4) { + fprintf(fp, "mov %%eax, (%%rcx)\n"); + } else if (subscript->expr_type && subscript->expr_type->size == 2) { + fprintf(fp, "mov %%ax, (%%rcx)\n"); + } else if (subscript->expr_type && subscript->expr_type->size == 1) { + fprintf(fp, "mov %%al, (%%rcx)\n"); + } else { + fprintf(fp, "mov %%rax, (%%rcx)\n"); + } + } + } else { fprintf(fp, "# ERROR: left side of assignment must be identifier\n"); break; } - gen_expr(fp, expr->expr.binary.right); - int offset = get_var_offset(expr->expr.binary.left->expr.string.start, - expr->expr.binary.left->expr.string.len); - fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); + break; } case OP_ASSIGN_PTR: { diff --git a/test b/test new file mode 100755 index 0000000000000000000000000000000000000000..1b89d353242a021ce1ef52d7b784b465683311ed GIT binary patch literal 20368 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 literal 0 HcmV?d00001 diff --git a/test.s b/test.s new file mode 100644 index 0000000..b86c66e --- /dev/null +++ b/test.s @@ -0,0 +1,90 @@ +.section .text +.global main +main: +push %rbp +mov %rsp, %rbp +sub $256, %rsp +movb $72, -32(%rbp) +movb $101, -31(%rbp) +movb $108, -30(%rbp) +movb $108, -29(%rbp) +movb $111, -28(%rbp) +movb $32, -27(%rbp) +movb $119, -26(%rbp) +movb $111, -25(%rbp) +movb $114, -24(%rbp) +movb $108, -23(%rbp) +movb $100, -22(%rbp) +movb $33, -21(%rbp) +movb $10, -20(%rbp) +lea -32(%rbp), %rax +mov %rax, -48(%rbp) +mov $14, %rax +mov %rax, -40(%rbp) +mov -40(%rbp), %rax +push %rax +pop %rdi +call malloc +mov %rax, -56(%rbp) +mov -56(%rbp), %rcx +mov $0, %rax +push %rax +mov $13, %rax +mov %rax, %rdx +pop %rax +mov %rdx, %r8 +sub %rax, %r8 +inc %r8 +add %rcx, %rax +mov %rax, -88(%rbp) +mov %r8, -80(%rbp) +lea -88(%rbp), %rax +mov (%rax), %rcx +mov 8(%rax), %rdx +mov %rcx, -72(%rbp) +mov %rdx, -64(%rbp) +mov $0, %rax +mov %rax, -96(%rbp) +.L0: +mov -96(%rbp), %rax +mov %rax, %rcx +mov -40(%rbp), %rax +cmp %rax, %rcx +setl %al +movzx %al, %rax +test %rax, %rax +jz .L1 +mov -72(%rbp), %rcx +mov -96(%rbp), %rax +add %rcx, %rax +push %rax +mov -48(%rbp), %rcx +mov -96(%rbp), %rax +add %rcx, %rax +movzbl (%rax), %eax +pop %rcx +mov %al, (%rcx) +mov -96(%rbp), %rax +mov %rax, %rcx +mov $1, %rax +add %rcx, %rax +mov %rax, -96(%rbp) +jmp .L0 +.L1: +mov $1, %rax +push %rax +mov -72(%rbp), %rax +push %rax +mov -64(%rbp), %rax +push %rax +pop %rdx +pop %rsi +pop %rdi +call write +mov $0, %rax +mov %rbp, %rsp +pop %rbp +ret +mov %rbp, %rsp +pop %rbp +ret