implement array subscript for assignment in codegen

This commit is contained in:
Lorenzo Torres 2026-01-17 10:33:19 +01:00
parent 870cf8f0b4
commit 667769d1c0
3 changed files with 195 additions and 5 deletions

108
codegen.c
View file

@ -152,14 +152,114 @@ void gen_binary(FILE *fp, ast_node *expr)
fprintf(fp, "or %%rcx, %%rax\n"); fprintf(fp, "or %%rcx, %%rax\n");
break; break;
case OP_ASSIGN: { case OP_ASSIGN: {
if (expr->expr.binary.left->type != NODE_IDENTIFIER) { 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); gen_expr(fp, expr->expr.binary.right);
int offset = get_var_offset(expr->expr.binary.left->expr.string.start, int offset = get_var_offset(expr->expr.binary.left->expr.string.start,
expr->expr.binary.left->expr.string.len); expr->expr.binary.left->expr.string.len);
fprintf(fp, "mov %%rax, -%d(%%rbp)\n", offset); 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;
}
break; break;
} }
case OP_ASSIGN_PTR: { case OP_ASSIGN_PTR: {

BIN
test Executable file

Binary file not shown.

90
test.s Normal file
View file

@ -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