#ifndef PARSE_WONKY_STATEMENT_C
#define PARSE_WONKY_STATEMENT_C PARSE_WONKY_STATEMENT_C
#include "parse_statement.h"
struct AST* parse_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
if(translation_eof(translation_data))
return NULL;
switch(kw_get(translation_data))
{
case KW_NOTYPE:
push_translation_error("statement expected",translation_data);
return (struct AST*)get_error_tree(NULL);
case KW_OPEN_CURLY:
chomp(translation_data);
return parse_finish_compound_statement(translation_data,scope,parse_data);
case KW_IF:
chomp(translation_data);
return parse_finish_if_statement(translation_data,scope,parse_data);
case KW_SWITCH:
chomp(translation_data);
return parse_finish_switch_statement(translation_data,scope,parse_data);
case KW_WHILE:
chomp(translation_data);
return parse_finish_while_statement(translation_data,scope,parse_data);
case KW_DO:
chomp(translation_data);
return parse_finish_do_while_statement(translation_data,scope,parse_data);
case KW_FOR:
chomp(translation_data);
return parse_finish_for_statement(translation_data,scope,parse_data);
case KW_GOTO:
chomp(translation_data);
return parse_finish_goto_statement(translation_data,scope,parse_data);
case KW_CASE:
chomp(translation_data);
return parse_finish_case_statement(translation_data,scope,parse_data);
case KW_DEFAULT:
chomp(translation_data);
return parse_finish_default_statement(translation_data,scope,parse_data);
case KW_ID:
{
struct token_identifier *hold_token;
hold_token=(struct token_identifier*)get_next_token(translation_data);
if(check(translation_data,KW_COLUMN))
{
token_ptr_unget_token(translation_data->token_pointer,(struct token*)hold_token);
return parse_finish_labeled_statement(translation_data,scope,parse_data);
}else
{
token_ptr_unget_token(translation_data->token_pointer,(struct token*)hold_token);
return parse_expression_statement(translation_data,scope,parse_data);
}
}
case KW_CONTINUE:
chomp(translation_data);
return parse_finish_continue_statement(translation_data,parse_data);
case KW_BREAK:
chomp(translation_data);
return parse_finish_break_statement(translation_data,parse_data);
case KW_RETURN:
chomp(translation_data);
return parse_finish_return_statement(translation_data,scope,parse_data);
default:
return parse_expression_statement(translation_data,scope,parse_data);
}
}
/*
( declaration | statement )* }
*/
struct AST* parse_finish_compound_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST_Compound_Statement *hold;
hold=get_compound_statement_tree(scope);
while(!get_and_check(translation_data,KW_CLOSE_CURLY) && !has_no_tokens(translation_data))
{
if(is_type_name(translation_data,hold->scope))
parse_declaration(translation_data,hold->scope,hold->components);
else
Queue_Push(hold->components,parse_statement(translation_data,hold->scope,parse_data));
if(has_new_errors(translation_data))
chase_next_semicolumn(translation_data);
}
wonky_assert(is_valid_compound_statement(hold));
return (struct AST*)hold;
}
/*
( expression ) statement
( expression ) statement else statement
*/
struct AST* parse_finish_if_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST_If_Statement *hold;
hold=get_if_statement_tree();
if(get_and_check(translation_data,KW_OPEN_NORMAL))
{
hold->condition=parse_expression(translation_data,scope);
if(get_and_check(translation_data,KW_CLOSE_NORMAL))
{
hold->body_statement=parse_statement(translation_data,scope,parse_data);
}else
{
push_translation_error(" ')' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold);
}
if(get_and_check(translation_data,KW_ELSE))
{
hold->else_statement=parse_statement(translation_data,scope,parse_data);
return (struct AST*)hold;
}else
{
hold->else_statement=NULL;
return (struct AST*)hold;
}
}else
{
push_translation_error(" '(' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold);
}
wonky_assert(is_valid_if_statement(hold));
return (struct AST*)hold;
}
/*
( expression ) statement
*/
struct AST* parse_finish_switch_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST_Switch_Statement *hold;
struct AST_Expression *hold_control_expression;
struct AST *hold_body_statement;
if(get_and_check(translation_data,KW_OPEN_NORMAL))
{
hold_control_expression=(struct AST_Expression*)parse_expression(translation_data,scope);
if(get_and_check(translation_data,KW_CLOSE_NORMAL))
{
hold_body_statement
=
parse_statement(
translation_data,
scope,
&(struct Parse_Statement_Data)
{
.break_statement_owner=(struct AST*)hold,
.continue_statement_owner=parse_data->continue_statement_owner,
.current_switch_statement=hold,
}
);
hold=get_switch_statement_tree(hold_control_expression,hold_body_statement);
wonky_assert(is_valid_switch_statement(hold));
return (struct AST*)hold;
}else
{
push_translation_error(" ')' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold_control_expression);
}
}else
{
push_translation_error(" '(' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)NULL);
}
wonky_assert(SHOULD_NOT_REACH_HERE);
}
/*
( expression ) statement
*/
struct AST* parse_finish_while_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST_While_Statement *hold;
hold=get_while_statement_tree();
if(get_and_check(translation_data,KW_OPEN_NORMAL))
{
hold->condition=parse_expression(translation_data,scope);
if(get_and_check(translation_data,KW_CLOSE_NORMAL))
{
hold->body_statement
=
parse_statement(
translation_data,
scope,
&(struct Parse_Statement_Data)
{
.break_statement_owner=(struct AST*)hold,
.continue_statement_owner=(struct AST*)hold,
.current_switch_statement=parse_data->current_switch_statement,
}
);
wonky_assert(is_valid_while_statement(hold));
return (struct AST*)hold;
}else
{
push_translation_error(" ')' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold);
}
}else
{
push_translation_error(" '(' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold);
}
wonky_assert(SHOULD_NOT_REACH_HERE);
}
/*
statement while ( expression ) ;
*/
struct AST* parse_finish_do_while_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST_Do_While_Statement *hold;
hold=get_do_while_statement_tree();
hold->body_statement
=
parse_statement(
translation_data,
scope,
&(struct Parse_Statement_Data)
{
.break_statement_owner=(struct AST*)hold,
.continue_statement_owner=(struct AST*)hold,
.current_switch_statement=parse_data->current_switch_statement,
}
);
if(get_and_check(translation_data,KW_WHILE) && get_and_check(translation_data,KW_OPEN_NORMAL))
{
hold->condition=parse_expression(translation_data,scope);
if(get_and_check(translation_data,KW_CLOSE_NORMAL) && get_and_check(translation_data,KW_SEMICOLON))
{
wonky_assert(is_valid_do_while_statement(hold));
return (struct AST*)hold;
}else
{
push_translation_error(" ';' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold);
}
}else
{
push_translation_error("'do-while' statement is unfinished",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold);
}
}
/*
( [ expression ] ; [ expression ] ; [ expression ] ) statement
*/
struct AST* parse_finish_for_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST_For_Statement *hold;
hold=get_for_statement_tree();
if(!get_and_check(translation_data,KW_OPEN_NORMAL))
{
push_translation_error(" '(' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold);
}
hold->initialisation=parse_expression_statement(translation_data,scope,parse_data);
if(hold->initialisation->type==ERROR)
push_translation_error("expected expression or declaration in for loop initialisation",translation_data);
hold->condition=parse_expression_statement(translation_data,scope,parse_data);
if(get_and_check(translation_data,KW_CLOSE_NORMAL))
{
hold->update=get_nop_tree();
}else
{
hold->update=parse_expression(translation_data,scope);
if(!get_and_check(translation_data,KW_CLOSE_NORMAL))
{
push_translation_error(" ')' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold);
}
}
hold->body_statement
=
parse_statement(
translation_data,
scope,
&(struct Parse_Statement_Data)
{
.break_statement_owner=(struct AST*)hold,
.continue_statement_owner=(struct AST*)hold,
.current_switch_statement=parse_data->current_switch_statement,
}
);
wonky_assert(is_valid_for_statement(hold));
return (struct AST*)hold;
}
/*
id ;
*/
struct AST* parse_finish_goto_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST_Goto_Statement* ret;
if(check(translation_data,KW_ID))
{
struct token_identifier *hold_id_token;
hold_id_token=(struct token_identifier*)get_next_token(translation_data);
ret=get_goto_statement_tree(hold_id_token->id,scope,translation_data);
if(get_and_check(translation_data,KW_SEMICOLON))
{
wonky_assert(is_valid_goto_statement(ret));
return (struct AST*)ret;
}else
{
push_translation_error(" ';' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)ret);
}
}
else
{
push_translation_error(" label expected in goto statement",translation_data);
return (struct AST*)get_error_tree(NULL);
}
}
/*
;
*/
struct AST* parse_finish_continue_statement(struct Translation_Data* translation_data,struct Parse_Statement_Data *parse_data)
{
struct AST_Break_Continue_Statement *hold;
if(get_and_check(translation_data,KW_SEMICOLON))
{
hold=get_break_continue_statement_tree(parse_data->continue_statement_owner,translation_data,ST_CONTINUE);
wonky_assert(is_valid_break_continue_statement(hold));
return (struct AST*)hold;
}else
{
push_translation_error(" ';' expected",translation_data);
return (struct AST*)get_error_tree(NULL);
}
}
/*
;
*/
struct AST* parse_finish_break_statement(struct Translation_Data* translation_data,struct Parse_Statement_Data *parse_data)
{
struct AST_Break_Continue_Statement *hold;
if(get_and_check(translation_data,KW_SEMICOLON))
{
hold=get_break_continue_statement_tree(parse_data->break_statement_owner,translation_data,ST_BREAK);
wonky_assert(is_valid_break_continue_statement(hold));
return (struct AST*)hold;
}else
{
push_translation_error(" ';' expected",translation_data);
return (struct AST*)get_error_tree(NULL);
}
}
/*
id:
statement
*/
struct AST* parse_finish_labeled_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST *hold_statement;
struct token_identifier *hold_id;
struct AST_Labeled_Statement *hold;
/*id and ':' are checked for in the parse_statement function*/
hold_id=(struct token_identifier*)get_next_token(translation_data);
chomp(translation_data); /* ':' */
hold_statement=parse_statement(translation_data,scope,parse_data);
hold=get_labeled_statement_tree(hold_id->id,hold_statement,ST_LABEL,translation_data,scope);
wonky_assert(is_valid_labeled_statement(hold));
return (struct AST*)hold;
}
/*
constant-expresssion :
statement
*/
struct AST* parse_finish_case_statement(struct Translation_Data *translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST_Expression *hold_expression;
struct AST *hold_statement;
struct AST_Case_Statement *hold;
hold_expression=(struct AST_Expression*)parse_expression(translation_data,scope);
if(get_and_check(translation_data,KW_COLUMN))
{
hold_statement=parse_statement(translation_data,scope,parse_data);
hold=get_case_statement_tree(hold_statement,hold_expression,parse_data->current_switch_statement,translation_data);
wonky_assert(is_valid_case_statement(hold));
return (struct AST*)hold;
}else
{
push_translation_error(" ':' expected after expression in case statement",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold_expression);
}
wonky_assert(SHOULD_NOT_REACH_HERE);
}
/*
:
statement
*/
struct AST* parse_finish_default_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST *statement;
struct AST_Default_Statement *hold;
if(get_and_check(translation_data,KW_COLUMN))
{
statement=parse_statement(translation_data,scope,parse_data);
hold=get_default_statement_tree(statement,translation_data);
wonky_assert(is_valid_default_statement(hold));
return (struct AST*)hold;
}else
{
push_translation_error(" ':' expected in default statement",translation_data);
return (struct AST*)get_error_tree((struct AST*)NULL);
}
}
/*
[ expression ] ;
*/
struct AST* parse_finish_return_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST_Return_Statement *hold;
if(get_and_check(translation_data,KW_SEMICOLON))
{
hold=get_return_statement_tree(get_nop_tree(),translation_data,scope);
wonky_assert(is_valid_return_statement(hold));
return (struct AST*)hold;
}
hold=get_return_statement_tree(parse_expression(translation_data,scope),translation_data,scope);
if(get_and_check(translation_data,KW_SEMICOLON))
{
return (struct AST*)hold;
}else
{
push_translation_error(" ';' expected",translation_data);
return (struct AST*)get_error_tree((struct AST*)hold);
}
}
/*
[ expression ] ;
*/
struct AST* parse_expression_statement(struct Translation_Data* translation_data,struct Scope *scope,struct Parse_Statement_Data *parse_data)
{
struct AST *hold;
if(get_and_check(translation_data,KW_SEMICOLON))
{
hold=get_nop_tree();
return (struct AST*)hold;
}
hold=parse_expression(translation_data,scope);
if(hold==NULL)
{
push_translation_error(" in statement",translation_data);
return (struct AST*)get_error_tree(hold);
}
if(get_and_check(translation_data,KW_SEMICOLON))
{
wonky_assert(is_valid_ast(hold));
return hold;
}else
{
push_translation_error(" ';' expected",translation_data);
return (struct AST*)get_error_tree(hold);
}
}
void chase_next_semicolumn(struct Translation_Data *translation_data)
{
/*chase ; and start parsing next declaration*/
while(!get_and_check(translation_data,KW_SEMICOLON) && !get_and_check(translation_data,KW_CLOSE_CURLY) &&
!translation_eof(translation_data))
{
chomp(translation_data);
}
}
#endif