diff --git a/src/ast/ast.h b/src/ast/ast.h index 53bb7760..c0118ded 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -59,6 +59,7 @@ typedef enum AstType { AST_NULL_STMT, AST_IF_STMT, AST_WHILE_STMT, + AST_FOR_STMT, // expression // assignment-expression diff --git a/src/ctoken/ctoken.c b/src/ctoken/ctoken.c index cb04bd37..d34ff156 100644 --- a/src/ctoken/ctoken.c +++ b/src/ctoken/ctoken.c @@ -9,8 +9,8 @@ BaseType t_ctoken = { char* ctoken_types[] = { // non-punctuators - "char", "else", "enum", "if", "int", "long", "return", "sizeof", "struct", "typedef", "unsigned", "void", "while", - "identifier", "integer-constant", "character-constant", "string-literal", + "char", "else", "enum", "for", "if", "int", "long", "return", "sizeof", "struct", "typedef", "unsigned", "void", + "while", "identifier", "integer-constant", "character-constant", "string-literal", // punctuators "[", "]", "(", ")", "{", "}", ".", "->", "++", "--", "&", "*", "+", "-", "~", "!", "/", "%", "<", ">", "<=", ">=", "==", "!=", "^", "|", "&&", "||", "?", ":", ";", "=", diff --git a/src/ctoken/ctoken.h b/src/ctoken/ctoken.h index 7e4cdcf9..ad8fbc32 100644 --- a/src/ctoken/ctoken.h +++ b/src/ctoken/ctoken.h @@ -10,6 +10,7 @@ typedef enum CTokenType { CTOKEN_KEYWORD_CHAR, CTOKEN_KEYWORD_ELSE, CTOKEN_KEYWORD_ENUM, + CTOKEN_KEYWORD_FOR, CTOKEN_KEYWORD_IF, CTOKEN_KEYWORD_INT, CTOKEN_KEYWORD_LONG, diff --git a/src/immcgen/immcgen.c b/src/immcgen/immcgen.c index 4c551754..b0705ca6 100644 --- a/src/immcgen/immcgen.c +++ b/src/immcgen/immcgen.c @@ -73,6 +73,13 @@ Vector* immcgen_generate_immcode(Immcgen* immcgen) { case SRT_WHILE_STMT: codes = gen_while_stmt_immcode(immcgen); break; + case SRT_FOR_STMT: + immcgen->symbol_table = symboltable_enter_scope(immcgen->symbol_table); + immcgen->tag_table = tagtable_enter_scope(immcgen->tag_table); + codes = gen_for_stmt_immcode(immcgen); + immcgen->tag_table = tagtable_exit_scope(immcgen->tag_table); + immcgen->symbol_table = symboltable_exit_scope(immcgen->symbol_table); + break; case SRT_ASSIGN_EXPR: codes = gen_assignment_expr_immcode(immcgen); break; diff --git a/src/immcgen/statement.c b/src/immcgen/statement.c index 1cd70c30..35747359 100644 --- a/src/immcgen/statement.c +++ b/src/immcgen/statement.c @@ -130,14 +130,39 @@ Vector* gen_while_stmt_immcode(Immcgen* immcgen) { ImmcOpe* begin_label = new_label_immcope_from_id(begin_label_id); vector_push(codes, new_inst_immc(IMMC_INST_JMP, begin_label, NULL, NULL)); - Immc* end_code = vector_at(codes, vector_size(codes) - 1); - if (end_code->type == IMMC_LABEL) { - // reuse label created by child - free(end_label->label_name); - end_label->label_name = new_string(end_code->label->name); - return codes; + vector_push(codes, new_label_immc_from_id(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, end_label_id)); + + return codes; +} + +Vector* gen_for_stmt_immcode(Immcgen* immcgen) { + Vector* codes = new_vector(&t_immc); + + immcgen->label_id++; + int begin_label_id = immcgen->label_id; + immcgen->label_id++; + int end_label_id = immcgen->label_id; + + append_child_immcode(immcgen, codes, 0); + + vector_push(codes, new_label_immc_from_id(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, begin_label_id)); + + Srt* srt = immcgen->srt; + Srt* controling_stmt_srt = vector_at(immcgen->srt->children, 1); + if (controling_stmt_srt->type == SRT_EXPR_STMT) { + ImmcOpe* end_label = new_label_immcope_from_id(end_label_id); + immcgen->srt = controling_stmt_srt; + append_child_jmp_false_immcode(immcgen, codes, 0, end_label); + immcgen->srt = srt; } + append_child_immcode(immcgen, codes, 3); + + append_child_immcode(immcgen, codes, 2); + + ImmcOpe* begin_label = new_label_immcope_from_id(begin_label_id); + vector_push(codes, new_inst_immc(IMMC_INST_JMP, begin_label, NULL, NULL)); + vector_push(codes, new_label_immc_from_id(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, end_label_id)); return codes; diff --git a/src/immcgen/statement.h b/src/immcgen/statement.h index 4c6c1607..fb6e25b7 100644 --- a/src/immcgen/statement.h +++ b/src/immcgen/statement.h @@ -9,5 +9,6 @@ Vector* gen_expression_stmt_immcode(Immcgen* immcgen); Vector* gen_null_stmt_immcode(void); Vector* gen_if_else_stmt_immcode(Immcgen* immcgen); Vector* gen_while_stmt_immcode(Immcgen* immcgen); +Vector* gen_for_stmt_immcode(Immcgen* immcgen); #endif diff --git a/src/lexer/util.c b/src/lexer/util.c index 1a68f00c..1ce05b16 100644 --- a/src/lexer/util.c +++ b/src/lexer/util.c @@ -12,6 +12,7 @@ Map* new_keyword_map(void) { ctoken_map_add(keyword_map, "char", CTOKEN_KEYWORD_CHAR); ctoken_map_add(keyword_map, "else", CTOKEN_KEYWORD_ELSE); ctoken_map_add(keyword_map, "enum", CTOKEN_KEYWORD_ENUM); + ctoken_map_add(keyword_map, "for", CTOKEN_KEYWORD_FOR); ctoken_map_add(keyword_map, "if", CTOKEN_KEYWORD_IF); ctoken_map_add(keyword_map, "int", CTOKEN_KEYWORD_INT); ctoken_map_add(keyword_map, "long", CTOKEN_KEYWORD_LONG); diff --git a/src/parser/statement.c b/src/parser/statement.c index 7943543a..39e14861 100644 --- a/src/parser/statement.c +++ b/src/parser/statement.c @@ -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); } @@ -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)); @@ -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); +} diff --git a/src/parser/statement.h b/src/parser/statement.h index c5f128d9..b8eb795e 100644 --- a/src/parser/statement.h +++ b/src/parser/statement.h @@ -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 diff --git a/src/parser/util.c b/src/parser/util.c index d45e53c8..d62ed564 100644 --- a/src/parser/util.c +++ b/src/parser/util.c @@ -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) { diff --git a/src/parser/util.h b/src/parser/util.h index d1af74eb..2c5184d5 100644 --- a/src/parser/util.h +++ b/src/parser/util.h @@ -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); diff --git a/src/resolver/statement.c b/src/resolver/statement.c index 7266ce56..cb6fc0d5 100644 --- a/src/resolver/statement.c +++ b/src/resolver/statement.c @@ -34,6 +34,13 @@ ResolverReturn* resolve_stmt(Resolver* resolver) { case AST_WHILE_STMT: resolverret_assign(&srt, &errs, resolve_while_stmt(resolver)); break; + case AST_FOR_STMT: + resolver->symbol_table = symboltable_enter_scope(resolver->symbol_table); + resolver->tag_table = tagtable_enter_scope(resolver->tag_table); + resolverret_assign(&srt, &errs, resolve_for_stmt(resolver)); + resolver->symbol_table = symboltable_exit_scope(resolver->symbol_table); + resolver->tag_table = tagtable_exit_scope(resolver->tag_table); + break; default: fprintf(stderr, "\x1b[1;31mfatal error\x1b[0m: " "unreachable statement (in resolve_stmt)\n"); @@ -254,3 +261,86 @@ ResolverReturn* resolve_while_stmt(Resolver* resolver) { return new_resolverret(srt); } + +ResolverReturn* resolve_for_stmt(Resolver* resolver) { + Srt* srt = new_srt(SRT_FOR_STMT, 0); + Srt* child_srt = NULL; + Vector* errs = NULL; + Error* err = NULL; + Ast* ast = resolver->ast; + + resolver->ast = vector_at(ast->children, 0); + int decl_init = resolver->ast->type == AST_DECL; + if (decl_init) { + resolverret_assign(&child_srt, &errs, resolve_decl(resolver)); + } else { + resolverret_assign(&child_srt, &errs, resolve_stmt(resolver)); + } + resolver->ast = ast; + if (errs != NULL) { + delete_srt(srt); + return new_resolverret_errors(errs); + } + + vector_push(srt->children, child_srt); + + if (decl_init) { + int num_children = vector_size(child_srt->children); + for (int i = 0; i < num_children; i++) { + Srt* init_decl_srt = vector_at(child_srt->children, i); + Srt* decl_srt = vector_at(init_decl_srt->children, 0); + if (decl_srt->dtype->type != DTYPE_TYPEDEF) { + continue; + } + + errs = new_vector(&t_error); + err = new_error("typedef in for statement initializer is not allowed"); + vector_push(errs, err); + delete_srt(srt); + return new_resolverret_errors(errs); + } + } + + resolver->ast = vector_at(ast->children, 1); + resolverret_assign(&child_srt, &errs, resolve_stmt(resolver)); + resolver->ast = ast; + if (errs != NULL) { + delete_srt(srt); + return new_resolverret_errors(errs); + } + + vector_push(srt->children, child_srt); + + if (child_srt->type == SRT_EXPR_STMT) { + Srt* controling_expr_srt = vector_at(child_srt->children, 0); + if (!dtype_isscalar(controling_expr_srt->dtype)) { + errs = new_vector(&t_error); + err = new_error("condition of for statement should have scalar type"); + vector_push(errs, err); + delete_srt(srt); + return new_resolverret_errors(errs); + } + } + + resolver->ast = vector_at(ast->children, 2); + resolverret_assign(&child_srt, &errs, resolve_stmt(resolver)); + resolver->ast = ast; + if (errs != NULL) { + delete_srt(srt); + return new_resolverret_errors(errs); + } + + vector_push(srt->children, child_srt); + + resolver->ast = vector_at(ast->children, 3); + resolverret_assign(&child_srt, &errs, resolve_stmt(resolver)); + resolver->ast = ast; + if (errs != NULL) { + delete_srt(srt); + return new_resolverret_errors(errs); + } + + vector_push(srt->children, child_srt); + + return new_resolverret(srt); +} diff --git a/src/resolver/statement.h b/src/resolver/statement.h index db8108d6..bd0e5099 100644 --- a/src/resolver/statement.h +++ b/src/resolver/statement.h @@ -10,5 +10,6 @@ ResolverReturn* resolve_expression_stmt(Resolver* resolver); ResolverReturn* resolve_null_stmt(void); ResolverReturn* resolve_if_else_stmt(Resolver* resolver); ResolverReturn* resolve_while_stmt(Resolver* resolver); +ResolverReturn* resolve_for_stmt(Resolver* resolver); #endif diff --git a/src/srt/srt.h b/src/srt/srt.h index a537a553..d6b43648 100644 --- a/src/srt/srt.h +++ b/src/srt/srt.h @@ -29,6 +29,7 @@ typedef enum SrtType { SRT_NULL_STMT, SRT_IF_STMT, SRT_WHILE_STMT, + SRT_FOR_STMT, // expression // assignment-expression diff --git a/test-fixtures/for/expected.txt b/test-fixtures/for/expected.txt new file mode 100644 index 00000000..4c8eee4d --- /dev/null +++ b/test-fixtures/for/expected.txt @@ -0,0 +1,17 @@ +0 +1 +2 +3 +4 + +2 +4 +8 +16 +32 +64 +128 +256 +512 +1024 +2048 diff --git a/test-fixtures/for/main.c b/test-fixtures/for/main.c new file mode 100644 index 00000000..5e4bd1fa --- /dev/null +++ b/test-fixtures/for/main.c @@ -0,0 +1,22 @@ +void put_int(int x); +void put_str(char* str); +void put_blank_line(void); + +int main(void) { + for (; 0;) { + put_str("ERROR: for loop should not be executed"); + } + + for (int i = 0; i < 5; i++) { + put_int(i); + } + put_blank_line(); + + int i = 0, y = 0, z = 1; + for (i = 0; i < 11; i++) { + z = 2 * z; + put_int(z); + } + + return 0; +} diff --git a/test-fixtures/x-mergesort/main.c b/test-fixtures/x-mergesort/main.c index 3fb049dc..c5b94f39 100644 --- a/test-fixtures/x-mergesort/main.c +++ b/test-fixtures/x-mergesort/main.c @@ -54,10 +54,8 @@ int main(void) { int array[10] = {13, 3, 9, 8, 5, 1, 4, 11, 2, 7}; merge_sort(array, 0, 9); - int i = 0; - while (i < 10) { + for (int i = 0; i < 10; ++i) { put_int(array[i]); - i++; } return 0; diff --git a/tests/immcgen/test_statement.c b/tests/immcgen/test_statement.c index 1268a59a..725f1f31 100644 --- a/tests/immcgen/test_statement.c +++ b/tests/immcgen/test_statement.c @@ -19,6 +19,9 @@ void test_immcgen_if_stmt(void); void test_immcgen_if_else_stmt(void); void test_immcgen_if_else_stmt_chain(void); void test_immcgen_while_stmt(void); +void test_immcgen_for_stmt_init_declaration(void); +void test_immcgen_for_stmt_init_expression(void); +void test_immcgen_for_stmt_all_null(void); void run_stmt_immcgen_test(Srt* input, SymbolTable* local_table, int return_label_id, Vector* expected); @@ -41,6 +44,9 @@ CU_Suite* add_test_suite_stmt_immcgen(void) { CU_ADD_TEST(suite, test_immcgen_if_else_stmt); CU_ADD_TEST(suite, test_immcgen_if_else_stmt_chain); CU_ADD_TEST(suite, test_immcgen_while_stmt); + CU_ADD_TEST(suite, test_immcgen_for_stmt_init_declaration); + CU_ADD_TEST(suite, test_immcgen_for_stmt_init_expression); + CU_ADD_TEST(suite, test_immcgen_for_stmt_all_null); return suite; } @@ -1126,6 +1132,230 @@ void test_immcgen_while_stmt(void) { delete_vector(expected); } +void test_immcgen_for_stmt_init_declaration(void) { + Srt* input = new_srt( + SRT_FOR_STMT, 4, // non-terminal + new_srt(SRT_DECL_LIST, 1, // non-terminal + new_srt(SRT_INIT_DECL, 2, // non-terminal + new_identifier_srt(SRT_DECL, new_integer_dtype(DTYPE_INT), new_string("i")), + new_srt(SRT_INIT, 1, // non-terminal + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 0))))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt(SRT_LESS_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 10)))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_POSTINC_EXPR, new_integer_dtype(DTYPE_INT), 1, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))))), + new_srt( + SRT_CMPD_STMT, 1, // non-terminal + new_srt( + SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x"))), + new_dtyped_srt(SRT_MUL_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 2))))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_immc); + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 0), // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L0"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // dst + new_mem_immcope(8), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JGEQ, // inst + new_label_immcope(new_string(".L1")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 10))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // dst + new_mem_immcope(4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_MUL, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 2))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(4), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // dst + new_mem_immcope(8), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 4), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_ADD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 1))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(8), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L1"))); + + run_stmt_immcgen_test(input, local_table, -1, expected); + + delete_vector(expected); +} + +void test_immcgen_for_stmt_init_expression(void) { + Srt* input = new_srt( + SRT_FOR_STMT, 4, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))), + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("n")))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_GREATER_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0)))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_POSTDEC_EXPR, new_integer_dtype(DTYPE_INT), 1, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))))), + new_srt( + SRT_CMPD_STMT, 1, // non-terminal + new_srt( + SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x"))), + new_dtyped_srt(SRT_DIV_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 2))))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("i"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("n"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + + Vector* expected = new_vector(&t_immc); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // dst + new_mem_immcope(8), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(4), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 0), // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L0"))); + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // dst + new_mem_immcope(4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JLEQ, // inst + new_label_immcope(new_string(".L1")), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 1), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 0))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // dst + new_mem_immcope(12), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_DIV, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 2), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 2))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(12), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 3), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 4), // dst + new_mem_immcope(4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_LOAD, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 5), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_SUB, // inst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 4), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 4), // fst_src + new_signed_int_immcope(IMMC_SUFFIX_LONG, INTEGER_INT, 1))); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_STORE, // inst + new_mem_immcope(4), // dst + new_signed_reg_immcope(IMMC_SUFFIX_LONG, 4), // fst_src + NULL)); // snd_src + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L1"))); + + run_stmt_immcgen_test(input, local_table, -1, expected); + + delete_vector(expected); +} + +void test_immcgen_for_stmt_all_null(void) { + Srt* input = new_srt(SRT_FOR_STMT, 4, // non-terminal + new_srt(SRT_NULL_STMT, 0), new_srt(SRT_NULL_STMT, 0), new_srt(SRT_NULL_STMT, 0), + new_srt(SRT_CMPD_STMT, 0)); + + Vector* expected = new_vector(&t_immc); + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L0"))); + vector_push(expected, + new_inst_immc(IMMC_INST_JMP, // inst + new_label_immcope(new_string(".L0")), // dst + NULL, // fst_src + NULL)); // snd_src + vector_push(expected, new_label_immc(IMMC_LABEL_NORMAL, IMMC_VIS_NONE, new_string(".L1"))); + + run_stmt_immcgen_test(input, NULL, -1, expected); + + delete_vector(expected); +} + void run_stmt_immcgen_test(Srt* input, SymbolTable* local_table, int return_label_id, Vector* expected) { Immcgen* immcgen = new_immcgen(input); if (local_table != NULL) { diff --git a/tests/lexer/test_lexer.c b/tests/lexer/test_lexer.c index 193df4f2..0941457d 100644 --- a/tests/lexer/test_lexer.c +++ b/tests/lexer/test_lexer.c @@ -14,6 +14,7 @@ void test_read_declaration_pointer_with_init(void); void test_read_declaration_aggregate_with_init(void); void test_read_statement_if_else(void); void test_read_statement_while(void); +void test_read_statement_for(void); void test_read_assignment_expr(void); void test_read_conditional_expr(void); void test_read_logical_expr(void); @@ -48,6 +49,7 @@ CU_Suite* add_test_suite_lexer(void) { CU_ADD_TEST(suite, test_read_declaration_aggregate_with_init); CU_ADD_TEST(suite, test_read_statement_if_else); CU_ADD_TEST(suite, test_read_statement_while); + CU_ADD_TEST(suite, test_read_statement_for); CU_ADD_TEST(suite, test_read_assignment_expr); CU_ADD_TEST(suite, test_read_conditional_expr); CU_ADD_TEST(suite, test_read_decimal_integer_constant); @@ -416,6 +418,41 @@ void test_read_statement_while(void) { delete_vector(expected); } +void test_read_statement_for(void) { + char* input = "for (int i = 0; i < 10; i++) { x += 1; y *= 2; }"; + + Vector* expected = new_vector(&t_ctoken); + vector_push(expected, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(expected, new_ctoken(CTOKEN_LPAREN)); + vector_push(expected, new_ctoken(CTOKEN_KEYWORD_INT)); + vector_push(expected, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(expected, new_ctoken(CTOKEN_EQUAL)); + vector_push(expected, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 0))); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(expected, new_ctoken(CTOKEN_LESS)); + vector_push(expected, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10))); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_identifier_ctoken(CTOKEN_IDENT, new_string("i"))); + vector_push(expected, new_ctoken(CTOKEN_PLUS_PLUS)); + vector_push(expected, new_ctoken(CTOKEN_RPAREN)); + vector_push(expected, new_ctoken(CTOKEN_LBRACE)); + vector_push(expected, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + vector_push(expected, new_ctoken(CTOKEN_PLUS_EQUAL)); + vector_push(expected, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 1))); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_identifier_ctoken(CTOKEN_IDENT, new_string("y"))); + vector_push(expected, new_ctoken(CTOKEN_ASTERISK_EQUAL)); + vector_push(expected, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 2))); + vector_push(expected, new_ctoken(CTOKEN_SEMICOLON)); + vector_push(expected, new_ctoken(CTOKEN_RBRACE)); + vector_push(expected, new_ctoken(CTOKEN_EOF)); + + run_lexer_test(input, expected); + + delete_vector(expected); +} + void test_read_assignment_expr(void) { char* input = "x86 = 64; x += 1; x -= 1; x *= 2; x /= 2; x %= 2; x &= 1; x ^= 1; x |= 1;"; diff --git a/tests/parser/test_expression_error.c b/tests/parser/test_expression_error.c index 2a53c4a6..5e9db8ad 100644 --- a/tests/parser/test_expression_error.c +++ b/tests/parser/test_expression_error.c @@ -160,7 +160,7 @@ void test_parse_modulo_assignment_expr_error(void) { vector_push(input, new_ctoken(CTOKEN_PERCENT_EQUAL)); vector_push(input, new_ctoken(CTOKEN_EOF)); - Error* expected = new_error("unexpected token %="); + Error* expected = new_error("unexpected token %%="); run_expr_parser_error_test(input, NULL, expected); diff --git a/tests/parser/test_statement.c b/tests/parser/test_statement.c index 79aead8b..4bb1f180 100644 --- a/tests/parser/test_statement.c +++ b/tests/parser/test_statement.c @@ -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); @@ -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; } @@ -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; diff --git a/tests/parser/test_statement_error.c b/tests/parser/test_statement_error.c index fba86bd6..5efbe0ce 100644 --- a/tests/parser/test_statement_error.c +++ b/tests/parser/test_statement_error.c @@ -16,6 +16,15 @@ void test_parse_while_stmt_error_controlling_lparen(void); void test_parse_while_stmt_error_controlling_expr(void); void test_parse_while_stmt_error_controlling_rparen(void); void test_parse_while_stmt_error_body(void); +void test_parse_for_stmt_error_lparen(void); +void test_parse_for_stmt_error_init_decl(void); +void test_parse_for_stmt_error_init_expr(void); +void test_parse_for_stmt_error_init_expr_semicolon(void); +void test_parse_for_stmt_error_controlling_expr(void); +void test_parse_for_stmt_error_controlling_expr_semicolon(void); +void test_parse_for_stmt_error_expr(void); +void test_parse_for_stmt_error_expr_rparen(void); +void test_parse_for_stmt_error_body(void); void run_stmt_parser_error_test(Vector* input, Error* expected); @@ -34,6 +43,15 @@ CU_Suite* add_test_suite_stmt_parser_error(void) { CU_ADD_TEST(suite, test_parse_while_stmt_error_controlling_expr); CU_ADD_TEST(suite, test_parse_while_stmt_error_controlling_rparen); CU_ADD_TEST(suite, test_parse_while_stmt_error_body); + CU_ADD_TEST(suite, test_parse_for_stmt_error_lparen); + CU_ADD_TEST(suite, test_parse_for_stmt_error_init_decl); + CU_ADD_TEST(suite, test_parse_for_stmt_error_init_expr); + CU_ADD_TEST(suite, test_parse_for_stmt_error_init_expr_semicolon); + CU_ADD_TEST(suite, test_parse_for_stmt_error_controlling_expr); + CU_ADD_TEST(suite, test_parse_for_stmt_error_controlling_expr_semicolon); + CU_ADD_TEST(suite, test_parse_for_stmt_error_expr); + CU_ADD_TEST(suite, test_parse_for_stmt_error_expr_rparen); + CU_ADD_TEST(suite, test_parse_for_stmt_error_body); return suite; } @@ -266,6 +284,199 @@ void test_parse_while_stmt_error_body(void) { delete_error(expected); } +void test_parse_for_stmt_error_lparen(void) { + Vector* input = new_vector(&t_ctoken); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_FOR)); + vector_push(input, new_ctoken(CTOKEN_KEYWORD_INT)); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + 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_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("token ( expected, but got int"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_init_decl(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("x"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + 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)); + + Error* expected = new_error("unexpected token ;"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_init_expr(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("x"))); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + 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)); + + Error* expected = new_error("unexpected token ;"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_init_expr_semicolon(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("x"))); + 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_COLON)); + 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)); + + Error* expected = new_error("token ; expected, but got :"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_controlling_expr(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("x"))); + vector_push(input, new_ctoken(CTOKEN_EXCLAM_EQUAL)); + 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)); + + Error* expected = new_error("unexpected token ;"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_controlling_expr_semicolon(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("x"))); + vector_push(input, new_ctoken(CTOKEN_EXCLAM_EQUAL)); + vector_push(input, new_iliteral_ctoken(CTOKEN_INT, new_signed_iliteral(INTEGER_INT, 10))); + vector_push(input, new_identifier_ctoken(CTOKEN_IDENT, new_string("x"))); + 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)); + + Error* expected = new_error("token ; expected, but got identifier"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_expr(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_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)); + + Error* expected = new_error("unexpected token ;"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_expr_rparen(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_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("token ) expected, but got {"); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + +void test_parse_for_stmt_error_body(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_ctoken(CTOKEN_SEMICOLON)); + vector_push(input, new_ctoken(CTOKEN_RPAREN)); + vector_push(input, new_ctoken(CTOKEN_EQUAL)); + vector_push(input, new_ctoken(CTOKEN_LBRACE)); + vector_push(input, new_ctoken(CTOKEN_RBRACE)); + vector_push(input, new_ctoken(CTOKEN_EOF)); + + Error* expected = new_error("unexpected token ="); + + run_stmt_parser_error_test(input, expected); + + delete_error(expected); +} + void run_stmt_parser_error_test(Vector* input, Error* expected) { Parser* parser = new_parser(input); Ast* ret = NULL; diff --git a/tests/resolver/test_statement.c b/tests/resolver/test_statement.c index 565bdfad..bbdb4ec6 100644 --- a/tests/resolver/test_statement.c +++ b/tests/resolver/test_statement.c @@ -25,6 +25,12 @@ void test_resolve_if_stmt(void); void test_resolve_if_else_stmt(void); void test_resolve_if_else_stmt_chain(void); void test_resolve_while_stmt(void); +void test_resolve_for_stmt_init_declaration(void); +void test_resolve_for_stmt_init_expression(void); +void test_resolve_for_stmt_init_null(void); +void test_resolve_for_stmt_condition_null(void); +void test_resolve_for_stmt_expression_null(void); +void test_resolve_for_stmt_all_null(void); void run_stmt_resolver_test(Ast* input, SymbolTable* local_table, DType* return_dtype, Srt* expected); @@ -53,6 +59,12 @@ CU_Suite* add_test_suite_stmt_resolver(void) { CU_ADD_TEST(suite, test_resolve_if_else_stmt); CU_ADD_TEST(suite, test_resolve_if_else_stmt_chain); CU_ADD_TEST(suite, test_resolve_while_stmt); + CU_ADD_TEST(suite, test_resolve_for_stmt_init_declaration); + CU_ADD_TEST(suite, test_resolve_for_stmt_init_expression); + CU_ADD_TEST(suite, test_resolve_for_stmt_init_null); + CU_ADD_TEST(suite, test_resolve_for_stmt_condition_null); + CU_ADD_TEST(suite, test_resolve_for_stmt_expression_null); + CU_ADD_TEST(suite, test_resolve_for_stmt_all_null); return suite; } @@ -1149,6 +1161,249 @@ void test_resolve_while_stmt(void) { delete_srt(expected); } +void test_resolve_for_stmt_init_declaration(void) { + Ast* input = + 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)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + + Srt* expected = new_srt( + SRT_FOR_STMT, 4, // non-terminal + new_srt(SRT_DECL_LIST, 1, // non-terminal + new_srt(SRT_INIT_DECL, 2, // non-terminal + new_identifier_srt(SRT_DECL, new_integer_dtype(DTYPE_INT), new_string("i")), + new_srt(SRT_INIT, 1, // non-terminal + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 0))))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt(SRT_LESS_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 10)))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_POSTINC_EXPR, new_integer_dtype(DTYPE_INT), 1, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))))), + new_srt( + SRT_CMPD_STMT, 1, // non-terminal + new_srt( + SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x"))), + new_dtyped_srt(SRT_MUL_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 2))))))); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + +void test_resolve_for_stmt_init_expression(void) { + Ast* input = + 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)))))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("i"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("n"), new_integer_dtype(DTYPE_INT)); + symboltable_define_memory(local_table, new_string("x"), new_integer_dtype(DTYPE_INT)); + + Srt* expected = new_srt( + SRT_FOR_STMT, 4, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))), + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("n")))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_GREATER_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0)))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_POSTDEC_EXPR, new_integer_dtype(DTYPE_INT), 1, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))))), + new_srt( + SRT_CMPD_STMT, 1, // non-terminal + new_srt( + SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x"))), + new_dtyped_srt(SRT_DIV_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("x")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 2))))))); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + +void test_resolve_for_stmt_init_null(void) { + Ast* input = 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)); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("i"), new_integer_dtype(DTYPE_INT)); + + Srt* expected = new_srt( + SRT_FOR_STMT, 4, // non-terminal + new_srt(SRT_NULL_STMT, 0), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt(SRT_LESS_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 10)))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_POSTINC_EXPR, new_integer_dtype(DTYPE_INT), 1, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))))), + new_srt(SRT_CMPD_STMT, 0)); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + +void test_resolve_for_stmt_condition_null(void) { + Ast* input = 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)); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("i"), new_integer_dtype(DTYPE_INT)); + + Srt* expected = new_srt( + SRT_FOR_STMT, 4, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0)))), + new_srt(SRT_NULL_STMT, 0), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_POSTINC_EXPR, new_integer_dtype(DTYPE_INT), 1, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))))), + new_srt(SRT_CMPD_STMT, 0)); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + +void test_resolve_for_stmt_expression_null(void) { + Ast* input = 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)); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("i"), new_integer_dtype(DTYPE_INT)); + + Srt* expected = new_srt( + SRT_FOR_STMT, 4, // non-terminal + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt( + SRT_ASSIGN_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_dtyped_srt(SRT_ADDR_EXPR, new_pointer_dtype(new_integer_dtype(DTYPE_INT)), 1, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i"))), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), new_signed_iliteral(INTEGER_INT, 0)))), + new_srt(SRT_EXPR_STMT, 1, // non-terminal + new_dtyped_srt(SRT_LESS_EXPR, new_integer_dtype(DTYPE_INT), 2, // non-terminal + new_identifier_srt(SRT_IDENT_EXPR, new_integer_dtype(DTYPE_INT), new_string("i")), + new_iliteral_srt(SRT_INT_EXPR, new_integer_dtype(DTYPE_INT), + new_signed_iliteral(INTEGER_INT, 10)))), + new_srt(SRT_NULL_STMT, 0), new_srt(SRT_CMPD_STMT, 0)); + + run_stmt_resolver_test(input, local_table, NULL, expected); + + delete_srt(expected); +} + +void test_resolve_for_stmt_all_null(void) { + Ast* input = 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)); + + Srt* expected = new_srt(SRT_FOR_STMT, 4, // non-terminal + new_srt(SRT_NULL_STMT, 0), new_srt(SRT_NULL_STMT, 0), new_srt(SRT_NULL_STMT, 0), + new_srt(SRT_CMPD_STMT, 0)); + + run_stmt_resolver_test(input, NULL, NULL, expected); + + delete_srt(expected); +} + void run_stmt_resolver_test(Ast* input, SymbolTable* local_table, DType* return_dtype, Srt* expected) { Resolver* resolver = new_resolver(input); resolver->trans_unit_srt = new_srt(SRT_TRAS_UNIT, 0); diff --git a/tests/resolver/test_statement_error.c b/tests/resolver/test_statement_error.c index 322b7549..e357a8f4 100644 --- a/tests/resolver/test_statement_error.c +++ b/tests/resolver/test_statement_error.c @@ -15,6 +15,14 @@ void test_resolve_if_else_stmt_error_else_child(void); void test_resolve_while_stmt_error_condition_child(void); void test_resolve_while_stmt_error_condition_non_scalar(void); void test_resolve_while_stmt_error_body_child(void); +void test_resolve_for_stmt_error_init_decl_child(void); +void test_resolve_for_stmt_error_init_expr_child(void); +void test_resolve_for_stmt_error_init_decl_typedef(void); +void test_resolve_for_stmt_error_init_decl_out_of_scope(void); +void test_resolve_for_stmt_error_condition_child(void); +void test_resolve_for_stmt_error_condition_non_scalar(void); +void test_resolve_for_stmt_error_expression_child(void); +void test_resolve_for_stmt_error_body_child(void); void run_stmt_resolver_error_test(Ast* input, SymbolTable* local_table, DType* return_dtype, Vector* expected); @@ -33,6 +41,14 @@ CU_Suite* add_test_suite_stmt_resolver_error(void) { CU_ADD_TEST(suite, test_resolve_while_stmt_error_condition_child); CU_ADD_TEST(suite, test_resolve_while_stmt_error_condition_non_scalar); CU_ADD_TEST(suite, test_resolve_while_stmt_error_body_child); + CU_ADD_TEST(suite, test_resolve_for_stmt_error_init_decl_child); + CU_ADD_TEST(suite, test_resolve_for_stmt_error_init_expr_child); + CU_ADD_TEST(suite, test_resolve_for_stmt_error_init_decl_typedef); + CU_ADD_TEST(suite, test_resolve_for_stmt_error_init_decl_out_of_scope); + CU_ADD_TEST(suite, test_resolve_for_stmt_error_condition_child); + CU_ADD_TEST(suite, test_resolve_for_stmt_error_condition_non_scalar); + CU_ADD_TEST(suite, test_resolve_for_stmt_error_expression_child); + CU_ADD_TEST(suite, test_resolve_for_stmt_error_body_child); return suite; } @@ -324,6 +340,182 @@ void test_resolve_while_stmt_error_body_child(void) { delete_vector(expected); } +void test_resolve_for_stmt_error_init_decl_child(void) { + Ast* input = new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_DECL, 2, // non-terminal + new_ast(AST_DECL_SPECS, 2, // non-terminal + new_ast(AST_TYPE_LONG, 0), new_ast(AST_TYPE_CHAR, 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_NULL_STMT, 0), new_ast(AST_NULL_STMT, 0), new_ast(AST_CMPD_STMT, 0)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("combination of type specifiers is invalid")); + + run_stmt_resolver_error_test(input, NULL, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_for_stmt_error_init_expr_child(void) { + Ast* input = 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_NULL_STMT, 0), new_ast(AST_CMPD_STMT, 0)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("identifier 'i' is used before declared")); + + run_stmt_resolver_error_test(input, NULL, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_for_stmt_error_init_decl_typedef(void) { + Ast* input = new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_DECL, 2, // non-terminal + new_ast(AST_DECL_SPECS, 2, // non-terminal + new_ast(AST_STG_TYPEDEF, 0), new_ast(AST_TYPE_LONG, 0)), + new_ast(AST_INIT_DECLOR_LIST, 2, // non-terminal + new_ast(AST_INIT_DECLOR, 1, // non-terminal + new_identifier_ast(AST_IDENT_DECLOR, new_string("i"))), + new_ast(AST_INIT_DECLOR, 1, // non-terminal + new_identifier_ast(AST_IDENT_DECLOR, new_string("j"))))), + new_ast(AST_NULL_STMT, 0), new_ast(AST_NULL_STMT, 0), new_ast(AST_CMPD_STMT, 0)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("typedef in for statement initializer is not allowed")); + + run_stmt_resolver_error_test(input, NULL, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_for_stmt_error_init_decl_out_of_scope(void) { + Ast* input = + new_ast(AST_CMPD_STMT, 2, // non-terminal + 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, 0)), + 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))))); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("identifier 'i' is used before declared")); + + run_stmt_resolver_error_test(input, NULL, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_for_stmt_error_condition_child(void) { + Ast* input = 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("v")), + new_iliteral_ast(AST_INT_EXPR, new_signed_iliteral(INTEGER_INT, 10)))), + new_ast(AST_NULL_STMT, 0), new_ast(AST_CMPD_STMT, 0)); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("v"), new_pointer_dtype(new_integer_dtype(DTYPE_INT))); + + Vector* expected = new_vector(&t_error); + vector_push(expected, + new_error("binary < expression should be either arithmetic < arithmetic or pointer < pointer")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_for_stmt_error_condition_non_scalar(void) { + Ast* input = new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_NULL_STMT, 0), + new_ast(AST_EXPR_STMT, 1, // non-terminal + new_identifier_ast(AST_IDENT_EXPR, new_string("x"))), + new_ast(AST_NULL_STMT, 0), new_ast(AST_CMPD_STMT, 0)); + + Vector* members = new_vector(&t_dstructmember); + vector_push(members, new_dstructmember(new_string("member"), new_integer_dtype(DTYPE_INT))); + + SymbolTable* local_table = new_symboltable(); + symboltable_define_memory(local_table, new_string("x"), new_unnamed_struct_dtype(members)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("condition of for statement should have scalar type")); + + run_stmt_resolver_error_test(input, local_table, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_for_stmt_error_expression_child(void) { + Ast* input = new_ast(AST_FOR_STMT, 4, // non-terminal + new_ast(AST_NULL_STMT, 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)); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("identifier 'i' is used before declared")); + + run_stmt_resolver_error_test(input, NULL, NULL, expected); + + delete_vector(expected); +} + +void test_resolve_for_stmt_error_body_child(void) { + Ast* input = + 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)))))); + + Vector* expected = new_vector(&t_error); + vector_push(expected, new_error("identifier 'x' is used before declared")); + + run_stmt_resolver_error_test(input, NULL, NULL, expected); + + delete_vector(expected); +} + void run_stmt_resolver_error_test(Ast* input, SymbolTable* local_table, DType* return_dtype, Vector* expected) { Resolver* resolver = new_resolver(input); resolver->trans_unit_srt = new_srt(SRT_TRAS_UNIT, 0);