Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 108 additions & 2 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,12 @@ void read_inner_var_decl(var_t *vd, bool anon, bool is_param)
{
/* Preserve typedef pointer level - don't reset if already inherited */
vd->init_val = 0;
if (is_param) {
/* However, if the parsed variable is a function parameter,
* reset its pointer level to zero.
*/
vd->ptr_level = 0;
}

while (lex_accept(T_asterisk)) {
vd->ptr_level++;
Expand Down Expand Up @@ -4917,6 +4923,49 @@ void read_func_body(func_t *func)
label_idx = 0;
}

void print_ptr_level(int level)
{
while (level > 0) {
printf("*");
level--;
}
}

void print_func_decl(func_t *func, const char *prefix, bool newline)
{
if (prefix)
printf("%s", prefix);

if (func->return_def.is_const_qualified)
printf("const ");
printf("%s ", func->return_def.type->type_name);
print_ptr_level(func->return_def.ptr_level -
func->return_def.type->ptr_level);
printf("%s(", func->return_def.var_name);

for (int i = 0; i < func->num_params; i++) {
var_t *var = &func->param_defs[i];

if (var->is_const_qualified)
printf("const ");
printf("%s ", var->type->type_name);

print_ptr_level(var->ptr_level - var->type->ptr_level);

printf("%s", var->var_name);

if (i != func->num_params - 1)
printf(", ");
}

if (func->va_args)
printf(", ...");
printf(")");

if (newline)
printf("\n");
}

/* if first token is type */
void read_global_decl(block_t *block, bool is_const)
{
Expand All @@ -4929,12 +4978,69 @@ void read_global_decl(block_t *block, bool is_const)

if (lex_peek(T_open_bracket, NULL)) {
/* function */
func_t *func = add_func(var->var_name, false);
func_t *func = find_func(var->var_name);
func_t func_tmp;
bool check_decl = false;

if (func) {
memcpy(&func_tmp, func, sizeof(func_t));
check_decl = true;
} else
func = add_func(var->var_name, false);

memcpy(&func->return_def, var, sizeof(var_t));
block->locals.size--;

read_parameter_list_decl(func, 0);

if (check_decl) {
/* Validate whether the previous declaration and the current
* one differ.
*/
if ((func->return_def.type != func_tmp.return_def.type) ||
(func->return_def.ptr_level != func_tmp.return_def.ptr_level) ||
(func->return_def.is_const_qualified !=
func_tmp.return_def.is_const_qualified)) {
printf("Error: conflicting types for the function %s.\n",
func->return_def.var_name);
print_func_decl(&func_tmp, "before: ", true);
print_func_decl(func, "after: ", true);
abort();
}

if (func->num_params != func_tmp.num_params) {
printf(
"Error: confilcting number of arguments for the function "
"%s.\n",
func->return_def.var_name);
print_func_decl(&func_tmp, "before: ", true);
print_func_decl(func, "after: ", true);
abort();
}

for (int i = 0; i < func->num_params; i++) {
var_t *func_var = &func->param_defs[i];
var_t *func_tmp_var = &func_tmp.param_defs[i];
if ((func_var->type != func_tmp_var->type) ||
(func_var->ptr_level != func_tmp_var->ptr_level) ||
(func_var->is_const_qualified !=
func_tmp_var->is_const_qualified)) {
printf("Error: confilcting types for the function %s.\n",
func->return_def.var_name);
print_func_decl(&func_tmp, "before: ", true);
print_func_decl(func, "after: ", true);
abort();
}
}

if (func->va_args != func_tmp.va_args) {
printf("Error: conflicting types for the function %s.\n",
func->return_def.var_name);
print_func_decl(&func_tmp, "before: ", true);
print_func_decl(func, "after: ", true);
abort();
}
}

if (lex_peek(T_open_curly, NULL)) {
read_func_body(func);
return;
Expand Down
117 changes: 117 additions & 0 deletions tests/driver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5690,6 +5690,123 @@ int main() {
}
EOF

begin_category "Function parsing" "Forward declaration and implementation"

# Normal case
try_output 0 "Hello" << EOF
void func(char *ptr);

void func(char *ptr)
{
while (*ptr) {
printf("%c", *ptr);
ptr++;
}
}

int main()
{
func("Hello");
return 0;
}
EOF

# Incorrect function returning type
try_compile_error << EOF
void func(void);

int **func(void)
{
return 3;
}

int main()
{
func();
return 0;
}
EOF

# Incorrect number of parameters
try_compile_error << EOF
void func(void *a);

void func(void *a, int x)
{
return 3;
}

int main()
{
func();
return 0;
}
EOF

# Conflicting parameter types
try_compile_error << EOF
void func(void *a, char x);

void func(void *a, int x)
{
return 3;
}

int main()
{
func();
return 0;
}
EOF

# Conflicting parameter types (variadic parameters)
try_compile_error << EOF
void func(void *a);

void func(void *a, ...)
{
return 3;
}

int main()
{
func();
return 0;
}
EOF

# Incorrect function returning type (const)
try_compile_error << EOF
void *func(int *a, char x);

const void *func(int *a, char x)
{
return 3;
}

int main()
{
func();
return 0;
}
EOF

# Conflicting parameter types (const)
try_compile_error << EOF
void func(int *a, char x);

void func(const int *a, char x)
{
return 3;
}

int main()
{
func();
return 0;
}
EOF

# Test Results Summary

echo ""
Expand Down