First working solution of new task

This commit is contained in:
Jan-Niclas Loosen
2026-03-05 18:03:55 +01:00
parent 691d6eba8c
commit de46c67129
11 changed files with 1077 additions and 9 deletions

View File

@@ -7,9 +7,11 @@ import matplotlib.image as mpimg
import matplotlib.pyplot as plt
from graphviz import Source
import cfg_build
import lib.console as cnsl
import syntax
import triplayacc as yacc
from cfa.analysis_dot import analysis_to_dot, run_all_analyses
from cfg.CFG import CFG
from vistram.tram import *
from vistram.vistram import MachineUI
@@ -63,13 +65,54 @@ def pretty_print(node, indent=0):
print(f"{prefix} {key}: {value}")
def print_analysis_reports(cfg, analyses: dict, ru_edges: dict[int, list[int]]):
"""Print compact Live Variables and Reached Uses reports to console."""
lv = analyses["lv"]
ru = analyses["ru"]
_ = ru
node_by_id = {n.id: n for n in cfg.nodes()}
def node_text(nid: int) -> str:
node = node_by_id.get(nid)
if node is None:
return "<unknown>"
lbl = node.dot_label()
return str(lbl) if lbl is not None else "<no-label>"
print("\nLive Variables Report")
print("---------------------")
node_ids = sorted(set(lv.in_sets.keys()) | set(lv.out_sets.keys()))
for nid in node_ids:
in_set = sorted(lv.in_sets.get(nid, set()))
out_set = sorted(lv.out_sets.get(nid, set()))
if not in_set and not out_set:
continue
print(f"n{nid} [{node_text(nid)}]: In={in_set} Out={out_set}")
print("\nReached Uses Report")
print("-------------------")
has_ru = False
for def_id in sorted(ru_edges):
uses = sorted(set(ru_edges[def_id]))
if not uses:
continue
has_ru = True
use_desc = [f"n{uid} [{node_text(uid)}]" for uid in uses]
print(f"n{def_id} [{node_text(def_id)}] -> {use_desc}")
if not has_ru:
print("(no reached uses)")
if __name__ == "__main__":
print("\nTRIPLA Parser and TRIPLA to TRAM Compiler")
while True:
mode = cnsl.prompt_choice("\nSelect action:", ["Parse .tripla", "Compile .tripla", "CFG for .tripla", "Exit"])
mode = cnsl.prompt_choice(
"\nSelect action:",
["Parse .tripla", "Compile .tripla", "CFG for .tripla", "Analyze .tripla", "Exit"],
)
if mode == 3:
if mode == 4:
print("\nBye Bye.")
break
@@ -157,6 +200,7 @@ if __name__ == "__main__":
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)
@@ -166,6 +210,46 @@ if __name__ == "__main__":
render_diagram(dot_str)
print("Rendered CFG diagram.")
elif mode == 3:
# Reset 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"
print(f"\nRunning {analysis_name}")
try:
_analyses, annotations, ru_edges = run_all_analyses(cfg)
except Exception as exc:
print(f"Analysis failed: {exc}")
continue
print(
f"Done. {len(annotations)} LV annotation node(s), "
f"{len(ru_edges)} RU definition node(s)."
)
dot_str = analysis_to_dot(cfg, annotations, analysis_name, ru_edges)
if cnsl.prompt_confirmation("\nPrint analysis reports to console?"):
print_analysis_reports(cfg, _analyses, ru_edges)
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.")