Compare commits

...

17 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
122 changed files with 3680 additions and 521 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 os
import cfg_build import tkinter as tk
import syntax from pathlib import Path
from pathlib import Path import matplotlib
from graphviz import Source import matplotlib.image as mpimg
from vistram.tram import * import matplotlib.pyplot as plt
from graphviz import Source
import tkinter as tk
from vistram.vistram import MachineUI import cfg_build
import lib.console as cnsl
import matplotlib.pyplot as plt import syntax
import matplotlib.image as mpimg import triplayacc as yacc
import lib.console as cnsl from cfa.LiveVariables import LiveVariables
import os from cfa.ReachedUses import ReachedUses
from cfa.to_dot import analysis_to_dot
from cfg.CFG import CFG from cfg.CFG import CFG
from cfg.CFG_Node import (CFG_START, CFG_END) from vistram.tram import *
from vistram.vistram import MachineUI
import matplotlib from optimizations.optimize import optimize
matplotlib.use("TkAgg")
matplotlib.use("TkAgg")
# Assembles the AST into TRAM code
def assemble(ast): # Assembles the AST into TRAM code
code = ast.code({}, 0) def assemble(ast):
return code + [halt()] code = ast.code({}, 0)
return code + [halt()]
def make_cfg(ast):
start = CFG_START() def make_cfg(ast):
end = CFG_END() return CFG(ast)
last = ast.cfa(start, end) # Renders a diagram of the AST
if last is not None: def render_diagram(dot_string: str):
last.add_child(end) # Set DPI for PNG
os.environ["GV_FILE_DPI"] = "300"
return CFG(start, end)
src = Source(dot_string, format="png", engine="dot")
png_path = src.render(cleanup=True)
# Renders a diagram of the AST
def render_diagram(dot_string: str): img = mpimg.imread(png_path)
# Set DPI for PNG
os.environ["GV_FILE_DPI"] = "300" fig = plt.figure(figsize=(12, 12))
fig.canvas.manager.window.wm_title("TRIPLA AST Viewer")
src = Source(dot_string, format="png", engine="dot")
png_path = src.render(cleanup=True) plt.imshow(img)
plt.axis("off")
img = mpimg.imread(png_path) plt.show()
fig = plt.figure(figsize=(12, 12)) # Pretty prints the AST
fig.canvas.manager.window.wm_title("TRIPLA AST Viewer") def pretty_print(node, indent=0):
prefix = " " * indent
plt.imshow(img) print(f"{prefix}{type(node).__name__}:")
plt.axis("off")
plt.show() for key, value in node.__dict__.items():
if isinstance(value, syntax.EXPRESSION):
# Pretty prints the AST pretty_print(value, indent + 4)
def pretty_print(node, indent=0):
prefix = " " * indent elif isinstance(value, list):
print(f"{prefix}{type(node).__name__}:") print(f"{prefix} {key}: [")
for element in value:
for key, value in node.__dict__.items(): if isinstance(element, syntax.EXPRESSION):
if isinstance(value, syntax.EXPRESSION): pretty_print(element, indent + 4)
pretty_print(value, indent + 4) else:
print(" " * (indent + 4) + str(element))
elif isinstance(value, list): print(f"{prefix} ]")
print(f"{prefix} {key}: [")
for element in value: else:
if isinstance(element, syntax.EXPRESSION): print(f"{prefix} {key}: {value}")
pretty_print(element, indent + 4)
else: # Print compact Live Variables and Reached Uses reports to console.
print(" " * (indent + 4) + str(element)) def print_analysis_reports(cfg, analyses: dict):
print(f"{prefix} ]") lv = analyses["lv"]
ru = analyses["ru"]
else: ru_edges = ru.reached_uses_by_node()
print(f"{prefix} {key}: {value}") node_by_id = {n.id: n for n in cfg.nodes()}
def node_text(nid: int) -> str:
if __name__ == "__main__": node = node_by_id.get(nid)
print("\nTRIPLA Parser and TRIPLA to TRAM Compiler") if node is None:
return "<unknown>"
while True: lbl = node.dot_label()
mode = cnsl.prompt_choice("\nSelect action:", ["Parse .tripla", "Compile .tripla", "CFG for .tripla", "Exit"]) return str(lbl) if lbl is not None else "<no-label>"
if mode == 3: print("\nLive Variables Report")
print("\nBye Bye.") print("---------------------")
break node_ids = sorted(set(lv.incoming.keys()) | set(lv.outgoing.keys()))
for nid in node_ids:
base = Path(__file__).parent / "triplaprograms" in_set = sorted(lv.incoming.get(nid, set()))
programs = sorted([f for f in base.glob("*.tripla")]) out_set = sorted(lv.outgoing.get(nid, set()))
if not programs: if not in_set and not out_set:
print("\nNo .tripla files found.") continue
continue print(f"n{nid} [{node_text(nid)}]: In={in_set} Out={out_set}")
idx = cnsl.prompt_choice("\nSelect TRIPLA program:", [p.name for p in programs]) print("\nReached Uses Report")
path = programs[idx] print("-------------------")
has_ru = False
source = path.read_text() for def_id in sorted(ru_edges):
ast = yacc.parser.parse(source) uses = sorted(set(ru_edges[def_id]))
if not uses:
if mode == 0: continue
# Pretty print has_ru = True
if cnsl.prompt_confirmation("\nPretty-print AST?"): use_desc = [f"n{uid} [{node_text(uid)}]" for uid in uses]
print("") print(f"n{def_id} [{node_text(def_id)}] -> {use_desc}")
pretty_print(ast) if not has_ru:
print("(no reached uses)")
# Export DOT
dot_str = ast.to_dot() if __name__ == "__main__":
if cnsl.prompt_confirmation("Export AST as .dot file?"): print("\nTRIPLA Parser and TRIPLA to TRAM Compiler")
default = f"{path.stem}.dot"
filename = input(f"Filename [{default}]: ").strip() while True:
if not filename: mode = cnsl.prompt_choice(
filename = default "\nSelect action:",
try: ["Parse .tripla", "Compile .tripla", "CFG for .tripla", "Analyze .tripla", "Exit"],
base_dir = Path(__file__).parent )
out_path = base_dir / filename
with open(out_path, "w") as f: if mode == 4:
f.write(dot_str) print("\nBye Bye.")
print(f"Saved DOT file as: {out_path}") break
except Exception as e:
print(f"Could not save DOT file: {e}") base = Path(__file__).parent / "triplaprograms"
programs = sorted([f for f in base.glob("*.tripla")])
# Display AST diagram if not programs:
if cnsl.prompt_confirmation("Display AST diagram?"): print("\nNo .tripla files found.")
render_diagram(dot_str) continue
print("Rendered AST diagram.")
idx = cnsl.prompt_choice("\nSelect TRIPLA program:", [p.name for p in programs])
elif mode == 1: path = programs[idx]
tram_code = assemble(ast)
source = path.read_text()
# Print TRAM code ast = yacc.parser.parse(source)
if cnsl.prompt_confirmation("\nPrint TRAM code to console?"):
print("\nGenerated TRAM code:\n") if mode == 0:
for instr in tram_code: if cnsl.prompt_confirmation("\nOptimize AST?", default="y"):
print(instr.toString()) ast = optimize(ast)
# Save TRAM code # Pretty print
if cnsl.prompt_confirmation("Save TRAM code as .tram file?"): if cnsl.prompt_confirmation("\nPretty-print AST?"):
base_dir = Path(__file__).parent / "tramcodes" print("")
base_dir.mkdir(exist_ok=True) pretty_print(ast)
default = f"{path.stem}.tram" # Export DOT
filename = input(f"Filename [{default}]: ").strip() dot_str = ast.to_dot()
if not filename: if cnsl.prompt_confirmation("Export AST as .dot file?"):
filename = default default = f"{path.stem}.dot"
filename = input(f"Filename [{default}]: ").strip()
out_path = base_dir / filename if not filename:
with open(out_path, "w") as f: filename = default
for instr in tram_code: try:
f.write(instr.toString() + "\n") base_dir = Path(__file__).parent
out_path = base_dir / filename
print(f"Saved TRAM code to: {out_path}") with open(out_path, "w") as f:
f.write(dot_str)
# Display TRAM code in Visual TRAM UI print(f"Saved DOT file as: {out_path}")
if cnsl.prompt_confirmation("Display TRAM code in Visual TRAM UI?"): except Exception as e:
root = tk.Tk() print(f"Could not save DOT file: {e}")
ui = MachineUI(root)
ui.machine.initial_program = tram_code # Display AST diagram
ui.machine.reset() if cnsl.prompt_confirmation("Display AST diagram?"):
root.mainloop() render_diagram(dot_str)
print("Rendered AST diagram.")
elif mode == 2:
cfg = make_cfg(ast) elif mode == 1:
if cnsl.prompt_confirmation("\nOptimize AST?", default="y"):
dot_str = cfg.to_dot() ast = optimize(ast)
if cnsl.prompt_confirmation("\nExport CFG as .dot file?"):
default = f"{path.stem}_cfg.dot" tram_code = assemble(ast)
filename = input(f"Filename [{default}]: ").strip()
if not filename: # Print TRAM code
filename = default if cnsl.prompt_confirmation("\nPrint TRAM code to console?"):
print("\nGenerated TRAM code:\n")
out_path = Path(__file__).parent / filename for instr in tram_code:
with open(out_path, "w") as f: print(instr.toString())
f.write(dot_str)
# Save TRAM code
print(f"Saved CFG DOT file as: {out_path}") if cnsl.prompt_confirmation("Save TRAM code as .tram file?"):
base_dir = Path(__file__).parent / "tramcodes"
if cnsl.prompt_confirmation("Display CFG diagram?"): base_dir.mkdir(exist_ok=True)
render_diagram(dot_str)
print("Rendered CFG diagram.") 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,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) ggT(a-b, b)
else else
ggT(b-a, a) 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) { let g(a) {
a*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