Skip to content

Commit d4ad60c

Browse files
committed
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
1 parent 3ce9b6d commit d4ad60c

File tree

2 files changed

+432
-7
lines changed

2 files changed

+432
-7
lines changed

src/parser.c

Lines changed: 226 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,10 +1250,6 @@ void read_full_var_decl(var_t *vd, int anon, int is_param)
12501250

12511251
vd->type = type;
12521252

1253-
/* Inherit pointer level from typedef */
1254-
if (type->ptr_level > 0)
1255-
vd->is_ptr = type->ptr_level;
1256-
12571253
read_inner_var_decl(vd, anon, is_param);
12581254
}
12591255

@@ -2156,6 +2152,96 @@ void read_expr(block_t *parent, basic_block_t **bb)
21562152
if (get_operator_prio(top_op) >= get_operator_prio(op)) {
21572153
rs2 = opstack_pop();
21582154
rs1 = opstack_pop();
2155+
2156+
/* Handle pointer arithmetic for addition and subtraction */
2157+
if ((top_op == OP_add || top_op == OP_sub) &&
2158+
(rs1->is_ptr ||
2159+
(rs1->type && rs1->type->ptr_level > 0) ||
2160+
rs2->is_ptr ||
2161+
(rs2->type && rs2->type->ptr_level > 0))) {
2162+
var_t *ptr_var = NULL;
2163+
var_t *int_var = NULL;
2164+
int element_size = 0;
2165+
2166+
/* Determine which operand is the pointer */
2167+
if (rs1->is_ptr ||
2168+
(rs1->type && rs1->type->ptr_level > 0)) {
2169+
ptr_var = rs1;
2170+
int_var = rs2;
2171+
2172+
/* Calculate element size */
2173+
if (rs1->is_ptr) {
2174+
element_size = rs1->type->size;
2175+
} else if (rs1->type && rs1->type->ptr_level > 0) {
2176+
/* Typedef pointer */
2177+
switch (rs1->type->base_type) {
2178+
case TYPE_char:
2179+
element_size = TY_char->size;
2180+
break;
2181+
case TYPE_int:
2182+
element_size = TY_int->size;
2183+
break;
2184+
case TYPE_void:
2185+
element_size = 1;
2186+
break;
2187+
default:
2188+
element_size = rs1->type->size;
2189+
break;
2190+
}
2191+
}
2192+
} else if (rs2->is_ptr ||
2193+
(rs2->type && rs2->type->ptr_level > 0)) {
2194+
/* Only for addition (p + n == n + p) */
2195+
if (top_op == OP_add) {
2196+
ptr_var = rs2;
2197+
int_var = rs1;
2198+
2199+
/* Calculate element size */
2200+
if (rs2->is_ptr) {
2201+
element_size = rs2->type->size;
2202+
} else if (rs2->type &&
2203+
rs2->type->ptr_level > 0) {
2204+
/* Typedef pointer */
2205+
switch (rs2->type->base_type) {
2206+
case TYPE_char:
2207+
element_size = TY_char->size;
2208+
break;
2209+
case TYPE_int:
2210+
element_size = TY_int->size;
2211+
break;
2212+
case TYPE_void:
2213+
element_size = 1;
2214+
break;
2215+
default:
2216+
element_size = rs2->type->size;
2217+
break;
2218+
}
2219+
}
2220+
/* Swap operands so pointer is rs1 */
2221+
rs1 = ptr_var;
2222+
rs2 = int_var;
2223+
}
2224+
}
2225+
2226+
/* If we need to scale the integer operand */
2227+
if (ptr_var && element_size > 1) {
2228+
/* Create multiplication by element size */
2229+
var_t *size_const = require_var(parent);
2230+
gen_name_to(size_const->var_name);
2231+
size_const->init_val = element_size;
2232+
add_insn(parent, *bb, OP_load_constant, size_const,
2233+
NULL, NULL, 0, NULL);
2234+
2235+
var_t *scaled = require_var(parent);
2236+
gen_name_to(scaled->var_name);
2237+
add_insn(parent, *bb, OP_mul, scaled, int_var,
2238+
size_const, 0, NULL);
2239+
2240+
/* Use scaled value as rs2 */
2241+
rs2 = scaled;
2242+
}
2243+
}
2244+
21592245
vd = require_var(parent);
21602246
gen_name_to(vd->var_name);
21612247
opstack_push(vd);
@@ -2271,6 +2357,90 @@ void read_expr(block_t *parent, basic_block_t **bb)
22712357
rs2 = opstack_pop();
22722358
rs1 = opstack_pop();
22732359

2360+
/* Handle pointer arithmetic for addition and subtraction */
2361+
if ((top_op == OP_add || top_op == OP_sub) &&
2362+
(rs1->is_ptr || (rs1->type && rs1->type->ptr_level > 0) ||
2363+
rs2->is_ptr || (rs2->type && rs2->type->ptr_level > 0))) {
2364+
var_t *ptr_var = NULL;
2365+
var_t *int_var = NULL;
2366+
int element_size = 0;
2367+
2368+
/* Determine which operand is the pointer */
2369+
if (rs1->is_ptr || (rs1->type && rs1->type->ptr_level > 0)) {
2370+
ptr_var = rs1;
2371+
int_var = rs2;
2372+
2373+
/* Calculate element size */
2374+
if (rs1->is_ptr) {
2375+
element_size = rs1->type->size;
2376+
} else if (rs1->type && rs1->type->ptr_level > 0) {
2377+
/* Typedef pointer */
2378+
switch (rs1->type->base_type) {
2379+
case TYPE_char:
2380+
element_size = TY_char->size;
2381+
break;
2382+
case TYPE_int:
2383+
element_size = TY_int->size;
2384+
break;
2385+
case TYPE_void:
2386+
element_size = 1;
2387+
break;
2388+
default:
2389+
element_size = rs1->type->size;
2390+
break;
2391+
}
2392+
}
2393+
} else if (rs2->is_ptr || (rs2->type && rs2->type->ptr_level > 0)) {
2394+
/* Only for addition (p + n == n + p) */
2395+
if (top_op == OP_add) {
2396+
ptr_var = rs2;
2397+
int_var = rs1;
2398+
2399+
/* Calculate element size */
2400+
if (rs2->is_ptr) {
2401+
element_size = rs2->type->size;
2402+
} else if (rs2->type && rs2->type->ptr_level > 0) {
2403+
/* Typedef pointer */
2404+
switch (rs2->type->base_type) {
2405+
case TYPE_char:
2406+
element_size = TY_char->size;
2407+
break;
2408+
case TYPE_int:
2409+
element_size = TY_int->size;
2410+
break;
2411+
case TYPE_void:
2412+
element_size = 1;
2413+
break;
2414+
default:
2415+
element_size = rs2->type->size;
2416+
break;
2417+
}
2418+
}
2419+
/* Swap operands so pointer is rs1 */
2420+
rs1 = ptr_var;
2421+
rs2 = int_var;
2422+
}
2423+
}
2424+
2425+
/* If we need to scale the integer operand */
2426+
if (ptr_var && element_size > 1) {
2427+
/* Create multiplication by element size */
2428+
var_t *size_const = require_var(parent);
2429+
gen_name_to(size_const->var_name);
2430+
size_const->init_val = element_size;
2431+
add_insn(parent, *bb, OP_load_constant, size_const, NULL, NULL,
2432+
0, NULL);
2433+
2434+
var_t *scaled = require_var(parent);
2435+
gen_name_to(scaled->var_name);
2436+
add_insn(parent, *bb, OP_mul, scaled, int_var, size_const, 0,
2437+
NULL);
2438+
2439+
/* Use scaled value as rs2 */
2440+
rs2 = scaled;
2441+
}
2442+
}
2443+
22742444
/* Constant folding for binary operations */
22752445
if (rs1 && rs2 && rs1->init_val && !rs1->is_ptr && !rs1->is_global &&
22762446
rs2->init_val && !rs2->is_ptr && !rs2->is_global) {
@@ -2421,11 +2591,15 @@ void read_lvalue(lvalue_t *lvalue,
24212591
}
24222592

24232593
/* var must be either a pointer or an array of some type */
2424-
if (var->is_ptr == 0 && var->array_size == 0)
2594+
/* For typedef pointers, check the type's ptr_level */
2595+
bool is_typedef_pointer = (var->type && var->type->ptr_level > 0);
2596+
if (var->is_ptr == 0 && var->array_size == 0 && !is_typedef_pointer)
24252597
error("Cannot apply square operator to non-pointer");
24262598

24272599
/* if nested pointer, still pointer */
2428-
if (var->is_ptr <= 1 && var->array_size == 0) {
2600+
/* Also handle typedef pointers which have is_ptr == 0 */
2601+
if ((var->is_ptr <= 1 || is_typedef_pointer) &&
2602+
var->array_size == 0) {
24292603
/* For typedef pointers, get the size of the base type that the
24302604
* pointer points to
24312605
*/
@@ -2645,7 +2819,31 @@ void read_lvalue(lvalue_t *lvalue,
26452819
side_effect[se_idx].opcode = OP_load_constant;
26462820
vd = require_var(parent);
26472821
gen_name_to(vd->var_name);
2648-
vd->init_val = 1;
2822+
2823+
/* Calculate increment size based on pointer type */
2824+
int increment_size = 1;
2825+
if (lvalue->is_ptr && !lvalue->is_reference) {
2826+
increment_size = lvalue->type->size;
2827+
} else if (!lvalue->is_reference && lvalue->type &&
2828+
lvalue->type->ptr_level > 0) {
2829+
/* This is a typedef pointer */
2830+
switch (lvalue->type->base_type) {
2831+
case TYPE_char:
2832+
increment_size = TY_char->size;
2833+
break;
2834+
case TYPE_int:
2835+
increment_size = TY_int->size;
2836+
break;
2837+
case TYPE_void:
2838+
increment_size = 1;
2839+
break;
2840+
default:
2841+
increment_size = lvalue->type->size;
2842+
break;
2843+
}
2844+
}
2845+
vd->init_val = increment_size;
2846+
26492847
side_effect[se_idx].rd = vd;
26502848
side_effect[se_idx].rs1 = NULL;
26512849
side_effect[se_idx].rs2 = NULL;
@@ -2960,6 +3158,27 @@ bool read_body_assignment(char *token,
29603158
*/
29613159
if (lvalue.is_ptr && !lvalue.is_reference)
29623160
increment_size = lvalue.type->size;
3161+
/* Also check for typedef pointers which have is_ptr == 0 */
3162+
else if (!lvalue.is_reference && lvalue.type &&
3163+
lvalue.type->ptr_level > 0) {
3164+
/* This is a typedef pointer, get the base type size */
3165+
switch (lvalue.type->base_type) {
3166+
case TYPE_char:
3167+
increment_size = TY_char->size;
3168+
break;
3169+
case TYPE_int:
3170+
increment_size = TY_int->size;
3171+
break;
3172+
case TYPE_void:
3173+
/* void pointers treated as byte pointers */
3174+
increment_size = 1;
3175+
break;
3176+
default:
3177+
/* For struct pointers and other types */
3178+
increment_size = lvalue.type->size;
3179+
break;
3180+
}
3181+
}
29633182

29643183
/* If operand is a reference, read the value and push to stack for
29653184
* the incoming addition/subtraction. Otherwise, use the top element

0 commit comments

Comments
 (0)