#ifndef WONKY_PARSE_DECLARATION_C
#define WONKY_PARSE_DECLARATION_C WONKY_PARSE_DECLARATION_C
#include <parse_declaration.h>
#warning main(){return 0;} segfaults wonky
/*declaration-specifiers init-declarator (,init-declarator)* ;*/
/* init-declarator: declarator [ = initializer ] */
void parse_declaration_inner(struct Translation_Data *translation_data,struct Scope *scope,struct Queue *where_to_push_objects,struct Queue *where_to_push_function_definitions,_Bool parse_function_definitions)
{
struct Denotation_Prototype *prototype;
struct Denoted *hold;
prototype=parse_declaration_specifiers(translation_data,scope);
while(!get_and_check(translation_data,KW_SEMICOLON))
{
hold=parse_declarator(translation_data,scope,prototype);
if(hold->denotation==DT_Function)
{
//Scope_Push(scope,hold,translation_data);
/*check if this is a function definition*/
if(parse_function_definitions && get_and_check(translation_data,KW_OPEN_CURLY))
{
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);
resolve_function_linkage(scope,translation_data,(struct Denoted_Function*)hold);
push_function_declaration_into_linkage(translation_data,get_function_declaration_tree(scope,(struct Denoted_Function*)hold));
}
}else if(hold->denotation==DT_Object)
{
parse_finish_object_declaration(translation_data,scope,(struct Denoted_Object*)hold,where_to_push_objects);
}else if(hold->denotation==DT_Typedef)
{
Scope_Push(scope,hold,translation_data);
}else
{
/*TODO error*/
Queue_Push(where_to_push_objects,get_declaration_error_tree(hold));
push_translation_error("declaration expected",translation_data);
/*search for end of erronous declaration*/
break;
}
wonky_assert(is_valid_denoted(hold));
parse_function_definitions=0; /*here so we don't have int a,main(){ return 0 }*/
if(!get_and_check(translation_data,KW_COMMA) && !check(translation_data,KW_SEMICOLON))
{
/*TODO error*/
Queue_Push(where_to_push_objects,get_declaration_error_tree(NULL));
push_translation_error("Semicolon expected",translation_data);
break;
}
}
wonky_free(prototype);
}
void parse_external_definition(struct Translation_Data *translation_data,struct AST_Translation_Unit *unit)
{
parse_declaration_inner(translation_data,unit->file_scope,unit->object_declarations,unit->function_definitions,1);
}
void parse_declaration(struct Translation_Data *translation_data,struct Scope *scope,struct Queue *where_to_push_declarations)
{
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 AST_Compound_Statement *function_body;
struct AST_Function_Definition *function_definition;
function_type=(struct Type_Function*)function->type;
function->function_scope=(struct Function_Scope*)get_function_scope(scope,function);
function_type->function_prototype_scope->parent=(struct Scope*)function->function_scope;
wonky_assert(is_valid_denoted_function(function) && is_valid_type((struct Type*)function_type));
resolve_function_linkage(scope,translation_data,function);
Scope_Push(scope,(struct Denoted*)function,translation_data);
function_body
=
(struct AST_Compound_Statement*)
parse_finish_compound_statement(
translation_data,
(struct Scope*)function_type->function_prototype_scope,
&(struct Parse_Statement_Data)
{
.break_statement_owner=NULL,
.continue_statement_owner=NULL,
.current_switch_statement=NULL,
}
);
wonky_assert(is_valid_compound_statement(function_body));
function_definition=get_function_definition_tree(scope,function,function_body,translation_data);
push_function_definition_into_linkage(translation_data,function_definition);
Queue_Push(where_to_push,function_definition);
}
void parse_finish_object_declaration(struct Translation_Data *translation_data,struct Scope *scope,struct Denoted_Object *object,struct Queue *where_to_push)
{
struct Initialiser *initializer=NULL;
struct AST_Expression *to_be_initialised;
struct AST_Object_Declaration *object_declaration;
to_be_initialised=(struct AST_Expression*)get_designator_tree_from_denoted_object(object,translation_data);
if(get_and_check(translation_data,KW_EQ))
{
initializer=parse_initialiser(translation_data,scope,object->object->type);
wonky_assert(is_valid_initialiser(initializer));
}
object_declaration=get_object_declaration_tree(object,initializer);
resolve_object_linkage(scope,translation_data,object);
Scope_Push(scope,(struct Denoted*)object,translation_data);
push_object_into_linkage(translation_data,object_declaration);
Queue_Push(where_to_push,object_declaration);
}
struct Denotation_Prototype* parse_specifier_qualifier_list(struct Translation_Data *translation_data,struct Scope *scope)
{
return parse_declaration_specifiers_inner(translation_data,scope,0);
}
struct Denotation_Prototype* parse_declaration_specifiers(struct Translation_Data *translation_data,struct Scope *scope)
{
return parse_declaration_specifiers_inner(translation_data,scope,1);
}
/*declaration-specifiers:
( storage-class-specifier type-specifier type-qualifier function-specifier)* */
struct Denotation_Prototype* parse_declaration_specifiers_inner(struct Translation_Data *translation_data,struct Scope *scope,char parse_storage_class)
{
enum LEXER_TYPE hold_kw;
struct Denotation_Prototype *ret;
ret=(struct Denotation_Prototype*)get_denotation_prototype(translation_data->program);
while(1)
{
hold_kw=kw_get(translation_data);
switch(hold_kw)
{
case KW_SIGNED:
chomp(translation_data);
if(ret->sign==TSIGN_NONE)
{
ret->sign=TSIGN_SIGNED;
}
else
{
push_generic_error(translation_data->program,"unexpected 'signed' in type");
if(ret->sign==TSIGN_SIGNED)
push_generic_note(translation_data->program,"when it is unsigned");
else
push_generic_note(translation_data->program,"when it is already signed");
}
break;
case KW_UNSIGNED:
chomp(translation_data);
if(ret->sign==TSIGN_NONE)
{
ret->sign=TSIGN_UNSIGNED;
}
else
{
push_generic_error(translation_data->program,"unexpected 'unsigned' in type");
if(ret->sign==TSIGN_SIGNED)
push_generic_note(translation_data->program,"when it is signed");
else
push_generic_note(translation_data->program,"when it is already unsigned");
}
break;
case KW_CONST:
chomp(translation_data);
ret->is_const=1;
break;
case KW_VOLATILE:
chomp(translation_data);
ret->is_volatile=1;
break;
case KW_INT:
chomp(translation_data);
if(ret->specifier!=TS_NONE)
{
push_generic_error(translation_data->program,"more than one type specifier given");
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
ret->specifier=TS_INT;
break;
case KW_VOID:
chomp(translation_data);
if(ret->specifier!=TS_NONE)
{
push_generic_error(translation_data->program,"more than one type specifier given");
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
ret->specifier=TS_VOID;
break;
case KW_CHAR:
chomp(translation_data);
if(ret->specifier!=TS_NONE)
{
push_generic_error(translation_data->program,"more than one type specifier given");
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
ret->specifier=TS_CHAR;
break;
case KW_DOUBLE:
chomp(translation_data);
if(ret->specifier!=TS_NONE)
{
push_generic_error(translation_data->program,"more than one type specifier given");
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
ret->specifier=TS_DOUBLE;
break;
case KW_FLOAT:
chomp(translation_data);
if(ret->specifier!=TS_NONE)
{
push_generic_error(translation_data->program,"more than one type specifier given");
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
ret->specifier=TS_FLOAT;
break;
case KW_LONG:
chomp(translation_data);
if(ret->constraint!=TC_NONE)
{
if(ret->constraint==TC_LONG)
{
ret->constraint=TC_LONG_LONG;
break;
}else
{
if(ret->constraint==TC_LONG_LONG)
push_generic_error(translation_data->program,"yeah ... it's big");
else if(ret->constraint==TC_SHORT)
push_generic_error(translation_data->program,"long and short constraints contradict");
else
wonky_assert(SHOULD_NOT_REACH_HERE);
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
}
ret->constraint=TC_LONG;
break;
case KW_SHORT:
chomp(translation_data);
if(ret->constraint!=TC_NONE)
{
switch(ret->constraint)
{
case TC_LONG:
push_generic_error(translation_data->program,"long and short constraints contradict");
break;
case TC_SHORT:
push_generic_error(translation_data->program,"it's not about the size, it's about how you use it");
break;
case TC_LONG_LONG:
push_generic_error(translation_data->program,"long long and short constraints contradict");
break;
default:
/*should not be able to enter here*/
wonky_assert(SHOULD_NOT_REACH_HERE);
}
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
ret->constraint=TC_SHORT;
break;
case KW_EXTERN:
if(!parse_storage_class)
goto exit;
chomp(translation_data);
if(ret->storage_class!=SCS_NONE)
{
switch(ret->storage_class)
{
case SCS_EXTERN:
push_generic_error(translation_data->program,"only one extern allowed >:|");
break;
case SCS_TYPEDEF:
case SCS_STATIC:
push_generic_error(translation_data->program,"only one storage class allowed >:|");
break;
default:
wonky_assert(SHOULD_NOT_REACH_HERE);
}
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
ret->storage_class=SCS_EXTERN;
break;
case KW_STATIC:
if(!parse_storage_class)
goto exit;
chomp(translation_data);
if(ret->storage_class!=SCS_NONE)
{
switch(ret->storage_class)
{
case SCS_STATIC:
push_generic_error(translation_data->program,"only one static allowed >:|");
break;
case SCS_EXTERN:
case SCS_TYPEDEF:
push_generic_error(translation_data->program,"only one storage class allowed >:|");
break;
default:
wonky_assert(SHOULD_NOT_REACH_HERE);
}
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
ret->storage_class=SCS_STATIC;
break;
case KW_TYPEDEF:
if(!parse_storage_class)
goto exit;
chomp(translation_data);
if(ret->storage_class!=SCS_NONE)
{
switch(ret->storage_class)
{
case SCS_STATIC:
case SCS_EXTERN:
case SCS_TYPEDEF:
push_generic_error(translation_data->program,"only one storage class allowed >:|");
break;
default:
wonky_assert(SHOULD_NOT_REACH_HERE);
}
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
ret->storage_class=SCS_TYPEDEF;
break;
case KW_STRUCT:
ret->specifier=TS_STRUCT;
goto hack;
case KW_UNION:
ret->specifier=TS_UNION;
hack:
chomp(translation_data);
if(check(translation_data,KW_ID))
{
struct identifier *id;
struct token_identifier *hold_token;
struct Denoted_Struct_Union *tag;
hold_token=(struct token_identifier*)get_next_token(translation_data);
wonky_assert(hold_token->type=KW_ID);
id=hold_token->id;
tag=(struct Denoted_Struct_Union*)check_tag(scope,id);
if(tag==NULL)
{
struct Struct_Union *body;
body=get_struct_union_base(scope,ret->specifier,id);
Scope_Push(scope,get_denoted_struct_union(body),translation_data);
parse_struct_union_specifier_finish(translation_data,scope,body);
ret->struct_union=body;
}else
{
ret->struct_union=tag->struct_union;
if(ret->struct_union->specifier!=ret->specifier)
{
push_generic_error(translation_data->program,"more than one type specifier");
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
if(ret->struct_union->is_finished==0)
{
/*then this could be a definition*/
parse_struct_union_specifier_finish(translation_data,scope,ret->struct_union);
}
}
}else
{
ret->struct_union=get_struct_union_base(scope,ret->specifier,NULL);
parse_struct_union_specifier_finish(translation_data,scope,ret->struct_union);
if(ret->struct_union->is_finished==0)
{
push_generic_error(translation_data->program,"expected a struct tag or a struct definition");
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
}
break;
case KW_ENUM:
chomp(translation_data);
ret->specifier=TS_ENUM;
if(check(translation_data,KW_ID))
{
struct identifier *id;
struct token_identifier *hold_token;
struct Denoted_Enum *enumerator;
hold_token=(struct token_identifier*)get_next_token(translation_data);
wonky_assert(hold_token->type=KW_ID);
id=hold_token->id;
enumerator=(struct Denoted_Enum*)check_tag(scope,id);
if(enumerator==NULL)
{
struct Enum *body;
body=get_enum_base(id);
Scope_Push(scope,get_denoted_enum(body),translation_data);
parse_enum_specifier_finish(translation_data,scope,body);
ret->enumerator=body;
}else
{
ret->enumerator=enumerator->enumeration;
if(enumerator->denotation!=DT_Enum)
{
return (struct Denotation_Prototype*)get_denoted_error((struct Denoted*)ret);
}
if(ret->enumerator->is_finished==0)
{
/*this could be an enum definition*/
parse_enum_specifier_finish(translation_data,scope,ret->enumerator);
}
}
}else
{
/*tagless enumeration*/
ret->enumerator=get_enum_base(NULL);
parse_enum_specifier_finish(translation_data,scope,ret->enumerator);
}
break;
case KW_ID:
if(ret->specifier==TS_NONE)
{
struct Denoted *hold;
struct token_identifier *hold_token;
struct identifier *id;
hold_token=(struct token_identifier*)get_next_token(translation_data);
wonky_assert(hold_token->type=KW_ID);
id=hold_token->id;
hold=check_ordinary(scope,id);
if(hold!=NULL && hold->denotation==DT_Typedef)
{
ret->type=((struct Denoted_Type*)hold)->type;
chomp(translation_data);
return ret;
}
/*falltrough - this has not been typedefed*/
}
/*falltrough (it is possible to overwrite typedef id from upper scope)*/
default:
exit:
if(ret->specifier==TS_ENUM)
{
ret->type=(struct Type*)get_enum_type(ret);
}else if(ret->specifier==TS_STRUCT || ret->specifier==TS_UNION)
{
ret->type=(struct Type*)get_struct_union_type(ret);
}else if(ret->type==NULL)
{
ret->type=(struct Type*)get_basic_type(ret);
}
return ret;
}
}
}
/*
declarator:
( pointer ( type-qualifier )* )* direct-declarator
*/
struct Denoted* parse_declarator(struct Translation_Data *translation_data,struct Scope *scope,struct Denotation_Prototype *prototype)
{
struct Denoted_Base *temp;
struct Denoted *ret;
temp=get_denoted_base(prototype);
parse_declarator_inner(translation_data,scope,temp);
ret=extract_denoted(temp,prototype,0);
delete_denoted_base(temp);
return ret;
}
void parse_declarator_inner(struct Translation_Data *translation_data,struct Scope *scope,struct Denoted_Base *base)
{
enum LEXER_TYPE hold;
char is_const;
char is_volatile;
while(get_and_check(translation_data,KW_STAR))
{
is_const=is_volatile=0;
while(1)
{
hold=kw_get(translation_data);
if(hold==KW_CONST)
{
chomp(translation_data);
is_const=1;
}else if(hold==KW_VOLATILE)
{
chomp(translation_data);
is_volatile=1;
}else
{
break;
}
}
base->type=(struct Type*)get_pointer_type(base->type,is_const,is_volatile);
}
parse_direct_declarator(translation_data,scope,base);
}
/*
direct-declarator:
id direct-declarator-finish
( declarator ) direct-declarator-finish
*/
void parse_direct_declarator(struct Translation_Data *translation_data,struct Scope *scope,struct Denoted_Base *base)
{
if(check(translation_data,KW_ID))
{
struct token_identifier *hold_token;
struct identifier *id;
hold_token=(struct token_identifier*)get_next_token(translation_data);
wonky_assert(hold_token->type=KW_ID);
id=hold_token->id;
base->id=id;
parse_direct_declarator_finish(translation_data,scope,base);
}else if(get_and_check(translation_data,KW_OPEN_NORMAL))
{
struct Type *hold_first_part;
struct Type *hold_middle_part;
hold_first_part=base->type;
base->type=NULL;
parse_declarator_inner(translation_data,scope,base);
if(get_and_check(translation_data,KW_CLOSE_NORMAL))
{
hold_middle_part=base->type;
base->type=hold_first_part;
parse_declarator_inner(translation_data,scope,base);
if(!rebase_type(hold_middle_part,base->type))
{
base->type=hold_middle_part;
}else
{
wonky_assert(SHOULD_NOT_REACH_HERE);
}
}else
{
base->type=get_type_error(hold_first_part);
push_generic_error(translation_data->program,"Expected a ')' at %L");
}
}else
{
/*this might be an abstract declarator*/
parse_direct_declarator_finish(translation_data,scope,base);
}
}
/*
direct-declarator-finish:
( [ constant-expression ] | (parameter-list) | ( [id-list] ) )*
*/
void parse_direct_declarator_finish(struct Translation_Data *translation_data,struct Scope *scope,struct Denoted_Base *base)
{
struct AST *hold_expression;
while(1)
{
if(get_and_check(translation_data,KW_OPEN_SQUARE))
{
if(get_and_check(translation_data,KW_CLOSE_SQUARE))
{
hold_expression=NULL;
}else
{
hold_expression=parse_expression(translation_data,scope);
if(!get_and_check(translation_data,KW_CLOSE_SQUARE))
{
/*TODO error*/
push_generic_error(translation_data->program,"']' expected");
base->type=(struct Type*)get_type_error(base->type);
delete_ast(hold_expression);
return;
}
}
parse_direct_declarator_finish(translation_data,scope,base);
base->type=get_array_type(base->type,hold_expression,translation_data);
}else if(get_and_check(translation_data,KW_OPEN_NORMAL))
{
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=wonky_malloc(sizeof(struct Queue));
Queue_Init(parameters);
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
{
break;
}
}
}
/*
struct-union-specifier-finish:
{ ( struct-declaration )* }
*/
void parse_struct_union_specifier_finish(struct Translation_Data *translation_data,struct Scope *scope,struct Struct_Union *base)
{
if(get_and_check(translation_data,KW_OPEN_CURLY))
{
base->is_finished=1;
while(parse_struct_declaration(translation_data,base))
if(get_and_check(translation_data,KW_CLOSE_CURLY))
return ;
/*TODO error*/
push_generic_error(translation_data->program,"expected closing curly bracket from struct declaration");
return;
}
}
/*
struct-declaration:
specifier-qualifier-list ( struct-declarator )* ;
*/
char parse_struct_declaration(struct Translation_Data *translation_data,struct Struct_Union *base)
{
struct Denotation_Prototype *prototype;
struct Denoted *hold_denoted;
struct Denoted_Object *hold_denoted_object;
prototype=parse_specifier_qualifier_list(translation_data,(struct Scope*)base->inner_namespace);
while(!get_and_check(translation_data,KW_SEMICOLON))
{
hold_denoted=parse_struct_declarator(translation_data,(struct Scope*)base->inner_namespace,prototype);
if(hold_denoted!=NULL && hold_denoted->denotation!=DT_Error)
{
if(hold_denoted->denotation==DT_Object)
{
hold_denoted_object=(struct Denoted_Object*)hold_denoted;
Scope_Push((struct Scope*)base->inner_namespace,hold_denoted,translation_data);
Queue_Push(base->members,hold_denoted);
if(type_is_constant_or_has_constant_member(hold_denoted_object->object->type))
base->has_constant_member=1;
}else
{
push_generic_error(translation_data->program,"non object declaration in struct definition");
}
}else
{
wonky_free(prototype);
push_generic_error(translation_data->program,"there is a problem with the declarator");
return 0;
}
if(!get_and_check(translation_data,KW_COMMA) && !check(translation_data,KW_SEMICOLON))
{
wonky_free(prototype);
push_generic_error(translation_data->program,"semi column expected in struct declaration");
return 0;
}
}
wonky_free(prototype);
return 1;
}
/*
struct-declarator:
declarator
[ declarator ] : constant-expression
*/
struct Denoted* parse_struct_declarator(struct Translation_Data *translation_data,struct Scope *scope,struct Denotation_Prototype *prototype)
{
struct Denoted_Object *hold_denoted_object;
struct AST_Expression *hold_number_of_bits_expression;
if(get_and_check(translation_data,KW_COLUMN))
{
/*unnamed bitfields are possible*/
hold_denoted_object=(struct Denoted_Object*)get_denoted_object(NULL,SCS_NONE,prototype->type,NULL);
}else
{
/*we cast it but it is still unsure if it has object type so we imediately check*/
hold_denoted_object=(struct Denoted_Object*)parse_declarator(translation_data,scope,prototype);
if(hold_denoted_object->denotation!=DT_Object)
{
/*TODO error*/
push_generic_error(translation_data->program,"expected object type for bitfield");
return get_denoted_error((struct Denoted*)hold_denoted_object);
}
if(get_and_check(translation_data,KW_COLUMN))
{
hold_number_of_bits_expression=(struct AST_Expression*)parse_expression(translation_data,scope);
hold_denoted_object->object=convert_object_to_bitfield(hold_denoted_object->object,hold_number_of_bits_expression,translation_data);
}
}
return (struct Denoted*)hold_denoted_object;
}
/*
enum-specifier-finish
{ ( enumeration-constant [ = constant-expression ] , )* }
*/
void parse_enum_specifier_finish(struct Translation_Data *translation_data,struct Scope *scope,struct Enum *enumeration)
{
struct identifier *id;
struct Denoted_Enum_Const *hold;
int where_in_enumeration=0;
if(get_and_check(translation_data,KW_OPEN_CURLY))
{
enumeration->is_finished=1;
do
{
if(check(translation_data,KW_ID))
{
id=((struct token_identifier*)get_next_token(translation_data))->id;
if(get_and_check(translation_data,KW_EQ))
{
hold=(struct Denoted_Enum_Const*)get_denoted_enum_const_expr(id,enumeration,parse_expression(translation_data,scope),translation_data);
Queue_Push(enumeration->consts,hold);
where_in_enumeration=hold->value+1;
}else
{
Queue_Push(enumeration->consts,get_denoted_enum_const_num(id,enumeration,where_in_enumeration));
++where_in_enumeration;
}
if(!get_and_check(translation_data,KW_COMMA) && get_and_check(translation_data,KW_CLOSE_CURLY))
{
return;
}else
{
/*TODO error*/
push_generic_error(translation_data->program,"enum definition error");
Queue_Push(enumeration->consts,get_denoted_error(NULL));
return ;
}
}else
{
/*TODO error*/
push_generic_error(translation_data->program,"enum definition error, expected an id");
Queue_Push(enumeration->consts,get_denoted_error(NULL));
return ;
}
}while(!get_and_check(translation_data,KW_CLOSE_CURLY));
}
}
/*
parameter-list:
(declaratoion-specifiers (declarator | abstract-declarator),)* [ ... ]
returns 1 if it's a variadic function
0 otherwise
*/
_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 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);
parse_declarator_inner(translation_data,(struct Scope*)function_prototype_scope,base);
if(base->denotation!=DT_Object)
{
/*TODO error*/
push_generic_error(translation_data->program,"expected object declaration in function prototype");
// delete_denoted(hold);
delete_denoted_prototype(prototype);
delete_denoted_base(base);
return 0;
}
hold=extract_denoted(base,prototype,1);
if(((struct Denoted_Object*)hold)->id!=NULL)
Scope_Push((struct Scope*)function_prototype_scope,hold,translation_data);
Queue_Push(parameters,((struct Denoted_Object*)hold));
delete_denoted_prototype(prototype);
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 is_variadic;
}
/*
type-name:
specifier-qualifier-list [abstract-declarator]
*/
struct Type* parse_type_name(struct Translation_Data *translation_data,struct Scope *scope)
{
struct Denotation_Prototype *prototype;
struct Type *ret;
prototype=parse_specifier_qualifier_list(translation_data,scope);
ret=parse_abstract_declarator(translation_data,scope,prototype);
delete_denoted_prototype(prototype);
return ret;
}
/*
abstract-declarator:
( pointer )* abstract-direct-declarator
*/
struct Type* parse_abstract_declarator(struct Translation_Data *translation_data,struct Scope *scope,struct Denotation_Prototype *prototype)
{
struct Denoted_Base *base;
struct Type *ret;
base=get_denoted_base(prototype);
parse_declarator_inner(translation_data,scope,base);
if(base->denotation==DT_Error || base->id!=NULL)
{
/*TODO error*/
push_generic_error(translation_data->program,"unexpedted id in abstract declarator");
delete_denoted_base(base);
ret=base->type;
return ret;
}
ret=base->type;
delete_denoted_base(base);
return ret;
}
/*
initializer:
assignment-expression
{ initializer-list [,] }
*/
struct Initialiser* parse_initialiser(struct Translation_Data *translation_data,struct Scope *scope,struct Type *type_of_initialised)
{
if(get_and_check(translation_data,KW_OPEN_CURLY))
return parse_initialiser_list(translation_data,scope,type_of_initialised);
else
return parse_simple_initialiser(translation_data,scope,type_of_initialised);
}
/*
initilizer-list:
( initialiser-list-component ',' )*
*/
struct Initialiser* parse_initialiser_list(struct Translation_Data *translation_data,struct Scope *scope,struct Type *type_of_initialised)
{
if(type_is_an_array(type_of_initialised))
return parse_initialiser_list_for_array(translation_data,scope,(struct Type_Array*)type_of_initialised);
else if(type_is_struct_union(type_of_initialised))
return parse_initialiser_list_for_struct_union(translation_data,scope,(struct Type_Struct_Union*)type_of_initialised);
else
{
push_generic_error(translation_data->program,"expected aggregate type in compound initialisation, got %T instead",type_of_initialised);
return get_initialiser_error(NULL);
}
}
/*
initilizer-list:
( initialiser-list-component ',' )*
*/
struct Initialiser* parse_initialiser_list_for_struct_union(struct Translation_Data *translation_data,struct Scope *scope,struct Type_Struct_Union *type_of_initialised)
{
struct Queue_Node *current_object;
struct Initialiser *current_initialiser;
struct Queue *components;
current_object=type_of_initialised->struct_union->members->first;
components=wonky_malloc(sizeof(struct Queue));
Queue_Init(components);
do{
current_initialiser=parse_initialiser_list_component(translation_data,scope,(struct Type*)type_of_initialised);
if(current_initialiser->kind==INITIALISER_ERROR)
{
return current_initialiser;
}else if(current_initialiser->kind!=INITIALISER_DENOTED)
{
Queue_Push(
components,
get_denoted_initialiser((struct Denoted_Object*)current_object->data,current_initialiser,translation_data)
);
current_object=current_object->prev;
}else
{
for(
current_object=type_of_initialised->struct_union->members->first;
current_object!=NULL && current_object->data!=((struct Initialiser_Denoted*)current_initialiser)->to_be_initialised;
current_object=current_object->prev
);
current_object=current_object->prev;
Queue_Push(components,current_initialiser);
}
}while(get_and_check(translation_data,KW_COMMA));
if(get_and_check(translation_data,KW_CLOSE_CURLY))
return get_compound_initialiser((struct Type*)type_of_initialised,components,translation_data);
else
return get_initialiser_error(get_compound_initialiser((struct Type*)type_of_initialised,components,translation_data));
}
/*
initilizer-list:
( initialiser-list-component ',' )*
*/
struct Initialiser* parse_initialiser_list_for_array(struct Translation_Data *translation_data,struct Scope *scope,struct Type_Array *type_of_initialised)
{
struct Queue *components;
size_t current_object;
struct Initialiser *current_initialiser;
components=wonky_malloc(sizeof(struct Queue));
Queue_Init(components);
do{
current_initialiser=parse_initialiser_list_component(translation_data,scope,(struct Type*)type_of_initialised);
if(current_initialiser->kind==INITIALISER_ERROR)
{
return current_initialiser;
}else if(current_initialiser->kind!=INITIALISER_INDEXED)
{
Queue_Push(
components,
get_indexed_initialiser(type_of_initialised->is_array_of,current_object,current_initialiser,translation_data)
);
++current_object;
}else
{
Queue_Push(components,current_initialiser);
current_object=((struct Initialiser_Indexed*)current_initialiser)->index+1;
}
}while(get_and_check(translation_data,KW_COMMA));
if(get_and_check(translation_data,KW_CLOSE_CURLY))
return get_compound_initialiser((struct Type*)type_of_initialised,components,translation_data);
else
return get_initialiser_error(get_compound_initialiser((struct Type*)type_of_initialised,components,translation_data));
}
/*
assignment-expression
*/
struct Initialiser* parse_simple_initialiser(struct Translation_Data *translation_data,struct Scope *scope,struct Type *type_of_initialised)
{
struct AST_Expression *assignment_expression;
assignment_expression=parse_assignment_expression(translation_data,scope);
return get_initialiser_expression(assignment_expression,type_of_initialised,translation_data);
}
/*
initialiser-list-component:
[ designation ] initialiser
*/
struct Initialiser* parse_initialiser_list_component(struct Translation_Data *translation_data,struct Scope *scope,struct Type *type_of_initialised)
{
if(check(translation_data,KW_DOT) || check(translation_data,KW_OPEN_SQUARE))
return parse_designation(translation_data,scope,type_of_initialised);
else
return parse_initialiser(translation_data,scope,type_of_initialised);
}
/*
designation:
designator-list '='
designator-list:
( designator )+
designator:
'[' constant-expression ']'
'.' identifier
*/
/*TODO: make this iterative XD*/
struct Initialiser* parse_designation(struct Translation_Data *translation_data,struct Scope *scope,struct Type *type_of_initialised)
{
if(get_and_check(translation_data,KW_OPEN_SQUARE))
parse_indexed_initialiser(translation_data,scope,type_of_initialised);
else if(get_and_check(translation_data,KW_DOT))
parse_member_initialiser(translation_data,scope,type_of_initialised);
else if(get_and_check(translation_data,KW_EQ))
return parse_initialiser(translation_data,scope,type_of_initialised);
else
{
push_generic_error(translation_data->program,"expected '=' in initialiser designation");
return get_initialiser_error(NULL);
}
}
struct Initialiser* parse_indexed_initialiser(struct Translation_Data *translation_data,struct Scope *scope,struct Type *type_of_initialised)
{
struct AST_Expression *index_expression;
struct Type_Array *real_type;
if(!type_is_an_array(type_of_initialised))
{
push_generic_error(translation_data->program,"expected array type in indexed initialiser, instead got a %T",type_of_initialised);
return get_initialiser_error(NULL);
}
real_type=(struct Type_Array*)type_of_initialised;
index_expression=(struct AST_Expression*)parse_expression(translation_data,scope);
if(get_and_check(translation_data,KW_CLOSE_CURLY))
{
size_t eval;
eval=evaluate_const_expression_integer((struct AST*)index_expression,translation_data);
return get_indexed_initialiser(real_type->is_array_of,eval,parse_designation(translation_data,scope,real_type->is_array_of),translation_data);
}else
{
size_t eval;
eval=evaluate_const_expression_integer((struct AST*)index_expression,translation_data);
return get_initialiser_error(
get_indexed_initialiser(real_type->is_array_of,eval,parse_designation(translation_data,scope,real_type->is_array_of),translation_data)
);
}
}
struct Initialiser* parse_member_initialiser(struct Translation_Data *translation_data,struct Scope *scope,struct Type *type_of_initialised)
{
struct Denoted_Object *member;
struct Type_Struct_Union *real_type;
struct identifier *id;
if(!type_is_struct_union(type_of_initialised))
{
push_generic_error(translation_data->program,"expected struct/union type in initialiser, got %T instead",type_of_initialised);
return get_initialiser_error(NULL);
}
if(!check(translation_data,KW_ID))
{
push_generic_error(translation_data->program,"expected id in the initialisation of type %T",type_of_initialised);
return get_initialiser_error(NULL);
}
id=((struct token_identifier*)get_next_token(translation_data))->id;
real_type=(struct Type_Struct_Union*)type_of_initialised;
member=check_struct_union_member(real_type->struct_union->inner_namespace,id);
if(member==NULL)
{
push_generic_error(translation_data->program,"%t is not a member of %T",id,type_of_initialised);
push_translation_note("in initialiser",translation_data);
return get_initialiser_error(NULL);
}
return get_denoted_initialiser(member,parse_initialiser(translation_data,scope,member->object->type),translation_data);
}
const const const const const const const const const const const const const const const const const const const const const const const char const const const constant;
#endif