diff --git a/include/type.hpp b/include/type.hpp index 5e4f3299..5e76df45 100644 --- a/include/type.hpp +++ b/include/type.hpp @@ -176,9 +176,9 @@ class FuncType : public Type { class StructType : public Type { public: - /// @param id The identifier of a struct type. - explicit StructType(std::string id, - std::vector> field_types) + /// @param id The identifier of the struct type. May be empty ("") for unnamed + /// structs. + StructType(std::string id, std::vector> field_types) : id_{std::move(id)}, field_types_{std::move(field_types)} {} bool IsStruct() const noexcept override { @@ -197,9 +197,9 @@ class StructType : public Type { class UnionType : public Type { public: - /// @param id The identifier of a union type. - explicit UnionType(std::string id, - std::vector> field_types) + /// @param id The identifier of the union type. May be empty ("") for unnamed + /// unions. + UnionType(std::string id, std::vector> field_types) : id_{std::move(id)}, field_types_{std::move(field_types)} {} bool IsUnion() const noexcept override { diff --git a/lexer.l b/lexer.l index 89d56d90..61cf7fad 100644 --- a/lexer.l +++ b/lexer.l @@ -48,7 +48,7 @@ integer [0-9]+ ":" { return yy::parser::make_COLON(yylloc); } "," { return yy::parser::make_COMMA(yylloc); } -"." { return yy::parser::make_PERIOD(yylloc); } +"." { return yy::parser::make_DOT(yylloc); } /* operators */ "-" { return yy::parser::make_MINUS(yylloc); } diff --git a/parser.y b/parser.y index a9bc2332..19a47ada 100644 --- a/parser.y +++ b/parser.y @@ -79,7 +79,7 @@ std::unique_ptr ResolveType(std::unique_ptr resolved_type, %token MINUS PLUS STAR DIV MOD ASSIGN %token EXCLAMATION TILDE AMPERSAND QUESTION -%token COMMA PERIOD SEMICOLON COLON +%token COMMA DOT SEMICOLON COLON // (), {}, [] %token LEFT_PAREN RIGHT_PAREN LEFT_CURLY RIGHT_CURLY LEFT_SQUARE RIGHT_SQUARE @@ -388,25 +388,24 @@ arg: expr { /* 6.7 Declarations */ /* Declaration specifiers can be either a 'type' or a 'declaration of type'. */ /* TODO: init declarator list */ -/* TODO: If the init declarator doesn't present, e.g., `int;`, the declaration is still valid. */ decl: declaration_specifiers init_declarator_opt SEMICOLON { auto decl_specifers = $1; auto init_decl = $2; if (std::holds_alternative>(decl_specifers)) { auto type = std::move(std::get>(decl_specifers)); - init_decl->type = ResolveType(std::move(type), std::move(init_decl->type)); + if (init_decl) { + init_decl->type = ResolveType(std::move(type), std::move(init_decl->type)); + } else { // unnamed primitive type + init_decl = std::make_unique(Loc(@1), "", std::move(type)); + } + $$ = std::move(init_decl); } else { auto decl = std::move(std::get>(decl_specifers)); - auto rec_decl = dynamic_cast(decl.get()); + auto* rec_decl = dynamic_cast(decl.get()); assert(rec_decl); - if (auto* rec_var_decl = dynamic_cast(init_decl.get())) { - // A struct or union variable. - rec_var_decl->type = ResolveType(std::move(rec_decl->type), std::move(rec_var_decl->type)); - decl = std::move(init_decl); - } else if (auto* arr_decl = dynamic_cast(init_decl.get())) { - // An array with struct or union elements. - arr_decl->type = ResolveType(std::move(rec_decl->type), std::move(arr_decl->type)); + if (init_decl) { + init_decl->type = ResolveType(std::move(rec_decl->type), std::move(init_decl->type)); decl = std::move(init_decl); } @@ -446,11 +445,10 @@ init_declarator: declarator { $$ = $1; } arr_decl->init_list = std::move(init_expr_list); } else if (auto* var_decl = dynamic_cast(decl.get())) { // Declares a struct or union variable. - auto rec_decl = std::make_unique(Loc(@1), + decl = std::make_unique(Loc(@1), std::move(var_decl->id), std::move(var_decl->type), std::move(init_expr_list)); - decl = std::move(rec_decl); } } $$ = std::move(decl); @@ -483,7 +481,7 @@ struct_or_union_specifier: struct_or_union id_opt LEFT_CURLY struct_declaration_ type = std::make_unique(std::move(type_id), std::move(field_types)); } - $$ = std::make_unique(Loc(@2), decl_id ? std::move(decl_id->id) : "", std::move(type), std::move(field_list)); + $$ = std::make_unique(Loc(@2), std::move(type_id), std::move(type), std::move(field_list)); } | struct_or_union ID { auto type = $1; @@ -491,11 +489,10 @@ struct_or_union_specifier: struct_or_union id_opt LEFT_CURLY struct_declaration_ auto field_list = std::vector>{}; auto field_types = std::vector>{}; - auto type_id = decl_id; if (type->IsStruct()) { - type = std::make_unique(std::move(type_id), std::move(field_types)); + type = std::make_unique(std::move(decl_id), std::move(field_types)); } else { - type = std::make_unique(std::move(type_id), std::move(field_types)); + type = std::make_unique(std::move(decl_id), std::move(field_types)); } $$ = std::make_unique(Loc(@2), std::move(decl_id), std::move(type), std::move(field_list)); @@ -589,7 +586,7 @@ direct_declarator: ID { auto type = std::make_unique(std::move(declarator->type), $3); if (!dynamic_cast(declarator.get())) { // If the declarator is not yet a array declarator, we need to construct one. - $$ = std::make_unique(Loc(@1), declarator->id, std::move(type), /* init list */ std::vector>{}); + $$ = std::make_unique(Loc(@1), declarator->id, std::move(type), std::vector>{}); } else { declarator->type = std::move(type); $$ = std::move(declarator); @@ -709,7 +706,6 @@ direct_abstract_declarator_opt: direct_abstract_declarator { $$ = $1; } ; /* 6.7.8 Initialization */ -/* The current object shall have array type and the expression shall be an integer constant expression. */ initializer: LEFT_CURLY initializer_list comma_opt RIGHT_CURLY { $$ = $2; } | assign_expr { $$ = std::make_unique(Loc(@1), std::vector>{}, $1); } ; @@ -743,10 +739,8 @@ designator_list: designator { } ; -/* The current object shall have array type and the expression shall be an integer constant expression. */ designator: LEFT_SQUARE const_expr RIGHT_SQUARE { $$ = std::make_unique(Loc(@2), $2); } - /* The current object shall have structure or union type and the identifier shall be the name of a member of that type. */ - | PERIOD ID { $$ = std::make_unique(Loc(@2), $2); } + | DOT ID { $$ = std::make_unique(Loc(@2), $2); } ; comma_opt: COMMA diff --git a/src/type_checker.cpp b/src/type_checker.cpp index 96f0dd2c..e321eaa7 100644 --- a/src/type_checker.cpp +++ b/src/type_checker.cpp @@ -356,11 +356,14 @@ void TypeChecker::Visit(InitExprNode& init_expr) { } void TypeChecker::Visit(ArrDesNode& arr_des) { + /* ArrDesNode shall have array type and the expression shall be an integer + * constant expression. */ arr_des.index->Accept(*this); } void TypeChecker::Visit(IdDesNode& id_des) { - /* do nothing */ + /* IdDesNode does nothing and shall have structure or union type and the + * identifier shall be the name of a member of that type. */ } void TypeChecker::Visit(NullExprNode&) { diff --git a/test/typecheck/decl.c b/test/typecheck/decl.c index b0f92348..6fe845ec 100644 --- a/test/typecheck/decl.c +++ b/test/typecheck/decl.c @@ -1,4 +1,5 @@ int main() { int i = 0; int j; + int; } diff --git a/test/typecheck/decl.exp b/test/typecheck/decl.exp index 55717e33..bcb3f0cd 100644 --- a/test/typecheck/decl.exp +++ b/test/typecheck/decl.exp @@ -4,3 +4,4 @@ ProgramNode <1:1> VarDeclNode <2:7> i: int IntConstExprNode <2:11> 0: int VarDeclNode <3:7> j: int + VarDeclNode <4:3> : int diff --git a/test/typecheck/struct.c b/test/typecheck/struct.c index 700dcdd5..730e598a 100644 --- a/test/typecheck/struct.c +++ b/test/typecheck/struct.c @@ -21,7 +21,7 @@ int main() { struct birth bd2 = {3, 3, 1998}; - struct birth bd3[3] = { [0].date = 4, [1].year = 1999}; + struct birth bd3[3] = {[0].date = 4, [1].year = 1999}; return 0; } diff --git a/test/typecheck/struct.exp b/test/typecheck/struct.exp index d20fe9bb..ed1ce232 100644 --- a/test/typecheck/struct.exp +++ b/test/typecheck/struct.exp @@ -28,15 +28,15 @@ ProgramNode <1:1> InitExprNode <22:23> IntConstExprNode <22:29> 1998: int ArrDeclNode <24:16> bd3: struct birth[3] - InitExprNode <24:27> - ArrDesNode <24:28> - IntConstExprNode <24:28> 0: int - IdDesNode <24:31> date - IntConstExprNode <24:38> 4: int - InitExprNode <24:27> - ArrDesNode <24:42> - IntConstExprNode <24:42> 1: int - IdDesNode <24:45> year - IntConstExprNode <24:52> 1999: int + InitExprNode <24:26> + ArrDesNode <24:27> + IntConstExprNode <24:27> 0: int + IdDesNode <24:30> date + IntConstExprNode <24:37> 4: int + InitExprNode <24:26> + ArrDesNode <24:41> + IntConstExprNode <24:41> 1: int + IdDesNode <24:44> year + IntConstExprNode <24:51> 1999: int ReturnStmtNode <26:3> IntConstExprNode <26:10> 0: int diff --git a/test/typecheck/union.c b/test/typecheck/union.c index 8d9d0772..31138bfe 100644 --- a/test/typecheck/union.c +++ b/test/typecheck/union.c @@ -15,12 +15,12 @@ int main() { int e; }; - // It's a legal case, but compiler will show warning of excessing elements. + // It's a legal case, but compilers like GCC may show warning of excessing elements. // The value of the members is 3. union shape s = {3, 4, 5}; // Three members in circle variable share the same memory location, so every member is 1. union shape circle = {.circle = 1}; - union shape puzzles[3] = { [0].circle = 1, [1].triangle = 2, [2].square = 4}; + union shape puzzles[3] = {[0].circle = 1, [1].triangle = 2, [2].square = 4}; return 0; } diff --git a/test/typecheck/union.exp b/test/typecheck/union.exp index 0caa1064..1720cbc6 100644 --- a/test/typecheck/union.exp +++ b/test/typecheck/union.exp @@ -24,20 +24,20 @@ ProgramNode <1:1> IdDesNode <22:26> circle IntConstExprNode <22:35> 1: int ArrDeclNode <23:15> puzzles: union shape[3] - InitExprNode <23:30> - ArrDesNode <23:31> - IntConstExprNode <23:31> 0: int - IdDesNode <23:34> circle - IntConstExprNode <23:43> 1: int - InitExprNode <23:30> - ArrDesNode <23:47> - IntConstExprNode <23:47> 1: int - IdDesNode <23:50> triangle - IntConstExprNode <23:61> 2: int - InitExprNode <23:30> - ArrDesNode <23:65> - IntConstExprNode <23:65> 2: int - IdDesNode <23:68> square - IntConstExprNode <23:77> 4: int + InitExprNode <23:29> + ArrDesNode <23:30> + IntConstExprNode <23:30> 0: int + IdDesNode <23:33> circle + IntConstExprNode <23:42> 1: int + InitExprNode <23:29> + ArrDesNode <23:46> + IntConstExprNode <23:46> 1: int + IdDesNode <23:49> triangle + IntConstExprNode <23:60> 2: int + InitExprNode <23:29> + ArrDesNode <23:64> + IntConstExprNode <23:64> 2: int + IdDesNode <23:67> square + IntConstExprNode <23:76> 4: int ReturnStmtNode <25:3> IntConstExprNode <25:10> 0: int