diff --git a/Project-02-03-04/Source.gv.png b/Project-02-03-04/Source.gv.png new file mode 100644 index 0000000..bde5764 Binary files /dev/null and b/Project-02-03-04/Source.gv.png differ diff --git a/Project-02-03-04/cfg_build.py b/Project-02-03-04/cfg_build.py index 4e7ebfa..193d933 100644 --- a/Project-02-03-04/cfg_build.py +++ b/Project-02-03-04/cfg_build.py @@ -8,174 +8,150 @@ from cfg.CFG_Node import ( import compiler import syntax - -# ------------------------------------------------- -# Global function environment -# ------------------------------------------------- - -FUNCTIONS = {} # name -> (func_start, func_end) - - -# ------------------------------------------------- -# Expressions — NO CFG NODES -# ------------------------------------------------- +FUNCTIONS = {} class CONST(compiler.CONST): def cfa(self, pred, end): - return pred - + n = CFG_Node(self) + pred.add_child(n) + n.add_child(end) if end else None + return n class ID(compiler.ID): def cfa(self, pred, end): - return pred - + n = CFG_Node(self) + pred.add_child(n) + n.add_child(end) if end else None + return n class AOP(compiler.AOP): def cfa(self, pred, end): - return pred - + left_node = self.arg1.cfa(pred, None) + right_node = self.arg2.cfa(left_node, None) + op_node = CFG_Node(self) + right_node.add_child(op_node) + op_node.add_child(end) if end else None + return op_node class COMP(compiler.COMP): def cfa(self, pred, end): - return pred - + left_node = self.arg1.cfa(pred, None) + right_node = self.arg2.cfa(left_node, None) + comp_node = CFG_Node(self.operator) + right_node.add_child(comp_node) + comp_node.add_child(end) if end else None + return comp_node class EQOP(compiler.EQOP): def cfa(self, pred, end): - return pred - + left_node = self.arg1.cfa(pred, None) + right_node = self.arg2.cfa(left_node, None) + eqop_node = CFG_Node(self) + right_node.add_child(eqop_node) + eqop_node.add_child(end) if end else None + return eqop_node class LOP(compiler.LOP): def cfa(self, pred, end): - return pred - - -# ------------------------------------------------- -# Statements -# ------------------------------------------------- + n = CFG_Node(self) + pred.add_child(n) + n.add_child(end) if end else None + return n class ASSIGN(compiler.ASSIGN): def cfa(self, pred, end): - n = CFG_Node(self) - pred.add_child(n) - return n - + expr_node = self.expr.cfa(pred, None) + assign_node = CFG_Node(self) + expr_node.add_child(assign_node) + assign_node.add_child(end) if end else None + return assign_node class SEQ(compiler.SEQ): def cfa(self, pred, end): - mid = self.exp1.cfa(pred, end) + mid = self.exp1.cfa(pred, None) if mid is None: return None return self.exp2.cfa(mid, end) - class IF(compiler.IF): def cfa(self, pred, end): - # decision node (condition only) - cond = CFG_DIAMOND(self.cond) - pred.add_child(cond) - - # explicit branch entries + cond_node = self.cond.cfa(pred, None) + diamond = CFG_DIAMOND(self.cond) + cond_node.add_child(diamond) then_entry = CFG_Node() else_entry = CFG_Node() - cond.add_child(then_entry) - cond.add_child(else_entry) - - # join node + diamond.add_child(then_entry) + diamond.add_child(else_entry) join = CFG_Node() - - then_end = self.exp1.cfa(then_entry, end) - else_end = self.exp2.cfa(else_entry, end) - - if then_end is not None: - then_end.add_child(join) - if else_end is not None: - else_end.add_child(join) - + join.add_child(end) if end else None + then_end = self.exp1.cfa(then_entry, join) + else_end = self.exp2.cfa(else_entry, join) return join - class WHILE(compiler.WHILE): def cfa(self, pred, end): - # loop condition - cond = CFG_DIAMOND(self.cond) - pred.add_child(cond) - - # body entry + cond_node = self.cond.cfa(pred, None) + diamond = CFG_DIAMOND(self.cond) + cond_node.add_child(diamond) body_entry = CFG_Node() - cond.add_child(body_entry) - - body_end = self.body.cfa(body_entry, end) + diamond.add_child(body_entry) + body_end = self.body.cfa(body_entry, diamond) if body_end is not None: - body_end.add_child(cond) # back-edge - - # loop exit + body_end.add_child(diamond) after = CFG_Node() - cond.add_child(after) - + diamond.add_child(after) + after.add_child(end) if end else None return after - -# ------------------------------------------------- -# Functions / calls (interprocedural CFG) -# ------------------------------------------------- - class CALL(compiler.CALL): def cfa(self, pred, end): - call = CFG_CALL(self) - pred.add_child(call) + call_node = CFG_Node(self) + call_node.label = f"START {self.f_name}({', '.join(map(str, self.arg))})" + pred.add_child(call_node) - # continuation after return cont = CFG_Node() + cont.add_child(end) if end else None if self.f_name not in FUNCTIONS: raise RuntimeError(f"Call to undefined function '{self.f_name}'") f_start, f_end = FUNCTIONS[self.f_name] - # call → function entry - call.add_child(f_start) - - # function exit → continuation - f_end.add_child(cont) + # Create return node from function + return_node = CFG_Node(self) + return_node.label = f"END {self.f_name}({', '.join(map(str, self.arg))})" + f_end.add_child(return_node) + return_node.add_child(cont) + call_node.add_child(f_start) return cont - class DECL(compiler.DECL): def cfa(self, pred, end): - # function entry / exit f_start = CFG_Node(self) + f_start.label = f"START {self.f_name}({', '.join(self.params)})" f_end = CFG_Node(self) + f_end.label = f"END {self.f_name}({', '.join(self.params)})" - # register function FUNCTIONS[self.f_name] = (f_start, f_end) - - # build function body body_end = self.body.cfa(f_start, f_end) if body_end is not None: body_end.add_child(f_end) - - # function declaration does not alter current control flow return pred - class LET(compiler.LET): def cfa(self, pred, end): current = pred - decls = self.decl if isinstance(self.decl, list) else [self.decl] for d in decls: - current = d.cfa(current, end) + current = d.cfa(current, None) if current is None: return None - return self.body.cfa(current, end) - class RETURN(syntax.EXPRESSION): def cfa(self, pred, end): n = CFG_RETURN(self) pred.add_child(n) - n.add_child(end) # return to function exit - return None # no fallthrough + n.add_child(end) + return None diff --git a/Project-02-03-04/example_cfg.dot b/Project-02-03-04/example_cfg.dot new file mode 100644 index 0000000..8262d1b --- /dev/null +++ b/Project-02-03-04/example_cfg.dot @@ -0,0 +1,64 @@ +digraph CFG { + node [fontname="Helvetica"]; + n31 [label="START", shape=circle]; + n31 -> n59; + n59 [label="f(2,3)", shape=box]; + n59 -> n33; + n33 [label="f(['x', 'y', 'z']) { y = 2; z = 3; let g(['x']) { x = 7; if ((y > 0)) then { g(y) } else { x = 8 }; x } in (g(x) + x) }", shape=box]; + n33 -> n35; + n35 [label="2", shape=box]; + n35 -> n36; + n36 [label="y = 2", shape=box]; + n36 -> n37; + n37 [label="3", shape=box]; + n37 -> n38; + n38 [label="z = 3", shape=box]; + n38 -> n55; + n55 [label="g(x)", shape=box]; + n55 -> n39; + n39 [label="g(['x']) { x = 7; if ((y > 0)) then { g(y) } else { x = 8 }; x }", shape=box]; + n39 -> n41; + n41 [label="7", shape=box]; + n41 -> n42; + n42 [label="x = 7", shape=box]; + n42 -> n43; + n43 [label="y", shape=box]; + n43 -> n44; + n44 [label="0", shape=box]; + n44 -> n45; + n45 [label="(y > 0)", shape=box]; + n45 -> n46; + n46 [label="(y > 0)", shape=diamond]; + n46 -> n47; + n47 [label="", shape=box]; + n47 -> n50; + n50 [label="g(y)", shape=box]; + n50 -> n39; + n46 -> n48; + n48 [label="", shape=box]; + n48 -> n52; + n52 [label="8", shape=box]; + n52 -> n53; + n53 [label="x = 8", shape=box]; + n53 -> n49; + n49 [label="", shape=box]; + n49 -> n54; + n54 [label="x", shape=box]; + n54 -> n40; + n40 [label="g(['x']) { x = 7; if ((y > 0)) then { g(y) } else { x = 8 }; x }", shape=box]; + n40 -> n51; + n51 [label="", shape=box]; + n51 -> n49; + n40 -> n56; + n56 [label="", shape=box]; + n56 -> n57; + n57 [label="x", shape=box]; + n57 -> n58; + n58 [label="(g(x) + x)", shape=box]; + n58 -> n34; + n34 [label="f(['x', 'y', 'z']) { y = 2; z = 3; let g(['x']) { x = 7; if ((y > 0)) then { g(y) } else { x = 8 }; x } in (g(x) + x) }", shape=box]; + n34 -> n60; + n60 [label="", shape=box]; + n60 -> n32; + n32 [label="END", shape=doublecircle]; +} \ No newline at end of file diff --git a/Project-02-03-04/triplaprograms/example.tripla b/Project-02-03-04/triplaprograms/example.tripla new file mode 100644 index 0000000..249bb65 --- /dev/null +++ b/Project-02-03-04/triplaprograms/example.tripla @@ -0,0 +1,11 @@ +let f(x,y,z) { + y=2; + z=3; + let g(x) { + x=7; + if (y>0) + then g(y) + else x=8; + x + } in g(x)+x +} in f(2,3) \ No newline at end of file