try to improve diagrams
This commit is contained in:
BIN
Project-02-03-04/Source.gv.png
Normal file
BIN
Project-02-03-04/Source.gv.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -8,174 +8,150 @@ from cfg.CFG_Node import (
|
|||||||
import compiler
|
import compiler
|
||||||
import syntax
|
import syntax
|
||||||
|
|
||||||
|
FUNCTIONS = {}
|
||||||
# -------------------------------------------------
|
|
||||||
# Global function environment
|
|
||||||
# -------------------------------------------------
|
|
||||||
|
|
||||||
FUNCTIONS = {} # name -> (func_start, func_end)
|
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------
|
|
||||||
# Expressions — NO CFG NODES
|
|
||||||
# -------------------------------------------------
|
|
||||||
|
|
||||||
class CONST(compiler.CONST):
|
class CONST(compiler.CONST):
|
||||||
def cfa(self, pred, end):
|
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):
|
class ID(compiler.ID):
|
||||||
def cfa(self, pred, end):
|
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):
|
class AOP(compiler.AOP):
|
||||||
def cfa(self, pred, end):
|
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):
|
class COMP(compiler.COMP):
|
||||||
def cfa(self, pred, end):
|
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):
|
class EQOP(compiler.EQOP):
|
||||||
def cfa(self, pred, end):
|
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):
|
class LOP(compiler.LOP):
|
||||||
def cfa(self, pred, end):
|
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
|
||||||
# Statements
|
|
||||||
# -------------------------------------------------
|
|
||||||
|
|
||||||
class ASSIGN(compiler.ASSIGN):
|
class ASSIGN(compiler.ASSIGN):
|
||||||
def cfa(self, pred, end):
|
def cfa(self, pred, end):
|
||||||
n = CFG_Node(self)
|
expr_node = self.expr.cfa(pred, None)
|
||||||
pred.add_child(n)
|
assign_node = CFG_Node(self)
|
||||||
return n
|
expr_node.add_child(assign_node)
|
||||||
|
assign_node.add_child(end) if end else None
|
||||||
|
return assign_node
|
||||||
|
|
||||||
class SEQ(compiler.SEQ):
|
class SEQ(compiler.SEQ):
|
||||||
def cfa(self, pred, end):
|
def cfa(self, pred, end):
|
||||||
mid = self.exp1.cfa(pred, end)
|
mid = self.exp1.cfa(pred, None)
|
||||||
if mid is None:
|
if mid is None:
|
||||||
return None
|
return None
|
||||||
return self.exp2.cfa(mid, end)
|
return self.exp2.cfa(mid, end)
|
||||||
|
|
||||||
|
|
||||||
class IF(compiler.IF):
|
class IF(compiler.IF):
|
||||||
def cfa(self, pred, end):
|
def cfa(self, pred, end):
|
||||||
# decision node (condition only)
|
cond_node = self.cond.cfa(pred, None)
|
||||||
cond = CFG_DIAMOND(self.cond)
|
diamond = CFG_DIAMOND(self.cond)
|
||||||
pred.add_child(cond)
|
cond_node.add_child(diamond)
|
||||||
|
|
||||||
# explicit branch entries
|
|
||||||
then_entry = CFG_Node()
|
then_entry = CFG_Node()
|
||||||
else_entry = CFG_Node()
|
else_entry = CFG_Node()
|
||||||
cond.add_child(then_entry)
|
diamond.add_child(then_entry)
|
||||||
cond.add_child(else_entry)
|
diamond.add_child(else_entry)
|
||||||
|
|
||||||
# join node
|
|
||||||
join = CFG_Node()
|
join = CFG_Node()
|
||||||
|
join.add_child(end) if end else None
|
||||||
then_end = self.exp1.cfa(then_entry, end)
|
then_end = self.exp1.cfa(then_entry, join)
|
||||||
else_end = self.exp2.cfa(else_entry, end)
|
else_end = self.exp2.cfa(else_entry, join)
|
||||||
|
|
||||||
if then_end is not None:
|
|
||||||
then_end.add_child(join)
|
|
||||||
if else_end is not None:
|
|
||||||
else_end.add_child(join)
|
|
||||||
|
|
||||||
return join
|
return join
|
||||||
|
|
||||||
|
|
||||||
class WHILE(compiler.WHILE):
|
class WHILE(compiler.WHILE):
|
||||||
def cfa(self, pred, end):
|
def cfa(self, pred, end):
|
||||||
# loop condition
|
cond_node = self.cond.cfa(pred, None)
|
||||||
cond = CFG_DIAMOND(self.cond)
|
diamond = CFG_DIAMOND(self.cond)
|
||||||
pred.add_child(cond)
|
cond_node.add_child(diamond)
|
||||||
|
|
||||||
# body entry
|
|
||||||
body_entry = CFG_Node()
|
body_entry = CFG_Node()
|
||||||
cond.add_child(body_entry)
|
diamond.add_child(body_entry)
|
||||||
|
body_end = self.body.cfa(body_entry, diamond)
|
||||||
body_end = self.body.cfa(body_entry, end)
|
|
||||||
if body_end is not None:
|
if body_end is not None:
|
||||||
body_end.add_child(cond) # back-edge
|
body_end.add_child(diamond)
|
||||||
|
|
||||||
# loop exit
|
|
||||||
after = CFG_Node()
|
after = CFG_Node()
|
||||||
cond.add_child(after)
|
diamond.add_child(after)
|
||||||
|
after.add_child(end) if end else None
|
||||||
return after
|
return after
|
||||||
|
|
||||||
|
|
||||||
# -------------------------------------------------
|
|
||||||
# Functions / calls (interprocedural CFG)
|
|
||||||
# -------------------------------------------------
|
|
||||||
|
|
||||||
class CALL(compiler.CALL):
|
class CALL(compiler.CALL):
|
||||||
def cfa(self, pred, end):
|
def cfa(self, pred, end):
|
||||||
call = CFG_CALL(self)
|
call_node = CFG_Node(self)
|
||||||
pred.add_child(call)
|
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 = CFG_Node()
|
||||||
|
cont.add_child(end) if end else None
|
||||||
|
|
||||||
if self.f_name not in FUNCTIONS:
|
if self.f_name not in FUNCTIONS:
|
||||||
raise RuntimeError(f"Call to undefined function '{self.f_name}'")
|
raise RuntimeError(f"Call to undefined function '{self.f_name}'")
|
||||||
|
|
||||||
f_start, f_end = FUNCTIONS[self.f_name]
|
f_start, f_end = FUNCTIONS[self.f_name]
|
||||||
|
|
||||||
# call → function entry
|
# Create return node from function
|
||||||
call.add_child(f_start)
|
return_node = CFG_Node(self)
|
||||||
|
return_node.label = f"END {self.f_name}({', '.join(map(str, self.arg))})"
|
||||||
# function exit → continuation
|
f_end.add_child(return_node)
|
||||||
f_end.add_child(cont)
|
return_node.add_child(cont)
|
||||||
|
|
||||||
|
call_node.add_child(f_start)
|
||||||
return cont
|
return cont
|
||||||
|
|
||||||
|
|
||||||
class DECL(compiler.DECL):
|
class DECL(compiler.DECL):
|
||||||
def cfa(self, pred, end):
|
def cfa(self, pred, end):
|
||||||
# function entry / exit
|
|
||||||
f_start = CFG_Node(self)
|
f_start = CFG_Node(self)
|
||||||
|
f_start.label = f"START {self.f_name}({', '.join(self.params)})"
|
||||||
f_end = CFG_Node(self)
|
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)
|
FUNCTIONS[self.f_name] = (f_start, f_end)
|
||||||
|
|
||||||
# build function body
|
|
||||||
body_end = self.body.cfa(f_start, f_end)
|
body_end = self.body.cfa(f_start, f_end)
|
||||||
if body_end is not None:
|
if body_end is not None:
|
||||||
body_end.add_child(f_end)
|
body_end.add_child(f_end)
|
||||||
|
|
||||||
# function declaration does not alter current control flow
|
|
||||||
return pred
|
return pred
|
||||||
|
|
||||||
|
|
||||||
class LET(compiler.LET):
|
class LET(compiler.LET):
|
||||||
def cfa(self, pred, end):
|
def cfa(self, pred, end):
|
||||||
current = pred
|
current = pred
|
||||||
|
|
||||||
decls = self.decl if isinstance(self.decl, list) else [self.decl]
|
decls = self.decl if isinstance(self.decl, list) else [self.decl]
|
||||||
for d in decls:
|
for d in decls:
|
||||||
current = d.cfa(current, end)
|
current = d.cfa(current, None)
|
||||||
if current is None:
|
if current is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self.body.cfa(current, end)
|
return self.body.cfa(current, end)
|
||||||
|
|
||||||
|
|
||||||
class RETURN(syntax.EXPRESSION):
|
class RETURN(syntax.EXPRESSION):
|
||||||
def cfa(self, pred, end):
|
def cfa(self, pred, end):
|
||||||
n = CFG_RETURN(self)
|
n = CFG_RETURN(self)
|
||||||
pred.add_child(n)
|
pred.add_child(n)
|
||||||
n.add_child(end) # return to function exit
|
n.add_child(end)
|
||||||
return None # no fallthrough
|
return None
|
||||||
|
|||||||
64
Project-02-03-04/example_cfg.dot
Normal file
64
Project-02-03-04/example_cfg.dot
Normal file
@@ -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];
|
||||||
|
}
|
||||||
11
Project-02-03-04/triplaprograms/example.tripla
Normal file
11
Project-02-03-04/triplaprograms/example.tripla
Normal file
@@ -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)
|
||||||
Reference in New Issue
Block a user