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 0000000..1b89d35 Binary files /dev/null and b/test differ 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