From 5c1c4adf943621e6742536eed8178eaf93514983 Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Tue, 26 Aug 2025 13:12:53 +0800 Subject: [PATCH] Fix typedef pointer arithmetic and array ops This commit fixes multiple issues with typedef pointer handling: 1. Remove incorrect pointer level inheritance in read_full_var_decl() - Previously caused double indirection bugs with typedef pointers - Variables now maintain separate pointer levels from their types 2. Implement proper pointer arithmetic for typedef pointers - Add scaling for binary addition/subtraction (p+n, p-n, n+p) - Fix increment/decrement operators (++p, p++, --p, p--) - Calculate element size based on base type (int=4, char=1, etc.) 3. Enable array indexing for typedef pointers - Recognize typedef pointers in square bracket operations - Properly calculate element sizes for array access --- src/parser.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++-- tests/driver.sh | 206 ++++++++++++++++++++++++++++++++++ 2 files changed, 485 insertions(+), 12 deletions(-) diff --git a/src/parser.c b/src/parser.c index 14b56e9b..c1b73d42 100644 --- a/src/parser.c +++ b/src/parser.c @@ -281,7 +281,8 @@ var_t *truncate_unchecked(block_t *block, var_t *resize_var(block_t *block, basic_block_t **bb, var_t *from, var_t *to) { bool is_from_ptr = from->ptr_level || from->array_size, - is_to_ptr = to->ptr_level || to->array_size; + is_to_ptr = to->ptr_level || to->array_size || + (to->type && to->type->ptr_level > 0); if (is_from_ptr && is_to_ptr) return from; @@ -1291,10 +1292,6 @@ void read_full_var_decl(var_t *vd, bool anon, bool is_param) vd->type = type; - /* Inherit pointer level from typedef */ - if (type->ptr_level > 0) - vd->ptr_level = type->ptr_level; - read_inner_var_decl(vd, anon, is_param); } @@ -1569,8 +1566,28 @@ void handle_single_dereference(block_t *parent, basic_block_t **bb) vd = require_deref_var(parent, var->type, var->ptr_level); if (lvalue.ptr_level > 1) sz = PTR_SIZE; - else - sz = lvalue.type->size; + else { + /* For typedef pointers, get the size of the pointed-to type */ + if (lvalue.type && lvalue.type->ptr_level > 0) { + /* This is a typedef pointer */ + switch (lvalue.type->base_type) { + case TYPE_char: + sz = TY_char->size; + break; + case TYPE_int: + sz = TY_int->size; + break; + case TYPE_void: + sz = 1; + break; + default: + sz = lvalue.type->size; + break; + } + } else { + sz = lvalue.type->size; + } + } gen_name_to(vd->var_name); opstack_push(vd); add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL); @@ -1628,8 +1645,29 @@ void handle_multiple_dereference(block_t *parent, basic_block_t **bb) lvalue.ptr_level > i ? lvalue.ptr_level - i - 1 : 0); if (lvalue.ptr_level > i + 1) sz = PTR_SIZE; - else - sz = lvalue.type->size; + else { + /* For typedef pointers, get the size of the pointed-to type */ + if (lvalue.type && lvalue.type->ptr_level > 0 && + i == deref_count - 1) { + /* This is a typedef pointer on the final dereference */ + switch (lvalue.type->base_type) { + case TYPE_char: + sz = TY_char->size; + break; + case TYPE_int: + sz = TY_int->size; + break; + case TYPE_void: + sz = 1; + break; + default: + sz = lvalue.type->size; + break; + } + } else { + sz = lvalue.type->size; + } + } gen_name_to(vd->var_name); opstack_push(vd); add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL); @@ -2197,6 +2235,99 @@ void read_expr(block_t *parent, basic_block_t **bb) if (get_operator_prio(top_op) >= get_operator_prio(op)) { rs2 = opstack_pop(); rs1 = opstack_pop(); + + /* Handle pointer arithmetic for addition and subtraction */ + if ((top_op == OP_add || top_op == OP_sub) && + (rs1->ptr_level || + (rs1->type && rs1->type->ptr_level > 0) || + rs2->ptr_level || + (rs2->type && rs2->type->ptr_level > 0))) { + var_t *ptr_var = NULL; + var_t *int_var = NULL; + int element_size = 0; + + /* Determine which operand is the pointer */ + if (rs1->ptr_level || + (rs1->type && rs1->type->ptr_level > 0)) { + ptr_var = rs1; + int_var = rs2; + + /* Calculate element size */ + if (rs1->ptr_level && rs1->type) { + element_size = rs1->type->size; + } else if (rs1->type && rs1->type->ptr_level > 0) { + /* Typedef pointer */ + switch (rs1->type->base_type) { + case TYPE_char: + element_size = TY_char->size; + break; + case TYPE_int: + element_size = TY_int->size; + break; + case TYPE_void: + element_size = 1; + break; + default: + element_size = + rs1->type ? rs1->type->size : PTR_SIZE; + break; + } + } + } else if (rs2->ptr_level || + (rs2->type && rs2->type->ptr_level > 0)) { + /* Only for addition (p + n == n + p) */ + if (top_op == OP_add) { + ptr_var = rs2; + int_var = rs1; + + /* Calculate element size */ + if (rs2->ptr_level && rs2->type) { + element_size = rs2->type->size; + } else if (rs2->type && + rs2->type->ptr_level > 0) { + /* Typedef pointer */ + switch (rs2->type->base_type) { + case TYPE_char: + element_size = TY_char->size; + break; + case TYPE_int: + element_size = TY_int->size; + break; + case TYPE_void: + element_size = 1; + break; + default: + element_size = rs2->type + ? rs2->type->size + : PTR_SIZE; + break; + } + } + /* Swap operands so pointer is rs1 */ + rs1 = ptr_var; + rs2 = int_var; + } + } + + /* If we need to scale the integer operand */ + if (ptr_var && element_size > 1) { + /* Create multiplication by element size */ + var_t *size_const = require_var(parent); + gen_name_to(size_const->var_name); + size_const->init_val = element_size; + add_insn(parent, *bb, OP_load_constant, size_const, + NULL, NULL, 0, NULL); + + var_t *scaled = require_var(parent); + gen_name_to(scaled->var_name); + add_insn(parent, *bb, OP_mul, scaled, int_var, + size_const, 0, NULL); + + /* Use scaled value as rs2 */ + rs2 = scaled; + } + } + vd = require_var(parent); gen_name_to(vd->var_name); opstack_push(vd); @@ -2312,6 +2443,92 @@ void read_expr(block_t *parent, basic_block_t **bb) rs2 = opstack_pop(); rs1 = opstack_pop(); + /* Handle pointer arithmetic for addition and subtraction */ + if ((top_op == OP_add || top_op == OP_sub) && + (rs1->ptr_level || (rs1->type && rs1->type->ptr_level > 0) || + rs2->ptr_level || (rs2->type && rs2->type->ptr_level > 0))) { + var_t *ptr_var = NULL; + var_t *int_var = NULL; + int element_size = 0; + + /* Determine which operand is the pointer */ + if (rs1->ptr_level || (rs1->type && rs1->type->ptr_level > 0)) { + ptr_var = rs1; + int_var = rs2; + + /* Calculate element size */ + if (rs1->ptr_level && rs1->type) { + element_size = rs1->type->size; + } else if (rs1->type && rs1->type->ptr_level > 0) { + /* Typedef pointer */ + switch (rs1->type->base_type) { + case TYPE_char: + element_size = TY_char->size; + break; + case TYPE_int: + element_size = TY_int->size; + break; + case TYPE_void: + element_size = 1; + break; + default: + element_size = rs1->type ? rs1->type->size : PTR_SIZE; + break; + } + } + } else if (rs2->ptr_level || + (rs2->type && rs2->type->ptr_level > 0)) { + /* Only for addition (p + n == n + p) */ + if (top_op == OP_add) { + ptr_var = rs2; + int_var = rs1; + + /* Calculate element size */ + if (rs2->ptr_level && rs2->type) { + element_size = rs2->type->size; + } else if (rs2->type && rs2->type->ptr_level > 0) { + /* Typedef pointer */ + switch (rs2->type->base_type) { + case TYPE_char: + element_size = TY_char->size; + break; + case TYPE_int: + element_size = TY_int->size; + break; + case TYPE_void: + element_size = 1; + break; + default: + element_size = + rs2->type ? rs2->type->size : PTR_SIZE; + break; + } + } + /* Swap operands so pointer is rs1 */ + rs1 = ptr_var; + rs2 = int_var; + } + } + + /* If we need to scale the integer operand */ + if (ptr_var && element_size > 1) { + /* Create multiplication by element size */ + var_t *size_const = require_var(parent); + gen_name_to(size_const->var_name); + size_const->init_val = element_size; + add_insn(parent, *bb, OP_load_constant, size_const, NULL, NULL, + 0, NULL); + + var_t *scaled = require_var(parent); + gen_name_to(scaled->var_name); + add_insn(parent, *bb, OP_mul, scaled, int_var, size_const, 0, + NULL); + + /* Use scaled value as rs2 */ + rs2 = scaled; + } + } + /* Constant folding for binary operations */ if (rs1 && rs2 && rs1->init_val && !rs1->ptr_level && !rs1->is_global && rs2->init_val && !rs2->ptr_level && !rs2->is_global) { @@ -2462,11 +2679,16 @@ void read_lvalue(lvalue_t *lvalue, } /* var must be either a pointer or an array of some type */ - if (var->ptr_level == 0 && var->array_size == 0) + /* For typedef pointers, check the type's ptr_level */ + bool is_typedef_pointer = (var->type && var->type->ptr_level > 0); + if (var->ptr_level == 0 && var->array_size == 0 && + !is_typedef_pointer) error("Cannot apply square operator to non-pointer"); /* if nested pointer, still pointer */ - if (var->ptr_level <= 1 && var->array_size == 0) { + /* Also handle typedef pointers which have ptr_level == 0 */ + if ((var->ptr_level <= 1 || is_typedef_pointer) && + var->array_size == 0) { /* For typedef pointers, get the size of the base type that the * pointer points to */ @@ -2695,7 +2917,31 @@ void read_lvalue(lvalue_t *lvalue, side_effect[se_idx].opcode = OP_load_constant; vd = require_var(parent); gen_name_to(vd->var_name); - vd->init_val = 1; + + /* Calculate increment size based on pointer type */ + int increment_size = 1; + if (lvalue->ptr_level && !lvalue->is_reference) { + increment_size = lvalue->type->size; + } else if (!lvalue->is_reference && lvalue->type && + lvalue->type->ptr_level > 0) { + /* This is a typedef pointer */ + switch (lvalue->type->base_type) { + case TYPE_char: + increment_size = TY_char->size; + break; + case TYPE_int: + increment_size = TY_int->size; + break; + case TYPE_void: + increment_size = 1; + break; + default: + increment_size = lvalue->type->size; + break; + } + } + vd->init_val = increment_size; + side_effect[se_idx].rd = vd; side_effect[se_idx].rs1 = NULL; side_effect[se_idx].rs2 = NULL; @@ -3010,6 +3256,27 @@ bool read_body_assignment(char *token, */ if (lvalue.ptr_level && !lvalue.is_reference) increment_size = lvalue.type->size; + /* Also check for typedef pointers which have is_ptr == 0 */ + else if (!lvalue.is_reference && lvalue.type && + lvalue.type->ptr_level > 0) { + /* This is a typedef pointer, get the base type size */ + switch (lvalue.type->base_type) { + case TYPE_char: + increment_size = TY_char->size; + break; + case TYPE_int: + increment_size = TY_int->size; + break; + case TYPE_void: + /* void pointers treated as byte pointers */ + increment_size = 1; + break; + default: + /* For struct pointers and other types */ + increment_size = lvalue.type->size; + break; + } + } /* If operand is a reference, read the value and push to stack for * the incoming addition/subtraction. Otherwise, use the top element diff --git a/tests/driver.sh b/tests/driver.sh index a372db8c..56284c49 100755 --- a/tests/driver.sh +++ b/tests/driver.sh @@ -1064,6 +1064,212 @@ int main() { } EOF +# typedef pointer tests - testing fixes for typedef pointer compilation issues +# These tests verify typedef pointer functionality after: +# 1. Removing incorrect pointer level inheritance in read_full_var_decl() +# 2. Adding typedef pointer recognition in array indexing operations +# 3. Implementing proper pointer arithmetic scaling for typedef pointers + +# Test 1: Basic typedef pointer declaration and dereference +try_ 42 << EOF +typedef int *int_ptr; +int main() { + int x = 42; + int_ptr p = &x; + return *p; /* Basic dereference - WORKING */ +} +EOF + +# Test 2: Multiple typedef pointer variables +try_ 55 << EOF +typedef int *int_ptr; +int main() { + int a = 55, b = 100; + int_ptr p1 = &a; + int_ptr p2 = &b; + return *p1; /* Should return 55 - WORKING */ +} +EOF + +# Test 3: Typedef pointer in function parameters +try_ 30 << EOF +typedef int *int_ptr; +int add_via_ptr(int_ptr a, int_ptr b) { + return *a + *b; +} +int main() { + int x = 10, y = 20; + return add_via_ptr(&x, &y); /* Function call with typedef pointers - WORKING */ +} +EOF + +# Test 4: Multiple typedef declarations +try_ 7 << EOF +typedef int *int_ptr; +typedef char *char_ptr; +int main() { + int x = 7; + char c = 'A'; + int_ptr ip = &x; + char_ptr cp = &c; + return *ip; /* Different typedef pointer types - WORKING */ +} +EOF + +# Test 5: Global typedef pointer +try_ 88 << EOF +typedef int *int_ptr; +int global_value = 88; +int_ptr global_ptr; +int main() { + global_ptr = &global_value; + return *global_ptr; /* Global typedef pointer - WORKING */ +} +EOF + +# Test 6: Typedef pointer initialization +try_ 100 << EOF +typedef int *int_ptr; +int main() { + int val = 100; + int_ptr p = &val; /* Initialize at declaration */ + int result = *p; + return result; /* Indirect usage - WORKING */ +} +EOF + +# Test 7: Nested typedef pointer usage in expressions +try_ 15 << EOF +typedef int *int_ptr; +int main() { + int x = 5, y = 10; + int_ptr px = &x; + int_ptr py = &y; + return *px + *py; /* Expression with multiple derefs - WORKING */ +} +EOF + +# Test 8: Typedef pointer assignment after declaration +try_ 25 << EOF +typedef int *int_ptr; +int main() { + int value = 25; + int_ptr ptr; + ptr = &value; /* Assignment after declaration */ + return *ptr; /* WORKING */ +} +EOF + +# Test 9: Typedef pointer array indexing +try_ 100 << EOF +typedef int *int_ptr; +int main() { + int values[3] = {42, 100, 200}; + int_ptr p = values; + return p[1]; /* Array indexing - NOW WORKING with fix */ +} +EOF + +# Test 10: Complex array indexing with typedef pointer +try_ 90 << EOF +typedef int *int_ptr; +int main() { + int arr[5] = {10, 20, 30, 40, 50}; + int_ptr p = arr; + return p[0] + p[2] + p[4]; /* Multiple array accesses */ +} +EOF + +# Test 11: Typedef pointer arithmetic - increment +try_ 20 << EOF +typedef int *int_ptr; +int main() { + int values[3] = {10, 20, 30}; + int_ptr p = values; + p++; /* Move to next element */ + return *p; /* Should return 20 */ +} +EOF + +# Test 12: Typedef pointer arithmetic - addition +try_ 40 << EOF +typedef int *int_ptr; +int main() { + int values[5] = {10, 20, 30, 40, 50}; + int_ptr p = values; + p = p + 3; /* Move forward by 3 elements */ + return *p; /* Should return 40 */ +} +EOF + +# Test 13: Typedef pointer arithmetic - subtraction +try_ 30 << EOF +typedef int *int_ptr; +int main() { + int values[5] = {10, 20, 30, 40, 50}; + int_ptr p = values + 4; /* Point to last element */ + p = p - 2; /* Move back by 2 elements */ + return *p; /* Should return 30 */ +} +EOF + +# Test 14: Typedef pointer arithmetic - prefix increment +try_ 20 << EOF +typedef int *int_ptr; +int main() { + int values[3] = {10, 20, 30}; + int_ptr p = values; + ++p; /* Prefix increment */ + return *p; /* Should return 20 */ +} +EOF + +# Test 15: Typedef pointer arithmetic - postfix increment +try_ 10 << EOF +typedef int *int_ptr; +int main() { + int values[3] = {10, 20, 30}; + int_ptr p = values; + int val = *p++; /* Get value, then increment */ + return val; /* Should return 10 */ +} +EOF + +# Test 16: Typedef pointer arithmetic - decrement +try_ 20 << EOF +typedef int *int_ptr; +int main() { + int values[3] = {10, 20, 30}; + int_ptr p = values + 2; /* Point to values[2] */ + p--; /* Move back one element */ + return *p; /* Should return 20 */ +} +EOF + +# Test 17: Typedef char pointer arithmetic +try_ 98 << EOF +typedef char *char_ptr; +int main() { + char chars[5] = {'a', 'b', 'c', 'd', 'e'}; + char_ptr p = chars; + p = p + 1; /* Move forward by 1 byte */ + return *p; /* Should return 'b' = 98 */ +} +EOF + +# Test 18: Mixed typedef pointer operations +try_ 35 << EOF +typedef int *int_ptr; +int main() { + int values[10] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50}; + int_ptr p = values; + p = p + 2; /* Move to values[2] = 15 */ + p++; /* Move to values[3] = 20 */ + p = p + 3; /* Move to values[6] = 35 */ + return *p; +} +EOF + # Category: Function Pointers begin_category "Function Pointers" "Testing function pointer declarations and calls"