From ee97fefe6dc725ee0be5f81f9bd267f8f75c1c1a Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Thu, 28 Aug 2025 18:49:05 +0800 Subject: [PATCH 1/2] Remove unused code --- src/lexer.c | 5 ----- src/riscv.c | 9 --------- 2 files changed, 14 deletions(-) diff --git a/src/lexer.c b/src/lexer.c index 1ebf6fe9..26ded95a 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -150,11 +150,6 @@ bool is_whitespace(char c) char peek_char(int offset); -/* is it backslash-newline? */ -bool is_linebreak(char c) -{ - return c == '\\' && peek_char(1) == '\n'; -} bool is_newline(char c) { diff --git a/src/riscv.c b/src/riscv.c index 3ea8b57e..fd47bb90 100644 --- a/src/riscv.c +++ b/src/riscv.c @@ -377,15 +377,6 @@ int __ecall(void) return rv_encode_I(rv_ecall, __zero, __zero, 0); } -int __ebreak(void) -{ - return rv_encode_I(rv_ebreak, __zero, __zero, 1); -} - -int __nop(void) -{ - return __addi(__zero, __zero, 0); -} int __mul(rv_reg rd, rv_reg rs1, rv_reg rs2) { From add88495f6d14a7110eb9853cf62b9be16bd9060 Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Tue, 26 Aug 2025 16:36:25 +0800 Subject: [PATCH 2/2] Implement pointer difference arithmetic This commit adds comprehensive pointer difference support (ptr1 - ptr2) that was missing from the existing pointer arithmetic implementation: - Pointer difference calculation: It computes element count by dividing byte difference by element size (char=1, int=4, etc.) - Expression support: Enables complex expressions like *(p + (q - r)) - Unified element size detection: Consistent logic for both regular and typedef pointers across all arithmetic operations --- src/parser.c | 354 +++++++++++++++++++++++++++++++++++++++++++++++- tests/driver.sh | 130 ++++++++++++++++++ 2 files changed, 481 insertions(+), 3 deletions(-) diff --git a/src/parser.c b/src/parser.c index 11160b6b..40c38674 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2198,7 +2198,164 @@ void read_expr(block_t *parent, basic_block_t **bb) vd = require_var(parent); gen_name_to(vd->var_name); opstack_push(vd); - add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL); + + /* Handle pointer arithmetic: + * - If both operands are pointers (subtraction), divide by + * element size + * - If one operand is a pointer, handle scaling + * appropriately + */ + if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) { + /* Subtracting two pointers - divide by element size */ + var_t *diff = require_var(parent); + gen_name_to(diff->var_name); + add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL); + + /* Get the element size */ + int elem_size = 4; /* Default to int size */ + if (rs1->type) { + /* For pointers, check what they point to */ + if (rs1->is_ptr || rs1->type->ptr_level > 0) { + switch (rs1->type->base_type) { + case TYPE_char: + elem_size = 1; + break; + case TYPE_int: + elem_size = 4; + break; + default: + elem_size = 4; + break; + } + } else { + /* For non-pointers, use the type size */ + if (rs1->type->size > 0) { + elem_size = rs1->type->size; + } else { + elem_size = 4; + } + } + } + + /* Divide by element size */ + if (elem_size > 1) { + var_t *size_const = require_var(parent); + size_const->init_val = elem_size; + gen_name_to(size_const->var_name); + add_insn(parent, *bb, OP_load_constant, size_const, + NULL, NULL, 0, NULL); + add_insn(parent, *bb, OP_div, vd, diff, size_const, + 0, NULL); + } else { + /* If element size is 1, no division needed - use + * assignment */ + add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0, + NULL); + } + } else if ((top_op == OP_add || top_op == OP_sub) && + (rs1->is_ptr || + (rs1->type && rs1->type->ptr_level > 0)) && + !rs2->is_ptr) { + /* Pointer +/- integer: scale the integer by element + * size */ + int elem_size = 4; + if (rs1->type) { + /* For pointers, check what they point to */ + if (rs1->is_ptr || rs1->type->ptr_level > 0) { + switch (rs1->type->base_type) { + case TYPE_char: + elem_size = 1; + break; + case TYPE_int: + elem_size = 4; + break; + default: + elem_size = 4; + break; + } + } else { + /* For non-pointers, use the type size */ + if (rs1->type->size > 0) { + elem_size = rs1->type->size; + } else { + elem_size = 4; + } + } + } + + /* Scale the integer operand if needed */ + if (elem_size > 1) { + var_t *scaled = require_var(parent); + gen_name_to(scaled->var_name); + var_t *size_const = require_var(parent); + size_const->init_val = elem_size; + gen_name_to(size_const->var_name); + add_insn(parent, *bb, OP_load_constant, size_const, + NULL, NULL, 0, NULL); + add_insn(parent, *bb, OP_mul, scaled, rs2, + size_const, 0, NULL); + add_insn(parent, *bb, top_op, vd, rs1, scaled, 0, + NULL); + } else { + add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, + NULL); + } + /* Result is still a pointer */ + vd->is_ptr = rs1->is_ptr; + vd->type = rs1->type; + } else if ((top_op == OP_add) && !rs1->is_ptr && + (rs2->is_ptr || + (rs2->type && rs2->type->ptr_level > 0))) { + /* Integer + pointer: scale the integer by element size + */ + int elem_size = 4; + if (rs2->type) { + /* For pointers, check what they point to */ + if (rs2->is_ptr || rs2->type->ptr_level > 0) { + switch (rs2->type->base_type) { + case TYPE_char: + elem_size = 1; + break; + case TYPE_int: + elem_size = 4; + break; + default: + elem_size = 4; + break; + } + } else { + /* For non-pointers, use the type size */ + if (rs2->type->size > 0) { + elem_size = rs2->type->size; + } else { + elem_size = 4; + } + } + } + + /* Scale the integer operand if needed */ + if (elem_size > 1) { + var_t *scaled = require_var(parent); + gen_name_to(scaled->var_name); + var_t *size_const = require_var(parent); + size_const->init_val = elem_size; + gen_name_to(size_const->var_name); + add_insn(parent, *bb, OP_load_constant, size_const, + NULL, NULL, 0, NULL); + add_insn(parent, *bb, OP_mul, scaled, rs1, + size_const, 0, NULL); + add_insn(parent, *bb, top_op, vd, scaled, rs2, 0, + NULL); + } else { + add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, + NULL); + } + /* Result is a pointer */ + vd->is_ptr = rs2->is_ptr; + vd->type = rs2->type; + } else { + add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL); + } oper_stack_idx--; } else @@ -2390,14 +2547,205 @@ void read_expr(block_t *parent, basic_block_t **bb) vd = require_var(parent); gen_name_to(vd->var_name); opstack_push(vd); - add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL); + + /* Handle pointer subtraction */ + if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) { + var_t *diff = require_var(parent); + gen_name_to(diff->var_name); + add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL); + + int elem_size = 4; + if (rs1->type) { + /* For pointers, check what they point to */ + if (rs1->is_ptr || rs1->type->ptr_level > 0) { + switch (rs1->type->base_type) { + case TYPE_char: + elem_size = 1; + break; + case TYPE_int: + elem_size = 4; + break; + default: + elem_size = 4; + break; + } + } else { + /* For non-pointers, use the type size */ + if (rs1->type->size > 0) { + elem_size = rs1->type->size; + } else { + elem_size = 4; + } + } + } + + if (elem_size > 1) { + var_t *size_const = require_var(parent); + size_const->init_val = elem_size; + gen_name_to(size_const->var_name); + add_insn(parent, *bb, OP_load_constant, size_const, + NULL, NULL, 0, NULL); + add_insn(parent, *bb, OP_div, vd, diff, size_const, 0, + NULL); + } else { + /* If element size is 1, no division needed - use + * assignment */ + add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0, + NULL); + } + } else if ((top_op == OP_add || top_op == OP_sub) && + (rs1->is_ptr || + (rs1->type && rs1->type->ptr_level > 0)) && + !rs2->is_ptr) { + /* Pointer +/- integer: scale the integer by element size */ + int elem_size = 4; + if (rs1->type) { + /* For pointers, check what they point to */ + if (rs1->is_ptr || rs1->type->ptr_level > 0) { + switch (rs1->type->base_type) { + case TYPE_char: + elem_size = 1; + break; + case TYPE_int: + elem_size = 4; + break; + default: + elem_size = 4; + break; + } + } else { + /* For non-pointers, use the type size */ + if (rs1->type->size > 0) { + elem_size = rs1->type->size; + } else { + elem_size = 4; + } + } + } + + /* Scale the integer operand if needed */ + if (elem_size > 1) { + var_t *scaled = require_var(parent); + gen_name_to(scaled->var_name); + var_t *size_const = require_var(parent); + size_const->init_val = elem_size; + gen_name_to(size_const->var_name); + add_insn(parent, *bb, OP_load_constant, size_const, + NULL, NULL, 0, NULL); + add_insn(parent, *bb, OP_mul, scaled, rs2, size_const, + 0, NULL); + add_insn(parent, *bb, top_op, vd, rs1, scaled, 0, NULL); + } else { + add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL); + } + /* Result is still a pointer */ + vd->is_ptr = rs1->is_ptr; + vd->type = rs1->type; + } else { + add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL); + } } } else { /* Normal operation */ vd = require_var(parent); gen_name_to(vd->var_name); opstack_push(vd); - add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL); + + /* Handle pointer subtraction */ + if (top_op == OP_sub && rs1->is_ptr && rs2->is_ptr) { + var_t *diff = require_var(parent); + gen_name_to(diff->var_name); + add_insn(parent, *bb, OP_sub, diff, rs1, rs2, 0, NULL); + + int elem_size = 4; + if (rs1->type) { + /* For pointers, check what they point to */ + if (rs1->is_ptr || rs1->type->ptr_level > 0) { + switch (rs1->type->base_type) { + case TYPE_char: + elem_size = 1; + break; + case TYPE_int: + elem_size = 4; + break; + default: + elem_size = 4; + break; + } + } else { + /* For non-pointers, use the type size */ + if (rs1->type->size > 0) { + elem_size = rs1->type->size; + } else { + elem_size = 4; + } + } + } + + if (elem_size > 1) { + var_t *size_const = require_var(parent); + size_const->init_val = elem_size; + gen_name_to(size_const->var_name); + add_insn(parent, *bb, OP_load_constant, size_const, NULL, + NULL, 0, NULL); + add_insn(parent, *bb, OP_div, vd, diff, size_const, 0, + NULL); + } else { + /* If element size is 1, no division needed - use assignment + */ + add_insn(parent, *bb, OP_assign, vd, diff, NULL, 0, NULL); + } + } else if ((top_op == OP_add || top_op == OP_sub) && + (rs1->is_ptr || + (rs1->type && rs1->type->ptr_level > 0)) && + !rs2->is_ptr) { + /* Pointer +/- integer: scale the integer by element size */ + int elem_size = 4; + if (rs1->type) { + /* For pointers, check what they point to */ + if (rs1->is_ptr || rs1->type->ptr_level > 0) { + switch (rs1->type->base_type) { + case TYPE_char: + elem_size = 1; + break; + case TYPE_int: + elem_size = 4; + break; + default: + elem_size = 4; + break; + } + } else { + /* For non-pointers, use the type size */ + if (rs1->type->size > 0) { + elem_size = rs1->type->size; + } else { + elem_size = 4; + } + } + } + + /* Scale the integer operand if needed */ + if (elem_size > 1) { + var_t *scaled = require_var(parent); + gen_name_to(scaled->var_name); + var_t *size_const = require_var(parent); + size_const->init_val = elem_size; + gen_name_to(size_const->var_name); + add_insn(parent, *bb, OP_load_constant, size_const, NULL, + NULL, 0, NULL); + add_insn(parent, *bb, OP_mul, scaled, rs2, size_const, 0, + NULL); + add_insn(parent, *bb, top_op, vd, rs1, scaled, 0, NULL); + } else { + add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL); + } + /* Result is still a pointer */ + vd->is_ptr = rs1->is_ptr; + vd->type = rs1->type; + } else { + add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL); + } } } while (has_prev_log_op) { diff --git a/tests/driver.sh b/tests/driver.sh index a372db8c..21b5f3f0 100755 --- a/tests/driver.sh +++ b/tests/driver.sh @@ -1064,6 +1064,136 @@ int main() { } EOF +# Enhanced pointer arithmetic tests +# Test pointer difference calculation +try_ 7 << EOF +int main() { + int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + int *p = arr; + int *q = arr + 7; + int diff = q - p; /* Should be 7 */ + return diff; +} +EOF + +try_ 5 << EOF +int main() { + int arr[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int *start = arr + 2; + int *end = arr + 7; + return end - start; /* Should be 5 */ +} +EOF + +# Test pointer difference with char pointers +try_ 10 << EOF +int main() { + char str[20] = "Hello, World!"; + char *p = str; + char *q = str + 10; + return q - p; /* Should be 10 */ +} +EOF + +# Test pointer difference in expressions +try_ 7 << EOF +int main() { + int arr[20] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int *p = arr; + int *r = arr + 10; + int *s = arr + 3; + int v = *(p + (r - s)); /* p + 7 = arr[7] = 7 */ + return v; +} +EOF + +# Test complex pointer arithmetic with parentheses +try_ 10 << EOF +int main() { + int arr[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + int *p = arr; + /* Parenthesizing arithmetic ensures correct evaluation */ + int v = *(p + (5 - 2 + 3 * 2)); /* p + 9 = arr[9] = 10 */ + return v; +} +EOF + +# Test offset computed separately +try_ 10 << EOF +int main() { + int arr[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + int *p = arr; + int offset = 5 - 2 + 3 * 2; /* = 9 */ + int v = *(p + offset); /* arr[9] = 10 */ + return v; +} +EOF + +# Test array notation +try_ 10 << EOF +int main() { + int arr[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + int *p = arr; + int v = p[5 - 2 + 3 * 2]; /* p[9] = arr[9] = 10 */ + return v; +} +EOF + +# Test pointer arithmetic with variables +try_ 8 << EOF +int main() { + int arr[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int *p = arr; + int idx = 3; + int multiplier = 2; + int base = 1; + int v = *(p + (base + (idx * multiplier))); /* p + 7 = arr[7] = 8 */ + return v; +} +EOF + +# Test standard pointer + integer +try_ 6 << EOF +int main() { + int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int *p = arr; + int v = *(p + 5); /* arr[5] = 6 */ + return v; +} +EOF + +# Test pointer subtraction with offset +try_ 6 << EOF +int main() { + int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int *q = arr + 8; + int v = *(q - 3); /* q - 3 = arr[5] = 6 */ + return v; +} +EOF + +# Test nested parentheses in pointer arithmetic +try_ 11 << EOF +int main() { + int arr[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + int *p = arr; + int v = *(p + ((2 + 3) * 2)); /* p + 10 = arr[10] = 11 */ + return v; +} +EOF + +# Test multiple pointer variables +try_ 6 << EOF +int main() { + int arr[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int *p = arr; + int *q = p + 5; + int *base = &arr[0]; + int v = *(q + (p - base)); /* q is at arr[5], offset by 0, so arr[5] = 6 */ + return v; +} +EOF + # Category: Function Pointers begin_category "Function Pointers" "Testing function pointer declarations and calls"