Joos1W Compiler Framework
All Classes Functions Typedefs Pages
CFGBuilder.cc
1 #include "semantic/CFGBuilder.h"
2 
3 #include <cassert>
4 
5 #include "ast/AstNode.h"
6 #include "ast/Stmt.h"
7 #include "utils/Utils.h"
8 
9 namespace semantic {
10 
11 CFGBuilder::CFGInfo CFGBuilder::buildIteratively(const ast::Stmt* stmt,
12  CFGNode* parent) {
13  using CFGInfo = CFGBuilder::CFGInfo;
14  assert(stmt && "stmt is nullptr");
15  CFGInfo node = {alloc, nullptr};
16  if(auto forStmt = dyn_cast<ast::ForStmt>(stmt)) {
17  node = buildForStmt(forStmt);
18  } else if(auto ifStmt = dyn_cast<ast::IfStmt>(stmt)) {
19  node = buildIfStmt(ifStmt);
20  } else if(auto declStmt = dyn_cast<ast::DeclStmt>(stmt)) {
21  node = buildDeclStmt(declStmt);
22  } else if(auto exprStmt = dyn_cast<ast::ExprStmt>(stmt)) {
23  node = buildExprStmt(exprStmt);
24  } else if(auto returnStmt = dyn_cast<ast::ReturnStmt>(stmt)) {
25  node = buildReturnStmt(returnStmt);
26  } else if(auto whileStmt = dyn_cast<ast::WhileStmt>(stmt)) {
27  node = buildWhileStmt(whileStmt);
28  } else if(auto blockStmt = dyn_cast<ast::BlockStatement>(stmt)) {
29  node = buildBlockStmt(blockStmt);
30  if(!node.head) {
31  CFGNode* empty = alloc.new_object<CFGNode>(alloc, CFGNode::EmptyExpr{});
32  return CFGInfo{alloc, empty, empty};
33  }
34  } else {
35  CFGNode* empty = alloc.new_object<CFGNode>(alloc, CFGNode::EmptyExpr{});
36  return CFGInfo{alloc, empty, empty};
37  }
38 
39  assert(node.head && "node is nullptr");
40 
41  if(parent) {
42  connectCFGNode(parent, node.head);
43  }
44  return node;
45 }
46 
47 CFGBuilder::CFGInfo CFGBuilder::buildBlockStmt(
48  const ast::BlockStatement* blockStmt) {
49  CFGInfo node = {alloc, nullptr}, parent = {alloc, nullptr},
50  head = {alloc, nullptr};
51  for(auto stmt : blockStmt->stmts()) {
52  if(parent.head == nullptr) {
53  parent = buildIteratively(stmt);
54  head = parent;
55  } else {
56  node = buildIteratively(stmt);
57  connectLeafsToChild(parent, node.head);
58  parent = node;
59  }
60  }
61  CFGInfo info = CFGInfo{alloc, head.head};
62  for(auto leaf : parent.leafs) {
63  info.leafs.push_back(leaf);
64  }
65  return info;
66 }
67 
68 CFGBuilder::CFGInfo CFGBuilder::buildDeclStmt(const ast::DeclStmt* declStmt) {
69  CFGNode* node = alloc.new_object<CFGNode>(alloc, declStmt->decl());
70  return CFGInfo{alloc, node, node};
71 }
72 
73 CFGBuilder::CFGInfo CFGBuilder::buildExprStmt(const ast::ExprStmt* exprStmt) {
74  CFGNode* node = alloc.new_object<CFGNode>(alloc, exprStmt->expr());
75  return CFGInfo{alloc, node, node};
76 }
77 
78 CFGBuilder::CFGInfo CFGBuilder::buildForStmt(const ast::ForStmt* forStmt) {
79  CFGNode* condition = nullptr;
80  CFGInfo init = {alloc, nullptr};
81  if(forStmt->init()) {
82  init = buildIteratively(forStmt->init());
83  }
84 
85  if(forStmt->condition()) {
86  condition = alloc.new_object<CFGNode>(alloc, forStmt->condition());
87  ConstantReturnType const* ret =
88  constTypeResolver->Evaluate(forStmt->condition());
89 
90  if(ret->constantType == ConstantReturnType::type::BOOL) {
91  if(ret->value == 0) {
92  diag.ReportError(forStmt->condition()->location())
93  << "Unreachable statement in for loop body";
94  } else {
95  assert(ret->value == 1 && "invalid boolean value");
96  }
97  }
98  } else {
99  condition = alloc.new_object<CFGNode>(alloc, CFGNode::EmptyExpr{});
100  }
101 
102  if(init.head) connectCFGNode(init.head, condition);
103  CFGInfo body = buildIteratively(forStmt->body(), condition);
104  if(forStmt->update()) {
105  CFGInfo update = buildIteratively(forStmt->update());
106  connectLeafsToChild(body, update.head);
107  connectLeafsToChild(update, condition);
108  } else {
109  connectLeafsToChild(body, condition);
110  }
111  if(init.head) return CFGInfo{alloc, init.head, condition};
112  return CFGInfo{alloc, condition, condition};
113 }
114 
115 CFGBuilder::CFGInfo CFGBuilder::buildIfStmt(const ast::IfStmt* ifStmt) {
116  CFGNode* condition = alloc.new_object<CFGNode>(alloc, ifStmt->condition());
117 
118  CFGInfo info = {alloc, condition};
119  // by java rules, we allow if statements to have a constant condition
120  CFGInfo ifNode = buildIteratively(ifStmt->thenStmt(), condition);
121  info.leafs.insert(info.leafs.end(), ifNode.leafs.begin(), ifNode.leafs.end());
122  if(ifStmt->elseStmt()) {
123  CFGInfo elseNode = buildIteratively(ifStmt->elseStmt(), condition);
124  info.leafs.insert(
125  info.leafs.end(), elseNode.leafs.begin(), elseNode.leafs.end());
126  } else {
127  CFGNode* empty = alloc.new_object<CFGNode>(alloc, CFGNode::EmptyExpr{});
128  info.leafs.push_back(empty);
129  connectCFGNode(condition, empty);
130  }
131  return info;
132 }
133 
134 CFGBuilder::CFGInfo CFGBuilder::buildReturnStmt(
135  const ast::ReturnStmt* returnStmt) {
136  CFGNode* node = nullptr;
137  if(returnStmt->expr() == nullptr) {
138  node = alloc.new_object<CFGNode>(alloc, CFGNode::EmptyExpr{}, true);
139  } else {
140  node = alloc.new_object<CFGNode>(alloc, returnStmt->expr(), true);
141  }
142  return CFGInfo{alloc, node, node};
143 }
144 
145 CFGBuilder::CFGInfo CFGBuilder::buildWhileStmt(const ast::WhileStmt* whileStmt) {
146  CFGNode* condition = alloc.new_object<CFGNode>(alloc, whileStmt->condition());
147  ConstantReturnType const* ret =
148  constTypeResolver->Evaluate(whileStmt->condition());
149  CFGNode* leafNode = condition;
150  if(ret->constantType == ConstantReturnType::type::BOOL) {
151  if(ret->value == 0) {
152  diag.ReportError(whileStmt->condition()->location())
153  << "Unreachable statement in while loop body";
154  } else if(ret->value == 1) {
155  condition->setVisited(true);
156  leafNode = nullptr;
157  } else {
158  assert(false && "invalid boolean value");
159  }
160  }
161 
162  if(whileStmt->body()) {
163  CFGInfo body = buildIteratively(whileStmt->body(), condition);
164  connectLeafsToChild(body, condition);
165  }
166  if(leafNode) {
167  return CFGInfo{alloc, condition, leafNode};
168  }
169  return CFGInfo{alloc, condition};
170 }
171 
172 void CFGBuilder::connectCFGNode(CFGNode* parent, CFGNode* child) {
173  parent->children.push_back(child);
174  child->parents.push_back(parent);
175 }
176 
177 void CFGBuilder::connectLeafsToChild(CFGInfo parent, CFGNode* child) {
178  for(auto leaf : parent.leafs) {
179  connectCFGNode(leaf, child);
180  }
181  if(child->parents.empty()) {
182  if(child->location()) {
183  diag.ReportError(child->location().value()) << "Unreachable statement";
184  } else {
185  diag.ReportError(parent.head->location().value()) << "Unreachable statement";
186  }
187  }
188 }
189 
190 } // namespace semantic