Files
Construction-of-Compilers/Project-02-03/main.py
Jan-Niclas Loosen 99210f6e0d finish refactoring
2025-12-11 01:19:53 +01:00

147 lines
4.6 KiB
Python

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