New project structure

This commit is contained in:
Jan-Niclas Loosen
2026-03-03 16:45:00 +01:00
parent 9c18e5e044
commit 8a40cb2636
98 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1 @@
Author: Jan-Niclas Loosen (1540907)

View File

@@ -0,0 +1,117 @@
from typing import Any, Callable, Set
from .CFG_Node import *
class CFG:
def __init__(self, ast):
start = CFG_START()
start.dot_style = 'style=filled, color=gray'
end = CFG_END()
end.dot_style = 'style=filled, color=gray'
last = ast.cfa(start, end)
if last is not None:
last.add_child(end)
self.START = start
self.END = end
self.ast = ast
# Remove empty nodes and rewire edges
all_nodes = self.nodes()
nodes_to_remove = [node for node in all_nodes if node.is_empty()]
for node in nodes_to_remove:
self.__remove_and_rewire(node)
def nodes(self):
all_nodes = set()
self.__collect_nodes(self.START, all_nodes)
return all_nodes
def __collect_nodes(self, node, node_set):
if node in node_set:
return
node_set.add(node)
for child in node.children:
self.__collect_nodes(child, node_set)
def __remove_and_rewire(self, node):
original_children = list(node.children)
for parent in list(node.parents):
if node in parent.children:
# For diamond nodes, preserve the true and false bodies
if isinstance(node, CFG_DIAMOND):
targets = []
if len(original_children) >= 1:
true_target = self.__first_filled_child(original_children[0])
if true_target:
targets.append(true_target)
if len(original_children) >= 2:
false_target = self.__first_filled_child(original_children[1])
if false_target:
targets.append(false_target)
# For regular nodes, find all non-empty targets
else:
targets = []
for child in original_children:
target = self.__first_filled_child(child)
if target and target not in targets:
targets.append(target)
# Remove edge from parent to node
parent.remove_child(node, propagate=False)
# Add edges from parent to targets
for target in targets:
parent.add_child(target, propagate=False)
# Clear the node's connections
node.parents.clear()
node.children.clear()
def __first_filled_child(self, node):
if not node.is_empty():
return node
# Recursively check children
for child in sorted(node.children, key=lambda n: n.id):
result = self.__first_filled_child(child)
if result is not None:
return result
return None
def to_dot(self) -> str:
lines = ["digraph CFG {", ' node [fontname="Helvetica"];']
def emit(node: CFG_Node):
label = node.dot_label()
shape = node.dot_shape
style = node.dot_style
style_str = f", {style}" if style else ""
lines.append(f' n{node.id} [label="{label}", shape={shape}{style_str}];')
for i, child in enumerate(sorted(node.children, key=lambda n: n.id)):
edge_label = ""
if isinstance(node, CFG_DIAMOND):
if i == 0:
edge_label = ' [label="T"]'
elif i == 1:
edge_label = ' [label="F"]'
lines.append(f" n{node.id} -> n{child.id}{edge_label};")
self.traverse(emit, start=self.START)
lines.append("}")
return "\n".join(lines)
# Reusable traversal function
def traverse(self, fn: Callable[[CFG_Node], Any], start: CFG_Node | None = None) -> None:
start = start or self.START
visited: Set[int] = set()
def visit(node: CFG_Node):
if node.id in visited:
return
visited.add(node.id)
fn(node)
for child in sorted(node.children, key=lambda n: n.id):
visit(child)
visit(start)

View File

@@ -0,0 +1,96 @@
class CFG_Node:
__counter = 1
def __init__(self, ast_node=None):
self.ast_node = ast_node
self.children = set()
self.parents = set()
self.label = None
self.dot_shape = 'box'
self.dot_style = ''
self.id = CFG_Node.__counter
CFG_Node.__counter += 1
def get_children(self):
return self.children
def get_parents(self):
return self.parents
def add_child(self, child: 'CFG_Node', propagate=True):
if propagate:
child.parents.add(self)
self.children.add(child)
def add_parent(self, parent: 'CFG_Node', propagate=True):
if propagate:
parent.add_child(self)
self.parents.add(parent)
def remove_child(self, child: 'CFG_Node', propagate=True):
if propagate:
child.parents.remove(self)
self.children.remove(child)
def remove_parent(self, parent: 'CFG_Node', propagate=True):
if propagate:
parent.children.remove(self)
self.parents.remove(parent)
def dot_label(self):
# Prioritize custom label
if self.label is not None:
return self.label
# Build label from AST node
if self.ast_node is not None:
return str(self.ast_node)
return None
def is_filled(self):
return not self.is_empty()
def is_empty(self):
# Node is empty if it has no label and no related AST node
if self.label is None or self.label == "None":
if self.ast_node is not None:
# Node belongs to a ast node
return False
return True
# Node is required for the control flow
return False
class CFG_START(CFG_Node):
def __init__(self, ast_node=None):
super().__init__(ast_node)
self.dot_shape = "ellipse"
self.dot_style = 'style=filled, color=green'
self.label = "START"
class CFG_END(CFG_Node):
def __init__(self, ast_node=None):
super().__init__(ast_node)
self.dot_shape = "ellipse"
self.dot_style = 'style=filled, color=green'
self.label = "END"
class CFG_DIAMOND(CFG_Node):
def __init__(self, ast_node=None):
super().__init__(ast_node)
self.dot_shape = "diamond"
self.label = "<?>"
class CFG_CALL(CFG_Node):
def __init__(self, ast_node=None):
super().__init__(ast_node)
self.dot_style = 'style=filled, color=orange'
self.dot_shape = "box"
class CFG_RETURN(CFG_Node):
def __init__(self, ast_node=None):
super().__init__(ast_node)
self.dot_style = 'style=filled, color=orange'
self.dot_shape = "box"

View File

View File

@@ -0,0 +1,306 @@
from cfg.CFG_Node import (
CFG_Node,
CFG_CALL,
CFG_RETURN,
CFG_DIAMOND,
CFG_START,
CFG_END,
)
import compiler
import syntax
# Global registry for function start/end nodes
FUNCTIONS = {}
# Global variable to track the current function being processed
CURRENT_FUNCTION = None
class CONST(compiler.CONST):
def cfa(self, pred, end = None):
node = CFG_Node(self)
pred.add_child(node)
# Attach the end node if it is provided
if end is not None:
node.add_child(end)
return node
class ID(compiler.ID):
def cfa(self, pred, end = None):
node = CFG_Node(self)
pred.add_child(node)
# Attach the end node if it is provided
if end is not None:
node.add_child(end)
return node
class AOP(compiler.AOP):
def cfa(self, pred, end = None):
# Create nodes for the used expressions and attach
left_node = self.arg1.cfa(pred)
right_node = self.arg2.cfa(left_node)
# Create the operator node and attach
op_node = CFG_Node(self)
op_node.label = f"{str(self.arg1)} {self.operator} {str(self.arg2)}"
right_node.add_child(op_node)
# Attach the end node if it is provided
if end is not None:
op_node.add_child(end)
return op_node
class COMP(compiler.COMP):
def cfa(self, pred, end = None):
# Create nodes for the used expressions and attach
left_node = self.arg1.cfa(pred)
right_node = self.arg2.cfa(left_node)
# Create the comparison node and attach
comp_node = CFG_Node(self)
comp_node.label = f"{str(self.arg1)} {self.operator} {str(self.arg2)}"
right_node.add_child(comp_node)
# Attach the end node if it is provided
if end is not None:
comp_node.add_child(end)
return comp_node
class EQOP(compiler.EQOP):
def cfa(self, pred, end = None):
# Create nodes for the used expressions and attach
left_node = self.arg1.cfa(pred)
right_node = self.arg2.cfa(left_node)
# Create the comparison node and attach
eqop_node = CFG_Node(self)
eqop_node.label = f"{str(self.arg1)} {self.operator} {str(self.arg2)}"
right_node.add_child(eqop_node)
# Attach the end node if it is provided
if end is not None:
eqop_node.add_child(end)
return eqop_node
class LOP(compiler.LOP):
def cfa(self, pred, end = None):
# Create nodes for each operand separately
left_node = self.arg1.cfa(pred)
right_node = self.arg2.cfa(left_node)
# Create the logical operation node with just the operator
lop_node = CFG_Node(self)
lop_node.label = f"{str(self.arg1)} {self.operator} {str(self.arg2)}"
right_node.add_child(lop_node)
# Attach the end node if it is provided
if end is not None:
lop_node.add_child(end)
return lop_node
class ASSIGN(compiler.ASSIGN):
def cfa(self, pred, end = None):
# Unwraps expressions needed for assignment
expr_node = self.expr.cfa(pred)
# Assignment node
assign_node = CFG_Node(self)
expr_node.add_child(assign_node)
# Attach the end node if it is provided
if end is not None:
assign_node.add_child(end)
return assign_node
class SEQ(compiler.SEQ):
def cfa(self, pred, end = None):
mid = self.exp1.cfa(pred)
if mid is None:
return None
return self.exp2.cfa(mid, end)
class IF(compiler.IF):
def cfa(self, pred, end = None):
# Unwraps expressions needed for the condition
cond_node = self.cond.cfa(pred, None)
# Attach junction node
diamond = CFG_DIAMOND(self.cond)
cond_node.add_child(diamond)
# Define start and end entry and unwraps expressions
then_entry = CFG_Node()
diamond.add_child(then_entry)
else_entry = CFG_Node()
diamond.add_child(else_entry)
# Attach the end node if it is provided
join = CFG_Node()
if end is not None:
join.add_child(end)
# Connect the extracted expressions with the join
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 = None):
if hasattr(self.cond, 'arg1') and hasattr(self.cond, 'arg2'):
# This is a comparison operation (e.g., a > b)
# Create the condition evaluation nodes
left_node = self.cond.arg1.cfa(pred)
right_node = self.cond.arg2.cfa(left_node)
# Create the comparison node and attach
comp_node = CFG_Node(self.cond)
comp_node.label = f"{str(self.cond.arg1)} {self.cond.operator} {str(self.cond.arg2)}"
right_node.add_child(comp_node)
else:
# This is a simple condition (e.g., constant true/false)
cond_node = self.cond.cfa(pred)
comp_node = cond_node
# Attach junction node
diamond = CFG_DIAMOND(self.cond)
comp_node.add_child(diamond)
# Unwrap the loop body
body_entry = CFG_Node()
diamond.add_child(body_entry)
# The body should connect back to the start of condition evaluation
body_end = self.body.cfa(body_entry)
if body_end is not None:
# Connect the body end back to the condition evaluation
if hasattr(self.cond, 'arg1') and hasattr(self.cond, 'arg2'):
body_end.add_child(left_node)
else:
body_end.add_child(pred)
# Attach joining node
after = CFG_Node()
diamond.add_child(after)
# Attach the end node if it is provided
if end is not None:
after.add_child(end)
return after
class CALL(compiler.CALL):
def cfa(self, pred, end = None):
# Create nodes for all argument values
current_arg_node = pred
for i, arg in enumerate(self.arg):
current_arg_node = arg.cfa(current_arg_node)
# Create and attach the call node
call_node = CFG_CALL(self)
call_node.label = f"CALL {self.f_name}"
current_arg_node.add_child(call_node)
# Create and attach the exit node
cont = CFG_Node()
if end is not None:
cont.add_child(end)
# Find the functions in the function list
if self.f_name not in FUNCTIONS:
raise RuntimeError(f"Call to undefined function '{self.f_name}'")
# Determine the start and exit node of the function
f_start, f_end = FUNCTIONS[self.f_name]
# Create return node from function
return_node = CFG_RETURN(self)
return_node.label = f"RET {self.f_name}"
f_end.add_child(return_node)
return_node.add_child(cont)
# Span the start and exit nodes to the method body
call_node.add_child(f_start)
call_node.add_child(return_node)
# Return value flow for recursive calls
if CURRENT_FUNCTION is not None and self.f_name == CURRENT_FUNCTION:
return_node.add_child(cont)
return cont
class DECL(compiler.DECL):
def cfa(self, pred, end):
# Check if a function is already registered
if self.f_name in FUNCTIONS:
f_start, f_end = FUNCTIONS[self.f_name]
else:
# Span the method body into a start and end node
f_start = CFG_START(self)
f_start.label = f"START {self.f_name}({', '.join(self.params)})"
f_end = CFG_END(self)
f_end.label = f"END {self.f_name}({', '.join(self.params)})"
FUNCTIONS[self.f_name] = (f_start, f_end)
# Set the current function context for recursion detection
global CURRENT_FUNCTION
previous_function = CURRENT_FUNCTION
CURRENT_FUNCTION = self.f_name
try:
# Unwrap the method body
body_end = self.body.cfa(f_start, f_end)
# Attach the end node if it is provided
if body_end is not None:
body_end.add_child(f_end)
finally:
# Restore the previous function context
CURRENT_FUNCTION = previous_function
return pred
class LET(compiler.LET):
def cfa(self, pred, end = None):
# First pass: Register all function declarations
decls = self.decl if isinstance(self.decl, list) else [self.decl]
for d in decls:
if isinstance(d, compiler.DECL):
# Register function without building CFG yet
f_start = CFG_START(d)
f_start.label = f"START {d.f_name}({', '.join(d.params)})"
f_end = CFG_END(d)
f_end.label = f"END {d.f_name}({', '.join(d.params)})"
FUNCTIONS[d.f_name] = (f_start, f_end)
# Create a global entry node for the function
global_entry = CFG_Node()
global_entry.label = "None"
pred.add_child(global_entry)
current = global_entry
# Generate function declarations
for d in decls:
current = d.cfa(current, None)
if current is None:
return None
# Unwrap the body
body_result = self.body.cfa(current, end)
# Create global exit node
global_exit = CFG_Node()
global_exit.label = "None"
if body_result is not None:
body_result.add_child(global_exit)
# Attach the end node if it is provided
if end is not None:
global_exit.add_child(end)
return global_exit
class RETURN(syntax.EXPRESSION):
def cfa(self, pred, end):
n = CFG_RETURN(self)
pred.add_child(n)
n.add_child(end)
return None

View File

@@ -0,0 +1,23 @@
digraph CFG {
node [fontname="Helvetica"];
n1 [label="START", shape=ellipse, style=filled, color=gray];
n1 -> n7;
n7 [label="1", shape=box];
n7 -> n8;
n8 [label="2", shape=box];
n8 -> n9;
n9 [label="3", shape=box];
n9 -> n10;
n10 [label="CALL a", shape=box, style=filled, color=orange];
n10 -> n3;
n10 -> n12;
n3 [label="START a(x, y, z)", shape=ellipse, style=filled, color=green];
n3 -> n6;
n6 [label="x", shape=box];
n6 -> n4;
n4 [label="END a(x, y, z)", shape=ellipse, style=filled, color=green];
n4 -> n12;
n12 [label="RET a", shape=box, style=filled, color=orange];
n12 -> n2;
n2 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,127 @@
digraph CFG {
node [fontname="Helvetica"];
n14 [label="START", shape=ellipse, style=filled, color=gray];
n14 -> n65;
n65 [label="10", shape=box];
n65 -> n66;
n66 [label="CALL f1", shape=box, style=filled, color=orange];
n66 -> n16;
n66 -> n68;
n16 [label="START f1(b)", shape=ellipse, style=filled, color=green];
n16 -> n21;
n21 [label="b", shape=box];
n21 -> n22;
n22 [label="0", shape=box];
n22 -> n23;
n23 [label="b == 0", shape=box];
n23 -> n24;
n24 [label="<?>", shape=diamond];
n24 -> n28 [label="T"];
n24 -> n29 [label="F"];
n28 [label="0", shape=box];
n28 -> n17;
n17 [label="END f1(b)", shape=ellipse, style=filled, color=green];
n17 -> n34;
n17 -> n45;
n17 -> n49;
n17 -> n68;
n34 [label="RET f1", shape=box, style=filled, color=orange];
n34 -> n17;
n45 [label="RET f1", shape=box, style=filled, color=orange];
n45 -> n58;
n58 [label="a", shape=box];
n58 -> n59;
n59 [label="b", shape=box];
n59 -> n60;
n60 [label="a * b", shape=box];
n60 -> n61;
n61 [label="CALL g", shape=box, style=filled, color=orange];
n61 -> n50;
n61 -> n63;
n50 [label="START g(c)", shape=ellipse, style=filled, color=green];
n50 -> n53;
n53 [label="a", shape=box];
n53 -> n54;
n54 [label="b", shape=box];
n54 -> n55;
n55 [label="a * b", shape=box];
n55 -> n56;
n56 [label="c", shape=box];
n56 -> n57;
n57 [label="(a * b) * c", shape=box];
n57 -> n51;
n51 [label="END g(c)", shape=ellipse, style=filled, color=green];
n51 -> n63;
n63 [label="RET g", shape=box, style=filled, color=orange];
n63 -> n19;
n19 [label="END f2(a, b)", shape=ellipse, style=filled, color=green];
n19 -> n91;
n91 [label="RET f2", shape=box, style=filled, color=orange];
n91 -> n15;
n15 [label="END", shape=ellipse, style=filled, color=gray];
n49 [label="RET f1", shape=box, style=filled, color=orange];
n49 -> n58;
n68 [label="RET f1", shape=box, style=filled, color=orange];
n68 -> n70;
n70 [label="10", shape=box];
n70 -> n83;
n83 [label="20", shape=box];
n83 -> n84;
n84 [label="30", shape=box];
n84 -> n85;
n85 [label="CALL max", shape=box, style=filled, color=orange];
n85 -> n71;
n85 -> n87;
n71 [label="START max(a, b)", shape=ellipse, style=filled, color=green];
n71 -> n74;
n74 [label="a", shape=box];
n74 -> n75;
n75 [label="b", shape=box];
n75 -> n76;
n76 [label="a > b", shape=box];
n76 -> n77;
n77 [label="<?>", shape=diamond];
n77 -> n81 [label="T"];
n77 -> n82 [label="F"];
n81 [label="a", shape=box];
n81 -> n72;
n72 [label="END max(a, b)", shape=ellipse, style=filled, color=green];
n72 -> n87;
n87 [label="RET max", shape=box, style=filled, color=orange];
n87 -> n89;
n89 [label="CALL f2", shape=box, style=filled, color=orange];
n89 -> n18;
n89 -> n91;
n18 [label="START f2(a, b)", shape=ellipse, style=filled, color=green];
n18 -> n35;
n35 [label="a", shape=box];
n35 -> n36;
n36 [label="b", shape=box];
n36 -> n37;
n37 [label="a > b", shape=box];
n37 -> n38;
n38 [label="<?>", shape=diamond];
n38 -> n42 [label="T"];
n38 -> n46 [label="F"];
n42 [label="a", shape=box];
n42 -> n43;
n43 [label="CALL f1", shape=box, style=filled, color=orange];
n43 -> n16;
n43 -> n45;
n46 [label="b", shape=box];
n46 -> n47;
n47 [label="CALL f1", shape=box, style=filled, color=orange];
n47 -> n16;
n47 -> n49;
n82 [label="b", shape=box];
n82 -> n72;
n29 [label="b", shape=box];
n29 -> n30;
n30 [label="1", shape=box];
n30 -> n31;
n31 [label="b - 1", shape=box];
n31 -> n32;
n32 [label="CALL f1", shape=box, style=filled, color=orange];
n32 -> n16;
n32 -> n34;
}

View File

@@ -0,0 +1,27 @@
digraph CFG {
node [fontname="Helvetica"];
n92 [label="START", shape=ellipse, style=filled, color=gray];
n92 -> n94;
n94 [label="2", shape=box];
n94 -> n95;
n95 [label="x", shape=box];
n95 -> n96;
n96 [label="2 < x", shape=box];
n96 -> n97;
n97 [label="x", shape=box];
n97 -> n98;
n98 [label="9", shape=box];
n98 -> n99;
n99 [label="x > 9", shape=box];
n99 -> n100;
n100 [label="(2 < x) && (x > 9)", shape=box];
n100 -> n101;
n101 [label="<?>", shape=diamond];
n101 -> n105 [label="T"];
n101 -> n106 [label="F"];
n105 [label="1", shape=box];
n105 -> n93;
n93 [label="END", shape=ellipse, style=filled, color=gray];
n106 [label="0", shape=box];
n106 -> n93;
}

View File

@@ -0,0 +1,45 @@
digraph CFG {
node [fontname="Helvetica"];
n107 [label="START", shape=ellipse, style=filled, color=gray];
n107 -> n119;
n119 [label="1", shape=box];
n119 -> n120;
n120 [label="CALL a", shape=box, style=filled, color=orange];
n120 -> n109;
n120 -> n122;
n109 [label="START a(x)", shape=ellipse, style=filled, color=green];
n109 -> n116;
n116 [label="x", shape=box];
n116 -> n110;
n110 [label="END a(x)", shape=ellipse, style=filled, color=green];
n110 -> n122;
n122 [label="RET a", shape=box, style=filled, color=orange];
n122 -> n124;
n124 [label="2", shape=box];
n124 -> n125;
n125 [label="CALL b", shape=box, style=filled, color=orange];
n125 -> n111;
n125 -> n127;
n111 [label="START b(y)", shape=ellipse, style=filled, color=green];
n111 -> n117;
n117 [label="y", shape=box];
n117 -> n112;
n112 [label="END b(y)", shape=ellipse, style=filled, color=green];
n112 -> n127;
n127 [label="RET b", shape=box, style=filled, color=orange];
n127 -> n128;
n128 [label="3", shape=box];
n128 -> n129;
n129 [label="CALL c", shape=box, style=filled, color=orange];
n129 -> n113;
n129 -> n131;
n113 [label="START c(z)", shape=ellipse, style=filled, color=green];
n113 -> n118;
n118 [label="z", shape=box];
n118 -> n114;
n114 [label="END c(z)", shape=ellipse, style=filled, color=green];
n114 -> n131;
n131 [label="RET c", shape=box, style=filled, color=orange];
n131 -> n108;
n108 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,69 @@
digraph CFG {
node [fontname="Helvetica"];
n132 [label="START", shape=ellipse, style=filled, color=gray];
n132 -> n167;
n167 [label="2", shape=box];
n167 -> n168;
n168 [label="3", shape=box];
n168 -> n169;
n169 [label="CALL f", shape=box, style=filled, color=orange];
n169 -> n134;
n169 -> n171;
n134 [label="START f(x, y, z)", shape=ellipse, style=filled, color=green];
n134 -> n137;
n137 [label="2", shape=box];
n137 -> n138;
n138 [label="y = 2", shape=box];
n138 -> n139;
n139 [label="3", shape=box];
n139 -> n140;
n140 [label="z = 3", shape=box];
n140 -> n160;
n160 [label="x", shape=box];
n160 -> n161;
n161 [label="CALL g", shape=box, style=filled, color=orange];
n161 -> n141;
n161 -> n163;
n141 [label="START g(x)", shape=ellipse, style=filled, color=green];
n141 -> n144;
n144 [label="7", shape=box];
n144 -> n145;
n145 [label="x = 7", shape=box];
n145 -> n146;
n146 [label="y", shape=box];
n146 -> n147;
n147 [label="0", shape=box];
n147 -> n148;
n148 [label="y > 0", shape=box];
n148 -> n149;
n149 [label="<?>", shape=diamond];
n149 -> n153 [label="T"];
n149 -> n157 [label="F"];
n153 [label="y", shape=box];
n153 -> n154;
n154 [label="CALL g", shape=box, style=filled, color=orange];
n154 -> n141;
n154 -> n156;
n156 [label="RET g", shape=box, style=filled, color=orange];
n156 -> n159;
n159 [label="x", shape=box];
n159 -> n142;
n142 [label="END g(x)", shape=ellipse, style=filled, color=green];
n142 -> n156;
n142 -> n163;
n163 [label="RET g", shape=box, style=filled, color=orange];
n163 -> n164;
n164 [label="x", shape=box];
n164 -> n165;
n165 [label="g(x) + x", shape=box];
n165 -> n135;
n135 [label="END f(x, y, z)", shape=ellipse, style=filled, color=green];
n135 -> n171;
n171 [label="RET f", shape=box, style=filled, color=orange];
n171 -> n133;
n133 [label="END", shape=ellipse, style=filled, color=gray];
n157 [label="8", shape=box];
n157 -> n158;
n158 [label="x = 8", shape=box];
n158 -> n159;
}

View File

@@ -0,0 +1,268 @@
digraph CFG {
node [fontname="Helvetica"];
n173 [label="START", shape=ellipse, style=filled, color=gray];
n173 -> n338;
n338 [label="3", shape=box];
n338 -> n339;
n339 [label="CALL fac", shape=box, style=filled, color=orange];
n339 -> n191;
n339 -> n341;
n191 [label="START fac(x)", shape=ellipse, style=filled, color=green];
n191 -> n194;
n191 -> n210;
n191 -> n226;
n191 -> n242;
n191 -> n258;
n191 -> n274;
n191 -> n290;
n191 -> n306;
n191 -> n322;
n194 [label="x", shape=box];
n194 -> n195;
n195 [label="1", shape=box];
n195 -> n196;
n196 [label="x == 1", shape=box];
n196 -> n197;
n197 [label="<?>", shape=diamond];
n197 -> n201 [label="T"];
n197 -> n202 [label="F"];
n201 [label="1", shape=box];
n201 -> n192;
n192 [label="END fac(x)", shape=ellipse, style=filled, color=green];
n192 -> n207;
n192 -> n223;
n192 -> n239;
n192 -> n255;
n192 -> n271;
n192 -> n287;
n192 -> n303;
n192 -> n319;
n192 -> n335;
n192 -> n341;
n207 [label="RET fac", shape=box, style=filled, color=orange];
n207 -> n208;
n208 [label="x", shape=box];
n208 -> n209;
n209 [label="fac((x - 1)) * x", shape=box];
n209 -> n192;
n223 [label="RET fac", shape=box, style=filled, color=orange];
n223 -> n224;
n224 [label="x", shape=box];
n224 -> n225;
n225 [label="fac((x - 1)) * x", shape=box];
n225 -> n192;
n239 [label="RET fac", shape=box, style=filled, color=orange];
n239 -> n240;
n240 [label="x", shape=box];
n240 -> n241;
n241 [label="fac((x - 1)) * x", shape=box];
n241 -> n192;
n255 [label="RET fac", shape=box, style=filled, color=orange];
n255 -> n256;
n256 [label="x", shape=box];
n256 -> n257;
n257 [label="fac((x - 1)) * x", shape=box];
n257 -> n192;
n271 [label="RET fac", shape=box, style=filled, color=orange];
n271 -> n272;
n272 [label="x", shape=box];
n272 -> n273;
n273 [label="fac((x - 1)) * x", shape=box];
n273 -> n192;
n287 [label="RET fac", shape=box, style=filled, color=orange];
n287 -> n288;
n288 [label="x", shape=box];
n288 -> n289;
n289 [label="fac((x - 1)) * x", shape=box];
n289 -> n192;
n303 [label="RET fac", shape=box, style=filled, color=orange];
n303 -> n304;
n304 [label="x", shape=box];
n304 -> n305;
n305 [label="fac((x - 1)) * x", shape=box];
n305 -> n192;
n319 [label="RET fac", shape=box, style=filled, color=orange];
n319 -> n320;
n320 [label="x", shape=box];
n320 -> n321;
n321 [label="fac((x - 1)) * x", shape=box];
n321 -> n192;
n335 [label="RET fac", shape=box, style=filled, color=orange];
n335 -> n336;
n336 [label="x", shape=box];
n336 -> n337;
n337 [label="fac((x - 1)) * x", shape=box];
n337 -> n192;
n341 [label="RET fac", shape=box, style=filled, color=orange];
n341 -> n174;
n174 [label="END", shape=ellipse, style=filled, color=gray];
n202 [label="x", shape=box];
n202 -> n203;
n203 [label="1", shape=box];
n203 -> n204;
n204 [label="x - 1", shape=box];
n204 -> n205;
n205 [label="CALL fac", shape=box, style=filled, color=orange];
n205 -> n191;
n205 -> n207;
n210 [label="x", shape=box];
n210 -> n211;
n211 [label="1", shape=box];
n211 -> n212;
n212 [label="x == 1", shape=box];
n212 -> n213;
n213 [label="<?>", shape=diamond];
n213 -> n217 [label="T"];
n213 -> n218 [label="F"];
n217 [label="1", shape=box];
n217 -> n192;
n218 [label="x", shape=box];
n218 -> n219;
n219 [label="1", shape=box];
n219 -> n220;
n220 [label="x - 1", shape=box];
n220 -> n221;
n221 [label="CALL fac", shape=box, style=filled, color=orange];
n221 -> n191;
n221 -> n223;
n226 [label="x", shape=box];
n226 -> n227;
n227 [label="1", shape=box];
n227 -> n228;
n228 [label="x == 1", shape=box];
n228 -> n229;
n229 [label="<?>", shape=diamond];
n229 -> n233 [label="T"];
n229 -> n234 [label="F"];
n233 [label="1", shape=box];
n233 -> n192;
n234 [label="x", shape=box];
n234 -> n235;
n235 [label="1", shape=box];
n235 -> n236;
n236 [label="x - 1", shape=box];
n236 -> n237;
n237 [label="CALL fac", shape=box, style=filled, color=orange];
n237 -> n191;
n237 -> n239;
n242 [label="x", shape=box];
n242 -> n243;
n243 [label="1", shape=box];
n243 -> n244;
n244 [label="x == 1", shape=box];
n244 -> n245;
n245 [label="<?>", shape=diamond];
n245 -> n249 [label="T"];
n245 -> n250 [label="F"];
n249 [label="1", shape=box];
n249 -> n192;
n250 [label="x", shape=box];
n250 -> n251;
n251 [label="1", shape=box];
n251 -> n252;
n252 [label="x - 1", shape=box];
n252 -> n253;
n253 [label="CALL fac", shape=box, style=filled, color=orange];
n253 -> n191;
n253 -> n255;
n258 [label="x", shape=box];
n258 -> n259;
n259 [label="1", shape=box];
n259 -> n260;
n260 [label="x == 1", shape=box];
n260 -> n261;
n261 [label="<?>", shape=diamond];
n261 -> n265 [label="T"];
n261 -> n266 [label="F"];
n265 [label="1", shape=box];
n265 -> n192;
n266 [label="x", shape=box];
n266 -> n267;
n267 [label="1", shape=box];
n267 -> n268;
n268 [label="x - 1", shape=box];
n268 -> n269;
n269 [label="CALL fac", shape=box, style=filled, color=orange];
n269 -> n191;
n269 -> n271;
n274 [label="x", shape=box];
n274 -> n275;
n275 [label="1", shape=box];
n275 -> n276;
n276 [label="x == 1", shape=box];
n276 -> n277;
n277 [label="<?>", shape=diamond];
n277 -> n281 [label="T"];
n277 -> n282 [label="F"];
n281 [label="1", shape=box];
n281 -> n192;
n282 [label="x", shape=box];
n282 -> n283;
n283 [label="1", shape=box];
n283 -> n284;
n284 [label="x - 1", shape=box];
n284 -> n285;
n285 [label="CALL fac", shape=box, style=filled, color=orange];
n285 -> n191;
n285 -> n287;
n290 [label="x", shape=box];
n290 -> n291;
n291 [label="1", shape=box];
n291 -> n292;
n292 [label="x == 1", shape=box];
n292 -> n293;
n293 [label="<?>", shape=diamond];
n293 -> n297 [label="T"];
n293 -> n298 [label="F"];
n297 [label="1", shape=box];
n297 -> n192;
n298 [label="x", shape=box];
n298 -> n299;
n299 [label="1", shape=box];
n299 -> n300;
n300 [label="x - 1", shape=box];
n300 -> n301;
n301 [label="CALL fac", shape=box, style=filled, color=orange];
n301 -> n191;
n301 -> n303;
n306 [label="x", shape=box];
n306 -> n307;
n307 [label="1", shape=box];
n307 -> n308;
n308 [label="x == 1", shape=box];
n308 -> n309;
n309 [label="<?>", shape=diamond];
n309 -> n313 [label="T"];
n309 -> n314 [label="F"];
n313 [label="1", shape=box];
n313 -> n192;
n314 [label="x", shape=box];
n314 -> n315;
n315 [label="1", shape=box];
n315 -> n316;
n316 [label="x - 1", shape=box];
n316 -> n317;
n317 [label="CALL fac", shape=box, style=filled, color=orange];
n317 -> n191;
n317 -> n319;
n322 [label="x", shape=box];
n322 -> n323;
n323 [label="1", shape=box];
n323 -> n324;
n324 [label="x == 1", shape=box];
n324 -> n325;
n325 [label="<?>", shape=diamond];
n325 -> n329 [label="T"];
n325 -> n330 [label="F"];
n329 [label="1", shape=box];
n329 -> n192;
n330 [label="x", shape=box];
n330 -> n331;
n331 [label="1", shape=box];
n331 -> n332;
n332 [label="x - 1", shape=box];
n332 -> n333;
n333 [label="CALL fac", shape=box, style=filled, color=orange];
n333 -> n191;
n333 -> n335;
}

View File

@@ -0,0 +1,8 @@
digraph CFG {
node [fontname="Helvetica"];
n356 [label="START", shape=ellipse, style=filled, color=gray];
n356 -> n358;
n358 [label="0", shape=box];
n358 -> n357;
n357 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,52 @@
digraph CFG {
node [fontname="Helvetica"];
n359 [label="START", shape=ellipse, style=filled, color=gray];
n359 -> n382;
n382 [label="10", shape=box];
n382 -> n383;
n383 [label="8", shape=box];
n383 -> n384;
n384 [label="CALL func", shape=box, style=filled, color=orange];
n384 -> n361;
n384 -> n386;
n361 [label="START func(a, b)", shape=ellipse, style=filled, color=green];
n361 -> n364;
n364 [label="a", shape=box];
n364 -> n365;
n365 [label="0", shape=box];
n365 -> n366;
n366 [label="a > 0", shape=box];
n366 -> n367;
n367 [label="b", shape=box];
n367 -> n368;
n368 [label="a", shape=box];
n368 -> n369;
n369 [label="b != a", shape=box];
n369 -> n370;
n370 [label="(a > 0) && (b != a)", shape=box];
n370 -> n371;
n371 [label="<?>", shape=diamond];
n371 -> n362 [label="T"];
n371 -> n373 [label="F"];
n362 [label="END func(a, b)", shape=ellipse, style=filled, color=green];
n362 -> n386;
n386 [label="RET func", shape=box, style=filled, color=orange];
n386 -> n360;
n360 [label="END", shape=ellipse, style=filled, color=gray];
n373 [label="b", shape=box];
n373 -> n374;
n374 [label="1", shape=box];
n374 -> n375;
n375 [label="b + 1", shape=box];
n375 -> n376;
n376 [label="b = (b + 1)", shape=box];
n376 -> n377;
n377 [label="a", shape=box];
n377 -> n378;
n378 [label="1", shape=box];
n378 -> n379;
n379 [label="a - 1", shape=box];
n379 -> n380;
n380 [label="a = (a - 1)", shape=box];
n380 -> n366;
}

View File

@@ -0,0 +1,19 @@
digraph CFG {
node [fontname="Helvetica"];
n388 [label="START", shape=ellipse, style=filled, color=gray];
n388 -> n390;
n390 [label="1", shape=box];
n390 -> n391;
n391 [label="0", shape=box];
n391 -> n392;
n392 [label="1 >= 0", shape=box];
n392 -> n393;
n393 [label="<?>", shape=diamond];
n393 -> n397 [label="T"];
n393 -> n398 [label="F"];
n397 [label="1", shape=box];
n397 -> n389;
n389 [label="END", shape=ellipse, style=filled, color=gray];
n398 [label="0", shape=box];
n398 -> n389;
}

View File

@@ -0,0 +1,67 @@
digraph CFG {
node [fontname="Helvetica"];
n405 [label="START", shape=ellipse, style=filled, color=gray];
n405 -> n439;
n439 [label="2", shape=box];
n439 -> n440;
n440 [label="8", shape=box];
n440 -> n441;
n441 [label="CALL ggT", shape=box, style=filled, color=orange];
n441 -> n407;
n441 -> n443;
n407 [label="START ggT(a, b)", shape=ellipse, style=filled, color=green];
n407 -> n410;
n410 [label="a", shape=box];
n410 -> n411;
n411 [label="b", shape=box];
n411 -> n412;
n412 [label="a == b", shape=box];
n412 -> n413;
n413 [label="<?>", shape=diamond];
n413 -> n417 [label="T"];
n413 -> n418 [label="F"];
n417 [label="a", shape=box];
n417 -> n408;
n408 [label="END ggT(a, b)", shape=ellipse, style=filled, color=green];
n408 -> n431;
n408 -> n438;
n408 -> n443;
n431 [label="RET ggT", shape=box, style=filled, color=orange];
n431 -> n408;
n438 [label="RET ggT", shape=box, style=filled, color=orange];
n438 -> n408;
n443 [label="RET ggT", shape=box, style=filled, color=orange];
n443 -> n406;
n406 [label="END", shape=ellipse, style=filled, color=gray];
n418 [label="a", shape=box];
n418 -> n419;
n419 [label="b", shape=box];
n419 -> n420;
n420 [label="a > b", shape=box];
n420 -> n421;
n421 [label="<?>", shape=diamond];
n421 -> n425 [label="T"];
n421 -> n432 [label="F"];
n425 [label="a", shape=box];
n425 -> n426;
n426 [label="b", shape=box];
n426 -> n427;
n427 [label="a - b", shape=box];
n427 -> n428;
n428 [label="b", shape=box];
n428 -> n429;
n429 [label="CALL ggT", shape=box, style=filled, color=orange];
n429 -> n407;
n429 -> n431;
n432 [label="b", shape=box];
n432 -> n433;
n433 [label="a", shape=box];
n433 -> n434;
n434 [label="b - a", shape=box];
n434 -> n435;
n435 [label="a", shape=box];
n435 -> n436;
n436 [label="CALL ggT", shape=box, style=filled, color=orange];
n436 -> n407;
n436 -> n438;
}

View File

@@ -0,0 +1,111 @@
digraph CFG {
node [fontname="Helvetica"];
n445 [label="START", shape=ellipse, style=filled, color=gray];
n445 -> n499;
n499 [label="1", shape=box];
n499 -> n500;
n500 [label="2", shape=box];
n500 -> n501;
n501 [label="CALL f", shape=box, style=filled, color=orange];
n501 -> n447;
n501 -> n503;
n447 [label="START f(x, y)", shape=ellipse, style=filled, color=green];
n447 -> n452;
n452 [label="x", shape=box];
n452 -> n453;
n453 [label="0", shape=box];
n453 -> n454;
n454 [label="x == 0", shape=box];
n454 -> n455;
n455 [label="<?>", shape=diamond];
n455 -> n467 [label="T"];
n455 -> n475 [label="F"];
n467 [label="2", shape=box];
n467 -> n468;
n468 [label="y", shape=box];
n468 -> n469;
n469 [label="2 * y", shape=box];
n469 -> n470;
n470 [label="x", shape=box];
n470 -> n471;
n471 [label="CALL g", shape=box, style=filled, color=orange];
n471 -> n459;
n471 -> n473;
n459 [label="START g(x, z)", shape=ellipse, style=filled, color=green];
n459 -> n462;
n459 -> n478;
n462 [label="x", shape=box];
n462 -> n463;
n463 [label="y", shape=box];
n463 -> n464;
n464 [label="x * y", shape=box];
n464 -> n465;
n465 [label="z", shape=box];
n465 -> n466;
n466 [label="(x * y) + z", shape=box];
n466 -> n460;
n460 [label="END g(x, z)", shape=ellipse, style=filled, color=green];
n460 -> n473;
n460 -> n509;
n473 [label="RET g", shape=box, style=filled, color=orange];
n473 -> n448;
n448 [label="END f(x, y)", shape=ellipse, style=filled, color=green];
n448 -> n488;
n448 -> n503;
n488 [label="RET f", shape=box, style=filled, color=orange];
n488 -> n489;
n489 [label="a * f(a,i)", shape=box];
n489 -> n490;
n490 [label="a = (a * f(a,i))", shape=box];
n490 -> n491;
n491 [label="i", shape=box];
n491 -> n492;
n492 [label="1", shape=box];
n492 -> n493;
n493 [label="i - 1", shape=box];
n493 -> n494;
n494 [label="i = (i - 1)", shape=box];
n494 -> n478;
n478 [label="i", shape=box];
n478 -> n479;
n479 [label="0", shape=box];
n479 -> n480;
n480 [label="i > 0", shape=box];
n480 -> n481;
n481 [label="<?>", shape=diamond];
n481 -> n483 [label="T"];
n481 -> n496 [label="F"];
n483 [label="a", shape=box];
n483 -> n484;
n484 [label="a", shape=box];
n484 -> n485;
n485 [label="i", shape=box];
n485 -> n486;
n486 [label="CALL f", shape=box, style=filled, color=orange];
n486 -> n447;
n486 -> n488;
n496 [label="a", shape=box];
n496 -> n497;
n497 [label="42", shape=box];
n497 -> n498;
n498 [label="a + 42", shape=box];
n498 -> n460;
n503 [label="RET f", shape=box, style=filled, color=orange];
n503 -> n505;
n505 [label="3", shape=box];
n505 -> n506;
n506 [label="3", shape=box];
n506 -> n507;
n507 [label="CALL g", shape=box, style=filled, color=orange];
n507 -> n459;
n507 -> n509;
n509 [label="RET g", shape=box, style=filled, color=orange];
n509 -> n446;
n446 [label="END", shape=ellipse, style=filled, color=gray];
n475 [label="x", shape=box];
n475 -> n476;
n476 [label="1", shape=box];
n476 -> n477;
n477 [label="x + 1", shape=box];
n477 -> n448;
}

View File

@@ -0,0 +1,36 @@
digraph CFG {
node [fontname="Helvetica"];
n512 [label="START", shape=ellipse, style=filled, color=gray];
n512 -> n518;
n518 [label="5", shape=box];
n518 -> n519;
n519 [label="CALL m", shape=box, style=filled, color=orange];
n519 -> n514;
n519 -> n521;
n514 [label="START m(a)", shape=ellipse, style=filled, color=green];
n514 -> n517;
n517 [label="a", shape=box];
n517 -> n515;
n515 [label="END m(a)", shape=ellipse, style=filled, color=green];
n515 -> n521;
n521 [label="RET m", shape=box, style=filled, color=orange];
n521 -> n529;
n529 [label="5", shape=box];
n529 -> n530;
n530 [label="CALL m", shape=box, style=filled, color=orange];
n530 -> n523;
n530 -> n532;
n523 [label="START m(b)", shape=ellipse, style=filled, color=green];
n523 -> n526;
n526 [label="b", shape=box];
n526 -> n527;
n527 [label="1", shape=box];
n527 -> n528;
n528 [label="b + 1", shape=box];
n528 -> n524;
n524 [label="END m(b)", shape=ellipse, style=filled, color=green];
n524 -> n532;
n532 [label="RET m", shape=box, style=filled, color=orange];
n532 -> n513;
n513 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,46 @@
digraph CFG {
node [fontname="Helvetica"];
n534 [label="START", shape=ellipse, style=filled, color=gray];
n534 -> n540;
n540 [label="5", shape=box];
n540 -> n541;
n541 [label="CALL n", shape=box, style=filled, color=orange];
n541 -> n536;
n541 -> n543;
n536 [label="START n(a)", shape=ellipse, style=filled, color=green];
n536 -> n539;
n539 [label="a", shape=box];
n539 -> n537;
n537 [label="END n(a)", shape=ellipse, style=filled, color=green];
n537 -> n543;
n537 -> n554;
n543 [label="RET n", shape=box, style=filled, color=orange];
n543 -> n551;
n551 [label="5", shape=box];
n551 -> n552;
n552 [label="CALL n", shape=box, style=filled, color=orange];
n552 -> n536;
n552 -> n554;
n554 [label="RET n", shape=box, style=filled, color=orange];
n554 -> n555;
n555 [label="5", shape=box];
n555 -> n556;
n556 [label="CALL m", shape=box, style=filled, color=orange];
n556 -> n545;
n556 -> n558;
n545 [label="START m(a)", shape=ellipse, style=filled, color=green];
n545 -> n548;
n548 [label="a", shape=box];
n548 -> n549;
n549 [label="1", shape=box];
n549 -> n550;
n550 [label="a + 1", shape=box];
n550 -> n546;
n546 [label="END m(a)", shape=ellipse, style=filled, color=green];
n546 -> n558;
n558 [label="RET m", shape=box, style=filled, color=orange];
n558 -> n559;
n559 [label="n(5) + m(5)", shape=box];
n559 -> n535;
n535 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,23 @@
digraph CFG {
node [fontname="Helvetica"];
n561 [label="START", shape=ellipse, style=filled, color=gray];
n561 -> n563;
n563 [label="True", shape=box];
n563 -> n564;
n564 [label="True", shape=box];
n564 -> n565;
n565 [label="True", shape=box];
n565 -> n566;
n566 [label="True == True", shape=box];
n566 -> n567;
n567 [label="True || (True == True)", shape=box];
n567 -> n568;
n568 [label="<?>", shape=diamond];
n568 -> n572 [label="T"];
n568 -> n573 [label="F"];
n572 [label="1", shape=box];
n572 -> n562;
n562 [label="END", shape=ellipse, style=filled, color=gray];
n573 [label="0", shape=box];
n573 -> n562;
}

View File

@@ -0,0 +1,23 @@
digraph CFG {
node [fontname="Helvetica"];
n574 [label="START", shape=ellipse, style=filled, color=gray];
n574 -> n582;
n582 [label="5", shape=box];
n582 -> n583;
n583 [label="CALL g", shape=box, style=filled, color=orange];
n583 -> n576;
n583 -> n585;
n576 [label="START g(a)", shape=ellipse, style=filled, color=green];
n576 -> n579;
n579 [label="a", shape=box];
n579 -> n580;
n580 [label="a", shape=box];
n580 -> n581;
n581 [label="a * a", shape=box];
n581 -> n577;
n577 [label="END g(a)", shape=ellipse, style=filled, color=green];
n577 -> n585;
n585 [label="RET g", shape=box, style=filled, color=orange];
n585 -> n575;
n575 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,40 @@
digraph CFG {
node [fontname="Helvetica"];
n587 [label="START", shape=ellipse, style=filled, color=gray];
n587 -> n606;
n606 [label="10", shape=box];
n606 -> n607;
n607 [label="CALL f1", shape=box, style=filled, color=orange];
n607 -> n589;
n607 -> n609;
n589 [label="START f1(b)", shape=ellipse, style=filled, color=green];
n589 -> n592;
n592 [label="b", shape=box];
n592 -> n593;
n593 [label="0", shape=box];
n593 -> n594;
n594 [label="b == 0", shape=box];
n594 -> n595;
n595 [label="<?>", shape=diamond];
n595 -> n599 [label="T"];
n595 -> n600 [label="F"];
n599 [label="0", shape=box];
n599 -> n590;
n590 [label="END f1(b)", shape=ellipse, style=filled, color=green];
n590 -> n605;
n590 -> n609;
n605 [label="RET f1", shape=box, style=filled, color=orange];
n605 -> n590;
n609 [label="RET f1", shape=box, style=filled, color=orange];
n609 -> n588;
n588 [label="END", shape=ellipse, style=filled, color=gray];
n600 [label="b", shape=box];
n600 -> n601;
n601 [label="1", shape=box];
n601 -> n602;
n602 [label="b - 1", shape=box];
n602 -> n603;
n603 [label="CALL f1", shape=box, style=filled, color=orange];
n603 -> n589;
n603 -> n605;
}

View File

@@ -0,0 +1,127 @@
digraph CFG {
node [fontname="Helvetica"];
n611 [label="START", shape=ellipse, style=filled, color=gray];
n611 -> n662;
n662 [label="10", shape=box];
n662 -> n663;
n663 [label="CALL f1", shape=box, style=filled, color=orange];
n663 -> n613;
n663 -> n665;
n613 [label="START f1(b)", shape=ellipse, style=filled, color=green];
n613 -> n618;
n618 [label="b", shape=box];
n618 -> n619;
n619 [label="0", shape=box];
n619 -> n620;
n620 [label="b == 0", shape=box];
n620 -> n621;
n621 [label="<?>", shape=diamond];
n621 -> n625 [label="T"];
n621 -> n626 [label="F"];
n625 [label="0", shape=box];
n625 -> n614;
n614 [label="END f1(b)", shape=ellipse, style=filled, color=green];
n614 -> n631;
n614 -> n642;
n614 -> n646;
n614 -> n665;
n631 [label="RET f1", shape=box, style=filled, color=orange];
n631 -> n614;
n642 [label="RET f1", shape=box, style=filled, color=orange];
n642 -> n655;
n655 [label="a", shape=box];
n655 -> n656;
n656 [label="b", shape=box];
n656 -> n657;
n657 [label="a * b", shape=box];
n657 -> n658;
n658 [label="CALL g", shape=box, style=filled, color=orange];
n658 -> n647;
n658 -> n660;
n647 [label="START g(c)", shape=ellipse, style=filled, color=green];
n647 -> n650;
n650 [label="a", shape=box];
n650 -> n651;
n651 [label="b", shape=box];
n651 -> n652;
n652 [label="a * b", shape=box];
n652 -> n653;
n653 [label="c", shape=box];
n653 -> n654;
n654 [label="(a * b) * c", shape=box];
n654 -> n648;
n648 [label="END g(c)", shape=ellipse, style=filled, color=green];
n648 -> n660;
n660 [label="RET g", shape=box, style=filled, color=orange];
n660 -> n616;
n616 [label="END f2(a, b)", shape=ellipse, style=filled, color=green];
n616 -> n688;
n688 [label="RET f2", shape=box, style=filled, color=orange];
n688 -> n612;
n612 [label="END", shape=ellipse, style=filled, color=gray];
n646 [label="RET f1", shape=box, style=filled, color=orange];
n646 -> n655;
n665 [label="RET f1", shape=box, style=filled, color=orange];
n665 -> n667;
n667 [label="10", shape=box];
n667 -> n680;
n680 [label="20", shape=box];
n680 -> n681;
n681 [label="30", shape=box];
n681 -> n682;
n682 [label="CALL max", shape=box, style=filled, color=orange];
n682 -> n668;
n682 -> n684;
n668 [label="START max(a, b)", shape=ellipse, style=filled, color=green];
n668 -> n671;
n671 [label="a", shape=box];
n671 -> n672;
n672 [label="b", shape=box];
n672 -> n673;
n673 [label="a > b", shape=box];
n673 -> n674;
n674 [label="<?>", shape=diamond];
n674 -> n678 [label="T"];
n674 -> n679 [label="F"];
n678 [label="a", shape=box];
n678 -> n669;
n669 [label="END max(a, b)", shape=ellipse, style=filled, color=green];
n669 -> n684;
n684 [label="RET max", shape=box, style=filled, color=orange];
n684 -> n686;
n686 [label="CALL f2", shape=box, style=filled, color=orange];
n686 -> n615;
n686 -> n688;
n615 [label="START f2(a, b)", shape=ellipse, style=filled, color=green];
n615 -> n632;
n632 [label="a", shape=box];
n632 -> n633;
n633 [label="b", shape=box];
n633 -> n634;
n634 [label="a > b", shape=box];
n634 -> n635;
n635 [label="<?>", shape=diamond];
n635 -> n639 [label="T"];
n635 -> n643 [label="F"];
n639 [label="a", shape=box];
n639 -> n640;
n640 [label="CALL f1", shape=box, style=filled, color=orange];
n640 -> n613;
n640 -> n642;
n643 [label="b", shape=box];
n643 -> n644;
n644 [label="CALL f1", shape=box, style=filled, color=orange];
n644 -> n613;
n644 -> n646;
n679 [label="b", shape=box];
n679 -> n669;
n626 [label="b", shape=box];
n626 -> n627;
n627 [label="1", shape=box];
n627 -> n628;
n628 [label="b - 1", shape=box];
n628 -> n629;
n629 [label="CALL f1", shape=box, style=filled, color=orange];
n629 -> n613;
n629 -> n631;
}

View File

@@ -0,0 +1,27 @@
digraph CFG {
node [fontname="Helvetica"];
n689 [label="START", shape=ellipse, style=filled, color=gray];
n689 -> n698;
n698 [label="10", shape=box];
n698 -> n699;
n699 [label="8", shape=box];
n699 -> n700;
n700 [label="CALL func", shape=box, style=filled, color=orange];
n700 -> n691;
n700 -> n702;
n691 [label="START func(a, b)", shape=ellipse, style=filled, color=green];
n691 -> n694;
n694 [label="b", shape=box];
n694 -> n695;
n695 [label="1", shape=box];
n695 -> n696;
n696 [label="b + 1", shape=box];
n696 -> n697;
n697 [label="a = (b + 1)", shape=box];
n697 -> n692;
n692 [label="END func(a, b)", shape=ellipse, style=filled, color=green];
n692 -> n702;
n702 [label="RET func", shape=box, style=filled, color=orange];
n702 -> n690;
n690 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,31 @@
digraph CFG {
node [fontname="Helvetica"];
n704 [label="START", shape=ellipse, style=filled, color=gray];
n704 -> n706;
n706 [label="10", shape=box];
n706 -> n707;
n707 [label="8", shape=box];
n707 -> n708;
n708 [label="CALL func", shape=box, style=filled, color=orange];
n708 -> n691;
n708 -> n710;
n691 [label="START func(a, b)", shape=ellipse, style=filled, color=green];
n691 -> n694;
n694 [label="b", shape=box];
n694 -> n695;
n695 [label="1", shape=box];
n695 -> n696;
n696 [label="b + 1", shape=box];
n696 -> n697;
n697 [label="a = (b + 1)", shape=box];
n697 -> n692;
n692 [label="END func(a, b)", shape=ellipse, style=filled, color=green];
n692 -> n702;
n692 -> n710;
n702 [label="RET func", shape=box, style=filled, color=orange];
n702 -> n690;
n690 [label="END", shape=ellipse, style=filled, color=gray];
n710 [label="RET func", shape=box, style=filled, color=orange];
n710 -> n705;
n705 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,105 @@
digraph CFG {
node [fontname="Helvetica"];
n711 [label="START", shape=ellipse, style=filled, color=gray];
n711 -> n763;
n763 [label="2", shape=box];
n763 -> n764;
n764 [label="3", shape=box];
n764 -> n765;
n765 [label="CALL f", shape=box, style=filled, color=orange];
n765 -> n713;
n765 -> n767;
n713 [label="START f(a, b)", shape=ellipse, style=filled, color=green];
n713 -> n718;
n718 [label="a", shape=box];
n718 -> n719;
n719 [label="0", shape=box];
n719 -> n720;
n720 [label="a == 0", shape=box];
n720 -> n721;
n721 [label="<?>", shape=diamond];
n721 -> n725 [label="T"];
n721 -> n736 [label="F"];
n725 [label="2", shape=box];
n725 -> n726;
n726 [label="b", shape=box];
n726 -> n727;
n727 [label="2 + b", shape=box];
n727 -> n714;
n714 [label="END f(a, b)", shape=ellipse, style=filled, color=green];
n714 -> n761;
n714 -> n767;
n761 [label="RET f", shape=box, style=filled, color=orange];
n761 -> n762;
n762 [label="c * f((c - 1),d)", shape=box];
n762 -> n729;
n729 [label="END g(a, c)", shape=ellipse, style=filled, color=green];
n729 -> n741;
n729 -> n773;
n741 [label="RET g", shape=box, style=filled, color=orange];
n741 -> n742;
n742 [label="2 + g(a,b)", shape=box];
n742 -> n714;
n773 [label="RET g", shape=box, style=filled, color=orange];
n773 -> n712;
n712 [label="END", shape=ellipse, style=filled, color=gray];
n767 [label="RET f", shape=box, style=filled, color=orange];
n767 -> n769;
n769 [label="3", shape=box];
n769 -> n770;
n770 [label="2", shape=box];
n770 -> n771;
n771 [label="CALL g", shape=box, style=filled, color=orange];
n771 -> n728;
n771 -> n773;
n728 [label="START g(a, c)", shape=ellipse, style=filled, color=green];
n728 -> n731;
n728 -> n744;
n731 [label="a", shape=box];
n731 -> n732;
n732 [label="c", shape=box];
n732 -> n733;
n733 [label="a + c", shape=box];
n733 -> n734;
n734 [label="b", shape=box];
n734 -> n735;
n735 [label="(a + c) + b", shape=box];
n735 -> n729;
n744 [label="c", shape=box];
n744 -> n745;
n745 [label="0", shape=box];
n745 -> n746;
n746 [label="c == 0", shape=box];
n746 -> n747;
n747 [label="<?>", shape=diamond];
n747 -> n751 [label="T"];
n747 -> n754 [label="F"];
n751 [label="1", shape=box];
n751 -> n752;
n752 [label="d", shape=box];
n752 -> n753;
n753 [label="1 + d", shape=box];
n753 -> n729;
n754 [label="c", shape=box];
n754 -> n755;
n755 [label="c", shape=box];
n755 -> n756;
n756 [label="1", shape=box];
n756 -> n757;
n757 [label="c - 1", shape=box];
n757 -> n758;
n758 [label="d", shape=box];
n758 -> n759;
n759 [label="CALL f", shape=box, style=filled, color=orange];
n759 -> n713;
n759 -> n761;
n736 [label="2", shape=box];
n736 -> n737;
n737 [label="a", shape=box];
n737 -> n738;
n738 [label="b", shape=box];
n738 -> n739;
n739 [label="CALL g", shape=box, style=filled, color=orange];
n739 -> n728;
n739 -> n741;
}

View File

@@ -0,0 +1,42 @@
digraph CFG {
node [fontname="Helvetica"];
n774 [label="START", shape=ellipse, style=filled, color=gray];
n774 -> n793;
n793 [label="1", shape=box];
n793 -> n794;
n794 [label="2", shape=box];
n794 -> n795;
n795 [label="CALL f", shape=box, style=filled, color=orange];
n795 -> n776;
n795 -> n797;
n776 [label="START f(x, y)", shape=ellipse, style=filled, color=green];
n776 -> n786;
n786 [label="5", shape=box];
n786 -> n787;
n787 [label="CALL g", shape=box, style=filled, color=orange];
n787 -> n779;
n787 -> n789;
n779 [label="START g(x)", shape=ellipse, style=filled, color=green];
n779 -> n782;
n782 [label="x", shape=box];
n782 -> n783;
n783 [label="7", shape=box];
n783 -> n784;
n784 [label="x + 7", shape=box];
n784 -> n785;
n785 [label="y = (x + 7)", shape=box];
n785 -> n780;
n780 [label="END g(x)", shape=ellipse, style=filled, color=green];
n780 -> n789;
n789 [label="RET g", shape=box, style=filled, color=orange];
n789 -> n790;
n790 [label="x = g(5)", shape=box];
n790 -> n792;
n792 [label="y", shape=box];
n792 -> n777;
n777 [label="END f(x, y)", shape=ellipse, style=filled, color=green];
n777 -> n797;
n797 [label="RET f", shape=box, style=filled, color=orange];
n797 -> n775;
n775 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,61 @@
digraph CFG {
node [fontname="Helvetica"];
n799 [label="START", shape=ellipse, style=filled, color=gray];
n799 -> n830;
n830 [label="3", shape=box];
n830 -> n831;
n831 [label="CALL f", shape=box, style=filled, color=orange];
n831 -> n801;
n831 -> n833;
n801 [label="START f(x)", shape=ellipse, style=filled, color=green];
n801 -> n804;
n804 [label="2", shape=box];
n804 -> n805;
n805 [label="x", shape=box];
n805 -> n806;
n806 [label="2 * x", shape=box];
n806 -> n807;
n807 [label="x = (2 * x)", shape=box];
n807 -> n808;
n808 [label="x", shape=box];
n808 -> n809;
n809 [label="0", shape=box];
n809 -> n810;
n810 [label="x > 0", shape=box];
n810 -> n811;
n811 [label="<?>", shape=diamond];
n811 -> n815 [label="T"];
n811 -> n819 [label="F"];
n815 [label="x", shape=box];
n815 -> n816;
n816 [label="1", shape=box];
n816 -> n817;
n817 [label="x - 1", shape=box];
n817 -> n818;
n818 [label="x = (x - 1)", shape=box];
n818 -> n820;
n820 [label="x", shape=box];
n820 -> n821;
n821 [label="0", shape=box];
n821 -> n822;
n822 [label="x > 0", shape=box];
n822 -> n823;
n823 [label="<?>", shape=diamond];
n823 -> n802 [label="T"];
n823 -> n825 [label="F"];
n802 [label="END f(x)", shape=ellipse, style=filled, color=green];
n802 -> n833;
n833 [label="RET f", shape=box, style=filled, color=orange];
n833 -> n800;
n800 [label="END", shape=ellipse, style=filled, color=gray];
n825 [label="x", shape=box];
n825 -> n826;
n826 [label="1", shape=box];
n826 -> n827;
n827 [label="x - 1", shape=box];
n827 -> n828;
n828 [label="x = (x - 1)", shape=box];
n828 -> n820;
n819 [label="x", shape=box];
n819 -> n820;
}

View File

@@ -0,0 +1,23 @@
digraph CFG {
node [fontname="Helvetica"];
n835 [label="START", shape=ellipse, style=filled, color=gray];
n835 -> n843;
n843 [label="2", shape=box];
n843 -> n844;
n844 [label="CALL g", shape=box, style=filled, color=orange];
n844 -> n837;
n844 -> n846;
n837 [label="START g(x, y)", shape=ellipse, style=filled, color=green];
n837 -> n840;
n840 [label="3", shape=box];
n840 -> n841;
n841 [label="y = 3", shape=box];
n841 -> n842;
n842 [label="x", shape=box];
n842 -> n838;
n838 [label="END g(x, y)", shape=ellipse, style=filled, color=green];
n838 -> n846;
n846 [label="RET g", shape=box, style=filled, color=orange];
n846 -> n836;
n836 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,15 @@
digraph CFG {
node [fontname="Helvetica"];
n848 [label="START", shape=ellipse, style=filled, color=gray];
n848 -> n850;
n850 [label="True", shape=box];
n850 -> n851;
n851 [label="<?>", shape=diamond];
n851 -> n855 [label="T"];
n851 -> n856 [label="F"];
n855 [label="1", shape=box];
n855 -> n849;
n849 [label="END", shape=ellipse, style=filled, color=gray];
n856 [label="0", shape=box];
n856 -> n849;
}

View File

@@ -0,0 +1,19 @@
digraph CFG {
node [fontname="Helvetica"];
n857 [label="START", shape=ellipse, style=filled, color=gray];
n857 -> n859;
n859 [label="True", shape=box];
n859 -> n860;
n860 [label="False", shape=box];
n860 -> n861;
n861 [label="True && False", shape=box];
n861 -> n862;
n862 [label="<?>", shape=diamond];
n862 -> n866 [label="T"];
n862 -> n867 [label="F"];
n866 [label="1", shape=box];
n866 -> n858;
n858 [label="END", shape=ellipse, style=filled, color=gray];
n867 [label="0", shape=box];
n867 -> n858;
}

View File

@@ -0,0 +1,19 @@
digraph CFG {
node [fontname="Helvetica"];
n868 [label="START", shape=ellipse, style=filled, color=gray];
n868 -> n870;
n870 [label="True", shape=box];
n870 -> n871;
n871 [label="False", shape=box];
n871 -> n872;
n872 [label="True || False", shape=box];
n872 -> n873;
n873 [label="<?>", shape=diamond];
n873 -> n877 [label="T"];
n873 -> n878 [label="F"];
n877 [label="1", shape=box];
n877 -> n869;
n869 [label="END", shape=ellipse, style=filled, color=gray];
n878 [label="0", shape=box];
n878 -> n869;
}

View File

@@ -0,0 +1,19 @@
digraph CFG {
node [fontname="Helvetica"];
n879 [label="START", shape=ellipse, style=filled, color=gray];
n879 -> n881;
n881 [label="1", shape=box];
n881 -> n882;
n882 [label="2", shape=box];
n882 -> n883;
n883 [label="1 > 2", shape=box];
n883 -> n884;
n884 [label="<?>", shape=diamond];
n884 -> n888 [label="T"];
n884 -> n889 [label="F"];
n888 [label="1", shape=box];
n888 -> n880;
n880 [label="END", shape=ellipse, style=filled, color=gray];
n889 [label="0", shape=box];
n889 -> n880;
}

View File

@@ -0,0 +1,23 @@
digraph CFG {
node [fontname="Helvetica"];
n890 [label="START", shape=ellipse, style=filled, color=gray];
n890 -> n892;
n892 [label="2", shape=box];
n892 -> n893;
n893 [label="3", shape=box];
n893 -> n894;
n894 [label="5", shape=box];
n894 -> n895;
n895 [label="3 + 5", shape=box];
n895 -> n896;
n896 [label="2 > (3 + 5)", shape=box];
n896 -> n897;
n897 [label="<?>", shape=diamond];
n897 -> n901 [label="T"];
n897 -> n902 [label="F"];
n901 [label="1", shape=box];
n901 -> n891;
n891 [label="END", shape=ellipse, style=filled, color=gray];
n902 [label="0", shape=box];
n902 -> n891;
}

View File

@@ -0,0 +1,27 @@
digraph CFG {
node [fontname="Helvetica"];
n903 [label="START", shape=ellipse, style=filled, color=gray];
n903 -> n905;
n905 [label="1", shape=box];
n905 -> n906;
n906 [label="2", shape=box];
n906 -> n907;
n907 [label="1 > 2", shape=box];
n907 -> n908;
n908 [label="3", shape=box];
n908 -> n909;
n909 [label="5", shape=box];
n909 -> n910;
n910 [label="3 < 5", shape=box];
n910 -> n911;
n911 [label="(1 > 2) || (3 < 5)", shape=box];
n911 -> n912;
n912 [label="<?>", shape=diamond];
n912 -> n916 [label="T"];
n912 -> n917 [label="F"];
n916 [label="1", shape=box];
n916 -> n904;
n904 [label="END", shape=ellipse, style=filled, color=gray];
n917 [label="0", shape=box];
n917 -> n904;
}

View File

@@ -0,0 +1,23 @@
digraph CFG {
node [fontname="Helvetica"];
n918 [label="START", shape=ellipse, style=filled, color=gray];
n918 -> n920;
n920 [label="2", shape=box];
n920 -> n921;
n921 [label="0", shape=box];
n921 -> n922;
n922 [label="2 == 0", shape=box];
n922 -> n923;
n923 [label="False", shape=box];
n923 -> n924;
n924 [label="(2 == 0) == False", shape=box];
n924 -> n925;
n925 [label="<?>", shape=diamond];
n925 -> n929 [label="T"];
n925 -> n930 [label="F"];
n929 [label="1", shape=box];
n929 -> n919;
n919 [label="END", shape=ellipse, style=filled, color=gray];
n930 [label="0", shape=box];
n930 -> n919;
}

View File

@@ -0,0 +1,23 @@
digraph CFG {
node [fontname="Helvetica"];
n931 [label="START", shape=ellipse, style=filled, color=gray];
n931 -> n939;
n939 [label="10", shape=box];
n939 -> n940;
n940 [label="CALL square", shape=box, style=filled, color=orange];
n940 -> n933;
n940 -> n942;
n933 [label="START square(x)", shape=ellipse, style=filled, color=green];
n933 -> n936;
n936 [label="x", shape=box];
n936 -> n937;
n937 [label="x", shape=box];
n937 -> n938;
n938 [label="x * x", shape=box];
n938 -> n934;
n934 [label="END square(x)", shape=ellipse, style=filled, color=green];
n934 -> n942;
n942 [label="RET square", shape=box, style=filled, color=orange];
n942 -> n932;
n932 [label="END", shape=ellipse, style=filled, color=gray];
}

View File

@@ -0,0 +1,94 @@
digraph CFG {
node [fontname="Helvetica"];
n944 [label="START", shape=ellipse, style=filled, color=gray];
n944 -> n984;
n984 [label="2", shape=box];
n984 -> n985;
n985 [label="3", shape=box];
n985 -> n986;
n986 [label="CALL mult", shape=box, style=filled, color=orange];
n986 -> n946;
n986 -> n988;
n946 [label="START mult(a, b)", shape=ellipse, style=filled, color=green];
n946 -> n951;
n951 [label="a", shape=box];
n951 -> n952;
n952 [label="b", shape=box];
n952 -> n953;
n953 [label="a * b", shape=box];
n953 -> n947;
n947 [label="END mult(a, b)", shape=ellipse, style=filled, color=green];
n947 -> n978;
n947 -> n988;
n978 [label="RET mult", shape=box, style=filled, color=orange];
n978 -> n955;
n955 [label="END inc(a)", shape=ellipse, style=filled, color=green];
n955 -> n973;
n955 -> n982;
n973 [label="RET inc", shape=box, style=filled, color=orange];
n973 -> n955;
n982 [label="RET inc", shape=box, style=filled, color=orange];
n982 -> n949;
n949 [label="END add(a, b)", shape=ellipse, style=filled, color=green];
n949 -> n993;
n949 -> n996;
n993 [label="RET add", shape=box, style=filled, color=orange];
n993 -> n994;
n994 [label="CALL add", shape=box, style=filled, color=orange];
n994 -> n948;
n994 -> n996;
n948 [label="START add(a, b)", shape=ellipse, style=filled, color=green];
n948 -> n979;
n979 [label="a", shape=box];
n979 -> n980;
n980 [label="CALL inc", shape=box, style=filled, color=orange];
n980 -> n954;
n980 -> n982;
n954 [label="START inc(a)", shape=ellipse, style=filled, color=green];
n954 -> n957;
n957 [label="b", shape=box];
n957 -> n958;
n958 [label="0", shape=box];
n958 -> n959;
n959 [label="b != 0", shape=box];
n959 -> n960;
n960 [label="<?>", shape=diamond];
n960 -> n964 [label="T"];
n960 -> n974 [label="F"];
n964 [label="b", shape=box];
n964 -> n965;
n965 [label="1", shape=box];
n965 -> n966;
n966 [label="b - 1", shape=box];
n966 -> n967;
n967 [label="b = (b - 1)", shape=box];
n967 -> n968;
n968 [label="a", shape=box];
n968 -> n969;
n969 [label="1", shape=box];
n969 -> n970;
n970 [label="a + 1", shape=box];
n970 -> n971;
n971 [label="CALL inc", shape=box, style=filled, color=orange];
n971 -> n954;
n971 -> n973;
n974 [label="a", shape=box];
n974 -> n975;
n975 [label="1", shape=box];
n975 -> n976;
n976 [label="CALL mult", shape=box, style=filled, color=orange];
n976 -> n946;
n976 -> n978;
n996 [label="RET add", shape=box, style=filled, color=orange];
n996 -> n945;
n945 [label="END", shape=ellipse, style=filled, color=gray];
n988 [label="RET mult", shape=box, style=filled, color=orange];
n988 -> n989;
n989 [label="4", shape=box];
n989 -> n990;
n990 [label="5", shape=box];
n990 -> n991;
n991 [label="CALL add", shape=box, style=filled, color=orange];
n991 -> n948;
n991 -> n993;
}

View File

@@ -0,0 +1,52 @@
digraph CFG {
node [fontname="Helvetica"];
n998 [label="START", shape=ellipse, style=filled, color=gray];
n998 -> n1021;
n1021 [label="10", shape=box];
n1021 -> n1022;
n1022 [label="8", shape=box];
n1022 -> n1023;
n1023 [label="CALL func", shape=box, style=filled, color=orange];
n1023 -> n1000;
n1023 -> n1025;
n1000 [label="START func(a, b)", shape=ellipse, style=filled, color=green];
n1000 -> n1003;
n1003 [label="a", shape=box];
n1003 -> n1004;
n1004 [label="0", shape=box];
n1004 -> n1005;
n1005 [label="a > 0", shape=box];
n1005 -> n1006;
n1006 [label="b", shape=box];
n1006 -> n1007;
n1007 [label="a", shape=box];
n1007 -> n1008;
n1008 [label="b != a", shape=box];
n1008 -> n1009;
n1009 [label="(a > 0) && (b != a)", shape=box];
n1009 -> n1010;
n1010 [label="<?>", shape=diamond];
n1010 -> n1001 [label="T"];
n1010 -> n1012 [label="F"];
n1001 [label="END func(a, b)", shape=ellipse, style=filled, color=green];
n1001 -> n1025;
n1025 [label="RET func", shape=box, style=filled, color=orange];
n1025 -> n999;
n999 [label="END", shape=ellipse, style=filled, color=gray];
n1012 [label="b", shape=box];
n1012 -> n1013;
n1013 [label="1", shape=box];
n1013 -> n1014;
n1014 [label="b + 1", shape=box];
n1014 -> n1015;
n1015 [label="b = (b + 1)", shape=box];
n1015 -> n1016;
n1016 [label="a", shape=box];
n1016 -> n1017;
n1017 [label="1", shape=box];
n1017 -> n1018;
n1018 [label="a - 1", shape=box];
n1018 -> n1019;
n1019 [label="a = (a - 1)", shape=box];
n1019 -> n1005;
}

View File

@@ -0,0 +1,13 @@
digraph CFG {
node [fontname="Helvetica"];
n1027 [label="START", shape=ellipse, style=filled, color=gray];
n1027 -> n1029;
n1029 [label="True", shape=box];
n1029 -> n1030;
n1030 [label="<?>", shape=diamond];
n1030 -> n1028 [label="T"];
n1030 -> n1032 [label="F"];
n1028 [label="END", shape=ellipse, style=filled, color=gray];
n1032 [label="3", shape=box];
n1032 -> n1027;
}

View File

@@ -0,0 +1,78 @@
digraph CFG {
node [fontname="Helvetica"];
n1034 [label="START", shape=ellipse, style=filled, color=gray];
n1034 -> n1076;
n1076 [label="21", shape=box];
n1076 -> n1077;
n1077 [label="49", shape=box];
n1077 -> n1078;
n1078 [label="CALL wrapper", shape=box, style=filled, color=orange];
n1078 -> n1036;
n1078 -> n1080;
n1036 [label="START wrapper(a, b)", shape=ellipse, style=filled, color=green];
n1036 -> n1071;
n1071 [label="0", shape=box];
n1071 -> n1072;
n1072 [label="CALL ggt", shape=box, style=filled, color=orange];
n1072 -> n1039;
n1072 -> n1074;
n1039 [label="START ggt(noneSense)", shape=ellipse, style=filled, color=green];
n1039 -> n1042;
n1042 [label="a", shape=box];
n1042 -> n1043;
n1043 [label="b", shape=box];
n1043 -> n1044;
n1044 [label="a == b", shape=box];
n1044 -> n1045;
n1045 [label="<?>", shape=diamond];
n1045 -> n1049 [label="T"];
n1045 -> n1050 [label="F"];
n1049 [label="a", shape=box];
n1049 -> n1040;
n1040 [label="END ggt(noneSense)", shape=ellipse, style=filled, color=green];
n1040 -> n1074;
n1074 [label="RET ggt", shape=box, style=filled, color=orange];
n1074 -> n1037;
n1037 [label="END wrapper(a, b)", shape=ellipse, style=filled, color=green];
n1037 -> n1063;
n1037 -> n1070;
n1037 -> n1080;
n1063 [label="RET wrapper", shape=box, style=filled, color=orange];
n1063 -> n1040;
n1070 [label="RET wrapper", shape=box, style=filled, color=orange];
n1070 -> n1040;
n1080 [label="RET wrapper", shape=box, style=filled, color=orange];
n1080 -> n1035;
n1035 [label="END", shape=ellipse, style=filled, color=gray];
n1050 [label="a", shape=box];
n1050 -> n1051;
n1051 [label="b", shape=box];
n1051 -> n1052;
n1052 [label="a > b", shape=box];
n1052 -> n1053;
n1053 [label="<?>", shape=diamond];
n1053 -> n1057 [label="T"];
n1053 -> n1064 [label="F"];
n1057 [label="a", shape=box];
n1057 -> n1058;
n1058 [label="b", shape=box];
n1058 -> n1059;
n1059 [label="a - b", shape=box];
n1059 -> n1060;
n1060 [label="b", shape=box];
n1060 -> n1061;
n1061 [label="CALL wrapper", shape=box, style=filled, color=orange];
n1061 -> n1036;
n1061 -> n1063;
n1064 [label="b", shape=box];
n1064 -> n1065;
n1065 [label="a", shape=box];
n1065 -> n1066;
n1066 [label="b - a", shape=box];
n1066 -> n1067;
n1067 [label="a", shape=box];
n1067 -> n1068;
n1068 [label="CALL wrapper", shape=box, style=filled, color=orange];
n1068 -> n1036;
n1068 -> n1070;
}

View File

@@ -0,0 +1,51 @@
digraph CFG {
node [fontname="Helvetica"];
n1082 [label="START", shape=ellipse, style=filled, color=gray];
n1082 -> n1108;
n1108 [label="4", shape=box];
n1108 -> n1109;
n1109 [label="10", shape=box];
n1109 -> n1110;
n1110 [label="CALL wrapper", shape=box, style=filled, color=orange];
n1110 -> n1084;
n1110 -> n1112;
n1084 [label="START wrapper(number, threshold)", shape=ellipse, style=filled, color=green];
n1084 -> n1103;
n1103 [label="number", shape=box];
n1103 -> n1104;
n1104 [label="CALL square", shape=box, style=filled, color=orange];
n1104 -> n1087;
n1104 -> n1106;
n1087 [label="START square(x)", shape=ellipse, style=filled, color=green];
n1087 -> n1090;
n1090 [label="x", shape=box];
n1090 -> n1091;
n1091 [label="x", shape=box];
n1091 -> n1092;
n1092 [label="x * x", shape=box];
n1092 -> n1093;
n1093 [label="threshold", shape=box];
n1093 -> n1094;
n1094 [label="(x * x) > threshold", shape=box];
n1094 -> n1095;
n1095 [label="<?>", shape=diamond];
n1095 -> n1099 [label="T"];
n1095 -> n1100 [label="F"];
n1099 [label="x", shape=box];
n1099 -> n1088;
n1088 [label="END square(x)", shape=ellipse, style=filled, color=green];
n1088 -> n1106;
n1106 [label="RET square", shape=box, style=filled, color=orange];
n1106 -> n1085;
n1085 [label="END wrapper(number, threshold)", shape=ellipse, style=filled, color=green];
n1085 -> n1112;
n1112 [label="RET wrapper", shape=box, style=filled, color=orange];
n1112 -> n1083;
n1083 [label="END", shape=ellipse, style=filled, color=gray];
n1100 [label="x", shape=box];
n1100 -> n1101;
n1101 [label="x", shape=box];
n1101 -> n1102;
n1102 [label="x * x", shape=box];
n1102 -> n1088;
}

View File

@@ -0,0 +1,175 @@
import syntax
from vistram.tram import *
label_counter = 0
def new_label():
global label_counter
label_counter += 1
return Label(text=f"L{label_counter}")
# Rules E1, E2
def elab_def(decls, rho, nl):
r = dict(rho)
for d in decls:
r = d.elab(r, nl)
return r
# Rule K6
class CONST(syntax.CONST):
def code(self, rho, nl):
return [const(self.value)]
# Rule K3
class ID(syntax.ID):
def code(self, rho, nl):
k, nl_def = rho[self.name]
return [load(k, nl - nl_def)]
# Rule K7
class AOP(syntax.AOP):
def code(self, rho, nl):
c1 = self.arg1.code(rho, nl)
c2 = self.arg2.code(rho, nl)
match self.operator:
case "+":
return c1 + c2 + [add()]
case "-":
return c1 + c2 + [sub()]
case "*":
return c1 + c2 + [mul()]
case "/":
return c1 + c2 + [div()]
case _:
raise Exception(f"Unknown AOP operator.")
# Rule K5
class COMP(syntax.COMP):
def code(self, rho, nl):
c1 = self.arg1.code(rho, nl)
c2 = self.arg2.code(rho, nl)
match self.operator:
case "<":
return c1 + c2 + [lt()]
case ">":
return c1 + c2 + [gt()]
case "<=":
# leq is not implemented in vistra.tram
return LOP("||", COMP("<", self.arg1, self.arg2), EQOP("==", self.arg1, self.arg2)).code(rho, nl)
case ">=":
# geq is not implemented in vistra.tram
return LOP("||", COMP(">", self.arg1, self.arg2), EQOP("==", self.arg1, self.arg2)).code(rho, nl)
case _:
raise ValueError(f"Unknown COMP operator.")
# Rule K5
class EQOP(syntax.EQOP):
def code(self, rho, nl):
c1 = self.arg1.code(rho, nl)
c2 = self.arg2.code(rho, nl)
match self.operator:
case "==":
return c1 + c2 + [eq()]
case "!=":
return c1 + c2 + [neq()]
case _:
raise ValueError(f"Unknown EQOP operator.")
# see lecture code generation AND/OR
class LOP(syntax.LOP):
def code(self, rho, nl):
c1 = self.arg1.code(rho, nl)
c2 = self.arg2.code(rho, nl)
l1 = new_label()
l2 = new_label()
match self.operator:
case "&&":
return c1 + [ifzero(l1)] + [const(1)] + c2 + [mul()] + [goto(l2)] + [nop(l1)] + [const(0)] + [nop(l2)]
case "||":
return c1 + [ifzero(l1)] + [const(1)] + [goto(l2)] + [nop(l1)] + c2 + [nop(l2)]
case _:
raise ValueError("Unknown LOP operator.")
# Rule K4
class ASSIGN(syntax.ASSIGN):
def code(self, rho, nl):
c = self.expr.code(rho, nl)
k, nl_def = rho[self.var.name]
dif = nl - nl_def
return c + [store(k, dif), load(k, dif)]
# Rule K9
class SEQ(syntax.SEQ):
def code(self, rho, nl):
c1 = self.exp1.code(rho, nl)
c2 = self.exp2.code(rho, nl)
return c1 + [pop()] + c2
# Rule K10
class IF(syntax.IF):
def code(self, rho, nl):
l1 = new_label()
l2 = new_label()
c1 = self.cond.code(rho, nl)
c2 = self.exp1.code(rho, nl)
c3 = self.exp2.code(rho, nl)
return c1 + [ifzero(l1)] + c2 + [goto(l2)] + [nop(assigned_label=l1)] + c3 + [nop(assigned_label=l2)]
# Rule K11
class WHILE(syntax.WHILE):
def code(self, rho, nl):
l1 = new_label()
l2 = new_label()
l3 = new_label()
l4 = new_label()
c1 = self.cond.code(rho, nl)
c2 = self.body.code(rho, nl)
return c1 + [ifzero(l3), goto(l4)] + [nop(l1)] + c1 + [ifzero(l2), pop()] + [nop(l4)] + c2 + [goto(l1)] + [nop(l3), const(None), nop(l2)]
# Rule K2
class LET(syntax.LET):
def code(self, rho, nl):
l = new_label()
# Normalize to list
decls = self.decl if isinstance(self.decl, list) else [self.decl]
shared_rho = elab_def(decls, rho, nl)
ds = []
for d in decls:
ds += d.code(shared_rho, nl)
es = self.body.code(shared_rho, nl)
return [goto(l)] + ds + [nop(assigned_label=l)] + es
# Rule K13
class DECL(syntax.DECL):
def elab(self, rho, nl):
nested_rho = dict(rho)
nested_rho[self.f_name] = (new_label(), nl)
return nested_rho
def code(self, rho, nl):
l, _ = rho[self.f_name]
nested_rho = dict(rho)
for i, p in enumerate(self.params):
nested_rho[p] = (i, nl + 1)
c = self.body.code(nested_rho, nl + 1)
return [nop(assigned_label=l)] + c + [ireturn()]
# Rule K12
class CALL(syntax.CALL):
def code(self, rho, nl):
c = []
for a in self.arg:
c += a.code(rho, nl)
l, nl_def = rho[self.f_name]
return c + [invoke(len(self.arg), l, nl - nl_def)]

View File

View File

@@ -0,0 +1,22 @@
from pathlib import Path
def prompt_choice(prompt: str, options: list) -> int:
print(prompt)
for i, opt in enumerate(options, 1):
print(f" {i}. {opt}")
while True:
try:
s = input(f"Enter choice (1-{len(options)}): ").strip()
idx = int(s) - 1
if 0 <= idx < len(options):
return idx
except Exception:
pass
print(f"Invalid. Enter a number between 1-{len(options)}.")
def prompt_confirmation(question: str, default="y"):
s = input(f"{question} (y/n) [{default}]: ").strip().lower()
if not s:
s = default
return s.startswith("y")

171
Project-02-03-04-05/main.py Normal file
View File

@@ -0,0 +1,171 @@
import os
import tkinter as tk
from pathlib import Path
import matplotlib
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
from graphviz import Source
import lib.console as cnsl
import syntax
import triplayacc as yacc
from cfg.CFG import CFG
from vistram.tram import *
from vistram.vistram import MachineUI
matplotlib.use("TkAgg")
# Assembles the AST into TRAM code
def assemble(ast):
code = ast.code({}, 0)
return code + [halt()]
def make_cfg(ast):
return CFG(ast)
# Renders a diagram of the AST
def render_diagram(dot_string: str):
# Set DPI for PNG
os.environ["GV_FILE_DPI"] = "300"
src = Source(dot_string, format="png", engine="dot")
png_path = src.render(cleanup=True)
img = mpimg.imread(png_path)
fig = plt.figure(figsize=(12, 12))
fig.canvas.manager.window.wm_title("TRIPLA AST Viewer")
plt.imshow(img)
plt.axis("off")
plt.show()
# Pretty prints the AST
def pretty_print(node, indent=0):
prefix = " " * indent
print(f"{prefix}{type(node).__name__}:")
for key, value in node.__dict__.items():
if isinstance(value, syntax.EXPRESSION):
pretty_print(value, indent + 4)
elif isinstance(value, list):
print(f"{prefix} {key}: [")
for element in value:
if isinstance(element, syntax.EXPRESSION):
pretty_print(element, indent + 4)
else:
print(" " * (indent + 4) + str(element))
print(f"{prefix} ]")
else:
print(f"{prefix} {key}: {value}")
if __name__ == "__main__":
print("\nTRIPLA Parser and TRIPLA to TRAM Compiler")
while True:
mode = cnsl.prompt_choice("\nSelect action:", ["Parse .tripla", "Compile .tripla", "CFG for .tripla", "Exit"])
if mode == 3:
print("\nBye Bye.")
break
base = Path(__file__).parent / "triplaprograms"
programs = sorted([f for f in base.glob("*.tripla")])
if not programs:
print("\nNo .tripla files found.")
continue
idx = cnsl.prompt_choice("\nSelect TRIPLA program:", [p.name for p in programs])
path = programs[idx]
source = path.read_text()
ast = yacc.parser.parse(source)
if mode == 0:
# Pretty print
if cnsl.prompt_confirmation("\nPretty-print AST?"):
print("")
pretty_print(ast)
# Export DOT
dot_str = ast.to_dot()
if cnsl.prompt_confirmation("Export AST as .dot file?"):
default = f"{path.stem}.dot"
filename = input(f"Filename [{default}]: ").strip()
if not filename:
filename = default
try:
base_dir = Path(__file__).parent
out_path = base_dir / filename
with open(out_path, "w") as f:
f.write(dot_str)
print(f"Saved DOT file as: {out_path}")
except Exception as e:
print(f"Could not save DOT file: {e}")
# Display AST diagram
if cnsl.prompt_confirmation("Display AST diagram?"):
render_diagram(dot_str)
print("Rendered AST diagram.")
elif mode == 1:
tram_code = assemble(ast)
# Print TRAM code
if cnsl.prompt_confirmation("\nPrint TRAM code to console?"):
print("\nGenerated TRAM code:\n")
for instr in tram_code:
print(instr.toString())
# Save TRAM code
if cnsl.prompt_confirmation("Save TRAM code as .tram file?"):
base_dir = Path(__file__).parent / "tramcodes"
base_dir.mkdir(exist_ok=True)
default = f"{path.stem}.tram"
filename = input(f"Filename [{default}]: ").strip()
if not filename:
filename = default
out_path = base_dir / filename
with open(out_path, "w") as f:
for instr in tram_code:
f.write(instr.toString() + "\n")
print(f"Saved TRAM code to: {out_path}")
# Display TRAM code in Visual TRAM UI
if cnsl.prompt_confirmation("Display TRAM code in Visual TRAM UI?"):
root = tk.Tk()
ui = MachineUI(root)
ui.machine.initial_program = tram_code
ui.machine.reset()
root.mainloop()
elif mode == 2:
cfg = make_cfg(ast)
dot_str = cfg.to_dot()
if cnsl.prompt_confirmation("\nExport CFG as .dot file?"):
default = f"{path.stem}_cfg.dot"
filename = input(f"Filename [{default}]: ").strip()
if not filename:
filename = default
out_path = Path(__file__).parent / 'cfgdots' / filename
with open(out_path, "w") as f:
f.write(dot_str)
print(f"Saved CFG DOT file as: {out_path}")
if cnsl.prompt_confirmation("Display CFG diagram?"):
render_diagram(dot_str)
print("Rendered CFG diagram.")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,53 @@
# parsetab.py
# This file is automatically generated. Do not edit.
# pylint: disable=W,C,R
_tabversion = '3.10'
_lr_method = 'LALR'
_lr_signature = 'EleftSEMICOLONleftINleftELSEleftCOMMArightASSIGNleftCOMPleftEQOPleftAOPleftCOMPleftEQOPAOP ASSIGN COMMA COMP CONST DO ELSE EQOP FALSE ID IF IN LBRACE LET LOP LPAREN RBRACE RPAREN SEMICOLON THEN TRUE WHILEE : LET D IN EE : IDE : ID LPAREN A RPARENE : E AOP EE : LPAREN E RPARENE : CONSTE : ID ASSIGN EE : E SEMICOLON EE : IF B THEN E ELSE EE : WHILE B DO LBRACE E RBRACEA : EA : A COMMA ED : ID LPAREN V RPAREN LBRACE E RBRACED : D DV : IDV : V COMMA VB : E EQOP EB : E COMP EB : B EQOP BB : B LOP BB : TRUEB : FALSEB : LPAREN B RPAREN'
_lr_action_items = {'LET':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,]),'ID':([0,2,4,6,7,8,9,10,12,13,19,23,24,25,30,31,32,33,34,42,49,51,53,55,60,],[3,11,3,3,3,3,3,11,3,3,3,11,3,39,3,3,3,3,3,3,3,39,3,3,-13,]),'LPAREN':([0,3,4,6,7,8,9,11,12,13,19,24,30,31,32,33,34,42,49,53,55,],[4,12,4,19,19,4,4,25,4,4,19,4,4,19,19,4,4,4,4,4,4,]),'CONST':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,]),'IF':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,]),'WHILE':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,]),'$end':([1,3,5,21,22,28,29,38,41,57,58,],[0,-2,-6,-4,-8,-7,-5,-1,-3,-9,-10,]),'AOP':([1,3,5,14,16,21,22,27,28,29,36,38,41,43,46,47,52,54,57,58,59,],[8,-2,-6,8,8,-4,8,8,8,-5,8,8,-3,8,8,8,8,8,8,-10,8,]),'SEMICOLON':([1,3,5,14,16,21,22,27,28,29,36,38,41,43,46,47,52,54,57,58,59,],[9,-2,-6,9,9,-4,-8,9,-7,-5,9,-1,-3,9,9,9,9,9,-9,-10,9,]),'RPAREN':([3,5,14,17,18,21,22,26,27,28,29,35,36,38,39,40,41,44,45,46,47,48,52,56,57,58,],[-2,-6,29,-21,-22,-4,-8,41,-11,-7,-5,48,29,-1,-15,50,-3,-19,-20,-17,-18,-23,-12,-16,-9,-10,]),'EQOP':([3,5,15,16,17,18,20,21,22,28,29,35,36,38,41,44,45,46,47,48,57,58,],[-2,-6,31,33,-21,-22,31,-4,-8,-7,-5,31,33,-1,-3,-19,31,-17,-18,-23,-9,-10,]),'COMP':([3,5,16,21,22,28,29,36,38,41,57,58,],[-2,-6,34,-4,-8,-7,-5,34,-1,-3,-9,-10,]),'COMMA':([3,5,21,22,26,27,28,29,38,39,40,41,52,56,57,58,],[-2,-6,-4,-8,42,-11,-7,-5,-1,-15,51,-3,-12,-16,-9,-10,]),'ELSE':([3,5,21,22,28,29,38,41,43,57,58,],[-2,-6,-4,-8,-7,-5,-1,-3,53,-9,-10,]),'THEN':([3,5,15,17,18,21,22,28,29,38,41,44,45,46,47,48,57,58,],[-2,-6,30,-21,-22,-4,-8,-7,-5,-1,-3,-19,-20,-17,-18,-23,-9,-10,]),'LOP':([3,5,15,17,18,20,21,22,28,29,35,38,41,44,45,46,47,48,57,58,],[-2,-6,32,-21,-22,32,-4,-8,-7,-5,32,-1,-3,-19,32,-17,-18,-23,-9,-10,]),'DO':([3,5,17,18,20,21,22,28,29,38,41,44,45,46,47,48,57,58,],[-2,-6,-21,-22,37,-4,-8,-7,-5,-1,-3,-19,-20,-17,-18,-23,-9,-10,]),'RBRACE':([3,5,21,22,28,29,38,41,54,57,58,59,],[-2,-6,-4,-8,-7,-5,-1,-3,58,-9,-10,60,]),'ASSIGN':([3,],[13,]),'TRUE':([6,7,19,31,32,],[17,17,17,17,17,]),'FALSE':([6,7,19,31,32,],[18,18,18,18,18,]),'IN':([10,23,60,],[24,-14,-13,]),'LBRACE':([37,50,],[49,55,]),}
_lr_action = {}
for _k, _v in _lr_action_items.items():
for _x,_y in zip(_v[0],_v[1]):
if not _x in _lr_action: _lr_action[_x] = {}
_lr_action[_x][_k] = _y
del _lr_action_items
_lr_goto_items = {'E':([0,4,6,7,8,9,12,13,19,24,30,31,32,33,34,42,49,53,55,],[1,14,16,16,21,22,27,28,36,38,43,16,16,46,47,52,54,57,59,]),'D':([2,10,23,],[10,23,23,]),'B':([6,7,19,31,32,],[15,20,35,44,45,]),'A':([12,],[26,]),'V':([25,51,],[40,56,]),}
_lr_goto = {}
for _k, _v in _lr_goto_items.items():
for _x, _y in zip(_v[0], _v[1]):
if not _x in _lr_goto: _lr_goto[_x] = {}
_lr_goto[_x][_k] = _y
del _lr_goto_items
_lr_productions = [
("S' -> E","S'",1,None,None,None),
('E -> LET D IN E','E',4,'p_E_let','triplayacc.py',30),
('E -> ID','E',1,'p_E_id','triplayacc.py',34),
('E -> ID LPAREN A RPAREN','E',4,'p_E_call','triplayacc.py',38),
('E -> E AOP E','E',3,'p_E_aop','triplayacc.py',43),
('E -> LPAREN E RPAREN','E',3,'p_E_paren','triplayacc.py',47),
('E -> CONST','E',1,'p_E_const','triplayacc.py',52),
('E -> ID ASSIGN E','E',3,'p_E_assign','triplayacc.py',56),
('E -> E SEMICOLON E','E',3,'p_E_seq','triplayacc.py',60),
('E -> IF B THEN E ELSE E','E',6,'p_E_if','triplayacc.py',64),
('E -> WHILE B DO LBRACE E RBRACE','E',6,'p_E_while','triplayacc.py',68),
('A -> E','A',1,'p_A_single','triplayacc.py',77),
('A -> A COMMA E','A',3,'p_A_multiple','triplayacc.py',81),
('D -> ID LPAREN V RPAREN LBRACE E RBRACE','D',7,'p_D_single','triplayacc.py',89),
('D -> D D','D',2,'p_D_concat','triplayacc.py',93),
('V -> ID','V',1,'p_V_single','triplayacc.py',101),
('V -> V COMMA V','V',3,'p_V_multiple','triplayacc.py',105),
('B -> E EQOP E','B',3,'p_B_eqop_E','triplayacc.py',113),
('B -> E COMP E','B',3,'p_B_comp','triplayacc.py',117),
('B -> B EQOP B','B',3,'p_B_eqop_B','triplayacc.py',121),
('B -> B LOP B','B',3,'p_B_lop','triplayacc.py',125),
('B -> TRUE','B',1,'p_B_true','triplayacc.py',129),
('B -> FALSE','B',1,'p_B_false','triplayacc.py',133),
('B -> LPAREN B RPAREN','B',3,'p_B_paren','triplayacc.py',137),
]

View File

@@ -0,0 +1,183 @@
class EXPRESSION:
pp_count = 0
def __init__(self):
self.pp = EXPRESSION.pp_count
EXPRESSION.pp_count += 1
@staticmethod
def copy():
return EXPRESSION()
# Returns a list of tuples (edge_name, child_expression)
def children(self):
out = []
for key, value in self.__dict__.items():
if key == "pp":
continue
if isinstance(value, EXPRESSION):
out.append((key, value))
elif isinstance(value, list):
for i, elem in enumerate(value):
if isinstance(elem, EXPRESSION):
out.append((f"{key}{i}", elem))
return out
# Export AST to dot format
def to_dot(self, visited=None, root=True):
if visited is None:
visited = set()
# Prevent infinite recursion
if id(self) in visited:
return ""
visited.add(id(self))
parts = []
# Add a header at the root node
if root:
parts.append("digraph AST {\n")
# Append to label
label = type(self).__name__
if hasattr(self, "operator"):
label += f"({self.operator})"
if hasattr(self, "name"):
label += f"({self.name})"
if hasattr(self, "value"):
label += f"({self.value})"
parts.append(f' node{self.pp} [label="{label}"];\n')
# Draw edges
for edge_name, child in self.children():
parts.append(f' node{self.pp} -> node{child.pp} [label="{edge_name}"];\n')
parts.append(child.to_dot(visited, root=False))
# Add footer at the root node
if root:
parts.append("}\n")
return "".join(parts)
class LET(EXPRESSION):
def __init__(self, decls, body):
super().__init__()
self.decl = decls
self.body = body
def __str__(self):
return "let " + ", ".join(str(d) for d in self.decl) + " in " + str(self.body)
class DECL(EXPRESSION):
def __init__(self, f_name, params, body):
super().__init__()
self.f_name = f_name
self.params = params
self.body = body
def __str__(self):
return f"{self.f_name}({self.params}) {{ {self.body} }}"
class CALL(EXPRESSION):
def __init__(self, f_name, args):
super().__init__()
self.f_name = f_name
self.arg = args
def __str__(self):
return self.f_name + "(" + ",".join(str(a) for a in self.arg) + ")"
class ID(EXPRESSION):
def __init__(self, name):
super().__init__()
self.name = name
def __str__(self):
return self.name
class CONST(EXPRESSION):
def __init__(self, value):
super().__init__()
self.value = value
def __str__(self):
return str(self.value)
class AOP(EXPRESSION):
def __init__(self, operator, arg1, arg2):
super().__init__()
self.operator = operator
self.arg1 = arg1
self.arg2 = arg2
def __str__(self):
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
class EQOP(EXPRESSION):
def __init__(self, operator, arg1, arg2):
super().__init__()
self.operator = operator
self.arg1 = arg1
self.arg2 = arg2
def __str__(self):
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
class COMP(EXPRESSION):
def __init__(self, operator, arg1, arg2):
super().__init__()
self.operator = operator
self.arg1 = arg1
self.arg2 = arg2
def __str__(self):
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
class LOP(EXPRESSION):
def __init__(self, operator, arg1, arg2):
super().__init__()
self.operator = operator
self.arg1 = arg1
self.arg2 = arg2
def __str__(self):
return "(" + str(self.arg1) + " " + str(self.operator) + " " + str(self.arg2) + ")"
class ASSIGN(EXPRESSION):
def __init__(self, var, expr):
super().__init__()
self.var = var
self.expr = expr
def __str__(self):
return self.var.name + " = " + str(self.expr)
class SEQ(EXPRESSION):
def __init__(self, exp1, exp2):
super().__init__()
self.exp1 = exp1
self.exp2 = exp2
def __str__(self):
return str(self.exp1) + "; " + str(self.exp2)
class IF(EXPRESSION):
def __init__(self, cond, exp1, exp2):
super().__init__()
self.cond = cond
self.exp1 = exp1
self.exp2 = exp2
def __str__(self):
return "if (" + str(self.cond) + ") then { " + str(self.exp1) + " } else { " + str(self.exp2) + " }"
class WHILE(EXPRESSION):
def __init__(self, cond, body):
super().__init__()
self.cond = cond
self.body = body
def __str__(self):
return "while (" + str(self.cond) + ") do { " + str(self.body) + " }"

View File

@@ -0,0 +1,10 @@
GOTO L1
L2: NOP
LOAD 0 0
RETURN
L1: NOP
CONST 1
CONST 2
CONST 3
INVOKE 3 L2 0
HALT

View File

@@ -0,0 +1,65 @@
GOTO L1
L2: NOP
LOAD 0 0
CONST 0
EQ
IFZERO L4
CONST 0
GOTO L5
L4: NOP
LOAD 0 0
CONST 1
SUB
INVOKE 1 L2 1
L5: NOP
RETURN
L3: NOP
LOAD 0 0
LOAD 1 0
GT
IFZERO L6
LOAD 0 0
INVOKE 1 L2 1
GOTO L7
L6: NOP
LOAD 1 0
INVOKE 1 L2 1
POP
GOTO L8
L9: NOP
LOAD 0 1
LOAD 1 1
MUL
LOAD 0 0
MUL
RETURN
L8: NOP
LOAD 0 0
LOAD 1 0
MUL
INVOKE 1 L9 0
L7: NOP
RETURN
L1: NOP
CONST 10
INVOKE 1 L2 0
POP
CONST 10
GOTO L10
L11: NOP
LOAD 0 0
LOAD 1 0
GT
IFZERO L12
LOAD 0 0
GOTO L13
L12: NOP
LOAD 1 0
L13: NOP
RETURN
L10: NOP
CONST 20
CONST 30
INVOKE 2 L11 0
INVOKE 2 L3 0
HALT

View File

@@ -0,0 +1,42 @@
GOTO L1
L2: NOP
CONST 2
STORE 1 0
LOAD 1 0
POP
CONST 3
STORE 2 0
LOAD 2 0
POP
GOTO L3
L4: NOP
CONST 7
STORE 0 0
LOAD 0 0
POP
LOAD 1 1
CONST 0
GT
IFZERO L5
LOAD 1 1
INVOKE 1 L4 1
GOTO L6
L5: NOP
CONST 8
STORE 0 0
LOAD 0 0
L6: NOP
POP
LOAD 0 0
RETURN
L3: NOP
LOAD 0 0
INVOKE 1 L4 0
LOAD 0 0
ADD
RETURN
L1: NOP
CONST 2
CONST 3
INVOKE 2 L2 0
HALT

View File

@@ -0,0 +1,18 @@
CONST 1
CONST 0
GT
IFZERO L3
CONST 1
GOTO L4
L3: NOP
CONST 1
CONST 0
EQ
L4: NOP
IFZERO L1
CONST 1
GOTO L2
L1: NOP
CONST 0
L2: NOP
HALT

View File

@@ -0,0 +1,71 @@
GOTO L1
L2: NOP
LOAD 0 0
CONST 0
EQ
IFZERO L4
GOTO L6
L7: NOP
LOAD 0 0
LOAD 1 1
MUL
LOAD 1 0
ADD
RETURN
L6: NOP
CONST 2
LOAD 1 0
MUL
LOAD 0 0
INVOKE 2 L7 0
GOTO L5
L4: NOP
LOAD 0 0
CONST 1
ADD
L5: NOP
RETURN
L3: NOP
LOAD 1 0
CONST 0
GT
IFZERO L10
GOTO L11
L8: NOP
LOAD 1 0
CONST 0
GT
IFZERO L9
POP
L11: NOP
LOAD 0 0
LOAD 0 0
LOAD 1 0
INVOKE 2 L2 1
MUL
STORE 0 0
LOAD 0 0
POP
LOAD 1 0
CONST 1
SUB
STORE 1 0
LOAD 1 0
GOTO L8
L10: NOP
CONST None
L9: NOP
POP
LOAD 0 0
CONST 42
ADD
RETURN
L1: NOP
CONST 1
CONST 2
INVOKE 2 L2 0
POP
CONST 3
CONST 3
INVOKE 2 L3 0
HALT

View File

@@ -0,0 +1,92 @@
# ------------------------------------------------------------
# Tokenizer for the TRIPLA parser
# ------------------------------------------------------------
import ply.lex as lex
reserved = {
'let': 'LET',
'in': 'IN',
'if': 'IF',
'then': 'THEN',
'else': 'ELSE',
'while': 'WHILE',
'do': 'DO',
'true': 'TRUE',
'false': 'FALSE'
}
# List of token names.
tokens = [
'ID',
'CONST',
'AOP',
'COMP',
'EQOP',
'LOP',
'ASSIGN',
'LPAREN', 'RPAREN',
'LBRACE', 'RBRACE',
'COMMA',
'SEMICOLON',
] + list(reserved.values())
# Simple tokens
t_LPAREN = r'\('
t_RPAREN = r'\)'
t_LBRACE = r'\{'
t_RBRACE = r'\}'
t_COMMA = r','
t_SEMICOLON = r';'
t_ASSIGN = r'='
# Arithmetic operators
t_AOP = r'\+|\-|\*|/'
# Comparison operators
t_COMP = r'<=|>=|<|>'
# Equality operators
t_EQOP = r'==|!='
# Logical operators
t_LOP = r'\|\||&&'
# IDs
def t_ID(t):
r'[A-Za-z_][A-Za-z0-9_]*'
t.type = reserved.get(t.value, 'ID')
return t
# Constants
def t_CONST(t):
r'0|[1-9][0-9]*'
t.value = int(t.value)
return t
# Linebreaks
def t_newline(t):
r'\n+'
t.lexer.lineno += len(t.value)
# Ignore whitespace
t_ignore = ' \t'
# Single-line comment
def t_comment_single(t):
r'//.*'
pass
# Multi-line comment
def t_comment_multi(t):
r'/\*([^*]|\*+[^*/])*\*/'
t.lexer.lineno += t.value.count('\n')
pass
# Error handling
def t_error(t):
print("Illegal character '%s'" % t.value[0])
t.lexer.skip(1)
# Build the lexer
lexer = lex.lex()

View File

@@ -0,0 +1,2 @@
let a(x,y,z) {x}
in a(1,2,3)

View File

@@ -0,0 +1,15 @@
let
f1(b) {
if(b==0) then 0 else f1(b-1)
}
f2(a, b) {
if(a > b) then f1(a) else f1(b);
let g(c) {
a*b*c
} in g(a*b)
}
in
f1(10); f2(10, let max(a, b) {
if(a > b) then a else b
}
in max(20, 30))

View File

@@ -0,0 +1 @@
if 2 < x && x > 9 then 1 else 0

View File

@@ -0,0 +1,4 @@
let a(x) {x}
b(y) {y}
c(z) {z}
in a(1); b(2); c(3)

View 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)

View File

@@ -0,0 +1,38 @@
let
fac(x) {
if (x == 1) then 1
else fac(x-1)*x
}
fac(x) {
if (x == 1) then 1
else fac(x-1)*x
}
fac(x) {
if (x == 1) then 1
else fac(x-1)*x
}
fac(x) {
if (x == 1) then 1
else fac(x-1)*x
}
fac(x) {
if (x == 1) then 1
else fac(x-1)*x
}
fac(x) {
if (x == 1) then 1
else fac(x-1)*x
}
fac(x) {
if (x == 1) then 1
else fac(x-1)*x
}
fac(x) {
if (x == 1) then 1
else fac(x-1)*x
}
fac(x) {
if (x == 1) then 1
else fac(x-1)*x
}
in fac(3)

View File

@@ -0,0 +1 @@
let n(a) {a} in n(5) + m(5) ; let m(a) {a+1} in m(5)

View File

@@ -0,0 +1 @@
if (2 && 7 > 2) then 1 else 0

View File

@@ -0,0 +1,7 @@
let func(a,b) {
while ( a > 0 && b != a ) do {
b = b + 1;
a = a - 1
}
}
in func(10, 8)

View File

@@ -0,0 +1 @@
if 1 >= 0 then 1 else 0

View File

@@ -0,0 +1,12 @@
let ggT(a, b) {
if (a == b) then
a
else
do {
if (a > b) then
a = a - b
else
b = b - a
} while (a != b);
a
} in ggT(3528, 3780) // result should be 252

View File

@@ -0,0 +1,8 @@
let ggT(a, b) {
if (a == b) then
a
else if (a > b) then
ggT(a-b, b)
else
ggT(b-a, a)
} in ggT(2, 8)

View File

@@ -0,0 +1,16 @@
let f(x, y) {
if (x == 0) then
let g(x, z) {
x * y + z
} in g(2 * y, x)
else
x + 1
}
g (a, i) {
while (i > 0) do {
a = a * f(a, i);
i = i - 1
};
a + 42
}
in f (1, 2); g(3, 3)

View File

@@ -0,0 +1,3 @@
let f1(b) { if (b == 0) then 0 else f1(b-1) }
f2(a,b) { if (a > b) then f1(a) else f1(b) }
in f1(10); f2(10,-20)

View File

@@ -0,0 +1 @@
let m(a){a} in m(5);let m(b){b+1} in m(5)

View File

@@ -0,0 +1 @@
let n(a) {a} in n(5) ; let m(a) {a+1} in n(5) + m(5)

View File

@@ -0,0 +1 @@
if(true||true==true) then 1 else 0

View File

@@ -0,0 +1,3 @@
let g(a) {
a*a
} in g(5)

View File

@@ -0,0 +1,9 @@
let f1(b) {
if (b==0) then 0 else f1(b-1)
} in f1(10)
/*
f2(a,b) {
if (a>b) then f1(a) else f1(b)
}
in f1(10); f2(10,20)
*/

View File

@@ -0,0 +1,14 @@
let f1(b) {
if (b==0) then 0 else f1(b-1)
}
f2(a,b) {
if (a>b) then f1(a) else f1(b);
let g(c) {
a*b*c
}
in g(a*b)
}
in f1(10); f2(10, let max(a,b) {
if (a>b) then a else b
}
in max(20,30) )

View File

@@ -0,0 +1,4 @@
let func(a,b) {
a = b + 1
}
in func(10, 8)

View File

@@ -0,0 +1,9 @@
let func(a, b) {
let func(a, b) {
a * b
} in
do {
b = b + 1 * func(3, 1);
a = a - 1
} while ( a > 0 && b != a )
} in func(10, 8)

View File

@@ -0,0 +1,13 @@
let f(a, b) {
if (a == 0) then
2 + b
else
let g(a, c) {
a + c + b
} in 2 + g(a, b)
} g(c, d) {
if (c == 0) then
1 + d
else
c * f(c - 1, d)
} in f (2, 3); g (3, 2)

View File

@@ -0,0 +1,5 @@
let f(x, y) {
let g(x) {
y = x + 7
} in x = g(5); y
} in f(1, 2)

View File

@@ -0,0 +1,5 @@
let f(x) { x=2*x;
if (x>0) then x=x-1 else x;
while (x>0) do { x=x-1 }
}
in f(3)

View File

@@ -0,0 +1,4 @@
let g(x, y) {
y = 3;
x
} in g(2)

View File

@@ -0,0 +1 @@
if (true) then 1 else 0

View File

@@ -0,0 +1 @@
if (true && false) then 1 else 0

View File

@@ -0,0 +1 @@
if (true || false) then 1 else 0

View File

@@ -0,0 +1 @@
if (1 > 2) then 1 else 0

View File

@@ -0,0 +1 @@
if (2 > 3 + 5) then 1 else 0

View File

@@ -0,0 +1 @@
if (1 > 2 || 3 < 5) then 1 else 0

View File

@@ -0,0 +1 @@
if (2 == 0 == false) then 1 else 0

View File

@@ -0,0 +1,2 @@
let square(x) { x*x }
in square(10)

View File

@@ -0,0 +1,4 @@
let mult(a,b) { a*b }
add(a,b) { let inc(a) { if (b!=0) then b=b-1;inc(a+1) else mult(a,1) }
in inc(a) }
in add(mult(2,3),add(4,5))

View File

@@ -0,0 +1,7 @@
let func(a,b) {
while ( a > 0 && b != a ) do {
b = b + 1;
a = a - 1
}
}
in func(10, 8)

View File

@@ -0,0 +1,3 @@
while (true) do {
3
}

View File

@@ -0,0 +1,8 @@
let wrapper(a, b) {
let ggt(noneSense) {
if a == b then a
else
if a > b then wrapper(a-b, b)
else wrapper(b-a, a)
} in ggt(0)
} in wrapper(21, 49)

View File

@@ -0,0 +1,9 @@
let wrapper(number, threshold) {
let square(x) {
if x*x > threshold
then x
else x*x
}
in square(number)
}
in wrapper(4, 10)

View File

@@ -0,0 +1,148 @@
# ------------------------------------------------------------
# Grammar of the TRIPLA language
# ------------------------------------------------------------
import ply.yacc as yacc
import cfg_build as ast
from triplalex import tokens
precedence = (
('left', 'SEMICOLON'),
('left', 'IN'),
('left', 'ELSE'),
('left', 'COMMA'),
('right', 'ASSIGN'),
('left', 'COMP'),
('left', 'EQOP'),
('left', 'AOP'),
('left', 'COMP'),
('left', 'EQOP'),
)
start = 'E'
# ------------------------------------------------------------
# Rules for E
# ------------------------------------------------------------
def p_E_let(p):
'E : LET D IN E'
p[0] = ast.LET(p[2], p[4])
def p_E_id(p):
'E : ID'
p[0] = ast.ID(p[1])
def p_E_call(p):
'E : ID LPAREN A RPAREN'
# E : ID(A)
p[0] = ast.CALL(p[1], p[3])
def p_E_aop(p):
'E : E AOP E'
p[0] = ast.AOP(p[2], p[1], p[3])
def p_E_paren(p):
'E : LPAREN E RPAREN'
# E : (E)
p[0] = p[2]
def p_E_const(p):
'E : CONST'
p[0] = ast.CONST(p[1])
def p_E_assign(p):
'E : ID ASSIGN E'
p[0] = ast.ASSIGN(ast.ID(p[1]), p[3])
def p_E_seq(p):
'E : E SEMICOLON E'
p[0] = ast.SEQ(p[1], p[3])
def p_E_if(p):
'E : IF B THEN E ELSE E'
p[0] = ast.IF(p[2], p[4], p[6])
def p_E_while(p):
'E : WHILE B DO LBRACE E RBRACE'
p[0] = ast.WHILE(p[2], p[5])
# ------------------------------------------------------------
# Rules for A
# ------------------------------------------------------------
def p_A_single(p):
'A : E'
p[0] = [p[1]]
def p_A_multiple(p):
'A : A COMMA E'
p[0] = p[1] + [p[3]]
# ------------------------------------------------------------
# Rules for D
# ------------------------------------------------------------
def p_D_single(p):
'D : ID LPAREN V RPAREN LBRACE E RBRACE'
p[0] = [ast.DECL(p[1], p[3], p[6])]
def p_D_concat(p):
'D : D D'
p[0] = p[1] + p[2]
# ------------------------------------------------------------
# Rules for V
# ------------------------------------------------------------
def p_V_single(p):
'V : ID'
p[0] = [p[1]]
def p_V_multiple(p):
'V : V COMMA V'
p[0] = p[1] + p[3]
# ------------------------------------------------------------
# Rules for B
# ------------------------------------------------------------
def p_B_eqop_E(p):
'B : E EQOP E'
p[0] = ast.EQOP(p[2], p[1], p[3])
def p_B_comp(p):
'B : E COMP E'
p[0] = ast.COMP(p[2], p[1], p[3])
def p_B_eqop_B(p):
'B : B EQOP B'
p[0] = ast.EQOP(p[2], p[1], p[3])
def p_B_lop(p):
'B : B LOP B'
p[0] = ast.LOP(p[2], p[1], p[3])
def p_B_true(p):
'B : TRUE'
p[0] = ast.CONST(True)
def p_B_false(p):
'B : FALSE'
p[0] = ast.CONST(False)
def p_B_paren(p):
'B : LPAREN B RPAREN'
# B : (B)
p[0] = p[2]
# Error handling
def p_error(p):
if p:
print("Syntax error at token:", p.type, "value:", p.value)
else:
print("Syntax error at EOF")
parser = yacc.yacc()

View File

View File

@@ -0,0 +1,76 @@
# (c) Stephan Diehl, University of Trier, Germany, 2025
from . import tram
class Assembler:
@staticmethod
def read_tram_code(filename):
code = []
lines = []
labelmap = {}
linemap = {}
try:
with open(filename, 'r', encoding='utf-8') as f:
line_number = 0
for raw_line in f:
line = raw_line.strip()
if line.startswith("//") or line.startswith("#") or not line:
continue
if ":" in line:
labels_part = line[:line.index(':')]
labels = [label.strip() for label in labels_part.split(',')]
linemap[line_number] = labels
for label in labels:
labelmap[label] = tram.Label(line_number,label)
line = line[line.index(':') + 1:].strip()
lines.append(line)
line_number += 1
except IOError as e:
print(f"Fehler beim Lesen der Datei: {e}")
for i, line in enumerate(lines):
labels = [labelmap.get(label,None) for label in linemap.get(i,[])]
instr = Assembler.convert_to_instruction(line, labelmap, labels)
code.append(instr)
return code
@staticmethod
def convert_to_instruction(line, labelmap={}, labels=None):
parts = line.split()
instr =parts[0].upper()
arg1 = Assembler.arg_to_number(parts, 1, labelmap)
arg2 = Assembler.arg_to_number(parts, 2, labelmap)
arg3 = Assembler.arg_to_number(parts, 3, labelmap)
if instr == "CONST": code=tram.const(arg1,assigned_label=labels)
elif instr == "LOAD": code=tram.load(arg1, arg2,assigned_label=labels)
elif instr == "STORE": code=tram.store(arg1,arg2,assigned_label=labels)
elif instr == "ADD": code=tram.add(assigned_label=labels)
elif instr == "SUB": code=tram.sub(assigned_label=labels)
elif instr == "MUL": code=tram.mul(assigned_label=labels)
elif instr == "DIV": code=tram.div(assigned_label=labels)
elif instr == "LT": code=tram.lt(assigned_label=labels)
elif instr == "GT": code=tram.gt(assigned_label=labels)
elif instr == "EQ": code=tram.eq(assigned_label=labels)
elif instr == "NEQ": code=tram.neq(assigned_label=labels)
elif instr == "IFZERO": code=tram.ifzero(arg1,assigned_label=labels)
elif instr == "GOTO": code=tram.goto(arg1,assigned_label=labels)
elif instr == "HALT": code=tram.halt(assigned_label=labels)
elif instr == "NOP": code=tram.nop(assigned_label=labels)
elif instr == "INVOKE": code=tram.invoke(arg1,arg2,arg3,assigned_label=labels)
elif instr == "RETURN": code=tram.ireturn(assigned_label=labels)
elif instr == "POP": code=tram.pop(assigned_label=labels)
else:
print(f"Keine gültige Instruktion: {line}")
code = None
return code
@staticmethod
def arg_to_number(parts, index, labelmap):
if index >= len(parts):
return 0
arg = parts[index]
try:
return int(arg)
except ValueError:
return labelmap.get(arg, 0)

View File

@@ -0,0 +1,340 @@
# (c) Stephan Diehl, University of Trier, Germany, 2025
class TRAM:
def __init__(self, prog):
self.set_label_addresses(prog)
self.program=prog+[halt()]
self.print_prog(self.program)
self.pc = 0
self.stack = []
self.top = -1
self.pp = 0 #-1
self.fp = 0 #-1
def start(self):
while self.pc>=0:
self.print_instruction(self.program[self.pc])
self.program[self.pc].execute(self)
print(self.stack)
def set_label_addresses(self,code):
pos = 0
for instr in code:
for label in instr.assigned_labels:
label.address = pos
pos = pos + 1
def pop(self):
del self.stack[self.top]
self.top = self.top - 1
def push(self,v):
self.stack.append(v)
self.top = self.top + 1
def spp(self,d,pp,fp):
if (d==0):
return pp
else:
return self.spp(d-1,self.stack[self.fp+3],self.stack[self.fp+4])
def sfp(self, d, pp, fp):
if (d==0):
return fp
else:
return self.sfp(d-1, self.stack[self.fp+3], self.stack[self.fp+4])
def print_prog(self,prog):
pos=0
for instr in prog:
print(str(pos)+": ",end="")
pos=pos+1
self.print_instruction(instr)
def print_instruction(self, instr):
print(type(instr).__name__, end = "")
for attr in vars(instr).keys():
value=getattr(instr,attr)
if isinstance(value,list): continue
if isinstance(value,Label):
value="#"+str(value.address)
else:
value=str(value)
print(" "+value,end="")
print()
#################
class Label:
count=0
address=-1
def __init__(self,address=-1,text=""):
Label.count+=1
self.id=Label.count
self.address=address
if text=="":
self.text=f"L{Label.count}"
else:
self.text=text
def toString(self): return self.text
##################
class Instruction:
def __init__(self,assigned_label=None):
self.assigned_labels = []
if not assigned_label is None:
if isinstance(assigned_label,Label):
self.assigned_labels+=[assigned_label]
else:
self.assigned_labels+=assigned_label
def toString(self):
s=self.toStringx()
#print(s)
return(s)
def toStringx(self):
if (len(self.assigned_labels)==0):
return " "
else:
return ','.join( [ label.toString()
for label in self.assigned_labels] )+": "
class halt(Instruction):
def __init__(self,assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
tram.pc=-1
def toString(self): return super().toString()+"HALT"
class nop(Instruction):
def __init__(self,assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
tram.pc=tram.pc+1
def toString(self): return super().toString()+"NOP"
class pop(Instruction):
def __init__(self,assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
tram.pop()
tram.pc=tram.pc+1
def toString(self): return super().toString()+"POP"
class const(Instruction):
def __init__(self, k, assigned_label=None):
super().__init__(assigned_label=assigned_label)
self.k=k
def execute(self,tram):
tram.push(self.k)
tram.pc=tram.pc+1
def toString(self): return super().toString()+"CONST "+str(self.k)
class store(Instruction):
def __init__(self, k, d, assigned_label=None):
super().__init__(assigned_label=assigned_label)
self.k = k
self.d = d
def execute(self,tram):
tram.stack[tram.spp(self.d,tram.pp,tram.fp)+self.k]=tram.stack[tram.top]
tram.pop()
tram.pc=tram.pc+1
def toString(self):
return super().toString()+"STORE "+str(self.k)+" "+str(self.d)
class load(Instruction):
def __init__(self, k, d, assigned_label=None):
super().__init__(assigned_label=assigned_label)
self.k=k
self.d=d
def execute(self,tram):
tram.push(tram.stack[tram.spp(self.d,tram.pp,tram.fp)+self.k])
tram.pc=tram.pc+1
def toString(self):
return super().toString()+"LOAD "+str(self.k)+" "+str(self.d)
class add(Instruction):
def __init__(self, assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
tram.stack[tram.top-1]=tram.stack[tram.top-1]+tram.stack[tram.top]
tram.pop()
tram.pc=tram.pc+1
def toString(self): return super().toString()+"ADD"
class sub(Instruction):
def __init__(self, assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
tram.stack[tram.top-1]=tram.stack[tram.top-1]-tram.stack[tram.top]
tram.pop()
tram.pc=tram.pc+1
def toString(self): return super().toString() + "SUB"
class mul(Instruction):
def __init__(self, assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
tram.stack[tram.top-1]=tram.stack[tram.top-1]*tram.stack[tram.top]
tram.pop()
tram.pc=tram.pc+1
def toString(self): return super().toString() + "MUL"
class div(Instruction):
def __init__(self, assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
tram.stack[tram.top-1]=tram.stack[tram.top-1]/tram.stack[tram.top]
tram.pop()
tram.pc=tram.pc+1
def toString(self): return super().toString() + "DIV"
class lt(Instruction):
def __init__(self, assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
if tram.stack[tram.top-1]<tram.stack[tram.top]:
tram.stack[tram.top-1]=1
else:
tram.stack[tram.top-1]=0
tram.pop()
tram.pc=tram.pc+1
def toString(self): return super().toString() + "LT"
class gt(Instruction):
def __init__(self, assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
if tram.stack[tram.top-1]>tram.stack[tram.top]:
tram.stack[tram.top-1]=1
else:
tram.stack[tram.top-1]=0
tram.pop()
tram.pc=tram.pc+1
def toString(self): return super().toString() + "GT"
class eq(Instruction):
def __init__(self, assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
if tram.stack[tram.top-1]==tram.stack[tram.top]:
tram.stack[tram.top-1]=1
else:
tram.stack[tram.top-1]=0
tram.pop()
tram.pc=tram.pc+1
def toString(self): return super().toString() + "EQ"
class neq(Instruction):
def __init__(self, assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
if tram.stack[tram.top-1]!=tram.stack[tram.top]:
tram.stack[tram.top-1]=1
else:
tram.stack[tram.top-1]=0
tram.pop()
tram.pc=tram.pc+1
def toString(self): return super().toString() + "NEQ"
class goto(Instruction):
def __init__(self, label, assigned_label=None):
super().__init__(assigned_label=assigned_label)
self.label=label
def execute(self,tram):
tram.pc=self.label.address
def toString(self):
return super().toString() + "GOTO "+self.label.toString()
class ifzero(Instruction):
def __init__(self, label, assigned_label=None):
super().__init__(assigned_label=assigned_label)
self.label=label
def execute(self,tram):
if tram.stack[tram.top]==0:
tram.pc=self.label.address
else:
tram.pc=tram.pc+1
tram.pop()
def toString(self):
return super().toString() + "IFZERO "+self.label.toString()
class invoke(Instruction):
def __init__(self,n,label,d, assigned_label=None):
super().__init__(assigned_label=assigned_label)
self.n=n
self.label=label
self.d=d
def execute(self,tram):
tmp_top=tram.top
tram.push(tram.pc+1)
tram.push(tram.pp)
tram.push(tram.fp)
tram.push(tram.spp(self.d,tram.pp,tram.fp))
tram.push(tram.sfp(self.d,tram.pp,tram.fp))
tram.pp=tmp_top-self.n+1
tram.fp=tmp_top+1
tram.pc=self.label.address
def toString(self):
return super().toString() \
+ "INVOKE "+str(self.n)+" "+self.label.toString()+" "+str(self.d)
class ireturn(Instruction):
def __init__(self, assigned_label=None):
super().__init__(assigned_label=assigned_label)
def execute(self,tram):
res=tram.stack[tram.top]
tram.top=tram.pp
tram.pc=tram.stack[tram.fp]
tram.pp=tram.stack[tram.fp+1]
tram.fp=tram.stack[tram.fp+2]
del tram.stack[tram.top:]
tram.top=tram.top-1
tram.push(res)
def toString(self): return super().toString() + "RETURN"

View File

@@ -0,0 +1,220 @@
# (c) Stephan Diehl, University of Trier, Germany, 2025
import tkinter as tk
from copy import deepcopy
from tkinter import ttk
from tkinter import filedialog
import os
from .assembler import *
from .tram import *
import inspect
import re
"""
test_prog1=[const(1), const(2), const(5), store(1, 0), load(1, 0), add(), halt()]
L4=Label(4)
L7=Label(7)
L15=Label(15)
test_prog2=[const(4),
const(10),
invoke(2,L4,0),
halt(),
load(0,0,assigned_label=L4),
invoke(1,L7,0),
ireturn(),
load(0,0,assigned_label=L7),
load(0,0),
mul(),
load(1,1),
gt(),
ifzero(L15),
load(0,0),
ireturn(),
load(0,0,assigned_label=L15),
load(0,0),
mul(),
ireturn()]
"""
class AbstractMachine(TRAM):
def __init__(self):
self.initial_program = [] #Assembler.read_tram_code("examples/tramprograms/test.tram")
#self.initial_program = test_prog2
print(self.initial_program)
self.reset()
def reset(self):
super().__init__(self.initial_program)
self.program_text = [f"{instr.toString()}" for i, instr in enumerate(self.program)]
self.running = False
def step(self):
if self.pc >= len(self.program):
self.running = False
return ("Error: End of program store reached!", None)
if self.pc == -1:
self.running = False
return ("The program terminated normally!", None)
instr=self.program[self.pc]
self.print_instruction(instr)
instr.execute(self)
return (f"Ausgeführt: {instr.toString()}", instr)
class MachineUI:
def __init__(self, root):
self.root = root
self.machine = AbstractMachine()
self.previous_state = None
self.minimal_vis = False
self.current_instruction = None
root.title("Visual TRAM")
# Frames
control_frame = ttk.Frame(root)
control_frame.pack(pady=10)
display_frame = ttk.Frame(root)
display_frame.pack(padx=10, pady=5, fill="both", expand=True)
# Buttons
ttk.Button(control_frame, text="Start", command=self.start).grid(row=0, column=0, padx=5)
ttk.Button(control_frame, text="Stop", command=self.stop).grid(row=0, column=1, padx=5)
ttk.Button(control_frame, text="Step", command=self.step).grid(row=0, column=2, padx=5)
ttk.Button(control_frame, text="Reset", command=self.reset).grid(row=0, column=3, padx=5)
button = ttk.Button(control_frame, text="Open File", command=self.open_file).grid(row=0, column=4, padx=5)
# Add a label to show the selected file
self.label = ttk.Label(root, text="No file selected.", wraplength=800, justify="center")
self.label.pack(pady=20)
# Add a button to open the file browser
#button = ttk.Button(root, text="Open File", command=self.open_file)
#button.pack(pady=10)
# Textfelder
self.code_text = tk.Text(display_frame, width=35, height=32, wrap="none", bg="#f8f8f8")
self.code_text.pack(side="left", padx=10, pady=10, fill="both", expand=True)
self.code_text.tag_configure('highlight', background='#AAFFAA')
self.prev_state_text = tk.Text(display_frame, width=35, height=32, wrap="none", bg="#f0f8ff")
self.prev_state_text.pack(side="left", padx=10, pady=10, fill="both", expand=True)
self.state_text = tk.Text(display_frame, width=35, height=32, wrap="none", bg="#f0f8ff")
self.state_text.pack(side="left", padx=10, pady=10, fill="both", expand=True)
self.instr_text = tk.Text(display_frame, width=70, height=32, wrap="none", bg="#f0f8ff")
self.instr_text.pack(side="right", padx=10, pady=10, fill="both", expand=True)
self.state_text.tag_configure('blue', background='#AAAAFF')
self.prev_state_text.tag_configure('blue', background='#AAAAFF')
self.update_display()
def update_display(self):
# Programmkode anzeigen
self.code_text.delete("1.0", tk.END)
for i, line in enumerate(self.machine.program_text):
if i == self.machine.pc:
prefix = "-> "
self.code_text.insert(tk.END, f"{prefix}{i:02d}: {line}\n",'highlight')
else:
self.code_text.insert(tk.END, f" {i:02d}: {line}\n")
# Maschinenzustand anzeigen
self.update_state_display(self.machine, self.state_text)
if self.previous_state!=None:
self.update_state_display(self.previous_state, self.prev_state_text)
else:
self.prev_state_text.delete("1.0", tk.END)
self.previous_state = deepcopy(self.machine)
# Aktuell ausgeführte Instruktion anzeigen
if self.current_instruction != None:
(msg,instr) = self.current_instruction
self.instr_text.delete("1.0", tk.END)
self.instr_text.insert(tk.END, f"\n{msg}\n\n")
if instr!=None:
source_text= inspect.getsource(instr.execute)
source_text=source_text.replace("tram.","")
rest = source_text.split('\n', 1)[1] if '\n' in source_text else source_text
source_text = '\n'.join(line.lstrip() for line in rest.splitlines())
self.instr_text.insert(tk.END, source_text)
else:
self.instr_text.delete("1.0", tk.END)
def update_state_display(self, machine, tk_text):
tk_text.delete("1.0", tk.END)
tk_text.insert(tk.END, f"PC : {machine.pc}\n")
tk_text.insert(tk.END, f"FP : {machine.fp}\n")
tk_text.insert(tk.END, f"PP : {machine.pp}\n")
tk_text.insert(tk.END, f"TOP: {machine.top}\n\n")
if (self.minimal_vis == True):
tk_text.insert(tk.END, f"Stack: {machine.stack}\n")
else:
for i, value in enumerate(machine.stack):
suffix = " "
if i == machine.top: suffix += "<-TOP "
if i == machine.pp: suffix += "<-PP "
if i == machine.fp: suffix += "<-FP "
if i == machine.fp + 4: suffix += "<-end of frame "
if i >= machine.pp and i < machine.fp + 5:
tk_text.insert(tk.END, f"{i:02d}: {value}{suffix}\n", 'blue')
else:
tk_text.insert(tk.END, f"{i:02d}: {value}{suffix}\n")
def start(self):
self.machine.running = True
self.run_next()
def stop(self):
self.machine.running = False
def step(self):
self.current_instruction = self.machine.step()
self.update_display()
def run_next(self):
if self.machine.running:
self.step()
#msg = self.machine.step()
#self.update_display()
#if msg:
# self.state_text.insert(tk.END, f"\n{msg}\n")
if self.machine.running:
self.root.after(500, self.run_next) # Automatische Ausführung
def reset(self):
self.machine.reset()
self.previous_state=None
self.current_instruction=None
self.update_display()
def open_file(self):
# Define the starting directory
start_dir = os.path.expanduser("examples/tramprograms")
# Open the file browser starting in start_dir
filename = filedialog.askopenfilename(
initialdir=start_dir,
title="Select a File",
filetypes=(("TRAM files", "*.tram"), ("All files", "*.*"))
)
# Display the selected file path in the label
if filename:
self.label.config(text=f"Selected file:\n{filename}")
self.machine.initial_program = Assembler.read_tram_code(filename) #examples/tramprograms/test.tram")
self.reset()
if __name__ == "__main__":
root = tk.Tk()
app = MachineUI(root)
root.mainloop()