Skip to content

Commit

Permalink
Implement Record Declaration Node for struct and union
Browse files Browse the repository at this point in the history
  • Loading branch information
leewei05 committed May 10, 2024
1 parent 1867c90 commit 04ee10a
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 56 deletions.
19 changes: 4 additions & 15 deletions include/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,10 @@ struct DeclArrNode : public DeclNode {
std::vector<std::unique_ptr<ExprNode>> init_list;
};

struct DefStructNode : public DeclNode {
DefStructNode(Location loc, std::string id, std::unique_ptr<Type> type,
std::vector<std::unique_ptr<FieldNode>> field_list)
: DeclNode{loc, std::move(id), std::move(type)},
field_list{std::move(field_list)} {}

void Accept(NonModifyingVisitor&) const override;
void Accept(ModifyingVisitor&) override;

std::vector<std::unique_ptr<FieldNode>> field_list;
};

struct DefUnionNode : public DeclNode {
DefUnionNode(Location loc, std::string id, std::unique_ptr<Type> type,
std::vector<std::unique_ptr<FieldNode>> field_list)
/// @brief Record Declaration Node holds the definition of struct or union.
struct RecordDeclNode : public DeclNode {
RecordDeclNode(Location loc, std::string id, std::unique_ptr<Type> type,
std::vector<std::unique_ptr<FieldNode>> field_list)
: DeclNode{loc, std::move(id), std::move(type)},
field_list{std::move(field_list)} {}

Expand Down
2 changes: 2 additions & 0 deletions include/ast_dumper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class AstDumper : public NonModifyingVisitor {
void Visit(const LoopInitNode&) override;
void Visit(const DeclVarNode&) override;
void Visit(const DeclArrNode&) override;
void Visit(const RecordDeclNode&) override;
void Visit(const FieldNode&) override;
void Visit(const ParamNode&) override;
void Visit(const FuncDefNode&) override;
void Visit(const CompoundStmtNode&) override;
Expand Down
2 changes: 2 additions & 0 deletions include/qbe_ir_generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class QbeIrGenerator : public NonModifyingVisitor {
void Visit(const LoopInitNode&) override;
void Visit(const DeclVarNode&) override;
void Visit(const DeclArrNode&) override;
void Visit(const RecordDeclNode&) override;
void Visit(const FieldNode&) override;
void Visit(const ParamNode&) override;
void Visit(const FuncDefNode&) override;
void Visit(const CompoundStmtNode&) override;
Expand Down
2 changes: 2 additions & 0 deletions include/type_checker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class TypeChecker : public ModifyingVisitor {
void Visit(LoopInitNode&) override;
void Visit(DeclVarNode&) override;
void Visit(DeclArrNode&) override;
void Visit(RecordDeclNode&) override;
void Visit(FieldNode&) override;
void Visit(ParamNode&) override;
void Visit(FuncDefNode&) override;
void Visit(CompoundStmtNode&) override;
Expand Down
4 changes: 4 additions & 0 deletions include/visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ struct ExprNode;
struct DeclNode;
struct DeclVarNode;
struct DeclArrNode;
struct RecordDeclNode;
struct FieldNode;
struct ParamNode;
struct FuncDefNode;
struct LoopInitNode;
Expand Down Expand Up @@ -64,6 +66,8 @@ class Visitor {
virtual void Visit(CondMut<DeclNode>&){};
virtual void Visit(CondMut<DeclVarNode>&){};
virtual void Visit(CondMut<DeclArrNode>&){};
virtual void Visit(CondMut<RecordDeclNode>&){};
virtual void Visit(CondMut<FieldNode>&){};
virtual void Visit(CondMut<ParamNode>&){};
virtual void Visit(CondMut<FuncDefNode>&){};
virtual void Visit(CondMut<LoopInitNode>&){};
Expand Down
92 changes: 74 additions & 18 deletions parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -384,20 +384,28 @@ 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 SEMICOLON {
auto decl = $2;
decl->type = ResolveType($1, std::move(decl->type));
$$ = std::move(decl);
decl: declaration_specifiers init_declarator_opt SEMICOLON {
auto decl_specifers = $1;
auto init_decl = $2;
if (std::holds_alternative<std::unique_ptr<Type>>(decl_specifers)) {
auto type = std::move(std::get<std::unique_ptr<Type>>(decl_specifers));
init_decl->type = ResolveType(std::move(type), std::move(init_decl->type));
$$ = std::move(init_decl);
} else {
auto decl = std::move(std::get<std::unique_ptr<DeclNode>>(decl_specifers));
$$ = std::move(decl);
}
}
;

/* A declaration specifier declares part of the type of a declarator. */
/* TODO: storage class specifier, type qualifier, function specifier */
declaration_specifiers: type_specifier declaration_specifiers {
// Leave unimplemented; useless without support of other specifiers.
$$ = nullptr;
$$ = $1;
}
| type_specifier { $$ = $1; }
;
Expand Down Expand Up @@ -436,38 +444,86 @@ type_specifier: INT { $$ = std::make_unique<PrimType>(PrimitiveType::kInt); }
/* TODO: typedef name */
;

// Create a type struct or union
struct_or_union_specifier: struct_or_union id_opt LEFT_CURLY struct_declaration_list RIGHT_CURLY {}
| struct_or_union ID {}
struct_or_union_specifier: struct_or_union id_opt LEFT_CURLY struct_declaration_list RIGHT_CURLY {
// Field types for variable 'type' are unknown until now.
auto type = $1;
auto decl_id = $2;
auto field_list = $4;
auto field_types = std::vector<std::unique_ptr<Type>>{};
for (const auto& field : field_list) {
field_types.push_back(field->type->Clone());
}

if (dynamic_cast<StructType*>(type.get())) {
type = std::make_unique<StructType>(std::move(field_types));
} else {
type = std::make_unique<UnionType>(std::move(field_types));
}

if (decl_id) {
$$ = std::make_unique<RecordDeclNode>(Loc(@2), std::move(decl_id->id), std::move(type), std::move(field_list));
} else {
$$ = std::make_unique<RecordDeclNode>(Loc(@2), /* no id */ "", std::move(type), std::move(field_list));
}
}
| struct_or_union ID {
auto field_list = std::vector<std::unique_ptr<FieldNode>>{};
$$ = std::make_unique<RecordDeclNode>(Loc(@2), $2, $1, std::move(field_list));
}
;

struct_declaration_list: struct_declaration {}
| struct_declaration_list struct_declaration {}
struct_declaration_list: struct_declaration {
$$ = std::vector<std::unique_ptr<FieldNode>>{};
$$.push_back($1);
}
| struct_declaration_list struct_declaration {
$$ = $1;
$$.push_back($2);
}
;

/* TODO: struct_declarator_list_opt */
struct_declaration: specifier_qualifier_list struct_declarator_list SEMICOLON {}
struct_declaration: specifier_qualifier_list struct_declarator_list SEMICOLON {
auto type = $1;
auto decl = $2;
decl->type = ResolveType(std::move(type), std::move(decl->type));
$$ = std::move(decl);
}
;

struct_declarator_list: struct_declarator {}
struct_declarator_list: struct_declarator { $$ = $1; }
| struct_declarator_list COMMA struct_declarator
;

/* TODO: declarator_opt COLON const_expr */
struct_declarator: declarator {}
struct_declarator: declarator {
auto decl = $1;
$$ = std::make_unique<FieldNode>(Loc(@1), std::move(decl->id), std::move(decl->type));
}
;

/* TODO: type_qualifier specifier_qualifier_list_opt */
specifier_qualifier_list: type_specifier {}
specifier_qualifier_list: type_specifier {
$$ = std::move(std::get<std::unique_ptr<Type>>($1));
}
;

/* Identifier_opt is used for struct, union, enum. */
id_opt: ID {}
| epsilon {}
id_opt: ID {
auto type = std::make_unique<PrimType>(PrimitiveType::kUnknown);
$$ = std::make_unique<DeclVarNode>(Loc(@1), $1, std::move(type));
}
| epsilon { $$ = nullptr; }
;

struct_or_union: STRUCT {}
| UNION {}
struct_or_union: STRUCT {
auto field_types = std::vector<std::unique_ptr<Type>>{};
$$ = std::make_unique<StructType>(std::move(field_types));
}
| UNION {
auto field_types = std::vector<std::unique_ptr<Type>>{};
$$ = std::make_unique<UnionType>(std::move(field_types));
}
;

/* 6.7.5 Declarators */
Expand Down
12 changes: 2 additions & 10 deletions src/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,11 @@ void DeclArrNode::Accept(ModifyingVisitor& v) {
v.Visit(*this);
}

void DefStructNode::Accept(NonModifyingVisitor& v) const {
void RecordDeclNode::Accept(NonModifyingVisitor& v) const {
v.Visit(*this);
}

void DefStructNode::Accept(ModifyingVisitor& v) {
v.Visit(*this);
}

void DefUnionNode::Accept(NonModifyingVisitor& v) const {
v.Visit(*this);
}

void DefUnionNode::Accept(ModifyingVisitor& v) {
void RecordDeclNode::Accept(ModifyingVisitor& v) {
v.Visit(*this);
}

Expand Down
20 changes: 20 additions & 0 deletions src/ast_dumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,26 @@ void AstDumper::Visit(const DeclArrNode& arr_decl) {
indenter_.DecreaseLevel();
}

void AstDumper::Visit(const RecordDeclNode& record_decl) {
std::string id = "";
if (!record_decl.id.empty()) {
id += " " + record_decl.id;
}
std::cout << indenter_.Indent() << "RecordDeclNode <" << record_decl.loc
<< "> " << record_decl.type->ToString() << id << " definition\n";

indenter_.IncreaseLevel();
for (const auto& field : record_decl.field_list) {
field->Accept(*this);
}
indenter_.DecreaseLevel();
}

void AstDumper::Visit(const FieldNode& field) {
std::cout << indenter_.Indent() << "FieldNode <" << field.loc << "> "
<< field.id << ": " << field.type->ToString() << '\n';
}

void AstDumper::Visit(const ParamNode& parameter) {
std::cout << indenter_.Indent() << "ParamNode <" << parameter.loc << "> "
<< parameter.id << ": " << parameter.type->ToString() << '\n';
Expand Down
4 changes: 4 additions & 0 deletions src/qbe_ir_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ void QbeIrGenerator::Visit(const DeclArrNode& arr_decl) {
}
}

void QbeIrGenerator::Visit(const RecordDeclNode& struct_def) {}

void QbeIrGenerator::Visit(const FieldNode& field) {}

void QbeIrGenerator::Visit(const ParamNode& parameter) {
int id_num = NextLocalNum();
// TODO: support different data types
Expand Down
16 changes: 3 additions & 13 deletions src/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
#include <utility>
#include <vector>

#include "ast.hpp"

bool Type::IsEqual(PrimitiveType that) const noexcept {
return IsEqual(PrimType{that});
}
Expand Down Expand Up @@ -180,11 +178,7 @@ std::size_t StructType::size() const {
}

std::string StructType::ToString() const {
if (field_types_.size() > 0) {
return "definition";
}

return "";
return "struct";
}

std::unique_ptr<Type> StructType::Clone() const {
Expand All @@ -208,11 +202,7 @@ std::size_t UnionType::size() const {
}

std::string UnionType::ToString() const {
if (field_types_.size() > 0) {
return "definition";
}

return "";
return "union";
}

std::unique_ptr<Type> UnionType::Clone() const {
Expand All @@ -221,4 +211,4 @@ std::unique_ptr<Type> UnionType::Clone() const {
cloned_field_types.push_back(field_type->Clone());
}
return std::make_unique<UnionType>(std::move(cloned_field_types));
}
}
8 changes: 8 additions & 0 deletions src/type_checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ void TypeChecker::Visit(DeclArrNode& arr_decl) {
// TODO: Check initializer type
}

void TypeChecker::Visit(RecordDeclNode& struct_def) {
// TODO: Store record declaration in a new table under scope.
}

void TypeChecker::Visit(FieldNode& field) {
// TODO: Store field in corresponding record declaration, e.g., struct, union.
}

void TypeChecker::Visit(ParamNode& parameter) {
if (env_.Probe(parameter.id)) {
// TODO: redefinition of 'id'
Expand Down
17 changes: 17 additions & 0 deletions test/typecheck/struct.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
int main() {
struct ss;

struct birth {
int date;
int month;
int year;
};

struct {
int quarter;
int dime;
int penny;
};

return 0;
}
14 changes: 14 additions & 0 deletions test/typecheck/struct.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
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
ReturnStmtNode <16:3>
IntConstExprNode <16:10> 0: int
19 changes: 19 additions & 0 deletions test/typecheck/union.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
int main() {
union u;

union shape {
int square;
int circle;
int triangle;
};

union {
int a;
int b;
int c;
int d;
int e;
};

return 0;
}
16 changes: 16 additions & 0 deletions test/typecheck/union.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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
ReturnStmtNode <18:3>
IntConstExprNode <18:10> 0: int

0 comments on commit 04ee10a

Please sign in to comment.