import triplayacc as yacc import triplalex as lex import syntax from pathlib import Path from graphviz import Source import matplotlib.pyplot as plt import matplotlib.image as mpimg import os import matplotlib matplotlib.use("TkAgg") def render_ast_from_string(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() 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}") def export_dot_file(dot_string: str, filename: str): try: Path(filename).write_text(dot_string, encoding="utf-8") print(f"Saved DOT file as: {filename}") except Exception as e: print(f"Could not save DOT file: {e}") def __prompt_choice(prompt: str, options: list) -> int: print(prompt) for i, opt in enumerate(options, 1): print(f" {i}. {opt}") while True: try: s = input(f"Enter choice (1-{len(options)}): ").strip() idx = int(s) - 1 if 0 <= idx < len(options): return idx except Exception: pass print(f"Invalid. Enter a number between 1-{len(options)}.") def __prompt_yesno(question: str, default="y"): s = input(f"{question} (y/n) [{default}]: ").strip().lower() if not s: s = default return s.startswith("y") def __search_programs(): base = Path(__file__).parent / "triplaprograms" if not base.exists(): return [] return sorted([f for f in base.glob("*.tripla")]) if __name__ == "__main__": print("\nTRIPLA Parser Tool") while True: choice = __prompt_choice("\nSelect action:", ["Parse .tripla", "Exit"]) if choice == 1: print("\nBye Bye.") break programs = __search_programs() if not programs: print("\nNo .tripla files found.") continue idx = __prompt_choice("\nSelect program to parse:", [p.name for p in programs]) path = programs[idx] source = path.read_text() ast = yacc.parser.parse(source) # Pretty print if __prompt_yesno("\nPretty-print AST?"): print("") pretty_print(ast) # Export DOT dot_str = ast.to_dot() if __prompt_yesno("Export AST as .dot file?"): default = f"{path.stem}.dot" out = input(f"Filename [{default}]: ").strip() if not out: out = default export_dot_file(dot_str, out) # Display AST diagram if __prompt_yesno("Display AST diagram?"): render_ast_from_string(dot_str) print("Rendered AST diagram.")