Skip to content

Commit

Permalink
implement parser
Browse files Browse the repository at this point in the history
  • Loading branch information
kumachan-mis committed Oct 9, 2023
1 parent 6fd74df commit 48c78ab
Show file tree
Hide file tree
Showing 7 changed files with 508 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ typedef enum AstType {
AST_NULL_STMT,
AST_IF_STMT,
AST_WHILE_STMT,
AST_FOR_STMT,

// expression
// assignment-expression
Expand Down
74 changes: 67 additions & 7 deletions src/parser/statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ ParserReturn* parse_stmt(Parser* parser) {
return parse_if_else_stmt(parser);
case CTOKEN_KEYWORD_WHILE:
return parse_while_stmt(parser);
case CTOKEN_KEYWORD_FOR:
return parse_for_stmt(parser);
default:
return parse_expression_stmt(parser);
}
Expand All @@ -41,13 +43,7 @@ ParserReturn* parse_compound_stmt(Parser* parser) {
break;
}

int may_decl = -1;
errint_assign(&may_decl, &err, blockitem_may_decl(parser));
if (err != NULL) {
break;
}

if (may_decl) {
if (item_may_decl(parser)) {
parserret_assign(&child_ast, &err, parse_decl(parser));
} else {
parserret_assign(&child_ast, &err, parse_stmt(parser));
Expand Down Expand Up @@ -216,3 +212,67 @@ ParserReturn* parse_while_stmt(Parser* parser) {

return new_parserret(ast);
}

ParserReturn* parse_for_stmt(Parser* parser) {
Ast* ast = new_ast(AST_FOR_STMT, 0);
Ast* child_ast = NULL;
Error* err = NULL;

err = consume_ctoken(parser, CTOKEN_KEYWORD_FOR);
if (err != NULL) {
delete_ast(ast);
return new_parserret_error(err);
}

err = consume_ctoken(parser, CTOKEN_LPAREN);
if (err != NULL) {
delete_ast(ast);
return new_parserret_error(err);
}

if (item_may_decl(parser)) {
parserret_assign(&child_ast, &err, parse_decl(parser));
} else {
parserret_assign(&child_ast, &err, parse_expression_stmt(parser));
}
if (err != NULL) {
delete_ast(ast);
return new_parserret_error(err);
}
vector_push(ast->children, child_ast);

parserret_assign(&child_ast, &err, parse_expression_stmt(parser));
if (err != NULL) {
delete_ast(ast);
return new_parserret_error(err);
}
vector_push(ast->children, child_ast);

CToken* ctoken = vector_at(parser->ctokens, parser->index);
if (ctoken->type == CTOKEN_RPAREN) {
parser->index++;
vector_push(ast->children, new_ast(AST_NULL_STMT, 0));
} else {
parserret_assign(&child_ast, &err, parse_expr(parser));
if (err != NULL) {
delete_ast(ast);
return new_parserret_error(err);
}
vector_push(ast->children, new_ast(AST_EXPR_STMT, 1, child_ast));

err = consume_ctoken(parser, CTOKEN_RPAREN);
if (err != NULL) {
delete_ast(ast);
return new_parserret_error(err);
}
}

parserret_assign(&child_ast, &err, parse_stmt(parser));
if (err != NULL) {
delete_ast(ast);
return new_parserret_error(err);
}
vector_push(ast->children, child_ast);

return new_parserret(ast);
}
1 change: 1 addition & 0 deletions src/parser/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ ParserReturn* parse_return_stmt(Parser* parser);
ParserReturn* parse_expression_stmt(Parser* parser);
ParserReturn* parse_if_else_stmt(Parser* parser);
ParserReturn* parse_while_stmt(Parser* parser);
ParserReturn* parse_for_stmt(Parser* parser);

#endif
6 changes: 2 additions & 4 deletions src/parser/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,9 @@ ErrorableInt* external_may_function_definition(Parser* parser) {
return new_errint(ctoken->type == CTOKEN_LBRACE);
}

ErrorableInt* blockitem_may_decl(Parser* parser) {
int item_may_decl(Parser* parser) {
CToken* ctoken = vector_at(parser->ctokens, parser->index);
int may_decl =
ctoken_is_storage_class_specifier(ctoken) || ctoken_is_type_specifier(ctoken, parser->typedef_names_set);
return new_errint(may_decl);
return ctoken_is_storage_class_specifier(ctoken) || ctoken_is_type_specifier(ctoken, parser->typedef_names_set);
}

int ctoken_is_storage_class_specifier(CToken* ctoken) {
Expand Down
2 changes: 1 addition & 1 deletion src/parser/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "./parser.h"

ErrorableInt* external_may_function_definition(Parser* parser);
ErrorableInt* blockitem_may_decl(Parser* parser);
int item_may_decl(Parser* parser);
int ctoken_is_storage_class_specifier(CToken* ctoken);
int ctoken_is_type_specifier(CToken* ctoken, Set* typedef_names_set);
Error* consume_ctoken(Parser* parser, CTokenType ctoken_type);
Expand Down
227 changes: 227 additions & 0 deletions tests/parser/test_statement.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ void test_parse_if_stmt(void);
void test_parse_if_else_stmt(void);
void test_parse_if_else_stmt_chain(void);
void test_parse_while_stmt(void);
void test_parse_for_stmt_init_declaration(void);
void test_parse_for_stmt_init_expression(void);
void test_parse_for_stmt_init_null(void);
void test_parse_for_stmt_condition_null(void);
void test_parse_for_stmt_expression_null(void);
void test_parse_for_stmt_all_null(void);

void run_stmt_parser_test(Vector* input, Ast* expected);

Expand All @@ -44,6 +50,12 @@ CU_Suite* add_test_suite_stmt_parser(void) {
CU_ADD_TEST(suite, test_parse_if_else_stmt);
CU_ADD_TEST(suite, test_parse_if_else_stmt_chain);
CU_ADD_TEST(suite, test_parse_while_stmt);
CU_ADD_TEST(suite, test_parse_for_stmt_init_declaration);
CU_ADD_TEST(suite, test_parse_for_stmt_init_expression);
CU_ADD_TEST(suite, test_parse_for_stmt_init_null);
CU_ADD_TEST(suite, test_parse_for_stmt_condition_null);
CU_ADD_TEST(suite, test_parse_for_stmt_expression_null);
CU_ADD_TEST(suite, test_parse_for_stmt_all_null);
return suite;
}

Expand Down Expand Up @@ -962,6 +974,221 @@ void test_parse_while_stmt(void) {
delete_ast(expected);
}

void test_parse_for_stmt_init_declaration(void) {
Vector* input = new_vector(&t_ctoken);
vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR));
vector_push(input, new_ctoken(CTOKEN_LPAREN));
vector_push(input, new_ctoken(CTOKEN_KEYWORD_INT));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_EQUAL));
vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0)));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_LESS));
vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10)));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_PLUS_PLUS));
vector_push(input, new_ctoken(CTOKEN_RPAREN));
vector_push(input, new_ctoken(CTOKEN_LBRACE));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x")));
vector_push(input, new_ctoken(CTOKEN_ASTERISK_EQUAL));
vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 2)));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_ctoken(CTOKEN_RBRACE));
vector_push(input, new_ctoken(CTOKEN_EOF));

Ast* expected =
new_ast(AST_FOR_STMT, 4, // non-terminal
new_ast(AST_DECL, 2, // non-terminal
new_ast(AST_DECL_SPECS, 1, // non-terminal
new_ast(AST_TYPE_INT, 0)),
new_ast(AST_INIT_DECLOR_LIST, 1, // non-terminal
new_ast(AST_INIT_DECLOR, 2, // non-terminal
new_identifier_ast(AST_IDENT_DECLOR, new_string("i")),
new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0))))),
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_LESS_EXPR, 2, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")),
new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 10)))),
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_POSTINC_EXPR, 1, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")))),
new_ast(AST_CMPD_STMT, 1, // non-terminal
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_MUL_ASSIGN_EXPR, 2, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("x")),
new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2))))));

run_stmt_parser_test(input, expected);

delete_ast(expected);
}

void test_parse_for_stmt_init_expression(void) {
Vector* input = new_vector(&t_ctoken);
vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR));
vector_push(input, new_ctoken(CTOKEN_LPAREN));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_EQUAL));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("n")));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_GREATER));
vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0)));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_MINUS_MINUS));
vector_push(input, new_ctoken(CTOKEN_RPAREN));
vector_push(input, new_ctoken(CTOKEN_LBRACE));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x")));
vector_push(input, new_ctoken(CTOKEN_SLASH_EQUAL));
vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 2)));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_ctoken(CTOKEN_RBRACE));
vector_push(input, new_ctoken(CTOKEN_EOF));

Ast* expected =
new_ast(AST_FOR_STMT, 4, // non-terminal
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_ASSIGN_EXPR, 2, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")),
new_identifier_ast(AST_IDENT_EXPR, new_string("n")))),
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_GREATER_EXPR, 2, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")),
new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0)))),
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_POSTDEC_EXPR, 1, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")))),
new_ast(AST_CMPD_STMT, 1,
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_DIV_ASSIGN_EXPR, 2, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("x")),
new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 2))))));

run_stmt_parser_test(input, expected);

delete_ast(expected);
}

void test_parse_for_stmt_init_null(void) {
Vector* input = new_vector(&t_ctoken);
vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR));
vector_push(input, new_ctoken(CTOKEN_LPAREN));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_LESS));
vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10)));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_PLUS_PLUS));
vector_push(input, new_ctoken(CTOKEN_RPAREN));
vector_push(input, new_ctoken(CTOKEN_LBRACE));
vector_push(input, new_ctoken(CTOKEN_RBRACE));
vector_push(input, new_ctoken(CTOKEN_EOF));

Ast* expected = new_ast(AST_FOR_STMT, 4, // non-terminal
new_ast(AST_NULL_STMT, 0),
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_LESS_EXPR, 2, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")),
new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 10)))),
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_POSTINC_EXPR, 1, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")))),
new_ast(AST_CMPD_STMT, 0));

run_stmt_parser_test(input, expected);

delete_ast(expected);
}

void test_parse_for_stmt_condition_null(void) {
Vector* input = new_vector(&t_ctoken);
vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR));
vector_push(input, new_ctoken(CTOKEN_LPAREN));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_EQUAL));
vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0)));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_PLUS_PLUS));
vector_push(input, new_ctoken(CTOKEN_RPAREN));
vector_push(input, new_ctoken(CTOKEN_LBRACE));
vector_push(input, new_ctoken(CTOKEN_RBRACE));
vector_push(input, new_ctoken(CTOKEN_EOF));

Ast* expected = new_ast(AST_FOR_STMT, 4, // non-terminal
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_ASSIGN_EXPR, 2, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")),
new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0)))),
new_ast(AST_NULL_STMT, 0),
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_POSTINC_EXPR, 1, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")))),
new_ast(AST_CMPD_STMT, 0));

run_stmt_parser_test(input, expected);

delete_ast(expected);
}

void test_parse_for_stmt_expression_null(void) {
Vector* input = new_vector(&t_ctoken);
vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR));
vector_push(input, new_ctoken(CTOKEN_LPAREN));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_EQUAL));
vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0)));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("i")));
vector_push(input, new_ctoken(CTOKEN_LESS));
vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10)));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_ctoken(CTOKEN_RPAREN));
vector_push(input, new_ctoken(CTOKEN_LBRACE));
vector_push(input, new_ctoken(CTOKEN_RBRACE));
vector_push(input, new_ctoken(CTOKEN_EOF));

Ast* expected = new_ast(AST_FOR_STMT, 4, // non-terminal
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_ASSIGN_EXPR, 2, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")),
new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 0)))),
new_ast(AST_EXPR_STMT, 1, // non-terminal
new_ast(AST_LESS_EXPR, 2, // non-terminal
new_identifier_ast(AST_IDENT_EXPR, new_string("i")),
new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 10)))),
new_ast(AST_NULL_STMT, 0), new_ast(AST_CMPD_STMT, 0));

run_stmt_parser_test(input, expected);

delete_ast(expected);
}

void test_parse_for_stmt_all_null(void) {
Vector* input = new_vector(&t_ctoken);
vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR));
vector_push(input, new_ctoken(CTOKEN_LPAREN));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_ctoken(CTOKEN_SEMICOLON));
vector_push(input, new_ctoken(CTOKEN_RPAREN));
vector_push(input, new_ctoken(CTOKEN_LBRACE));
vector_push(input, new_ctoken(CTOKEN_RBRACE));
vector_push(input, new_ctoken(CTOKEN_EOF));

Ast* expected = new_ast(AST_FOR_STMT, 4, // non-terminal
new_ast(AST_NULL_STMT, 0), new_ast(AST_NULL_STMT, 0), new_ast(AST_NULL_STMT, 0),
new_ast(AST_CMPD_STMT, 0));

run_stmt_parser_test(input, expected);

delete_ast(expected);
}

void run_stmt_parser_test(Vector* input, Ast* expected) {
Parser* parser = new_parser(input);
Ast* actual = NULL;
Expand Down
Loading

0 comments on commit 48c78ab

Please sign in to comment.