Skip to content

Commit b4cd14d

Browse files
committed
Add va_list typedef and variadic function support
This commit adds va_list typedef for basic variadic function support and implement typedef pointer handling in parser (typedef char *string). In addition, this fixes *(++p) expression parsing in dereference context and corrects pointer arithmetic to increment by type size instead of 1. Close #202
1 parent 351a058 commit b4cd14d

File tree

4 files changed

+313
-15
lines changed

4 files changed

+313
-15
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 is_ptr; /* pointer level for typedef pointer types */
375376
};
376377

377378
/* lvalue details */

src/parser.c

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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->is_ptr > 0)
721+
vd->is_ptr = type->is_ptr;
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);
@@ -1529,7 +1546,12 @@ void read_lvalue(lvalue_t *lvalue,
15291546
if (prefix_op != OP_generic) {
15301547
vd = require_var(parent);
15311548
gen_name_to(vd->var_name);
1532-
vd->init_val = 1;
1549+
/* For pointer arithmetic, increment by the size of pointed-to type
1550+
*/
1551+
if (lvalue->is_ptr)
1552+
vd->init_val = lvalue->type->size;
1553+
else
1554+
vd->init_val = 1;
15331555
opstack_push(vd);
15341556
add_insn(parent, *bb, OP_load_constant, vd, NULL, NULL, 0, NULL);
15351557

@@ -1550,6 +1572,8 @@ void read_lvalue(lvalue_t *lvalue,
15501572
*/
15511573
add_insn(parent, *bb, OP_write, NULL, vd, rs1, lvalue->size,
15521574
NULL);
1575+
/* Push the new value onto the operand stack */
1576+
opstack_push(rs1);
15531577
} else {
15541578
rs1 = vd;
15551579
vd = operand_stack[operand_stack_idx - 1];
@@ -3037,6 +3061,14 @@ void read_global_statement(void)
30373061
type->base_type = base->base_type;
30383062
type->size = base->size;
30393063
type->num_fields = 0;
3064+
type->is_ptr = 0;
3065+
3066+
/* Handle pointer types in typedef: typedef char *string; */
3067+
while (lex_accept(T_asterisk)) {
3068+
type->is_ptr++;
3069+
type->size = PTR_SIZE;
3070+
}
3071+
30403072
lex_ident(T_identifier, type->type_name);
30413073
lex_expect(T_semicolon);
30423074
}

tests/driver.sh

Lines changed: 263 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1342,7 +1342,7 @@ int main()
13421342
}
13431343
EOF
13441344

1345-
# Logical-and, for loop condition
1345+
# Logical-and, for loop condition
13461346
try_output 0 "10" << EOF
13471347
int main()
13481348
{
@@ -1940,4 +1940,266 @@ int main()
19401940
}
19411941
EOF
19421942

1943+
# va_list and variadic function tests
1944+
# Note: Basic variadic functions now work with the typedef pointer fix.
1945+
# These tests use direct pointer arithmetic since shecc has limitations
1946+
# with va_list typedef forwarding between functions.
1947+
1948+
# Test 1: Sum calculation using variadic arguments
1949+
try_output 0 "Sum: 15" << EOF
1950+
int calculate_sum(int count, ...)
1951+
{
1952+
int sum = 0;
1953+
int i;
1954+
int *p;
1955+
1956+
p = &count;
1957+
p++;
1958+
1959+
for (i = 0; i < count; i++)
1960+
sum += p[i];
1961+
1962+
return sum;
1963+
}
1964+
1965+
int main()
1966+
{
1967+
int result = calculate_sum(5, 1, 2, 3, 4, 5);
1968+
printf("Sum: %d", result);
1969+
return 0;
1970+
}
1971+
EOF
1972+
1973+
# Test 2: Multiple integer arguments
1974+
try_output 0 "Multi: 10 20 255" << EOF
1975+
void multi_arg_test(int first, ...)
1976+
{
1977+
int *p;
1978+
int val1, val2;
1979+
1980+
/* Point to variadic arguments */
1981+
p = &first;
1982+
p++;
1983+
1984+
/* Get integer values */
1985+
val1 = p[0];
1986+
val2 = p[1];
1987+
1988+
printf("Multi: %d %d %d", first, val1, val2);
1989+
}
1990+
1991+
int main()
1992+
{
1993+
multi_arg_test(10, 20, 255);
1994+
return 0;
1995+
}
1996+
EOF
1997+
1998+
# Test 3: Variable argument count with different values
1999+
try_output 0 "Args: 1=100 2=200 3=300" << EOF
2000+
void print_args(int count, ...)
2001+
{
2002+
int *p = &count;
2003+
int i;
2004+
2005+
p++;
2006+
printf("Args:");
2007+
for (i = 0; i < count; i++)
2008+
printf(" %d=%d", i + 1, p[i]);
2009+
}
2010+
2011+
int main()
2012+
{
2013+
print_args(3, 100, 200, 300);
2014+
return 0;
2015+
}
2016+
EOF
2017+
2018+
# Test 4: Mixed argument types (integers with different sizes)
2019+
try_output 0 "Values: 42 -17 0 999" << EOF
2020+
void mixed_args(int first, ...)
2021+
{
2022+
int *p = &first;
2023+
2024+
printf("Values: %d", first);
2025+
printf(" %d", *(++p));
2026+
printf(" %d", *(++p));
2027+
printf(" %d", *(++p));
2028+
}
2029+
2030+
int main()
2031+
{
2032+
mixed_args(42, -17, 0, 999);
2033+
return 0;
2034+
}
2035+
EOF
2036+
2037+
# Test 5: Minimum and maximum finder
2038+
try_output 0 "Min: 5, Max: 50" << EOF
2039+
void find_min_max(int count, ...)
2040+
{
2041+
int *p = &count;
2042+
int i, min, max;
2043+
2044+
p++;
2045+
min = p[0];
2046+
max = p[0];
2047+
2048+
for (i = 1; i < count; i++) {
2049+
if (p[i] < min) min = p[i];
2050+
if (p[i] > max) max = p[i];
2051+
}
2052+
2053+
printf("Min: %d, Max: %d", min, max);
2054+
}
2055+
2056+
int main()
2057+
{
2058+
find_min_max(4, 10, 50, 5, 25);
2059+
return 0;
2060+
}
2061+
EOF
2062+
2063+
# Test 6: Simple printf-like function
2064+
try_output 0 "ERROR: Failed with code 42" << EOF
2065+
void error_log(int code, ...)
2066+
{
2067+
printf("ERROR: Failed with code %d", code);
2068+
}
2069+
2070+
int main()
2071+
{
2072+
error_log(42);
2073+
return 0;
2074+
}
2075+
EOF
2076+
2077+
# Test 7: Function with single variadic argument
2078+
try_output 0 "Single extra: 123" << EOF
2079+
void single_extra(int base, ...)
2080+
{
2081+
int *p = &base;
2082+
p++;
2083+
printf("Single extra: %d", *p);
2084+
}
2085+
2086+
int main()
2087+
{
2088+
single_extra(0, 123);
2089+
return 0;
2090+
}
2091+
EOF
2092+
2093+
# Test 8: Zero additional arguments
2094+
try_output 0 "Only required: 77" << EOF
2095+
void only_required(int value, ...)
2096+
{
2097+
printf("Only required: %d", value);
2098+
}
2099+
2100+
int main()
2101+
{
2102+
only_required(77);
2103+
return 0;
2104+
}
2105+
EOF
2106+
2107+
# Test 9: Arithmetic operations on variadic arguments
2108+
try_output 0 "Result: 25" << EOF
2109+
int arithmetic_va(int count, ...)
2110+
{
2111+
int *p = &count;
2112+
int result = 0;
2113+
int i;
2114+
2115+
p++;
2116+
for (i = 0; i < count; i++) {
2117+
if (i % 2 == 0)
2118+
result += p[i];
2119+
else
2120+
result -= p[i];
2121+
}
2122+
return result;
2123+
}
2124+
2125+
int main()
2126+
{
2127+
int res = arithmetic_va(4, 20, 5, 15, 5); /* 20 - 5 + 15 - 5 = 25 */
2128+
printf("Result: %d", res);
2129+
return 0;
2130+
}
2131+
EOF
2132+
2133+
# Test 10: Simple working variadic function test
2134+
try_output 0 "Variadic: 60" << EOF
2135+
int sum_three(int a, ...)
2136+
{
2137+
int *p = &a;
2138+
int v1 = p[0];
2139+
int v2 = p[1];
2140+
int v3 = p[2];
2141+
return v1 + v2 + v3;
2142+
}
2143+
2144+
int main()
2145+
{
2146+
printf("Variadic: %d", sum_three(10, 20, 30));
2147+
return 0;
2148+
}
2149+
EOF
2150+
2151+
# typedef pointer tests
2152+
try_ 42 << EOF
2153+
typedef int *int_ptr;
2154+
2155+
int main(void)
2156+
{
2157+
int x = 42;
2158+
int_ptr p = &x;
2159+
return *p;
2160+
}
2161+
EOF
2162+
2163+
try_output 0 "Hello" << EOF
2164+
typedef char *string;
2165+
2166+
int main(void)
2167+
{
2168+
char buf[] = "Hello";
2169+
string str = buf;
2170+
printf("%s", str);
2171+
return 0;
2172+
}
2173+
EOF
2174+
2175+
try_output 0 "Pointer arithmetic: 10 20 30" << EOF
2176+
typedef int *int_ptr;
2177+
2178+
int main(void)
2179+
{
2180+
int a = 10, b = 20, c = 30;
2181+
int_ptr ptr = &a;
2182+
2183+
printf("Pointer arithmetic:");
2184+
printf(" %d", *ptr);
2185+
ptr = &b;
2186+
printf(" %d", *ptr);
2187+
ptr = &c;
2188+
printf(" %d", *ptr);
2189+
return 0;
2190+
}
2191+
EOF
2192+
2193+
try_output 0 "Value: 42" << EOF
2194+
typedef int *int_ptr;
2195+
2196+
int main(void)
2197+
{
2198+
int value = 42;
2199+
int_ptr iptr = &value;
2200+
printf("Value: %d", *iptr);
2201+
return 0;
2202+
}
2203+
EOF
2204+
19432205
echo OK

0 commit comments

Comments
 (0)