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

110
codegen.c
View file

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