From af352f385605ceb8446c92850b827feda7b66f0b Mon Sep 17 00:00:00 2001 From: Lai-YT <381xvmvbib@gmail.com> Date: Sat, 8 Jun 2024 17:14:23 +0800 Subject: [PATCH 1/4] Support multiple declarations in a single statement A new statement node called `DeclStmtNode` has been introduced to hold multiple declarations. The AST nodes backed by non-terminals that take `decl` now accept a `DeclStmtNode` instead of a `DeclNode`. These nodes include `LoopInitNode` and `CompoundStmtNode`; other nodes remain unaffected. Since `DeclStmtNode` is simply a sequence of `DeclNode`s, the `Visit` functions will visit each `DeclNode` it holds. --- include/ast.hpp | 19 ++++- include/ast_dumper.hpp | 1 + include/qbe_ir_generator.hpp | 1 + include/type_checker.hpp | 1 + include/visitor.hpp | 2 + parser.y | 68 +++++++++------- src/ast.cpp | 8 ++ src/ast_dumper.cpp | 11 ++- src/qbe_ir_generator.cpp | 8 +- src/type_checker.cpp | 8 +- test/typecheck/array.c | 3 +- test/typecheck/array.exp | 34 ++++---- test/typecheck/array_param.exp | 15 ++-- test/typecheck/assignment_expr.exp | 3 +- test/typecheck/compound_stmt.exp | 10 ++- test/typecheck/cond_expr.exp | 20 ++--- test/typecheck/continue_stmt.exp | 5 +- test/typecheck/decl.c | 1 + test/typecheck/decl.exp | 17 +++- test/typecheck/do_while_single_stmt.exp | 5 +- test/typecheck/do_while_stmt.exp | 5 +- test/typecheck/for_nested_stmt.exp | 15 ++-- test/typecheck/for_stmt.c | 5 +- test/typecheck/for_stmt.exp | 52 ++++++++---- test/typecheck/func_call_param.exp | 28 ++++--- test/typecheck/func_pointer.exp | 35 ++++---- test/typecheck/func_pointer_param.exp | 5 +- test/typecheck/goto_stmt.exp | 8 +- test/typecheck/id_expr.exp | 8 +- test/typecheck/identifier.exp | 27 ++++--- test/typecheck/if_else_nested_single_stmt.exp | 5 +- test/typecheck/if_else_nested_stmt.exp | 5 +- test/typecheck/if_else_single_stmt.exp | 5 +- test/typecheck/if_else_stmt.exp | 5 +- test/typecheck/if_single_stmt.exp | 5 +- test/typecheck/if_stmt.exp | 5 +- test/typecheck/pointer.c | 2 + test/typecheck/pointer.exp | 27 ++++--- test/typecheck/pointer_param.exp | 17 ++-- test/typecheck/pointer_to_pointer.exp | 31 +++++--- test/typecheck/pointer_to_pointer_param.exp | 24 +++--- test/typecheck/postfix_arith_expr.exp | 12 +-- test/typecheck/struct.c | 2 + test/typecheck/struct.exp | 79 ++++++++++--------- test/typecheck/switch_stmt.exp | 5 +- test/typecheck/unary_expr.exp | 5 +- test/typecheck/union.c | 2 + test/typecheck/union.exp | 79 +++++++++---------- test/typecheck/while_single_stmt.exp | 5 +- test/typecheck/while_stmt.exp | 5 +- 50 files changed, 460 insertions(+), 293 deletions(-) diff --git a/include/ast.hpp b/include/ast.hpp index 299d6245..13b68599 100644 --- a/include/ast.hpp +++ b/include/ast.hpp @@ -105,6 +105,17 @@ struct DesNode // NOLINT(cppcoreguidelines-special-member-functions) std::make_unique(PrimitiveType::kUnknown); }; +/// @brief A declaration statement may declare multiple identifiers. +struct DeclStmtNode : public StmtNode { + DeclStmtNode(Location loc, std::vector> decls) + : StmtNode{loc}, decls{std::move(decls)} {} + + void Accept(NonModifyingVisitor&) const override; + void Accept(ModifyingVisitor&) override; + + std::vector> decls; +}; + struct VarDeclNode : public DeclNode { VarDeclNode(Location loc, std::string id, std::unique_ptr type, std::unique_ptr init = {}) @@ -189,18 +200,18 @@ struct FuncDefNode : public DeclNode { struct LoopInitNode : public AstNode { LoopInitNode( Location loc, - std::variant, std::unique_ptr> clause) + std::variant, std::unique_ptr> + clause) : AstNode{loc}, clause{std::move(clause)} {} void Accept(NonModifyingVisitor&) const override; void Accept(ModifyingVisitor&) override; - std::variant, std::unique_ptr> clause; + std::variant, std::unique_ptr> clause; }; struct CompoundStmtNode : public StmtNode { - using Item = - std::variant, std::unique_ptr>; + using Item = std::unique_ptr; CompoundStmtNode(Location loc, std::vector items) : StmtNode{loc}, items{std::move(items)} {} diff --git a/include/ast_dumper.hpp b/include/ast_dumper.hpp index 5dca1b3f..8173cc29 100644 --- a/include/ast_dumper.hpp +++ b/include/ast_dumper.hpp @@ -7,6 +7,7 @@ class AstDumper : public NonModifyingVisitor { public: + void Visit(const DeclStmtNode&) override; void Visit(const LoopInitNode&) override; void Visit(const VarDeclNode&) override; void Visit(const ArrDeclNode&) override; diff --git a/include/qbe_ir_generator.hpp b/include/qbe_ir_generator.hpp index 68b1a1d9..67c65430 100644 --- a/include/qbe_ir_generator.hpp +++ b/include/qbe_ir_generator.hpp @@ -14,6 +14,7 @@ class QbeIrGenerator : public NonModifyingVisitor { public: + void Visit(const DeclStmtNode&) override; void Visit(const LoopInitNode&) override; void Visit(const VarDeclNode&) override; void Visit(const ArrDeclNode&) override; diff --git a/include/type_checker.hpp b/include/type_checker.hpp index 39032a9b..b26a1338 100644 --- a/include/type_checker.hpp +++ b/include/type_checker.hpp @@ -10,6 +10,7 @@ class TypeChecker : public ModifyingVisitor { public: TypeChecker(ScopeStack& env) : env_{env} {} + void Visit(DeclStmtNode&) override; void Visit(LoopInitNode&) override; void Visit(VarDeclNode&) override; void Visit(ArrDeclNode&) override; diff --git a/include/visitor.hpp b/include/visitor.hpp index c20e66f8..97a2de31 100644 --- a/include/visitor.hpp +++ b/include/visitor.hpp @@ -11,6 +11,7 @@ struct StmtNode; struct ExprNode; struct DeclNode; struct DesNode; +struct DeclStmtNode; struct VarDeclNode; struct ArrDeclNode; struct RecordDeclNode; @@ -69,6 +70,7 @@ class Visitor { virtual void Visit(CondMut&){}; virtual void Visit(CondMut&){}; virtual void Visit(CondMut&){}; + virtual void Visit(CondMut&){}; virtual void Visit(CondMut&){}; virtual void Visit(CondMut&){}; virtual void Visit(CondMut&){}; diff --git a/parser.y b/parser.y index 19a47ada..18ad80af 100644 --- a/parser.y +++ b/parser.y @@ -102,13 +102,15 @@ std::unique_ptr ResolveType(std::unique_ptr resolved_type, %nterm > expr assign_expr expr_opt unary_expr postfix_expr primary_expr %nterm > const_expr cond_expr logic_or_expr logic_and_expr inclusive_or_expr exclusive_or_expr %nterm > and_expr eq_expr relational_expr shift_expr add_expr mul_expr cast_expr -%nterm > decl id_opt +%nterm > id_opt +%nterm > decl %nterm > parameter_declaration %nterm >> parameter_type_list_opt parameter_type_list parameter_list %nterm > struct_declaration struct_declarator struct_declarator_list %nterm >> struct_declaration_list // The followings also declare an identifier, however, their types are not yet fully resolved. -%nterm > declarator direct_declarator init_declarator_opt init_declarator +%nterm > declarator direct_declarator init_declarator +%nterm >> init_declarator_list_opt init_declarator_list // The abstract declarator is a declarator without an identifier, which are actually types. %nterm > abstract_declarator_opt abstract_declarator direct_abstract_declarator_opt direct_abstract_declarator %nterm > struct_or_union specifier_qualifier_list @@ -127,10 +129,9 @@ std::unique_ptr ResolveType(std::unique_ptr resolved_type, %nterm > func_def %nterm >> func_def_list_opt %nterm > loop_init -%nterm > stmt jump_stmt selection_stmt labeled_stmt +%nterm > stmt jump_stmt selection_stmt labeled_stmt block_item %nterm > compound_stmt %nterm > block_item_list block_item_list_opt -%nterm block_item // Resolve the ambiguity in the "dangling-else" grammar. // Example: IF LEFT_PAREN expr RIGHT_PAREN IF LEFT_PAREN expr RIGHT_PAREN stmt • ELSE stmt @@ -387,30 +388,47 @@ arg: expr { /* 6.7 Declarations */ /* Declaration specifiers can be either a 'type' or a 'declaration of type'. */ -/* TODO: init declarator list */ -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)); - 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)); +decl: declaration_specifiers init_declarator_list_opt SEMICOLON { + auto decl_specifiers = $1; + auto init_decl_list = $2; + // A single declaration may declare multiple identifiers. + auto decl_list = std::vector>{}; + if (std::holds_alternative>(decl_specifiers)) { + auto type = std::move(std::get>(decl_specifiers)); + for (auto& init_decl : init_decl_list) { + if (init_decl) { + init_decl->type = ResolveType(type->Clone(), std::move(init_decl->type)); + } else { // unnamed primitive type + init_decl = std::make_unique(Loc(@1), "", type->Clone()); + } + decl_list.push_back(std::move(init_decl)); } - - $$ = std::move(init_decl); } else { - auto decl = std::move(std::get>(decl_specifers)); + auto decl = std::move(std::get>(decl_specifiers)); auto* rec_decl = dynamic_cast(decl.get()); - assert(rec_decl); - if (init_decl) { - init_decl->type = ResolveType(std::move(rec_decl->type), std::move(init_decl->type)); - decl = std::move(init_decl); + for (auto& init_decl : init_decl_list) { + if (init_decl) { + init_decl->type = ResolveType(rec_decl->type->Clone(), std::move(init_decl->type)); + } + decl_list.push_back(std::move(init_decl)); } - - $$ = std::move(decl); } + $$ = std::make_unique(Loc(@1), std::move(decl_list)); + } + ; + +init_declarator_list_opt: init_declarator_list { $$ = $1; } + | epsilon { $$ = std::vector>{}; } + ; + +init_declarator_list: init_declarator { + $$ = std::vector>{}; + $$.push_back($1); + } + | init_declarator_list COMMA init_declarator { + auto init_decl_list = $1; + init_decl_list.push_back($3); + $$ = std::move(init_decl_list); } ; @@ -423,10 +441,6 @@ declaration_specifiers: type_specifier declaration_specifiers { | type_specifier { $$ = $1; } ; -init_declarator_opt: init_declarator { $$ = $1; } - | epsilon { $$ = nullptr; } - ; - /* A init declarator is a declarator with an optional initializer. */ init_declarator: declarator { $$ = $1; } | declarator ASSIGN initializer { diff --git a/src/ast.cpp b/src/ast.cpp index 46a0b88a..ec114981 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -52,6 +52,14 @@ void DesNode::Accept(ModifyingVisitor& v) { DesNode::~DesNode() = default; +void DeclStmtNode::Accept(NonModifyingVisitor& v) const { + v.Visit(*this); +} + +void DeclStmtNode::Accept(ModifyingVisitor& v) { + v.Visit(*this); +} + void VarDeclNode::Accept(NonModifyingVisitor& v) const { v.Visit(*this); } diff --git a/src/ast_dumper.cpp b/src/ast_dumper.cpp index f5afb592..055a42bf 100644 --- a/src/ast_dumper.cpp +++ b/src/ast_dumper.cpp @@ -90,6 +90,15 @@ std::string GetPostfixOperator(PostfixOperator op) { } // namespace +void AstDumper::Visit(const DeclStmtNode& decl_stmt) { + std::cout << indenter_.Indent() << "DeclStmtNode <" << decl_stmt.loc << ">\n"; + indenter_.IncreaseLevel(); + for (const auto& decl : decl_stmt.decls) { + decl->Accept(*this); + } + indenter_.DecreaseLevel(); +} + void AstDumper::Visit(const VarDeclNode& decl) { std::cout << indenter_.Indent() << "VarDeclNode <" << decl.loc << "> " << decl.id << ": " << decl.type->ToString() << '\n'; @@ -170,7 +179,7 @@ void AstDumper::Visit(const CompoundStmtNode& compound_stmt) { << ">\n"; indenter_.IncreaseLevel(); for (const auto& item : compound_stmt.items) { - std::visit([this](auto&& item) { item->Accept(*this); }, item); + item->Accept(*this); } indenter_.DecreaseLevel(); } diff --git a/src/qbe_ir_generator.cpp b/src/qbe_ir_generator.cpp index a3bad939..f92119ba 100644 --- a/src/qbe_ir_generator.cpp +++ b/src/qbe_ir_generator.cpp @@ -135,6 +135,12 @@ auto } // namespace +void QbeIrGenerator::Visit(const DeclStmtNode& decl_stmt) { + for (const auto& decl : decl_stmt.decls) { + decl->Accept(*this); + } +} + void QbeIrGenerator::Visit(const VarDeclNode& decl) { int id_num = NextLocalNum(); WriteInstr_("{} =l alloc{} {}", FuncScopeTemp{id_num}, decl.type->size(), @@ -268,7 +274,7 @@ void QbeIrGenerator::Visit(const CompoundStmtNode& compound_stmt) { // Thus, by moving label creation to an upper level, each block can have its // correct starting label. for (const auto& item : compound_stmt.items) { - std::visit([this](auto&& item) { item->Accept(*this); }, item); + item->Accept(*this); } } diff --git a/src/type_checker.cpp b/src/type_checker.cpp index e321eaa7..b00970fb 100644 --- a/src/type_checker.cpp +++ b/src/type_checker.cpp @@ -40,6 +40,12 @@ bool IsInBodyOf(BodyType type) { } // namespace +void TypeChecker::Visit(DeclStmtNode& decl_stmt) { + for (auto& decl : decl_stmt.decls) { + decl->Accept(*this); + } +} + void TypeChecker::Visit(VarDeclNode& decl) { if (decl.init) { decl.init->Accept(*this); @@ -195,7 +201,7 @@ void TypeChecker::Visit(LoopInitNode& loop_init) { void TypeChecker::Visit(CompoundStmtNode& compound_stmt) { env_.PushScope(ScopeKind::kBlock); for (auto& item : compound_stmt.items) { - std::visit([this](auto&& item) { item->Accept(*this); }, item); + item->Accept(*this); } env_.PopScope(); } diff --git a/test/typecheck/array.c b/test/typecheck/array.c index f7e50d39..f6144696 100644 --- a/test/typecheck/array.c +++ b/test/typecheck/array.c @@ -5,8 +5,7 @@ int main() { a[1] = 2; a[2] = a[1] + 1; - int b = 0; - int c[4] = {1, b = 2, 3, 4}; + int b = 0, c[4] = {1, b = 2, 3, 4}; return 0; } diff --git a/test/typecheck/array.exp b/test/typecheck/array.exp index f74e01ff..4cbefc83 100644 --- a/test/typecheck/array.exp +++ b/test/typecheck/array.exp @@ -1,7 +1,8 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - ArrDeclNode <2:7> a: int[3] + DeclStmtNode <2:3> + ArrDeclNode <2:7> a: int[3] ExprStmtNode <4:3> SimpleAssignmentExprNode <4:8> int ArrSubExprNode <4:3> int @@ -24,18 +25,19 @@ ProgramNode <1:1> IdExprNode <6:10> a: int[3] IntConstExprNode <6:12> 1: int IntConstExprNode <6:17> 1: int - VarDeclNode <8:7> b: int - IntConstExprNode <8:11> 0: int - ArrDeclNode <9:7> c: int[4] - InitExprNode <9:15> - IntConstExprNode <9:15> 1: int - InitExprNode <9:15> - SimpleAssignmentExprNode <9:20> int - IdExprNode <9:18> b: int - IntConstExprNode <9:22> 2: int - InitExprNode <9:15> - IntConstExprNode <9:25> 3: int - InitExprNode <9:15> - IntConstExprNode <9:28> 4: int - ReturnStmtNode <11:3> - IntConstExprNode <11:10> 0: int + DeclStmtNode <8:3> + VarDeclNode <8:7> b: int + IntConstExprNode <8:11> 0: int + ArrDeclNode <8:14> c: int[4] + InitExprNode <8:22> + IntConstExprNode <8:22> 1: int + InitExprNode <8:22> + SimpleAssignmentExprNode <8:27> int + IdExprNode <8:25> b: int + IntConstExprNode <8:29> 2: int + InitExprNode <8:22> + IntConstExprNode <8:32> 3: int + InitExprNode <8:22> + IntConstExprNode <8:35> 4: int + ReturnStmtNode <10:3> + IntConstExprNode <10:10> 0: int diff --git a/test/typecheck/array_param.exp b/test/typecheck/array_param.exp index 2b5cfb39..08d90704 100644 --- a/test/typecheck/array_param.exp +++ b/test/typecheck/array_param.exp @@ -6,13 +6,14 @@ ProgramNode <1:1> IntConstExprNode <4:10> 0: int FuncDefNode <7:5> main: int () CompoundStmtNode <7:12> - ArrDeclNode <8:7> a: int[3] - InitExprNode <8:15> - IntConstExprNode <8:15> 1: int - InitExprNode <8:15> - IntConstExprNode <8:18> 2: int - InitExprNode <8:15> - IntConstExprNode <8:21> 3: int + DeclStmtNode <8:3> + ArrDeclNode <8:7> a: int[3] + InitExprNode <8:15> + IntConstExprNode <8:15> 1: int + InitExprNode <8:15> + IntConstExprNode <8:18> 2: int + InitExprNode <8:15> + IntConstExprNode <8:21> 3: int ExprStmtNode <9:3> FuncCallExprNode <9:3> int IdExprNode <9:3> func: int (int*) diff --git a/test/typecheck/assignment_expr.exp b/test/typecheck/assignment_expr.exp index 404f0917..7d827bfa 100644 --- a/test/typecheck/assignment_expr.exp +++ b/test/typecheck/assignment_expr.exp @@ -1,7 +1,8 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> a: int + DeclStmtNode <2:3> + VarDeclNode <2:7> a: int ExprStmtNode <3:3> SimpleAssignmentExprNode <3:5> int IdExprNode <3:3> a: int diff --git a/test/typecheck/compound_stmt.exp b/test/typecheck/compound_stmt.exp index 58fac0fe..5a53bf85 100644 --- a/test/typecheck/compound_stmt.exp +++ b/test/typecheck/compound_stmt.exp @@ -1,16 +1,18 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 1: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 1: int ExprStmtNode <3:3> SimpleAssignmentExprNode <3:5> int IdExprNode <3:3> i: int BinaryExprNode <3:9> int + IdExprNode <3:7> i: int IntConstExprNode <3:11> 1: int - VarDeclNode <4:7> j: int - IntConstExprNode <4:11> 2: int + DeclStmtNode <4:3> + VarDeclNode <4:7> j: int + IntConstExprNode <4:11> 2: int ReturnStmtNode <5:3> BinaryExprNode <5:12> int + IdExprNode <5:10> i: int diff --git a/test/typecheck/cond_expr.exp b/test/typecheck/cond_expr.exp index eb134be6..c08d533f 100644 --- a/test/typecheck/cond_expr.exp +++ b/test/typecheck/cond_expr.exp @@ -1,14 +1,16 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> a: int - IntConstExprNode <2:11> 4: int - VarDeclNode <3:7> b: int - CondExprNode <3:18> int - BinaryExprNode <3:13> int == - IdExprNode <3:11> a: int - IntConstExprNode <3:16> 4: int - IntConstExprNode <3:20> 2: int - IntConstExprNode <3:24> 3: int + DeclStmtNode <2:3> + VarDeclNode <2:7> a: int + IntConstExprNode <2:11> 4: int + DeclStmtNode <3:3> + VarDeclNode <3:7> b: int + CondExprNode <3:18> int + BinaryExprNode <3:13> int == + IdExprNode <3:11> a: int + IntConstExprNode <3:16> 4: int + IntConstExprNode <3:20> 2: int + IntConstExprNode <3:24> 3: int ReturnStmtNode <4:3> IntConstExprNode <4:10> 0: int diff --git a/test/typecheck/continue_stmt.exp b/test/typecheck/continue_stmt.exp index e99c414e..92434813 100644 --- a/test/typecheck/continue_stmt.exp +++ b/test/typecheck/continue_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> a: int - IntConstExprNode <2:11> 0: int + DeclStmtNode <2:3> + VarDeclNode <2:7> a: int + IntConstExprNode <2:11> 0: int WhileStmtNode <3:3> // Do CompoundStmtNode <3:6> diff --git a/test/typecheck/decl.c b/test/typecheck/decl.c index 6fe845ec..dcb11921 100644 --- a/test/typecheck/decl.c +++ b/test/typecheck/decl.c @@ -2,4 +2,5 @@ int main() { int i = 0; int j; int; + int a, b = 1, c, d = 0; } diff --git a/test/typecheck/decl.exp b/test/typecheck/decl.exp index bcb3f0cd..e4cefdc7 100644 --- a/test/typecheck/decl.exp +++ b/test/typecheck/decl.exp @@ -1,7 +1,16 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 0: int - VarDeclNode <3:7> j: int - VarDeclNode <4:3> : int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 0: int + DeclStmtNode <3:3> + VarDeclNode <3:7> j: int + DeclStmtNode <4:3> + DeclStmtNode <5:3> + VarDeclNode <5:7> a: int + VarDeclNode <5:10> b: int + IntConstExprNode <5:14> 1: int + VarDeclNode <5:17> c: int + VarDeclNode <5:20> d: int + IntConstExprNode <5:24> 0: int diff --git a/test/typecheck/do_while_single_stmt.exp b/test/typecheck/do_while_single_stmt.exp index f4f24fbb..b02aec73 100644 --- a/test/typecheck/do_while_single_stmt.exp +++ b/test/typecheck/do_while_single_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 5: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 5: int WhileStmtNode <3:3> // Do ExprStmtNode <4:5> diff --git a/test/typecheck/do_while_stmt.exp b/test/typecheck/do_while_stmt.exp index 4f17ec10..ed3c4b70 100644 --- a/test/typecheck/do_while_stmt.exp +++ b/test/typecheck/do_while_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 0: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 0: int WhileStmtNode <3:3> // Do CompoundStmtNode <3:6> diff --git a/test/typecheck/for_nested_stmt.exp b/test/typecheck/for_nested_stmt.exp index 5f3564a9..ab386789 100644 --- a/test/typecheck/for_nested_stmt.exp +++ b/test/typecheck/for_nested_stmt.exp @@ -1,12 +1,14 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> k: int - IntConstExprNode <2:11> 0: int + DeclStmtNode <2:3> + VarDeclNode <2:7> k: int + IntConstExprNode <2:11> 0: int ForStmtNode <3:3> LoopInitNode <3:8> - VarDeclNode <3:12> i: int - IntConstExprNode <3:16> 0: int + DeclStmtNode <3:8> + VarDeclNode <3:12> i: int + IntConstExprNode <3:16> 0: int BinaryExprNode <3:21> int < IdExprNode <3:19> i: int IntConstExprNode <3:23> 5: int @@ -18,8 +20,9 @@ ProgramNode <1:1> CompoundStmtNode <3:37> ForStmtNode <4:5> LoopInitNode <4:10> - VarDeclNode <4:14> j: int - IntConstExprNode <4:18> 0: int + DeclStmtNode <4:10> + VarDeclNode <4:14> j: int + IntConstExprNode <4:18> 0: int BinaryExprNode <4:23> int < IdExprNode <4:21> j: int IntConstExprNode <4:25> 5: int diff --git a/test/typecheck/for_stmt.c b/test/typecheck/for_stmt.c index 0d7e244d..3b7c4fff 100644 --- a/test/typecheck/for_stmt.c +++ b/test/typecheck/for_stmt.c @@ -1,7 +1,10 @@ int main() { int j = 0; int i; - for (i = 0; i < 5; i = i + 1) { + for (i = 0 /* expr */; i < 5; i = i + 1) { + j = j + 1; + } + for (int a = 0, b = 5 /* decl */; a < b; a = a + 1) { j = j + 1; } diff --git a/test/typecheck/for_stmt.exp b/test/typecheck/for_stmt.exp index 9ecd3f31..c11d31d4 100644 --- a/test/typecheck/for_stmt.exp +++ b/test/typecheck/for_stmt.exp @@ -1,28 +1,52 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> j: int - IntConstExprNode <2:11> 0: int - VarDeclNode <3:7> i: int + DeclStmtNode <2:3> + VarDeclNode <2:7> j: int + IntConstExprNode <2:11> 0: int + DeclStmtNode <3:3> + VarDeclNode <3:7> i: int ForStmtNode <4:3> LoopInitNode <4:8> SimpleAssignmentExprNode <4:10> int IdExprNode <4:8> i: int IntConstExprNode <4:12> 0: int - BinaryExprNode <4:17> int < - IdExprNode <4:15> i: int - IntConstExprNode <4:19> 5: int - SimpleAssignmentExprNode <4:24> int - IdExprNode <4:22> i: int - BinaryExprNode <4:28> int + - IdExprNode <4:26> i: int - IntConstExprNode <4:30> 1: int - CompoundStmtNode <4:33> + BinaryExprNode <4:28> int < + IdExprNode <4:26> i: int + IntConstExprNode <4:30> 5: int + SimpleAssignmentExprNode <4:35> int + IdExprNode <4:33> i: int + BinaryExprNode <4:39> int + + IdExprNode <4:37> i: int + IntConstExprNode <4:41> 1: int + CompoundStmtNode <4:44> ExprStmtNode <5:5> SimpleAssignmentExprNode <5:7> int IdExprNode <5:5> j: int BinaryExprNode <5:11> int + IdExprNode <5:9> j: int IntConstExprNode <5:13> 1: int - ReturnStmtNode <8:3> - IntConstExprNode <8:10> 0: int + ForStmtNode <7:3> + LoopInitNode <7:8> + DeclStmtNode <7:8> + VarDeclNode <7:12> a: int + IntConstExprNode <7:16> 0: int + VarDeclNode <7:19> b: int + IntConstExprNode <7:23> 5: int + BinaryExprNode <7:39> int < + IdExprNode <7:37> a: int + IdExprNode <7:41> b: int + SimpleAssignmentExprNode <7:46> int + IdExprNode <7:44> a: int + BinaryExprNode <7:50> int + + IdExprNode <7:48> a: int + IntConstExprNode <7:52> 1: int + CompoundStmtNode <7:55> + ExprStmtNode <8:5> + SimpleAssignmentExprNode <8:7> int + IdExprNode <8:5> j: int + BinaryExprNode <8:11> int + + IdExprNode <8:9> j: int + IntConstExprNode <8:13> 1: int + ReturnStmtNode <11:3> + IntConstExprNode <11:10> 0: int diff --git a/test/typecheck/func_call_param.exp b/test/typecheck/func_call_param.exp index 98b6687d..805314d0 100644 --- a/test/typecheck/func_call_param.exp +++ b/test/typecheck/func_call_param.exp @@ -19,19 +19,21 @@ ProgramNode <1:1> IntConstExprNode <6:14> 5: int FuncDefNode <9:5> main: int () CompoundStmtNode <9:12> - VarDeclNode <10:7> a: int - FuncCallExprNode <10:11> int - IdExprNode <10:11> sum: int (int, int, int) - ArgExprNode <10:15> int - IntConstExprNode <10:15> 1: int - ArgExprNode <10:18> int - IntConstExprNode <10:18> 2: int - ArgExprNode <10:21> int - IntConstExprNode <10:21> 3: int - VarDeclNode <11:7> b: int - BinaryExprNode <11:13> int + - IdExprNode <11:11> a: int - IntConstExprNode <11:15> 4: int + DeclStmtNode <10:3> + VarDeclNode <10:7> a: int + FuncCallExprNode <10:11> int + IdExprNode <10:11> sum: int (int, int, int) + ArgExprNode <10:15> int + IntConstExprNode <10:15> 1: int + ArgExprNode <10:18> int + IntConstExprNode <10:18> 2: int + ArgExprNode <10:21> int + IntConstExprNode <10:21> 3: int + DeclStmtNode <11:3> + VarDeclNode <11:7> b: int + BinaryExprNode <11:13> int + + IdExprNode <11:11> a: int + IntConstExprNode <11:15> 4: int ReturnStmtNode <12:3> FuncCallExprNode <12:10> int IdExprNode <12:10> add_five: int (int) diff --git a/test/typecheck/func_pointer.exp b/test/typecheck/func_pointer.exp index b8004e72..e91799b6 100644 --- a/test/typecheck/func_pointer.exp +++ b/test/typecheck/func_pointer.exp @@ -9,30 +9,33 @@ ProgramNode <1:1> IdExprNode <2:14> b: int FuncDefNode <5:5> main: int () CompoundStmtNode <5:12> - VarDeclNode <6:9> p: int (*)(int, int) + DeclStmtNode <6:3> + VarDeclNode <6:9> p: int (*)(int, int) ExprStmtNode <7:3> SimpleAssignmentExprNode <7:5> int (*)(int, int) IdExprNode <7:3> p: int (*)(int, int) IdExprNode <7:7> add: int (int, int) - VarDeclNode <8:7> c: int - FuncCallExprNode <8:11> int - IdExprNode <8:11> p: int (*)(int, int) - ArgExprNode <8:13> int - IntConstExprNode <8:13> 2: int - ArgExprNode <8:16> int - IntConstExprNode <8:16> 3: int + DeclStmtNode <8:3> + VarDeclNode <8:7> c: int + FuncCallExprNode <8:11> int + IdExprNode <8:11> p: int (*)(int, int) + ArgExprNode <8:13> int + IntConstExprNode <8:13> 2: int + ArgExprNode <8:16> int + IntConstExprNode <8:16> 3: int ExprStmtNode <9:3> SimpleAssignmentExprNode <9:5> int (*)(int, int) IdExprNode <9:3> p: int (*)(int, int) UnaryExprNode <9:7> int (*)(int, int) & IdExprNode <9:8> add: int (int, int) - VarDeclNode <10:7> d: int - FuncCallExprNode <10:11> int - UnaryExprNode <10:12> int (int, int) * - IdExprNode <10:13> p: int (*)(int, int) - ArgExprNode <10:16> int - IntConstExprNode <10:16> 1: int - ArgExprNode <10:19> int - IntConstExprNode <10:19> 2: int + DeclStmtNode <10:3> + VarDeclNode <10:7> d: int + FuncCallExprNode <10:11> int + UnaryExprNode <10:12> int (int, int) * + IdExprNode <10:13> p: int (*)(int, int) + ArgExprNode <10:16> int + IntConstExprNode <10:16> 1: int + ArgExprNode <10:19> int + IntConstExprNode <10:19> 2: int ReturnStmtNode <11:3> IntConstExprNode <11:10> 0: int diff --git a/test/typecheck/func_pointer_param.exp b/test/typecheck/func_pointer_param.exp index 62cc1e76..c851cd30 100644 --- a/test/typecheck/func_pointer_param.exp +++ b/test/typecheck/func_pointer_param.exp @@ -28,8 +28,9 @@ ProgramNode <1:1> IntConstExprNode <12:10> 0: int FuncDefNode <15:5> main: int () CompoundStmtNode <15:12> - VarDeclNode <16:9> c: int (*)(int (*)(int, int), int, int) - IdExprNode <16:43> call: int (int (*)(int, int), int, int) + DeclStmtNode <16:3> + VarDeclNode <16:9> c: int (*)(int (*)(int, int), int, int) + IdExprNode <16:43> call: int (int (*)(int, int), int, int) ExprStmtNode <17:3> FuncCallExprNode <17:3> int IdExprNode <17:3> c: int (*)(int (*)(int, int), int, int) diff --git a/test/typecheck/goto_stmt.exp b/test/typecheck/goto_stmt.exp index 56a5ee89..6d6fc7cb 100644 --- a/test/typecheck/goto_stmt.exp +++ b/test/typecheck/goto_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 0: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 0: int CompoundStmtNode <3:3> IdLabeledStmtNode <4:3> begin ExprStmtNode <5:5> @@ -12,6 +13,7 @@ ProgramNode <1:1> IdExprNode <5:9> i: int IntConstExprNode <5:13> 1: int GotoStmtNode <9:3> begin - VarDeclNode <11:7> begin: int + DeclStmtNode <11:3> + VarDeclNode <11:7> begin: int ReturnStmtNode <12:3> IntConstExprNode <12:10> 0: int diff --git a/test/typecheck/id_expr.exp b/test/typecheck/id_expr.exp index 56b18ea9..9da7ac90 100644 --- a/test/typecheck/id_expr.exp +++ b/test/typecheck/id_expr.exp @@ -1,6 +1,8 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - VarDeclNode <3:7> j: int - IdExprNode <3:11> i: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + DeclStmtNode <3:3> + VarDeclNode <3:7> j: int + IdExprNode <3:11> i: int diff --git a/test/typecheck/identifier.exp b/test/typecheck/identifier.exp index 5011a6f7..bb431c8d 100644 --- a/test/typecheck/identifier.exp +++ b/test/typecheck/identifier.exp @@ -1,12 +1,21 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> _: int - VarDeclNode <3:7> __: int - VarDeclNode <4:7> i: int - VarDeclNode <5:7> _1: int - VarDeclNode <6:7> _i: int - VarDeclNode <7:7> _i1: int - VarDeclNode <8:7> _i1_: int - VarDeclNode <9:7> _I: int - VarDeclNode <10:7> _I1: int + DeclStmtNode <2:3> + VarDeclNode <2:7> _: int + DeclStmtNode <3:3> + VarDeclNode <3:7> __: int + DeclStmtNode <4:3> + VarDeclNode <4:7> i: int + DeclStmtNode <5:3> + VarDeclNode <5:7> _1: int + DeclStmtNode <6:3> + VarDeclNode <6:7> _i: int + DeclStmtNode <7:3> + VarDeclNode <7:7> _i1: int + DeclStmtNode <8:3> + VarDeclNode <8:7> _i1_: int + DeclStmtNode <9:3> + VarDeclNode <9:7> _I: int + DeclStmtNode <10:3> + VarDeclNode <10:7> _I1: int diff --git a/test/typecheck/if_else_nested_single_stmt.exp b/test/typecheck/if_else_nested_single_stmt.exp index d4cdda3d..acba3c3d 100644 --- a/test/typecheck/if_else_nested_single_stmt.exp +++ b/test/typecheck/if_else_nested_single_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 5: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 5: int IfStmtNode <3:3> BinaryExprNode <3:9> int < IdExprNode <3:7> i: int diff --git a/test/typecheck/if_else_nested_stmt.exp b/test/typecheck/if_else_nested_stmt.exp index 754e648c..3c53b089 100644 --- a/test/typecheck/if_else_nested_stmt.exp +++ b/test/typecheck/if_else_nested_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 25: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 25: int IfStmtNode <3:3> BinaryExprNode <3:9> int < IdExprNode <3:7> i: int diff --git a/test/typecheck/if_else_single_stmt.exp b/test/typecheck/if_else_single_stmt.exp index 6a61b743..02a5e8a8 100644 --- a/test/typecheck/if_else_single_stmt.exp +++ b/test/typecheck/if_else_single_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 2: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 2: int IfStmtNode <3:3> BinaryExprNode <3:9> int > IdExprNode <3:7> i: int diff --git a/test/typecheck/if_else_stmt.exp b/test/typecheck/if_else_stmt.exp index 5a24415f..e4341de5 100644 --- a/test/typecheck/if_else_stmt.exp +++ b/test/typecheck/if_else_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 2: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 2: int IfStmtNode <3:3> BinaryExprNode <3:9> int < IdExprNode <3:7> i: int diff --git a/test/typecheck/if_single_stmt.exp b/test/typecheck/if_single_stmt.exp index e9934ac7..eeaa172b 100644 --- a/test/typecheck/if_single_stmt.exp +++ b/test/typecheck/if_single_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 2: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 2: int IfStmtNode <3:3> BinaryExprNode <3:9> int > IdExprNode <3:7> i: int diff --git a/test/typecheck/if_stmt.exp b/test/typecheck/if_stmt.exp index d7af431a..2258c82c 100644 --- a/test/typecheck/if_stmt.exp +++ b/test/typecheck/if_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 2: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 2: int IfStmtNode <3:3> BinaryExprNode <3:9> int > IdExprNode <3:7> i: int diff --git a/test/typecheck/pointer.c b/test/typecheck/pointer.c index a643661c..8040876e 100644 --- a/test/typecheck/pointer.c +++ b/test/typecheck/pointer.c @@ -5,5 +5,7 @@ int main() { b = c; *c = 5; + int *x, y, *z = &c; + return *c; } diff --git a/test/typecheck/pointer.exp b/test/typecheck/pointer.exp index ca3ed2a3..c98c52ae 100644 --- a/test/typecheck/pointer.exp +++ b/test/typecheck/pointer.exp @@ -1,12 +1,15 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> a: int - IntConstExprNode <2:11> 10: int - VarDeclNode <3:8> b: int* - VarDeclNode <4:8> c: int* - UnaryExprNode <4:12> int* & - IdExprNode <4:13> a: int + DeclStmtNode <2:3> + VarDeclNode <2:7> a: int + IntConstExprNode <2:11> 10: int + DeclStmtNode <3:3> + VarDeclNode <3:8> b: int* + DeclStmtNode <4:3> + VarDeclNode <4:8> c: int* + UnaryExprNode <4:12> int* & + IdExprNode <4:13> a: int ExprStmtNode <5:3> SimpleAssignmentExprNode <5:5> int* IdExprNode <5:3> b: int* @@ -16,6 +19,12 @@ ProgramNode <1:1> UnaryExprNode <6:3> int * IdExprNode <6:4> c: int* IntConstExprNode <6:8> 5: int - ReturnStmtNode <8:3> - UnaryExprNode <8:10> int * - IdExprNode <8:11> c: int* + DeclStmtNode <8:3> + VarDeclNode <8:8> x: int* + VarDeclNode <8:11> y: int + VarDeclNode <8:15> z: int* + UnaryExprNode <8:19> int** & + IdExprNode <8:20> c: int* + ReturnStmtNode <10:3> + UnaryExprNode <10:10> int * + IdExprNode <10:11> c: int* diff --git a/test/typecheck/pointer_param.exp b/test/typecheck/pointer_param.exp index 437affb9..c45939b3 100644 --- a/test/typecheck/pointer_param.exp +++ b/test/typecheck/pointer_param.exp @@ -11,13 +11,16 @@ ProgramNode <1:1> IdExprNode <2:16> y: int* FuncDefNode <5:5> main: int () CompoundStmtNode <5:12> - VarDeclNode <6:7> a: int - IntConstExprNode <6:11> 3: int - VarDeclNode <7:7> b: int - IntConstExprNode <7:11> 5: int - VarDeclNode <8:8> c: int* - UnaryExprNode <8:12> int* & - IdExprNode <8:13> b: int + DeclStmtNode <6:3> + VarDeclNode <6:7> a: int + IntConstExprNode <6:11> 3: int + DeclStmtNode <7:3> + VarDeclNode <7:7> b: int + IntConstExprNode <7:11> 5: int + DeclStmtNode <8:3> + VarDeclNode <8:8> c: int* + UnaryExprNode <8:12> int* & + IdExprNode <8:13> b: int ReturnStmtNode <9:3> FuncCallExprNode <9:10> int IdExprNode <9:10> add: int (int*, int*) diff --git a/test/typecheck/pointer_to_pointer.exp b/test/typecheck/pointer_to_pointer.exp index 59dd53f9..e6eaa50f 100644 --- a/test/typecheck/pointer_to_pointer.exp +++ b/test/typecheck/pointer_to_pointer.exp @@ -1,14 +1,17 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> a: int - IntConstExprNode <2:11> 10: int - VarDeclNode <3:8> pa: int* - UnaryExprNode <3:13> int* & - IdExprNode <3:14> a: int - VarDeclNode <4:9> ppa: int** - UnaryExprNode <4:15> int** & - IdExprNode <4:16> pa: int* + DeclStmtNode <2:3> + VarDeclNode <2:7> a: int + IntConstExprNode <2:11> 10: int + DeclStmtNode <3:3> + VarDeclNode <3:8> pa: int* + UnaryExprNode <3:13> int* & + IdExprNode <3:14> a: int + DeclStmtNode <4:3> + VarDeclNode <4:9> ppa: int** + UnaryExprNode <4:15> int** & + IdExprNode <4:16> pa: int* ExprStmtNode <5:3> FuncCallExprNode <5:3> int IdExprNode <5:3> __builtin_print: int (int) @@ -16,11 +19,13 @@ ProgramNode <1:1> UnaryExprNode <5:19> int * UnaryExprNode <5:20> int* * IdExprNode <5:21> ppa: int** - VarDeclNode <7:7> b: int - IntConstExprNode <7:11> 20: int - VarDeclNode <8:8> pb: int* - UnaryExprNode <8:13> int* & - IdExprNode <8:14> b: int + DeclStmtNode <7:3> + VarDeclNode <7:7> b: int + IntConstExprNode <7:11> 20: int + DeclStmtNode <8:3> + VarDeclNode <8:8> pb: int* + UnaryExprNode <8:13> int* & + IdExprNode <8:14> b: int ExprStmtNode <9:3> SimpleAssignmentExprNode <9:8> int* UnaryExprNode <9:3> int* * diff --git a/test/typecheck/pointer_to_pointer_param.exp b/test/typecheck/pointer_to_pointer_param.exp index 18c9e765..587778b7 100644 --- a/test/typecheck/pointer_to_pointer_param.exp +++ b/test/typecheck/pointer_to_pointer_param.exp @@ -13,16 +13,20 @@ ProgramNode <1:1> IdExprNode <2:18> y: int** FuncDefNode <5:5> main: int () CompoundStmtNode <5:12> - VarDeclNode <6:7> a: int - IntConstExprNode <6:11> 3: int - VarDeclNode <7:7> b: int - IntConstExprNode <7:11> 5: int - VarDeclNode <8:8> c: int* - UnaryExprNode <8:12> int* & - IdExprNode <8:13> a: int - VarDeclNode <9:8> d: int* - UnaryExprNode <9:12> int* & - IdExprNode <9:13> b: int + DeclStmtNode <6:3> + VarDeclNode <6:7> a: int + IntConstExprNode <6:11> 3: int + DeclStmtNode <7:3> + VarDeclNode <7:7> b: int + IntConstExprNode <7:11> 5: int + DeclStmtNode <8:3> + VarDeclNode <8:8> c: int* + UnaryExprNode <8:12> int* & + IdExprNode <8:13> a: int + DeclStmtNode <9:3> + VarDeclNode <9:8> d: int* + UnaryExprNode <9:12> int* & + IdExprNode <9:13> b: int ReturnStmtNode <10:3> FuncCallExprNode <10:10> int IdExprNode <10:10> add: int (int**, int**) diff --git a/test/typecheck/postfix_arith_expr.exp b/test/typecheck/postfix_arith_expr.exp index 0121fc29..52c65587 100644 --- a/test/typecheck/postfix_arith_expr.exp +++ b/test/typecheck/postfix_arith_expr.exp @@ -1,17 +1,19 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> a: int - IntConstExprNode <2:11> 0: int + DeclStmtNode <2:3> + VarDeclNode <2:7> a: int + IntConstExprNode <2:11> 0: int ExprStmtNode <3:3> PostfixArithExprNode <3:3> int ++ IdExprNode <3:3> a: int ExprStmtNode <4:3> PostfixArithExprNode <4:3> int -- IdExprNode <4:3> a: int - VarDeclNode <6:8> b: int* - UnaryExprNode <6:12> int* & - IdExprNode <6:13> a: int + DeclStmtNode <6:3> + VarDeclNode <6:8> b: int* + UnaryExprNode <6:12> int* & + IdExprNode <6:13> a: int ExprStmtNode <7:3> PostfixArithExprNode <7:3> int* ++ IdExprNode <7:3> b: int* diff --git a/test/typecheck/struct.c b/test/typecheck/struct.c index 730e598a..9f8eba60 100644 --- a/test/typecheck/struct.c +++ b/test/typecheck/struct.c @@ -23,5 +23,7 @@ int main() { struct birth bd3[3] = {[0].date = 4, [1].year = 1999}; + struct birth a, *b, c[3]; + return 0; } diff --git a/test/typecheck/struct.exp b/test/typecheck/struct.exp index ed1ce232..09f5c8b7 100644 --- a/test/typecheck/struct.exp +++ b/test/typecheck/struct.exp @@ -1,42 +1,43 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - RecordDeclNode <2:10> struct ss definition - RecordDeclNode <4:10> struct birth definition - FieldNode <5:9> date: int - FieldNode <6:9> month: int - FieldNode <7:9> year: int - RecordDeclNode <10:9> struct definition - FieldNode <11:9> quarter: int - FieldNode <12:9> dime: int - FieldNode <13:9> penny: int - RecordVarDeclNode <16:16> bd1: struct birth - InitExprNode <17:5> - IdDesNode <17:6> date - IntConstExprNode <17:13> 1: int - InitExprNode <17:5> - IdDesNode <18:6> month - IntConstExprNode <18:14> 1: int - InitExprNode <17:5> - IdDesNode <19:6> year - IntConstExprNode <19:13> 1995: int - RecordVarDeclNode <22:16> bd2: struct birth - InitExprNode <22:23> - IntConstExprNode <22:23> 3: int - InitExprNode <22:23> - IntConstExprNode <22:26> 3: int - InitExprNode <22:23> - IntConstExprNode <22:29> 1998: int - ArrDeclNode <24:16> bd3: struct birth[3] - 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 + DeclStmtNode <2:3> + DeclStmtNode <4:3> + DeclStmtNode <10:3> + DeclStmtNode <16:3> + RecordVarDeclNode <16:16> bd1: struct birth + InitExprNode <17:5> + IdDesNode <17:6> date + IntConstExprNode <17:13> 1: int + InitExprNode <17:5> + IdDesNode <18:6> month + IntConstExprNode <18:14> 1: int + InitExprNode <17:5> + IdDesNode <19:6> year + IntConstExprNode <19:13> 1995: int + DeclStmtNode <22:3> + RecordVarDeclNode <22:16> bd2: struct birth + InitExprNode <22:23> + IntConstExprNode <22:23> 3: int + InitExprNode <22:23> + IntConstExprNode <22:26> 3: int + InitExprNode <22:23> + IntConstExprNode <22:29> 1998: int + DeclStmtNode <24:3> + ArrDeclNode <24:16> bd3: struct birth[3] + 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 + DeclStmtNode <26:3> + VarDeclNode <26:16> a: struct birth + VarDeclNode <26:20> b: struct birth* + ArrDeclNode <26:23> c: struct birth[3] + ReturnStmtNode <28:3> + IntConstExprNode <28:10> 0: int diff --git a/test/typecheck/switch_stmt.exp b/test/typecheck/switch_stmt.exp index 67498cd7..cd9da567 100644 --- a/test/typecheck/switch_stmt.exp +++ b/test/typecheck/switch_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> a: int - IntConstExprNode <2:11> 1: int + DeclStmtNode <2:3> + VarDeclNode <2:7> a: int + IntConstExprNode <2:11> 1: int SwitchStmtNode <3:3> IdExprNode <3:11> a: int CompoundStmtNode <3:14> diff --git a/test/typecheck/unary_expr.exp b/test/typecheck/unary_expr.exp index 4c302ca6..cf304fe3 100644 --- a/test/typecheck/unary_expr.exp +++ b/test/typecheck/unary_expr.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 1: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 1: int ExprStmtNode <3:3> UnaryExprNode <3:3> int -- IdExprNode <3:5> i: int diff --git a/test/typecheck/union.c b/test/typecheck/union.c index 31138bfe..503e8fde 100644 --- a/test/typecheck/union.c +++ b/test/typecheck/union.c @@ -22,5 +22,7 @@ int main() { union shape circle = {.circle = 1}; union shape puzzles[3] = {[0].circle = 1, [1].triangle = 2, [2].square = 4}; + union shape a, *b, c[3]; + return 0; } diff --git a/test/typecheck/union.exp b/test/typecheck/union.exp index 1720cbc6..b0e3343a 100644 --- a/test/typecheck/union.exp +++ b/test/typecheck/union.exp @@ -1,43 +1,42 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - RecordDeclNode <2:9> union u definition - RecordDeclNode <4:9> union shape definition - FieldNode <5:9> square: int - FieldNode <6:9> circle: int - FieldNode <7:9> triangle: int - RecordDeclNode <10:8> union definition - FieldNode <11:9> a: int - FieldNode <12:9> b: int - FieldNode <13:9> c: int - FieldNode <14:9> d: int - FieldNode <15:9> e: int - RecordVarDeclNode <20:15> s: union shape - InitExprNode <20:20> - IntConstExprNode <20:20> 3: int - InitExprNode <20:20> - IntConstExprNode <20:23> 4: int - InitExprNode <20:20> - IntConstExprNode <20:26> 5: int - RecordVarDeclNode <22:15> circle: union shape - InitExprNode <22:25> - IdDesNode <22:26> circle - IntConstExprNode <22:35> 1: int - ArrDeclNode <23:15> puzzles: union shape[3] - 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 + DeclStmtNode <2:3> + DeclStmtNode <4:3> + DeclStmtNode <10:3> + DeclStmtNode <20:3> + RecordVarDeclNode <20:15> s: union shape + InitExprNode <20:20> + IntConstExprNode <20:20> 3: int + InitExprNode <20:20> + IntConstExprNode <20:23> 4: int + InitExprNode <20:20> + IntConstExprNode <20:26> 5: int + DeclStmtNode <22:3> + RecordVarDeclNode <22:15> circle: union shape + InitExprNode <22:25> + IdDesNode <22:26> circle + IntConstExprNode <22:35> 1: int + DeclStmtNode <23:3> + ArrDeclNode <23:15> puzzles: union shape[3] + 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 + DeclStmtNode <25:3> + VarDeclNode <25:15> a: union shape + VarDeclNode <25:19> b: union shape* + ArrDeclNode <25:22> c: union shape[3] + ReturnStmtNode <27:3> + IntConstExprNode <27:10> 0: int diff --git a/test/typecheck/while_single_stmt.exp b/test/typecheck/while_single_stmt.exp index 9f137fa3..350eab05 100644 --- a/test/typecheck/while_single_stmt.exp +++ b/test/typecheck/while_single_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 5: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 5: int WhileStmtNode <3:3> // While BinaryExprNode <3:12> int > diff --git a/test/typecheck/while_stmt.exp b/test/typecheck/while_stmt.exp index 71f71b11..6eb96398 100644 --- a/test/typecheck/while_stmt.exp +++ b/test/typecheck/while_stmt.exp @@ -1,8 +1,9 @@ ProgramNode <1:1> FuncDefNode <1:5> main: int () CompoundStmtNode <1:12> - VarDeclNode <2:7> i: int - IntConstExprNode <2:11> 5: int + DeclStmtNode <2:3> + VarDeclNode <2:7> i: int + IntConstExprNode <2:11> 5: int WhileStmtNode <3:3> // While BinaryExprNode <3:12> int > From 544bf885a5104d8ed9f4200a592661e91d83246f Mon Sep 17 00:00:00 2001 From: Lai-YT <381xvmvbib@gmail.com> Date: Sat, 8 Jun 2024 17:48:20 +0800 Subject: [PATCH 2/4] Fix use-after-move Objects are placed in a valid but unspecified state after being moved-from. --- parser.y | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parser.y b/parser.y index 18ad80af..2101a41b 100644 --- a/parser.y +++ b/parser.y @@ -490,9 +490,9 @@ struct_or_union_specifier: struct_or_union id_opt LEFT_CURLY struct_declaration_ auto type_id = decl_id ? decl_id->id : ""; if (type->IsStruct()) { - type = std::make_unique(std::move(type_id), std::move(field_types)); + type = std::make_unique(type_id, std::move(field_types)); } else { - type = std::make_unique(std::move(type_id), std::move(field_types)); + type = std::make_unique(type_id, std::move(field_types)); } $$ = std::make_unique(Loc(@2), std::move(type_id), std::move(type), std::move(field_list)); @@ -504,9 +504,9 @@ struct_or_union_specifier: struct_or_union id_opt LEFT_CURLY struct_declaration_ auto field_types = std::vector>{}; if (type->IsStruct()) { - type = std::make_unique(std::move(decl_id), std::move(field_types)); + type = std::make_unique(decl_id, std::move(field_types)); } else { - type = std::make_unique(std::move(decl_id), std::move(field_types)); + type = std::make_unique(decl_id, std::move(field_types)); } $$ = std::make_unique(Loc(@2), std::move(decl_id), std::move(type), std::move(field_list)); From 44304764f42ea8e02135bf9042d4ed11c8b8c26e Mon Sep 17 00:00:00 2001 From: Lai-YT <381xvmvbib@gmail.com> Date: Sat, 8 Jun 2024 18:07:36 +0800 Subject: [PATCH 3/4] Inline type alias & rename data member Since an item of a compound statement is no longer an `std::variant`, we no longer use a type alias to simplify the type. Additionally, the data member has been renamed to remove the word `item`, which is a technical term used during parsing. --- include/ast.hpp | 7 +++---- parser.y | 6 +++--- src/ast_dumper.cpp | 4 ++-- src/qbe_ir_generator.cpp | 4 ++-- src/type_checker.cpp | 4 ++-- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/include/ast.hpp b/include/ast.hpp index 13b68599..d8f8534f 100644 --- a/include/ast.hpp +++ b/include/ast.hpp @@ -211,14 +211,13 @@ struct LoopInitNode : public AstNode { }; struct CompoundStmtNode : public StmtNode { - using Item = std::unique_ptr; - CompoundStmtNode(Location loc, std::vector items) - : StmtNode{loc}, items{std::move(items)} {} + CompoundStmtNode(Location loc, std::vector> stmts) + : StmtNode{loc}, stmts{std::move(stmts)} {} void Accept(NonModifyingVisitor&) const override; void Accept(ModifyingVisitor&) override; - std::vector items; + std::vector> stmts; }; /// @brief Root of the entire program. diff --git a/parser.y b/parser.y index 2101a41b..a4f12610 100644 --- a/parser.y +++ b/parser.y @@ -131,7 +131,7 @@ std::unique_ptr ResolveType(std::unique_ptr resolved_type, %nterm > loop_init %nterm > stmt jump_stmt selection_stmt labeled_stmt block_item %nterm > compound_stmt -%nterm > block_item_list block_item_list_opt +%nterm >> block_item_list block_item_list_opt // Resolve the ambiguity in the "dangling-else" grammar. // Example: IF LEFT_PAREN expr RIGHT_PAREN IF LEFT_PAREN expr RIGHT_PAREN stmt • ELSE stmt @@ -198,12 +198,12 @@ compound_stmt: LEFT_CURLY block_item_list_opt RIGHT_CURLY { block_item_list_opt: block_item_list { $$ = $1; } | epsilon { - $$ = std::vector{}; + $$ = std::vector>{}; } ; block_item_list: block_item { - $$ = std::vector{}; + $$ = std::vector>{}; $$.push_back($1); } | block_item_list block_item { diff --git a/src/ast_dumper.cpp b/src/ast_dumper.cpp index 055a42bf..58d644fd 100644 --- a/src/ast_dumper.cpp +++ b/src/ast_dumper.cpp @@ -178,8 +178,8 @@ void AstDumper::Visit(const CompoundStmtNode& compound_stmt) { std::cout << indenter_.Indent() << "CompoundStmtNode <" << compound_stmt.loc << ">\n"; indenter_.IncreaseLevel(); - for (const auto& item : compound_stmt.items) { - item->Accept(*this); + for (const auto& stmt : compound_stmt.stmts) { + stmt->Accept(*this); } indenter_.DecreaseLevel(); } diff --git a/src/qbe_ir_generator.cpp b/src/qbe_ir_generator.cpp index f92119ba..bb13e431 100644 --- a/src/qbe_ir_generator.cpp +++ b/src/qbe_ir_generator.cpp @@ -273,8 +273,8 @@ void QbeIrGenerator::Visit(const CompoundStmtNode& compound_stmt) { // because it doesn't know whether it is a if statement body or a function. // Thus, by moving label creation to an upper level, each block can have its // correct starting label. - for (const auto& item : compound_stmt.items) { - item->Accept(*this); + for (const auto& stmt : compound_stmt.stmts) { + stmt->Accept(*this); } } diff --git a/src/type_checker.cpp b/src/type_checker.cpp index b00970fb..04c40d5e 100644 --- a/src/type_checker.cpp +++ b/src/type_checker.cpp @@ -200,8 +200,8 @@ void TypeChecker::Visit(LoopInitNode& loop_init) { void TypeChecker::Visit(CompoundStmtNode& compound_stmt) { env_.PushScope(ScopeKind::kBlock); - for (auto& item : compound_stmt.items) { - item->Accept(*this); + for (auto& stmt : compound_stmt.stmts) { + stmt->Accept(*this); } env_.PopScope(); } From c7f2fe499074c126b74804724fec78a7f9ed1957 Mon Sep 17 00:00:00 2001 From: Lai-YT <381xvmvbib@gmail.com> Date: Sat, 8 Jun 2024 18:28:45 +0800 Subject: [PATCH 4/4] Add test on code generation for multiple declarations --- test/codegen/array.c | 4 +--- test/codegen/decl.c | 2 ++ test/codegen/decl.exp | 1 + test/codegen/for_stmt.c | 2 +- test/codegen/pointer.c | 3 +-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/codegen/array.c b/test/codegen/array.c index 56abd46f..3e6b375a 100644 --- a/test/codegen/array.c +++ b/test/codegen/array.c @@ -11,9 +11,7 @@ int main() { a[3] = 2 + a[2]; __builtin_print(a[3]); - int b = 2; - int c = 0; - int d[4] = {1, b, c = 3, 4}; + int b = 2, c = 0, d[4] = {1, b, c = 3, 4}; __builtin_print(d[0]); __builtin_print(d[1]); __builtin_print(d[2]); diff --git a/test/codegen/decl.c b/test/codegen/decl.c index 777cbfdb..3456caf2 100644 --- a/test/codegen/decl.c +++ b/test/codegen/decl.c @@ -7,5 +7,7 @@ int main() { int i; int j = 2; __builtin_print(j); + int a = 3, b; + __builtin_print(a); return 0; } diff --git a/test/codegen/decl.exp b/test/codegen/decl.exp index 0cfbf088..4792e70f 100644 --- a/test/codegen/decl.exp +++ b/test/codegen/decl.exp @@ -1 +1,2 @@ 2 +3 diff --git a/test/codegen/for_stmt.c b/test/codegen/for_stmt.c index 8950476f..c27e1eb9 100644 --- a/test/codegen/for_stmt.c +++ b/test/codegen/for_stmt.c @@ -12,7 +12,7 @@ int main() { // Nested for loop // int k = 0; - for (int i = 0; i < 5; i = i + 1) { + for (int i = 0, e = 5; i < e; i = i + 1) { for (int j = 0; j < 5; j = j + 1) { k = k + 1; } diff --git a/test/codegen/pointer.c b/test/codegen/pointer.c index 639e595c..5b0e33db 100644 --- a/test/codegen/pointer.c +++ b/test/codegen/pointer.c @@ -1,7 +1,6 @@ int main() { int a = 10; - int* b = &a; - int* c; + int *b = &a, *c; __builtin_print(a); *b = 5;