Skip to content

Commit 5a320be

Browse files
committed
Add va_list typedef and variadic function support
This commit implements comprehensive support for variadic functions, including: - Add built-in va_list typedef (int *) for variadic argument handling - Fix typedef pointer level preservation in parser - Add proper array indexing support for typedef pointers - Support pointer arithmetic with typedef pointers - Add expression dereferencing support: *(++p) The is_ptr field in type_t structure is used to track pointer levels for typedef'd pointer types, not as a boolean flag. This rename makes the field's purpose clearer and aligns with its actual usage as a counter throughout the codebase. This enables both traditional pointer arithmetic access to variadic arguments and modern va_list typedef forwarding between functions. Close #202
1 parent 351a058 commit 5a320be

File tree

4 files changed

+386
-18
lines changed

4 files changed

+386
-18
lines changed

lib/c.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545

4646
typedef int FILE;
4747

48+
/* va_list support for variadic functions */
49+
typedef int *va_list;
50+
4851
void abort(void);
4952

5053
int strlen(char *str)

src/defs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ struct type {
372372
int size;
373373
var_t fields[MAX_FIELDS];
374374
int num_fields;
375+
int ptr_level; /* pointer level for typedef pointer types */
375376
};
376377

377378
/* lvalue details */

src/parser.c

Lines changed: 72 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ void read_parameter_list_decl(func_t *func, int anon);
657657
void read_inner_var_decl(var_t *vd, int anon, int is_param)
658658
{
659659
vd->init_val = 0;
660-
vd->is_ptr = 0;
660+
/* Preserve typedef pointer level - don't reset if already inherited */
661661

662662
while (lex_accept(T_asterisk))
663663
vd->is_ptr++;
@@ -715,6 +715,11 @@ void read_full_var_decl(var_t *vd, int anon, int is_param)
715715
}
716716

717717
vd->type = type;
718+
719+
/* Inherit pointer level from typedef */
720+
if (type->ptr_level > 0)
721+
vd->is_ptr = type->ptr_level;
722+
718723
read_inner_var_decl(vd, anon, is_param);
719724
}
720725

@@ -963,21 +968,33 @@ void read_expr_operand(block_t *parent, basic_block_t **bb)
963968
lvalue_t lvalue;
964969

965970
int open_bracket = lex_accept(T_open_bracket);
966-
lex_peek(T_identifier, token);
967-
var_t *var = find_var(token, parent);
968-
read_lvalue(&lvalue, var, parent, bb, true, OP_generic);
969-
if (open_bracket)
971+
if (open_bracket) {
972+
/* Handle expressions like *(++p) */
973+
read_expr(parent, bb);
970974
lex_expect(T_close_bracket);
975+
rs1 = opstack_pop();
976+
/* Create a temporary variable for the dereferenced result */
977+
vd = require_var(parent);
978+
vd->type = TY_int; /* Default to int type for now */
979+
vd->is_ptr = 0;
980+
gen_name_to(vd->var_name);
981+
opstack_push(vd);
982+
add_insn(parent, *bb, OP_read, vd, rs1, NULL, vd->type->size, NULL);
983+
} else {
984+
lex_peek(T_identifier, token);
985+
var_t *var = find_var(token, parent);
986+
read_lvalue(&lvalue, var, parent, bb, true, OP_generic);
971987

972-
rs1 = opstack_pop();
973-
vd = require_deref_var(parent, var->type, var->is_ptr);
974-
if (lvalue.is_ptr > 1)
975-
sz = PTR_SIZE;
976-
else
977-
sz = lvalue.type->size;
978-
gen_name_to(vd->var_name);
979-
opstack_push(vd);
980-
add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL);
988+
rs1 = opstack_pop();
989+
vd = require_deref_var(parent, var->type, var->is_ptr);
990+
if (lvalue.is_ptr > 1)
991+
sz = PTR_SIZE;
992+
else
993+
sz = lvalue.type->size;
994+
gen_name_to(vd->var_name);
995+
opstack_push(vd);
996+
add_insn(parent, *bb, OP_read, vd, rs1, NULL, sz, NULL);
997+
}
981998
} else if (lex_accept(T_open_bracket)) {
982999
read_expr(parent, bb);
9831000
read_ternary_operation(parent, bb);
@@ -1374,8 +1391,31 @@ void read_lvalue(lvalue_t *lvalue,
13741391
error("Cannot apply square operator to non-pointer");
13751392

13761393
/* if nested pointer, still pointer */
1377-
if (var->is_ptr <= 1 && var->array_size == 0)
1378-
lvalue->size = lvalue->type->size;
1394+
if (var->is_ptr <= 1 && var->array_size == 0) {
1395+
/* For typedef pointers, get the size of the base type that the
1396+
* pointer points to
1397+
*/
1398+
if (lvalue->type->ptr_level > 0) {
1399+
/* This is a typedef pointer, get base type size */
1400+
switch (lvalue->type->base_type) {
1401+
case TYPE_char:
1402+
lvalue->size = TY_char->size;
1403+
break;
1404+
case TYPE_int:
1405+
lvalue->size = TY_int->size;
1406+
break;
1407+
case TYPE_void:
1408+
/* void pointers treated as byte pointers */
1409+
lvalue->size = 1;
1410+
break;
1411+
default:
1412+
lvalue->size = lvalue->type->size;
1413+
break;
1414+
}
1415+
} else {
1416+
lvalue->size = lvalue->type->size;
1417+
}
1418+
}
13791419

13801420
read_expr(parent, bb);
13811421

@@ -1529,7 +1569,12 @@ void read_lvalue(lvalue_t *lvalue,
15291569
if (prefix_op != OP_generic) {
15301570
vd = require_var(parent);
15311571
gen_name_to(vd->var_name);
1532-
vd->init_val = 1;
1572+
/* For pointer arithmetic, increment by the size of pointed-to type
1573+
*/
1574+
if (lvalue->is_ptr)
1575+
vd->init_val = lvalue->type->size;
1576+
else
1577+
vd->init_val = 1;
15331578
opstack_push(vd);
15341579
add_insn(parent, *bb, OP_load_constant, vd, NULL, NULL, 0, NULL);
15351580

@@ -1550,6 +1595,8 @@ void read_lvalue(lvalue_t *lvalue,
15501595
*/
15511596
add_insn(parent, *bb, OP_write, NULL, vd, rs1, lvalue->size,
15521597
NULL);
1598+
/* Push the new value onto the operand stack */
1599+
opstack_push(rs1);
15531600
} else {
15541601
rs1 = vd;
15551602
vd = operand_stack[operand_stack_idx - 1];
@@ -3037,6 +3084,14 @@ void read_global_statement(void)
30373084
type->base_type = base->base_type;
30383085
type->size = base->size;
30393086
type->num_fields = 0;
3087+
type->ptr_level = 0;
3088+
3089+
/* Handle pointer types in typedef: typedef char *string; */
3090+
while (lex_accept(T_asterisk)) {
3091+
type->ptr_level++;
3092+
type->size = PTR_SIZE;
3093+
}
3094+
30403095
lex_ident(T_identifier, type->type_name);
30413096
lex_expect(T_semicolon);
30423097
}

0 commit comments

Comments
 (0)