F diff --git a/src/debug/wobler/wobler_tests.h b/src/debug/wobler/wobler_tests.h
--- a/src/debug/wobler/wobler_tests.h
+++ b/src/debug/wobler/wobler_tests.h
.how_much_time_should_execution_take=TEST_TIME_BASELINE,
},
{
+ .filenames={"test_variadic_function.c"},
+ .test_function=should_compile,
+ .how_much_time_should_execution_take=TEST_TIME_BASELINE,
+ },
+ {
+ .filenames={"test_variadic_function_error.c"},
+ .test_function=should_not_compile,
+ .how_much_time_should_execution_take=TEST_TIME_BASELINE,
+ },
+ {
+ .filenames={"test_variadic_function_error2.c"},
+ .test_function=should_not_compile,
+ .how_much_time_should_execution_take=TEST_TIME_BASELINE,
+ },
+ {
.filenames={"test_declaration_speed.c"},
.test_function=should_compile,
.how_much_time_should_execution_take=TEST_TIME_BASELINE,
F diff --git a/src/frontend/parse/parse_declaration.c b/src/frontend/parse/parse_declaration.c
--- a/src/frontend/parse/parse_declaration.c
+++ b/src/frontend/parse/parse_declaration.c
{
parse_finish_function_definition(translation_data,scope,(struct Denoted_Function*)hold,where_to_push_function_definitions);
break; /*leave the declarator parser loop*/
+ }else
+ {
+ Scope_Push(scope,hold,translation_data);
}
}else if(hold->denotation==DT_Object)
{
{
parse_declaration_inner(translation_data,scope,where_to_push_declarations,where_to_push_declarations,0);
}
-
void parse_finish_function_definition(struct Translation_Data *translation_data,struct Scope *scope,struct Denoted_Function *function,struct Queue *where_to_push)
{
struct Type_Function *function_type;
{
struct Queue *parameters;
struct Normal_Scope *function_prototype_scope;
+ _Bool is_variadic=0;
function_prototype_scope=(struct Normal_Scope*)get_normal_scope(scope,FUNCTION_PROTOTYPE_SCOPE);
parameters=malloc(sizeof(struct Queue));
Queue_Init(parameters);
- parse_paramenter_list(translation_data,function_prototype_scope,parameters);
- base->type=(struct Type*)get_function_type(base->type,parameters,function_prototype_scope);
+ is_variadic=parse_paramenter_list(translation_data,function_prototype_scope,parameters);
+ base->type=(struct Type*)get_function_type(base->type,parameters,function_prototype_scope,is_variadic,translation_data);
}else
{
/*
parameter-list:
- (declaratoion-specifiers (declarator | abstract-declarator),)+
+ (declaratoion-specifiers (declarator | abstract-declarator),)* [ ... ]
+
+ returns 1 if it's a variadic function
+ 0 otherwise
*/
- void parse_paramenter_list(struct Translation_Data *translation_data,struct Normal_Scope *function_prototype_scope,struct Queue *parameters)
+ _Bool parse_paramenter_list(struct Translation_Data *translation_data,struct Normal_Scope *function_prototype_scope,struct Queue *parameters)
{
if(get_and_check(translation_data,KW_CLOSE_NORMAL))
- return;
+ return 0;
struct Denotation_Prototype *prototype;
struct Denoted_Base *base;
struct Denoted *hold;
+ _Bool is_variadic=0;
do
{
+ if(get_and_check(translation_data,KW_ELIPSIS))
+ {
+ is_variadic=1;
+ break;
+ }
prototype=parse_declaration_specifiers(translation_data,(struct Scope*)function_prototype_scope);
base=get_denoted_base(prototype);
// delete_denoted(hold);
delete_denoted_prototype(prototype);
delete_denoted_base(base);
- return;
+ return 0;
}
hold=extract_denoted(base,prototype,1);
delete_denoted_base(base);
}while(get_and_check(translation_data,KW_COMMA));
+
+
if(!get_and_check(translation_data,KW_CLOSE_NORMAL))
{
/*TODO error*/
push_translation_error("expected a ')' finishing the parameter list",translation_data);
Queue_Push(parameters,get_denoted_error(NULL));
- return;
}
+ return is_variadic;
}
/*
type-name:
F diff --git a/src/frontend/parse/parse_declaration.h b/src/frontend/parse/parse_declaration.h
--- a/src/frontend/parse/parse_declaration.h
+++ b/src/frontend/parse/parse_declaration.h
char parse_struct_declaration(struct Translation_Data *translation_data,struct Struct_Union *base);
struct Denoted* parse_struct_declarator(struct Translation_Data *translation_data,struct Scope *scope,struct Denotation_Prototype *prototype);
void parse_enum_specifier_finish(struct Translation_Data *translation_data,struct Scope *scope,struct Enum *enumeration);
- void parse_paramenter_list(struct Translation_Data *translation_data,struct Normal_Scope *function_prototype_scope,struct Queue *parameters);
+ _Bool parse_paramenter_list(struct Translation_Data *translation_data,struct Normal_Scope *function_prototype_scope,struct Queue *parameters);
struct Type* parse_type_name(struct Translation_Data *translation_data,struct Scope *scope);
struct Type* parse_abstract_declarator(struct Translation_Data *translation_data,struct Scope *scope,struct Denotation_Prototype *prototype);
F diff --git a/src/frontend/parse/parse_expression.c b/src/frontend/parse/parse_expression.c
--- a/src/frontend/parse/parse_expression.c
+++ b/src/frontend/parse/parse_expression.c
if(get_and_check(translation_data,KW_CLOSE_NORMAL))
{
- wonky_assert(is_valid_function_expression(ret));
+ wonky_assert(is_valid_ast((struct AST*)ret));
return ret;
}else
{
F diff --git a/src/semantics/ast.c b/src/semantics/ast.c
--- a/src/semantics/ast.c
+++ b/src/semantics/ast.c
size_t i;
if(id->type==ERROR)
+ {
+ while(arg_list->size>0)
+ delete_ast(Queue_Pop(arg_list));
return (struct AST_Function_Expression*)get_error_tree((struct AST*)id);
+ }
else
{
id_type=(struct Type_Function*)extract_expresion_value_type(id->value,translation_data);
F diff --git a/src/semantics/constraints/expression_constraints.c b/src/semantics/constraints/expression_constraints.c
--- a/src/semantics/constraints/expression_constraints.c
+++ b/src/semantics/constraints/expression_constraints.c
return 0;
}
- if(proposed_function_type->number_of_arguments!=proposed_function->number_of_arguments)
+ if(proposed_function_type->is_variadic)
+ {
+ if(proposed_function_type->number_of_arguments>proposed_function->number_of_arguments)
+ {
+ push_translation_error("to little arguments given for variadic function",translation_data);
+ return 0;
+ }
+ }else if(proposed_function_type->number_of_arguments!=proposed_function->number_of_arguments)
{
push_translation_error("mismatching number of arguments",translation_data);
return 0;
}
- for(i=0;i<proposed_function->number_of_arguments;++i)
+ for(i=0;i<proposed_function_type->number_of_arguments;++i)
{
if(proposed_function->arg_list[i]->type==ERROR)
if(!types_are_compatible_unqualified(expected_argument_type,given_argument_type))
{
- push_translation_error("incompatible types of argument",translation_data);
+ push_translation_error("incompatible types of arguments",translation_data);
+ push_translation_note("expected %T, but got %T",translation_data,expected_argument_type,given_argument_type);
return 0;
}
}
F diff --git a/src/semantics/identifiers/denoted.h b/src/semantics/identifiers/denoted.h
--- a/src/semantics/identifiers/denoted.h
+++ b/src/semantics/identifiers/denoted.h
size_t size;
_Bool is_const:1;
_Bool is_volatile:1;
+ _Bool is_variadic_function:1;
};
F diff --git a/src/semantics/value/type.c b/src/semantics/value/type.c
--- a/src/semantics/value/type.c
+++ b/src/semantics/value/type.c
return (struct Type*)ret;
}
- struct Type* get_function_type(struct Type *return_type,struct Queue *parameters,struct Normal_Scope* function_prototype_scope)
+ struct Type* get_function_type(struct Type *return_type,struct Queue *parameters,struct Normal_Scope* function_prototype_scope,_Bool is_variadic,struct Translation_Data *translation_data)
{
struct Type_Function *ret;
size_t i;
ret->number_of_arguments=parameters->size;
ret->arguments=malloc(sizeof(struct Denoted_Object*)*ret->number_of_arguments);
+ ret->is_variadic=is_variadic;
for(i=0;parameters->size>0;++i)
{
ret->arguments[i]=(struct Denoted_Object*)Queue_Pop(parameters);
free(parameters);
ret=(struct Type_Function*)type_check_and_push((struct Type*)ret,return_type->node,sizeof(struct Type_Function));
+ if(is_variadic && ret->number_of_arguments==0)
+ {
+ push_translation_error("variadic function needs atleast one named argument",translation_data);
+ return (struct Type*)get_type_error((struct Type*)ret);
+ }
+
wonky_assert(is_valid_type_function(ret));
return (struct Type*)ret;
}
F diff --git a/src/semantics/value/type.h b/src/semantics/value/type.h
--- a/src/semantics/value/type.h
+++ b/src/semantics/value/type.h
struct Denoted_Object** arguments;
struct Normal_Scope *function_prototype_scope;
+ _Bool is_variadic;
+
};
struct Type_Enum
{
struct Type* get_pointer_type(struct Type *points_to,_Bool is_const,_Bool is_volatile);
struct Type* get_array_type(struct Type *array_of,struct AST* number_of_elements,struct Translation_Data *translation_data);
struct Type* get_enum_type(struct Denotation_Prototype *prototype);
- struct Type* get_function_type(struct Type *return_type,struct Queue *parameters,struct Normal_Scope* function_prototype_scope);
+ struct Type* get_function_type(struct Type *return_type,struct Queue *parameters,struct Normal_Scope* function_prototype_scope,_Bool is_variadic,struct Translation_Data *translation_data);
struct Type_Basic* get_type_insecure(enum Type_Specifier type_specifier,enum Type_Signedness sign,enum Type_Constraint constraint,size_t type_size,struct Translation_Data *translation_data);
F diff --git a/tests/test_variadic_function.c b/tests/test_variadic_function.c
new file mode 100644
--- /dev/null
+++ b/tests/test_variadic_function.c
+
+ extern int printf(const char *format,...);
+
+
+ int main()
+ {
+ return printf("Hello %s \n","world!");
+ }
F diff --git a/tests/test_variadic_function_error.c b/tests/test_variadic_function_error.c
new file mode 100644
--- /dev/null
+++ b/tests/test_variadic_function_error.c
+ int a(...);
F diff --git a/tests/test_variadic_function_error2.c b/tests/test_variadic_function_error2.c
new file mode 100644
--- /dev/null
+++ b/tests/test_variadic_function_error2.c
+ int a(int a, int b,...);
+
+ int main()
+ {
+ return a(1);
+ }