Compare commits

...

19 Commits

Author SHA1 Message Date
Jan-Niclas Loosen
c83fcc4d47 remove documents 2026-03-13 18:15:04 +01:00
Jan-Niclas Loosen
9462ccd3ed Add compiler improvement 2026-03-12 11:32:41 +01:00
Jan-Niclas Loosen
438447e6de finish refactoring task 1 and 2 2026-03-08 17:21:09 +01:00
Jan-Niclas Loosen
605eaf3278 Start refactoring task 1 and 2 2026-03-08 16:33:07 +01:00
Jan-Niclas Loosen
de46c67129 First working solution of new task 2026-03-05 18:03:55 +01:00
Jan-Niclas Loosen
691d6eba8c gen prompts 2026-03-03 17:00:34 +01:00
Jan-Niclas Loosen
8a40cb2636 New project structure 2026-03-03 16:45:00 +01:00
Jan-Niclas Loosen
9c18e5e044 Add README.md 2026-01-23 13:41:42 +01:00
Jan-Niclas Loosen
d3b518974c Remove older prompt. 2026-01-23 13:29:55 +01:00
Jan-Niclas Loosen
d1bfba81f0 Comment correction 2026-01-23 13:22:15 +01:00
Jan-Niclas Loosen
f0877b5685 Add generated dot files 2026-01-23 13:01:50 +01:00
Jan-Niclas Loosen
add07249dc Fix recursion for each function name 2026-01-23 12:55:49 +01:00
Jan-Niclas Loosen
188cba7fa6 First acceptable solution 2026-01-23 11:32:20 +01:00
Jan-Niclas Loosen
51028555de Remove edges in constructor 2026-01-22 20:26:41 +01:00
Jan-Niclas Loosen
3abe8581b5 Refactor cfg_build.py 2026-01-22 18:18:13 +01:00
Jan-Niclas Loosen
489f385161 Before refactoring 2026-01-22 10:02:16 +01:00
Jan-Niclas Loosen
c66222050b first running version 2026-01-22 00:18:15 +01:00
Jan-Niclas Loosen
36ef2fd23d try to improve diagrams 2026-01-21 21:58:56 +01:00
Jan-Niclas Loosen
dfd4b4f305 Wire offline message 2026-01-17 00:14:44 +01:00
121 changed files with 3691 additions and 434 deletions

Binary file not shown.

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

View File

@@ -0,0 +1,128 @@
from __future__ import annotations
from collections import deque
from typing import TYPE_CHECKING
import cfg_build
import syntax
from cfg.CFG_Node import CFG_START
if TYPE_CHECKING:
from cfg.CFG import CFG
GLOBAL_SCOPE = ""
# A scoped variable: the function it belongs to, and its name.
# The scope is GLOBAL_SCOPE ("") for variables outside any function.
# e.g. ("f", "x") → variable "x" defined in function "f"
# ("", "x") → variable "x" at global scope
Var = tuple[str, str]
class BackwardAnalysis:
def __init__(self, cfg: "CFG") -> None:
self.cfg = cfg
self.uses: dict[int, set[Var]] = {}
self.defs: dict[int, set[Var]] = {}
self.__funcs: dict[str, tuple] = dict(cfg_build.FUNCTIONS)
self.__func_parent, self._func_params = self.__collect_function_metadata()
self.func_scope: dict[int, str] = self.__compute_function_scope()
self.__extract_uses_and_defs()
# Walk the AST and collect function-parent and parameter information.
def __collect_function_metadata(self) -> tuple[dict[str, str | None], dict[str, tuple[str, ...]]]:
func_parent: dict[str, str | None] = {}
func_params: dict[str, tuple[str, ...]] = {}
def visit(expr: syntax.EXPRESSION | None, current_func: str | None) -> None:
if expr is None:
return
if isinstance(expr, syntax.LET):
decls = expr.decl if isinstance(expr.decl, list) else [expr.decl]
# Register metadata for each declared function.
for d in decls:
if isinstance(d, syntax.DECL):
func_parent[d.f_name] = current_func
func_params[d.f_name] = tuple(d.params)
# Recurse into function bodies and the in-expression.
for d in decls:
if isinstance(d, syntax.DECL):
visit(d.body, d.f_name)
else:
visit(d, current_func)
visit(expr.body, current_func)
return
for _, child in expr.children():
visit(child, current_func)
visit(self.cfg.ast, None)
return func_parent, func_params
# Calculates the scope (in which function is it?) of each node in the CFG.
def __compute_function_scope(self) -> dict[int, str]:
# The first function whose BFS claims a node wins.
functions = self.__funcs
func_scope: dict[int, str] = {}
all_f_start_ids: set[int] = {fs.id for _, (fs, _) in functions.items()}
for f_name, (f_start, f_end) in functions.items():
queue: deque = deque([f_start])
while queue:
node = queue.popleft()
if node.id in func_scope:
continue # already claimed by an earlier function
func_scope[node.id] = f_name
# Stop here — do not follow into the caller context.
if node.id == f_end.id:
continue
for child in node.children:
# Do not follow into a different function's START.
if (
isinstance(child, CFG_START)
and child.id in all_f_start_ids
and child.id != f_start.id
):
continue
queue.append(child)
return func_scope
# Populate uses and defs for every node in the CFG.
def __extract_uses_and_defs(self) -> None:
for node in self.cfg.nodes():
nid = node.id
func = self.func_scope.get(nid)
ast = node.ast_node
uses: set[Var] = set()
defs: set[Var] = set()
if isinstance(node, CFG_START) and isinstance(ast, syntax.DECL):
# Function entry defines each formal parameter.
for param in ast.params:
defs.add((ast.f_name, param))
elif ast is not None:
if isinstance(ast, syntax.ID):
resolved = self.resolve_var(func, ast.name)
uses.add(resolved)
elif isinstance(ast, syntax.ASSIGN):
resolved = self.resolve_var(func, ast.var.name)
defs.add(resolved)
self.uses[nid] = uses
self.defs[nid] = defs
# Resolve a variables name and scope by walking up the hierarchy
def resolve_var(self, func: str | None, name: str) -> Var:
if func is None:
return GLOBAL_SCOPE, name
cur: str | None = func
seen: set[str] = set()
while cur is not None and cur not in seen:
seen.add(cur)
if name in self._func_params.get(cur, ()):
return cur, name
cur = self.__func_parent.get(cur)
# Fallback: local variable in the current function scope
return func, name

View File

@@ -0,0 +1,64 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from cfa.BackwardAnalysis import BackwardAnalysis, Var
if TYPE_CHECKING:
from cfg.CFG import CFG
class LiveVariables(BackwardAnalysis):
def __init__(self, cfg: "CFG") -> None:
# Base populates uses, defs, _func_scope, etc.
super().__init__(cfg)
self.gen: dict[int, set[Var]] = {}
self.kill: dict[int, set[Var]] = {}
self.incoming: dict[int, set[Var]] = {}
self.outgoing: dict[int, set[Var]] = {}
self.__init_sets()
self.solve()
# Initialize gen, kill, in, and out sets for all CFG nodes.
def __init_sets(self) -> None:
for node in self.cfg.nodes():
nid = node.id
# GEN(n) = USE(n); KILL(n) = DEF(n)
self.gen[nid] = set(self.uses[nid])
self.kill[nid] = set(self.defs[nid])
# IN(n) = GEN(n) = USE(n); OUT(n) = empty
self.incoming[nid] = set(self.gen[nid])
self.outgoing[nid] = set()
# Update the lists until the fixpoint.
def solve(self) -> None:
nodes = list(self.cfg.nodes())
known: set[int] = set(n.id for n in nodes)
# while there are changes do
changes = True
while changes:
changes = False
# for all v IN V do
for node in nodes:
nid = node.id
# OUT(n) = UNION IN(s) for all successors s
new_out: set[Var] = set()
for child in node.children:
if child.id in known:
new_out |= self.incoming[child.id]
# IN(n) = (OUT(n) MINUS KILL(n)) UNION GEN(n)
new_in: set[Var] = (new_out - self.kill[nid]) | self.gen[nid]
if new_out != self.outgoing[nid] or new_in != self.incoming[nid]:
self.outgoing[nid] = new_out
self.incoming[nid] = new_in
changes = True # there are changes -> loop again
# Return the living variables within each node
def live_vars_by_node(self) -> dict[int, set[Var]]:
return {nid: set(vs) for nid, vs in self.incoming.items() if vs}

View File

@@ -0,0 +1,97 @@
from __future__ import annotations
from typing import TYPE_CHECKING
from cfa.BackwardAnalysis import BackwardAnalysis, Var
if TYPE_CHECKING:
from cfg.CFG import CFG
# A single use-fact: the CFG node at which a variable is used.
# e.g. (42, ("f", "x")) -> variable "x" in function "f" is used at node 42
UseFact = tuple[int, Var]
class ReachedUses(BackwardAnalysis):
def __init__(self, cfg: "CFG") -> None:
# Base populates: uses, defs, _func_scope, _func_parent, _func_params.
super().__init__(cfg)
self.gen: dict[int, set[UseFact]] = {}
self.kill: dict[int, set[UseFact]] = {}
self.in_sets: dict[int, set[UseFact]] = {}
self.out_sets: dict[int, set[UseFact]] = {}
self.all_uses_by_var: dict[Var, set[UseFact]] = {}
self.__init_sets()
self.solve()
# Initialize gen, kill, in, and out sets for all CFG nodes.
def __init_sets(self) -> None:
for node in self.cfg.nodes():
nid = node.id
# GEN(n) = { (n.id, var) | var IN USE(n) }
self.gen[nid] = {(nid, var) for var in self.uses[nid]}
# IN(n) = GEN(n); OUT(n) = empty
self.in_sets[nid] = set(self.gen[nid])
self.out_sets[nid] = set()
# KILL(n) requires knowing all use-facts for a given variable — "at which nodes is variable x used anywhere?"
# all_uses_by_var builds this lookup once upfront: ("f", "x") -> { (42, ("f","x")), (17, ("f","x")) }
for nid, facts in self.gen.items():
for (uid, var) in facts:
self.all_uses_by_var.setdefault(var, set()).add((uid, var))
for node in self.cfg.nodes():
nid = node.id
# KILL(n) = { (uid, var) | var IN DEF(n), (uid, var) IN use_facts_by_var[var] }
# When n defines a variable, it kills all use-facts for that variable, because no use reachable from n
# can have been reached by an earlier definition of the same variable.
kill_n: set[UseFact] = set()
for var in self.defs[nid]:
if var in self.all_uses_by_var:
kill_n |= self.all_uses_by_var[var]
self.kill[nid] = kill_n
# Update the lists until the fixpoint.
def solve(self) -> None:
nodes = list(self.cfg.nodes())
known: set[int] = set(n.id for n in nodes)
# while there are changes do
changes = True
while changes:
changes = False
# for all v in V do
for node in nodes:
nid = node.id
# OUT(n) = UNION IN(s) for all successors s
new_out: set[UseFact] = set()
for child in node.children:
if child.id in known:
new_out |= self.in_sets[child.id]
# IN(n) = GEN(n) UNION (OUT(n) MINUS KILL(n))
new_in: set[UseFact] = self.gen[nid] | (new_out - self.kill[nid])
if new_out != self.out_sets[nid] or new_in != self.in_sets[nid]:
self.out_sets[nid] = new_out
self.in_sets[nid] = new_in
changes = True # there are changes -> loop again
# Return the final reached-uses result
def reached_uses_by_node(self) -> dict[int, list[int]]:
result: dict[int, list[int]] = {}
for node in self.cfg.nodes():
nid = node.id
defs_n = self.defs[nid]
if not defs_n:
continue
reached: set[int] = set()
for (uid, var) in self.out_sets[nid]:
if var in defs_n:
reached.add(uid)
result[nid] = sorted(reached)
return result

View File

@@ -0,0 +1,11 @@
from .BackwardAnalysis import BackwardAnalysis, Var
from .LiveVariables import LiveVariables
from .ReachedUses import ReachedUses, UseFact
__all__ = [
"Var",
"UseFact",
"BackwardAnalysis",
"LiveVariables",
"ReachedUses",
]

View File

@@ -0,0 +1,179 @@
import syntax
import colorsys
from cfg.CFG_Node import CFG_DIAMOND
# Builds annotations for the LiveVariables analysis.
def build_lv_annotations(cfg, lv) -> dict[int, str]:
node_by_id = {n.id: n for n in cfg.nodes()}
all_ids = set(lv.incoming.keys()) | set(lv.outgoing.keys())
return {
nid: (
"LivingVariables\\n"
f"In := {sorted(__lv_in_set(node_by_id[nid], lv))}\\n"
f"Out := {sorted(lv.outgoing.get(nid, set()))}"
)
for nid in all_ids
if lv.incoming.get(nid, set()) or lv.outgoing.get(nid, set())
if nid in node_by_id and __should_display_analysis(node_by_id[nid])
}
# For display only: IN(ASSIGN) has GEN = empty, so RHS variables are missing from incoming — they live at their
# own ID nodes. Add them here for a proper DOT annotation.
def __lv_in_set(node, analysis):
in_set = set(analysis.incoming.get(node.id, set()))
ast_node = node.ast_node
if isinstance(ast_node, syntax.ASSIGN):
func = analysis.func_scope.get(node.id)
rhs_vars = {
analysis.resolve_var(func, name)
for name in __expr_used_names(ast_node.expr)
}
in_set |= rhs_vars
return in_set
# For display only: the right-hand side of an ASSIGN has no dedicated CFG nodes, so LV places uses of "a", "b"
# at their own nodes — not at the ASSIGN. Recover them here to complete the DOT annotation at the ASSIGN node.
def __expr_used_names(expr) -> set[str]:
used: set[str] = set()
def visit(node):
if node is None:
return
if isinstance(node, syntax.ID):
used.add(node.name)
return
if isinstance(node, syntax.EXPRESSION):
for _, child in node.children():
visit(child)
visit(expr)
return used
# Weather a node should display analysis annotations
def __should_display_analysis(node) -> bool:
ast = node.ast_node
if isinstance(node, CFG_DIAMOND):
return False
if ast is None:
return False
return isinstance(
ast,
(
syntax.ASSIGN,
syntax.CALL,
syntax.IF,
syntax.WHILE,
syntax.DECL,
syntax.LET,
syntax.SEQ,
syntax.COMP,
syntax.EQOP,
syntax.LOP,
),
)
# Generates colors for CFG nodes based on their id.
def __node_color(node_id: int) -> tuple[str, str]:
# Golden-angle hue distribution gives stable, distinct colors.
hue = ((node_id * 0.6180339887498949) % 1.0)
edge_rgb = colorsys.hsv_to_rgb(hue, 0.70, 0.82)
fill_rgb = colorsys.hsv_to_rgb(hue, 0.28, 0.97)
def to_hex(rgb):
r, g, b = (int(round(c * 255)) for c in rgb)
return f"#{r:02x}{g:02x}{b:02x}"
return to_hex(edge_rgb), to_hex(fill_rgb)
# Return a DOT string for the CFG annotated with analysis results.
def analysis_to_dot(cfg, analyses: dict, analysis_name: str) -> str:
ru = analyses.get("ru")
lv = analyses.get("lv")
ru_edges = ru.reached_uses_by_node() if ru is not None else None
# DOT graph header
lines = [
"digraph CFG {",
f' // Analysis: {analysis_name}',
' graph [splines=ortho, overlap=false, ranksep=0.7, nodesep=0.45];',
' node [fontname="Helvetica"];',
]
# Build LV annotations and assign a color per annotated node
annotations = build_lv_annotations(cfg, lv)
color_nodes = set(annotations.keys()) | set((ru_edges or {}).keys())
node_colors = {nid: __node_color(nid) for nid in color_nodes}
# Emit each CFG node with its label, shape, and optional LV annotation note
def emit(node):
base_label = node.dot_label() or ""
shape = node.dot_shape
style = node.dot_style
style_str = f", {style}" if style else ""
lines.append(f' n{node.id} [label="{base_label}", shape={shape}{style_str}];')
if node.id in annotations:
ann_id = f"a{node.id}"
ann_label = annotations[node.id].replace('"', '\\"')
edge_color, fill_color = node_colors.get(node.id, ("#1f77b4", "#d9ecff"))
lines.append(
f' {ann_id} [label="{ann_label}", shape=note, '
f'style="filled", fillcolor="{fill_color}", color="{edge_color}", '
f'fontcolor="{edge_color}"];'
)
lines.append(
f' {ann_id} -> n{node.id} [style=dotted, arrowhead=none, '
f'color="{edge_color}"];'
)
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};")
cfg.traverse(emit, start=cfg.START)
# Draw dashed def -> use edges for Reached Uses
if ru_edges:
for idx, def_id in enumerate(sorted(ru_edges)):
use_ids = sorted(set(ru_edges[def_id]))
if not use_ids:
continue
# One routing hub per definition node to mimic UML-like
# "out to the side, then down/across to targets" connectors.
side = "e" if idx % 2 == 0 else "w"
source_port = "se" if side == "e" else "sw"
hub_id = f"rh{def_id}"
edge_color, fill_color = node_colors.get(def_id, ("#1f77b4", "#d9ecff"))
lines.append(
f' {hub_id} [shape=point, width=0.05, height=0.05, '
f'color="{edge_color}", fillcolor="{edge_color}", style=filled];'
)
lines.append(f" {{ rank=same; n{def_id}; {hub_id}; }}")
lines.append(
f' n{def_id}:{source_port} -> {hub_id} [color="{edge_color}", '
f'style=dashed, penwidth=1.2, arrowhead=none, constraint=false, '
f'tailclip=true, headclip=true];'
)
for use_id in use_ids:
if side == "e":
target_port = "ne" if (use_id % 2 == 0) else "se"
else:
target_port = "nw" if (use_id % 2 == 0) else "sw"
lines.append(
f' {hub_id} -> n{use_id}:{target_port} [color="{edge_color}", '
f'fontcolor="{edge_color}", fontsize=8, style=dashed, '
f'penwidth=1.0, arrowsize=0.6, constraint=false, '
f'tailclip=true, headclip=true];'
)
lines.append("}")
return "\n".join(lines)

View File

@@ -0,0 +1,188 @@
digraph CFG {
// Analysis: Live Variables + Reached Uses analyses
graph [splines=ortho, overlap=false, ranksep=0.7, nodesep=0.45];
node [fontname="Helvetica"];
n1 [label="START", shape=ellipse, style=filled, color=gray];
n1 -> n52;
n52 [label="10", shape=box];
n52 -> n53;
n53 [label="CALL f1", shape=box, style=filled, color=orange];
a53 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#d7b2f7", color="#8d3fd1", fontcolor="#8d3fd1"];
a53 -> n53 [style=dotted, arrowhead=none, color="#8d3fd1"];
n53 -> n3;
n53 -> n55;
n3 [label="START f1(b)", shape=ellipse, style=filled, color=green];
a3 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f1', 'b'), ('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#f7b2ef", color="#d13fbf", fontcolor="#d13fbf"];
a3 -> n3 [style=dotted, arrowhead=none, color="#d13fbf"];
n3 -> n8;
n8 [label="b", shape=box];
n8 -> n9;
n9 [label="0", shape=box];
n9 -> n10;
n10 [label="b == 0", shape=box];
a10 [label="LivingVariables\nIn := [('f1', 'b'), ('f2', 'a'), ('f2', 'b')]\nOut := [('f1', 'b'), ('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#f2f7b2", color="#c5d13f", fontcolor="#c5d13f"];
a10 -> n10 [style=dotted, arrowhead=none, color="#c5d13f"];
n10 -> n11;
n11 [label="<?>", shape=diamond];
n11 -> n15 [label="T"];
n11 -> n16 [label="F"];
n15 [label="0", shape=box];
n15 -> n4;
n4 [label="END f1(b)", shape=ellipse, style=filled, color=green];
a4 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#b2f7ec", color="#3fd1b9", fontcolor="#3fd1b9"];
a4 -> n4 [style=dotted, arrowhead=none, color="#3fd1b9"];
n4 -> n21;
n4 -> n32;
n4 -> n36;
n4 -> n55;
n21 [label="RET f1", shape=box, style=filled, color=orange];
a21 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#f7b2bb", color="#d13f51", fontcolor="#d13f51"];
a21 -> n21 [style=dotted, arrowhead=none, color="#d13f51"];
n21 -> n4;
n32 [label="RET f1", shape=box, style=filled, color=orange];
a32 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#e0b2f7", color="#a03fd1", fontcolor="#a03fd1"];
a32 -> n32 [style=dotted, arrowhead=none, color="#a03fd1"];
n32 -> n45;
n45 [label="a", shape=box];
n45 -> n46;
n46 [label="b", shape=box];
n46 -> n47;
n47 [label="a * b", shape=box];
n47 -> n48;
n48 [label="CALL g", shape=box, style=filled, color=orange];
a48 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#b2b3f7", color="#3f40d1", fontcolor="#3f40d1"];
a48 -> n48 [style=dotted, arrowhead=none, color="#3f40d1"];
n48 -> n37;
n48 -> n50;
n37 [label="START g(c)", shape=ellipse, style=filled, color=green];
a37 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b'), ('g', 'c')]", shape=note, style="filled", fillcolor="#f7b2e9", color="#d13fb3", fontcolor="#d13fb3"];
a37 -> n37 [style=dotted, arrowhead=none, color="#d13fb3"];
n37 -> n40;
n40 [label="a", shape=box];
n40 -> n41;
n41 [label="b", shape=box];
n41 -> n42;
n42 [label="a * b", shape=box];
n42 -> n43;
n43 [label="c", shape=box];
n43 -> n44;
n44 [label="(a * b) * c", shape=box];
n44 -> n38;
n38 [label="END g(c)", shape=ellipse, style=filled, color=green];
n38 -> n50;
n50 [label="RET g", shape=box, style=filled, color=orange];
n50 -> n6;
n6 [label="END f2(a, b)", shape=ellipse, style=filled, color=green];
n6 -> n78;
n78 [label="RET f2", shape=box, style=filled, color=orange];
n78 -> n2;
n2 [label="END", shape=ellipse, style=filled, color=gray];
n36 [label="RET f1", shape=box, style=filled, color=orange];
a36 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#d5f7b2", color="#89d13f", fontcolor="#89d13f"];
a36 -> n36 [style=dotted, arrowhead=none, color="#89d13f"];
n36 -> n45;
n55 [label="RET f1", shape=box, style=filled, color=orange];
n55 -> n57;
n57 [label="10", shape=box];
n57 -> n70;
n70 [label="20", shape=box];
n70 -> n71;
n71 [label="30", shape=box];
n71 -> n72;
n72 [label="CALL max", shape=box, style=filled, color=orange];
n72 -> n58;
n72 -> n74;
n58 [label="START max(a, b)", shape=ellipse, style=filled, color=green];
a58 [label="LivingVariables\nIn := []\nOut := [('max', 'a'), ('max', 'b')]", shape=note, style="filled", fillcolor="#f7b2f2", color="#d13fc6", fontcolor="#d13fc6"];
a58 -> n58 [style=dotted, arrowhead=none, color="#d13fc6"];
n58 -> n61;
n61 [label="a", shape=box];
n61 -> n62;
n62 [label="b", shape=box];
n62 -> n63;
n63 [label="a > b", shape=box];
a63 [label="LivingVariables\nIn := [('max', 'a'), ('max', 'b')]\nOut := [('max', 'a'), ('max', 'b')]", shape=note, style="filled", fillcolor="#f7b2cd", color="#d13f77", fontcolor="#d13f77"];
a63 -> n63 [style=dotted, arrowhead=none, color="#d13f77"];
n63 -> n64;
n64 [label="<?>", shape=diamond];
n64 -> n68 [label="T"];
n64 -> n69 [label="F"];
n68 [label="a", shape=box];
n68 -> n59;
n59 [label="END max(a, b)", shape=ellipse, style=filled, color=green];
n59 -> n74;
n74 [label="RET max", shape=box, style=filled, color=orange];
n74 -> n76;
n76 [label="CALL f2", shape=box, style=filled, color=orange];
n76 -> n5;
n76 -> n78;
n5 [label="START f2(a, b)", shape=ellipse, style=filled, color=green];
a5 [label="LivingVariables\nIn := []\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#f7d8b2", color="#d18e3f", fontcolor="#d18e3f"];
a5 -> n5 [style=dotted, arrowhead=none, color="#d18e3f"];
n5 -> n22;
n22 [label="a", shape=box];
n22 -> n23;
n23 [label="b", shape=box];
n23 -> n24;
n24 [label="a > b", shape=box];
a24 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#f7b2f7", color="#d13fd1", fontcolor="#d13fd1"];
a24 -> n24 [style=dotted, arrowhead=none, color="#d13fd1"];
n24 -> n25;
n25 [label="<?>", shape=diamond];
n25 -> n29 [label="T"];
n25 -> n33 [label="F"];
n29 [label="a", shape=box];
n29 -> n30;
n30 [label="CALL f1", shape=box, style=filled, color=orange];
a30 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#b2e6f7", color="#3fadd1", fontcolor="#3fadd1"];
a30 -> n30 [style=dotted, arrowhead=none, color="#3fadd1"];
n30 -> n3;
n30 -> n32;
n33 [label="b", shape=box];
n33 -> n34;
n34 [label="CALL f1", shape=box, style=filled, color=orange];
a34 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#f7b8b2", color="#d14a3f", fontcolor="#d14a3f"];
a34 -> n34 [style=dotted, arrowhead=none, color="#d14a3f"];
n34 -> n3;
n34 -> n36;
n69 [label="b", shape=box];
n69 -> n59;
n16 [label="b", shape=box];
n16 -> n17;
n17 [label="1", shape=box];
n17 -> n18;
n18 [label="b - 1", shape=box];
n18 -> n19;
n19 [label="CALL f1", shape=box, style=filled, color=orange];
a19 [label="LivingVariables\nIn := [('f2', 'a'), ('f2', 'b')]\nOut := [('f2', 'a'), ('f2', 'b')]", shape=note, style="filled", fillcolor="#d2b2f7", color="#813fd1", fontcolor="#813fd1"];
a19 -> n19 [style=dotted, arrowhead=none, color="#813fd1"];
n19 -> n3;
n19 -> n21;
rh3 [shape=point, width=0.05, height=0.05, color="#d13fbf", fillcolor="#d13fbf", style=filled];
{ rank=same; n3; rh3; }
n3:se -> rh3 [color="#d13fbf", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh3 -> n8:ne [color="#d13fbf", fontcolor="#d13fbf", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh3 -> n16:ne [color="#d13fbf", fontcolor="#d13fbf", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh5 [shape=point, width=0.05, height=0.05, color="#d18e3f", fillcolor="#d18e3f", style=filled];
{ rank=same; n5; rh5; }
n5:sw -> rh5 [color="#d18e3f", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh5 -> n22:nw [color="#d18e3f", fontcolor="#d18e3f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh5 -> n23:sw [color="#d18e3f", fontcolor="#d18e3f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh5 -> n29:sw [color="#d18e3f", fontcolor="#d18e3f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh5 -> n33:sw [color="#d18e3f", fontcolor="#d18e3f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh5 -> n40:nw [color="#d18e3f", fontcolor="#d18e3f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh5 -> n41:sw [color="#d18e3f", fontcolor="#d18e3f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh5 -> n45:sw [color="#d18e3f", fontcolor="#d18e3f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh5 -> n46:nw [color="#d18e3f", fontcolor="#d18e3f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh37 [shape=point, width=0.05, height=0.05, color="#d13fb3", fillcolor="#d13fb3", style=filled];
{ rank=same; n37; rh37; }
n37:se -> rh37 [color="#d13fb3", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh37 -> n43:se [color="#d13fb3", fontcolor="#d13fb3", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh58 [shape=point, width=0.05, height=0.05, color="#d13fc6", fillcolor="#d13fc6", style=filled];
{ rank=same; n58; rh58; }
n58:sw -> rh58 [color="#d13fc6", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh58 -> n61:sw [color="#d13fc6", fontcolor="#d13fc6", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh58 -> n62:nw [color="#d13fc6", fontcolor="#d13fc6", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh58 -> n68:nw [color="#d13fc6", fontcolor="#d13fc6", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh58 -> n69:sw [color="#d13fc6", fontcolor="#d13fc6", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
}

View File

@@ -0,0 +1,183 @@
digraph CFG {
// Analysis: Live Variables + Reached Uses
graph [splines=ortho, overlap=false, ranksep=0.7, nodesep=0.45];
node [fontname="Helvetica"];
n1 [label="START", shape=ellipse, style=filled, color=gray];
n1 -> n3;
n3 [label="33", shape=box];
n3 -> n4;
n4 [label="s = 33", shape=box];
a4 [label="LivingVariables\nIn := []\nOut := [('', 's')]", shape=note, style="filled", fillcolor="#b2f7ec", color="#3fd1b9", fontcolor="#3fd1b9"];
a4 -> n4 [style=dotted, arrowhead=none, color="#3fd1b9"];
n4 -> n5;
n5 [label="0", shape=box];
n5 -> n6;
n6 [label="i = 0", shape=box];
a6 [label="LivingVariables\nIn := [('', 's')]\nOut := [('', 'i'), ('', 's')]", shape=note, style="filled", fillcolor="#c3b2f7", color="#633fd1", fontcolor="#633fd1"];
a6 -> n6 [style=dotted, arrowhead=none, color="#633fd1"];
n6 -> n7;
n7 [label="0", shape=box];
n7 -> n8;
n8 [label="j = 0", shape=box];
a8 [label="LivingVariables\nIn := [('', 'i'), ('', 's')]\nOut := [('', 'i'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#f7b2c9", color="#d13f70", fontcolor="#d13f70"];
a8 -> n8 [style=dotted, arrowhead=none, color="#d13f70"];
n8 -> n9;
n9 [label="i", shape=box];
n9 -> n10;
n10 [label="j", shape=box];
n10 -> n11;
n11 [label="i + j", shape=box];
n11 -> n12;
n12 [label="t = (i + j)", shape=box];
a12 [label="LivingVariables\nIn := [('', 'i'), ('', 'j'), ('', 's')]\nOut := [('', 'i'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#b2f7d5", color="#3fd188", fontcolor="#3fd188"];
a12 -> n12 [style=dotted, arrowhead=none, color="#3fd188"];
n12 -> n13;
n13 [label="6", shape=box];
n13 -> n14;
n14 [label="f = 6", shape=box];
a14 [label="LivingVariables\nIn := [('', 'i'), ('', 'j'), ('', 's')]\nOut := [('', 'f'), ('', 'i'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#b2b8f7", color="#3f4bd1", fontcolor="#3f4bd1"];
a14 -> n14 [style=dotted, arrowhead=none, color="#3f4bd1"];
n14 -> n16;
n16 [label="s", shape=box];
n16 -> n17;
n17 [label="42", shape=box];
n17 -> n18;
n18 [label="s < 42", shape=box];
a18 [label="LivingVariables\nIn := [('', 'f'), ('', 'i'), ('', 'j'), ('', 's')]\nOut := [('', 'f'), ('', 'i'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#f7e6b2", color="#d1ac3f", fontcolor="#d1ac3f"];
a18 -> n18 [style=dotted, arrowhead=none, color="#d1ac3f"];
n18 -> n19;
n19 [label="<?>", shape=diamond];
n19 -> n2 [label="T"];
n19 -> n21 [label="F"];
n2 [label="END", shape=ellipse, style=filled, color=gray];
n21 [label="s", shape=box];
n21 -> n22;
n22 [label="1", shape=box];
n22 -> n23;
n23 [label="s - 1", shape=box];
n23 -> n24;
n24 [label="a = (s - 1)", shape=box];
a24 [label="LivingVariables\nIn := [('', 'f'), ('', 'i'), ('', 'j'), ('', 's')]\nOut := [('', 'f'), ('', 'i'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#f7b2f7", color="#d13fd1", fontcolor="#d13fd1"];
a24 -> n24 [style=dotted, arrowhead=none, color="#d13fd1"];
n24 -> n25;
n25 [label="i", shape=box];
n25 -> n26;
n26 [label="j", shape=box];
n26 -> n27;
n27 [label="i + j", shape=box];
n27 -> n28;
n28 [label="f", shape=box];
n28 -> n29;
n29 [label="1", shape=box];
n29 -> n30;
n30 [label="f + 1", shape=box];
n30 -> n31;
n31 [label="(i + j) * (f + 1)", shape=box];
n31 -> n32;
n32 [label="c = ((i + j) * (f + 1))", shape=box];
a32 [label="LivingVariables\nIn := [('', 'f'), ('', 'i'), ('', 'j'), ('', 's')]\nOut := [('', 'c'), ('', 'f'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#e0b2f7", color="#a03fd1", fontcolor="#a03fd1"];
a32 -> n32 [style=dotted, arrowhead=none, color="#a03fd1"];
n32 -> n33;
n33 [label="c", shape=box];
n33 -> n34;
n34 [label="0", shape=box];
n34 -> n35;
n35 [label="c > 0", shape=box];
a35 [label="LivingVariables\nIn := [('', 'c'), ('', 'f'), ('', 'j'), ('', 's')]\nOut := [('', 'c'), ('', 'f'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#b2c1f7", color="#3f5ed1", fontcolor="#3f5ed1"];
a35 -> n35 [style=dotted, arrowhead=none, color="#3f5ed1"];
n35 -> n36;
n36 [label="<?>", shape=diamond];
n36 -> n40 [label="T"];
n36 -> n44 [label="F"];
n40 [label="j", shape=box];
n40 -> n41;
n41 [label="c", shape=box];
n41 -> n42;
n42 [label="j / c", shape=box];
n42 -> n43;
n43 [label="j = (j / c)", shape=box];
a43 [label="LivingVariables\nIn := [('', 'c'), ('', 'f'), ('', 'j'), ('', 's')]\nOut := [('', 'f'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#b2d8f7", color="#3f8fd1", fontcolor="#3f8fd1"];
a43 -> n43 [style=dotted, arrowhead=none, color="#3f8fd1"];
n43 -> n48;
n48 [label="j", shape=box];
n48 -> n49;
n49 [label="2", shape=box];
n49 -> n50;
n50 [label="j * 2", shape=box];
n50 -> n51;
n51 [label="f", shape=box];
n51 -> n52;
n52 [label="(j * 2) / f", shape=box];
n52 -> n53;
n53 [label="i = ((j * 2) / f)", shape=box];
a53 [label="LivingVariables\nIn := [('', 'f'), ('', 'j'), ('', 's')]\nOut := [('', 'f'), ('', 'i'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#d7b2f7", color="#8d3fd1", fontcolor="#8d3fd1"];
a53 -> n53 [style=dotted, arrowhead=none, color="#8d3fd1"];
n53 -> n54;
n54 [label="s", shape=box];
n54 -> n55;
n55 [label="1", shape=box];
n55 -> n56;
n56 [label="s + 1", shape=box];
n56 -> n57;
n57 [label="s = (s + 1)", shape=box];
a57 [label="LivingVariables\nIn := [('', 'f'), ('', 'i'), ('', 'j'), ('', 's')]\nOut := [('', 'f'), ('', 'i'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#def7b2", color="#9bd13f", fontcolor="#9bd13f"];
a57 -> n57 [style=dotted, arrowhead=none, color="#9bd13f"];
n57 -> n16;
n44 [label="j", shape=box];
n44 -> n45;
n45 [label="c", shape=box];
n45 -> n46;
n46 [label="j * c", shape=box];
n46 -> n47;
n47 [label="i = (j * c)", shape=box];
a47 [label="LivingVariables\nIn := [('', 'c'), ('', 'f'), ('', 'j'), ('', 's')]\nOut := [('', 'f'), ('', 'j'), ('', 's')]", shape=note, style="filled", fillcolor="#f7c6b2", color="#d1693f", fontcolor="#d1693f"];
a47 -> n47 [style=dotted, arrowhead=none, color="#d1693f"];
n47 -> n48;
rh4 [shape=point, width=0.05, height=0.05, color="#3fd1b9", fillcolor="#3fd1b9", style=filled];
{ rank=same; n4; rh4; }
n4:se -> rh4 [color="#3fd1b9", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh4 -> n16:ne [color="#3fd1b9", fontcolor="#3fd1b9", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh4 -> n21:se [color="#3fd1b9", fontcolor="#3fd1b9", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh4 -> n54:ne [color="#3fd1b9", fontcolor="#3fd1b9", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh6 [shape=point, width=0.05, height=0.05, color="#633fd1", fillcolor="#633fd1", style=filled];
{ rank=same; n6; rh6; }
n6:sw -> rh6 [color="#633fd1", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh6 -> n9:sw [color="#633fd1", fontcolor="#633fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh6 -> n25:sw [color="#633fd1", fontcolor="#633fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh8 [shape=point, width=0.05, height=0.05, color="#d13f70", fillcolor="#d13f70", style=filled];
{ rank=same; n8; rh8; }
n8:se -> rh8 [color="#d13f70", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh8 -> n10:ne [color="#d13f70", fontcolor="#d13f70", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh8 -> n26:ne [color="#d13f70", fontcolor="#d13f70", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh8 -> n40:ne [color="#d13f70", fontcolor="#d13f70", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh8 -> n44:ne [color="#d13f70", fontcolor="#d13f70", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh8 -> n48:ne [color="#d13f70", fontcolor="#d13f70", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh14 [shape=point, width=0.05, height=0.05, color="#3f4bd1", fillcolor="#3f4bd1", style=filled];
{ rank=same; n14; rh14; }
n14:se -> rh14 [color="#3f4bd1", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh14 -> n28:ne [color="#3f4bd1", fontcolor="#3f4bd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh14 -> n51:se [color="#3f4bd1", fontcolor="#3f4bd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh32 [shape=point, width=0.05, height=0.05, color="#a03fd1", fillcolor="#a03fd1", style=filled];
{ rank=same; n32; rh32; }
n32:se -> rh32 [color="#a03fd1", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh32 -> n33:se [color="#a03fd1", fontcolor="#a03fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh32 -> n41:se [color="#a03fd1", fontcolor="#a03fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh32 -> n45:se [color="#a03fd1", fontcolor="#a03fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh43 [shape=point, width=0.05, height=0.05, color="#3f8fd1", fillcolor="#3f8fd1", style=filled];
{ rank=same; n43; rh43; }
n43:sw -> rh43 [color="#3f8fd1", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh43 -> n26:nw [color="#3f8fd1", fontcolor="#3f8fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh43 -> n40:nw [color="#3f8fd1", fontcolor="#3f8fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh43 -> n44:nw [color="#3f8fd1", fontcolor="#3f8fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh43 -> n48:nw [color="#3f8fd1", fontcolor="#3f8fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh53 [shape=point, width=0.05, height=0.05, color="#8d3fd1", fillcolor="#8d3fd1", style=filled];
{ rank=same; n53; rh53; }
n53:sw -> rh53 [color="#8d3fd1", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh53 -> n25:sw [color="#8d3fd1", fontcolor="#8d3fd1", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh57 [shape=point, width=0.05, height=0.05, color="#9bd13f", fillcolor="#9bd13f", style=filled];
{ rank=same; n57; rh57; }
n57:se -> rh57 [color="#9bd13f", style=dashed, penwidth=1.2, arrowhead=none, constraint=false, tailclip=true, headclip=true];
rh57 -> n16:ne [color="#9bd13f", fontcolor="#9bd13f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh57 -> n21:se [color="#9bd13f", fontcolor="#9bd13f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
rh57 -> n54:ne [color="#9bd13f", fontcolor="#9bd13f", fontsize=8, style=dashed, penwidth=1.0, arrowsize=0.6, constraint=false, tailclip=true, headclip=true];
}

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

@@ -0,0 +1,307 @@
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):
# Dedicated loop-head so every iteration re-evaluates the full condition.
cond_entry = CFG_Node()
pred.add_child(cond_entry)
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(cond_entry)
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(cond_entry)
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 loop body back to full condition evaluation.
body_end.add_child(cond_entry)
# 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,24 @@
digraph CFG {
// Analysis: Reached Uses
node [fontname="Helvetica"];
n1 [label="START", shape=ellipse, style=filled, color=gray];
n1 -> n9;
n9 [label="2", shape=box];
n9 -> n10;
n10 [label="CALL g", shape=box, style=filled, color=orange];
n10 -> n3;
n10 -> n12;
n3 [label="START g(x, y)\nRU: [8]", shape=ellipse, style=filled, color=green];
n3 -> n6;
n6 [label="3", shape=box];
n6 -> n7;
n7 [label="y = 3\nRU: []", shape=box];
n7 -> n8;
n8 [label="x", shape=box];
n8 -> n4;
n4 [label="END g(x, y)", shape=ellipse, style=filled, color=green];
n4 -> n12;
n12 [label="RET g", shape=box, style=filled, color=orange];
n12 -> n2;
n2 [label="END", shape=ellipse, style=filled, color=gray];
}

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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

@@ -1,183 +1,259 @@
import triplayacc as yacc
import cfg_build
import syntax
from pathlib import Path
from graphviz import Source
from vistram.tram import *
import tkinter as tk
from vistram.vistram import MachineUI
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import lib.console as cnsl
import os
from cfg.CFG import CFG
from cfg.CFG_Node import (CFG_START, CFG_END)
import matplotlib
matplotlib.use("TkAgg")
# Assembles the AST into TRAM code
def assemble(ast):
code = ast.code({}, 0)
return code + [halt()]
def make_cfg(ast):
start = CFG_START()
end = CFG_END()
last = ast.cfa(start, end)
if last is not None:
last.add_child(end)
return CFG(start, end)
# 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 / 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.")
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 cfg_build
import lib.console as cnsl
import syntax
import triplayacc as yacc
from cfa.LiveVariables import LiveVariables
from cfa.ReachedUses import ReachedUses
from cfa.to_dot import analysis_to_dot
from cfg.CFG import CFG
from vistram.tram import *
from vistram.vistram import MachineUI
from optimizations.optimize import optimize
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}")
# Print compact Live Variables and Reached Uses reports to console.
def print_analysis_reports(cfg, analyses: dict):
lv = analyses["lv"]
ru = analyses["ru"]
ru_edges = ru.reached_uses_by_node()
node_by_id = {n.id: n for n in cfg.nodes()}
def node_text(nid: int) -> str:
node = node_by_id.get(nid)
if node is None:
return "<unknown>"
lbl = node.dot_label()
return str(lbl) if lbl is not None else "<no-label>"
print("\nLive Variables Report")
print("---------------------")
node_ids = sorted(set(lv.incoming.keys()) | set(lv.outgoing.keys()))
for nid in node_ids:
in_set = sorted(lv.incoming.get(nid, set()))
out_set = sorted(lv.outgoing.get(nid, set()))
if not in_set and not out_set:
continue
print(f"n{nid} [{node_text(nid)}]: In={in_set} Out={out_set}")
print("\nReached Uses Report")
print("-------------------")
has_ru = False
for def_id in sorted(ru_edges):
uses = sorted(set(ru_edges[def_id]))
if not uses:
continue
has_ru = True
use_desc = [f"n{uid} [{node_text(uid)}]" for uid in uses]
print(f"n{def_id} [{node_text(def_id)}] -> {use_desc}")
if not has_ru:
print("(no reached uses)")
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", "Analyze .tripla", "Exit"],
)
if mode == 4:
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:
if cnsl.prompt_confirmation("\nOptimize AST?", default="y"):
ast = optimize(ast)
# 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:
if cnsl.prompt_confirmation("\nOptimize AST?", default="y"):
ast = optimize(ast)
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
out_path.parent.mkdir(exist_ok=True)
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.")
elif mode == 3:
# Reset the global CFG builder state so each analysis run is clean
cfg_build.FUNCTIONS.clear()
cfg_build.CURRENT_FUNCTION = None
cfg = make_cfg(ast)
analysis_name = "Live Variables + Reached Uses analyses"
print(f"\nRunning {analysis_name}")
try:
lv = LiveVariables(cfg)
ru = ReachedUses(cfg)
analyses = {"lv": lv, "ru": ru}
except Exception as exc:
print(f"Analysis failed: {exc}")
continue
if cnsl.prompt_confirmation("\nPrint analysis reports to console?"):
print_analysis_reports(cfg, analyses)
dot_str = analysis_to_dot(cfg, analyses, analysis_name)
if cnsl.prompt_confirmation("\nExport annotated CFG as .dot file?"):
default = f"{path.stem}_analysis.dot"
filename = input(f"Filename [{default}]: ").strip()
if not filename:
filename = default
out_dir = Path(__file__).parent / "cfadots"
out_dir.mkdir(exist_ok=True)
out_path = out_dir / filename
try:
with open(out_path, "w") as f:
f.write(dot_str)
print(f"Saved annotated DOT file as: {out_path}")
except Exception as exc:
print(f"Could not save DOT file: {exc}")
if cnsl.prompt_confirmation("Display annotated CFG diagram?"):
render_diagram(dot_str)
print("Rendered annotated CFG diagram.")

View File

@@ -0,0 +1,46 @@
from __future__ import annotations
import cfg_build
from cfg.CFG import CFG
from cfg.CFG_Node import CFG_Node
from cfa.ReachedUses import ReachedUses
from syntax import EXPRESSION, ASSIGN
from optimizations.Optimization import Optimization
class DeadAssignmentElimination(Optimization):
def __init__(self) -> None:
self._node_by_ast_id: dict[int, CFG_Node] = {}
self.__ru: ReachedUses | None = None
def setup(self, ast: EXPRESSION) -> None:
cfg_build.FUNCTIONS.clear()
cfg_build.CURRENT_FUNCTION = None
cfg = CFG(ast)
self.__ru = ReachedUses(cfg)
self._node_by_ast_id = {id(n.ast_node): n for n in self.__ru.cfg.nodes() if n.ast_node is not None}
def apply(self, node: EXPRESSION) -> EXPRESSION:
# Only ASSIGN nodes can be dead assignments.
if not isinstance(node, ASSIGN):
return node
# Find the CFG node corresponding to this AST node.
# If none is found, the node was not analyzed — leave it unchanged.
cfg_node = self._node_by_ast_id.get(id(node))
if cfg_node is None:
return node
ru = self.__ru
nid = cfg_node.id
defined_vars = ru.defs.get(nid, set())
out = ru.out_sets.get(nid, set())
# Check if any use-fact in OUT(n) belongs to a variable defined at n.
# If so, the assignment is live — at least one use is reachable from here.
for (_, var) in out:
if var in defined_vars:
return node
# No reached use found for the assigned variable — the assignment is dead.
# Replace ASSIGN(var, expr) with expr to preserve side effects on the RHS.
return node.expr

View File

@@ -0,0 +1,7 @@
from __future__ import annotations
from syntax import EXPRESSION
class Optimization:
def setup(self, ast: EXPRESSION) -> None: ...
def apply(self, node: EXPRESSION) -> EXPRESSION: ...

View File

@@ -0,0 +1,2 @@
from optimizations.DeadAssignmentElimination import DeadAssignmentElimination
from optimizations.Optimization import Optimization

View File

@@ -0,0 +1,36 @@
from __future__ import annotations
from optimizations.Optimization import Optimization
from optimizations.DeadAssignmentElimination import DeadAssignmentElimination
from syntax import EXPRESSION
# Traverses the AST and applies the given optimizations
def __apply_optimizations(node: EXPRESSION, optimizations: list[Optimization]) -> EXPRESSION:
for key, value in list(node.__dict__.items()):
if key == "pp":
continue
if isinstance(value, EXPRESSION):
new_child = __apply_optimizations(value, optimizations)
if new_child is not value:
setattr(node, key, new_child)
elif isinstance(value, list):
for i, elem in enumerate(value):
if isinstance(elem, EXPRESSION):
new_elem = __apply_optimizations(elem, optimizations)
if new_elem is not elem:
value[i] = new_elem
result: EXPRESSION = node
for opt in optimizations:
result = opt.apply(result)
return result
# Stores the active optimizations
ACTIVE_OPTIMIZATIONS: list[Optimization] = [
DeadAssignmentElimination(),
]
# Apply optimizations to the given AST node
def optimize(ast: EXPRESSION) -> EXPRESSION:
for opt in ACTIVE_OPTIMIZATIONS:
opt.setup(ast)
return __apply_optimizations(ast, ACTIVE_OPTIMIZATIONS)

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,12 @@
s = 33;
i = 0;
j = 0;
t = i + j;
f = 6;
while (s < 42) do {
a = s - 1;
c = (i + j) * (f + 1);
if (c > 0) then j = j / c else i = j * c;
i = (j * 2) / f;
s = s + 1
}

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,9 @@
let f(x, y)
{
let g(x)
{
y = x + 7
}
in x = g(5); y
}
in f(1, 2)

View File

@@ -5,4 +5,4 @@ let ggT(a, b) {
ggT(a-b, b)
else
ggT(b-a, a)
} in ggT(3528, 3780) // result should be 252
} in ggT(2, 8)

View File

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

View File

@@ -0,0 +1,9 @@
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,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)

Some files were not shown because too many files have changed in this diff Show More