Finish MaMaGUI and create MaMaMa
This commit is contained in:
1
.idea/dictionaries/project.xml
generated
1
.idea/dictionaries/project.xml
generated
@@ -1,6 +1,7 @@
|
|||||||
<component name="ProjectDictionaryState">
|
<component name="ProjectDictionaryState">
|
||||||
<dictionary name="project">
|
<dictionary name="project">
|
||||||
<words>
|
<words>
|
||||||
|
<w>btns</w>
|
||||||
<w>ldsp</w>
|
<w>ldsp</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
|
|||||||
@@ -1,133 +1,37 @@
|
|||||||
from typing import Dict, Optional, Tuple, List
|
from typing import Dict, Optional, Tuple, List, Any
|
||||||
|
|
||||||
class MaMa:
|
class MaMa:
|
||||||
def __init__(self, prog: Dict[int, str] | List[str], stack: Dict[int, int] | List[int] | None = None) -> None:
|
def __init__(self, prog: Dict[int, str] | List[str],
|
||||||
# Execution state
|
stack: Dict[int, int] | List[int] | None = None) -> None:
|
||||||
self.steps = 0
|
self.steps = 0
|
||||||
|
self.prog = {i: instr for i, instr in enumerate(prog)} if isinstance(prog, list) else prog
|
||||||
# Allow either dict or list for program input
|
|
||||||
if isinstance(prog, list):
|
|
||||||
self.prog = {i: instr for i, instr in enumerate(prog)}
|
|
||||||
else:
|
|
||||||
self.prog = prog
|
|
||||||
|
|
||||||
# Program counter
|
|
||||||
self.p_prog = 0
|
self.p_prog = 0
|
||||||
|
|
||||||
# Stack memory and pointer
|
|
||||||
self.stack: Dict[int, int] = {}
|
self.stack: Dict[int, int] = {}
|
||||||
self.p_stack = -1
|
self.p_stack = -1
|
||||||
self.initial_stack: Dict[int, int] = {}
|
self.halted = False
|
||||||
if stack is not None:
|
if stack is not None:
|
||||||
self.reload(stack)
|
|
||||||
|
|
||||||
# Machine halted flag
|
|
||||||
self.halted = False
|
|
||||||
|
|
||||||
# Macro system
|
|
||||||
self.macros: Dict[str, Dict[str, object]] = {}
|
|
||||||
self.call_stack: List[Tuple[Dict[int, str], int, Optional[str]]] = [] # (prog, return_pc, macro_name)
|
|
||||||
self.in_macro_stack: List[str] = [] # first = outermost, last = innermost
|
|
||||||
|
|
||||||
# Add new macro with parameters
|
|
||||||
def add_macro(self, name: str, prog: List[str] | Dict[int, str], args: List[str]) -> None:
|
|
||||||
if isinstance(prog, list):
|
|
||||||
prog = {i: instr for i, instr in enumerate(prog)}
|
|
||||||
self.macros[name] = {"prog": prog, "args": args}
|
|
||||||
|
|
||||||
# Restore initial machine state
|
|
||||||
def reload(self, stack: Dict[int, int] | List[int] | None = None) -> None:
|
|
||||||
if stack is None:
|
|
||||||
self.stack = dict(self.initial_stack)
|
|
||||||
else:
|
|
||||||
if isinstance(stack, list):
|
if isinstance(stack, list):
|
||||||
self.stack.update({i: v for i, v in enumerate(stack)})
|
self.stack = {i: v for i, v in enumerate(stack)}
|
||||||
else:
|
else:
|
||||||
self.stack.update(stack)
|
self.stack = dict(stack)
|
||||||
self.p_prog = 0
|
self.p_stack = max(self.stack.keys(), default=-1)
|
||||||
self.p_stack = max(self.stack.keys(), default=-1)
|
self.initial_stack = dict(self.stack)
|
||||||
self.halted = False
|
|
||||||
self.steps = 0
|
# -------------------------------------------------------------
|
||||||
self.call_stack = []
|
|
||||||
self.in_macro_stack = []
|
|
||||||
|
|
||||||
def run(self, max_steps: int = 1000) -> List[Dict[str, int | str | dict | list]]:
|
def run(self, max_steps: int = 1000) -> List[Dict[str, int | str | dict | list]]:
|
||||||
steps = 0
|
steps = 0
|
||||||
|
# always insert init configuration as step 0
|
||||||
journal = [self.config("init")]
|
journal = [self.config("init")]
|
||||||
while not self.halted and steps < max_steps:
|
while not self.halted and steps < max_steps:
|
||||||
journal.append(self.step())
|
journal.append(self.__step())
|
||||||
steps += 1
|
steps += 1
|
||||||
return journal
|
return journal
|
||||||
|
|
||||||
def is_halted(self) -> bool:
|
# -------------------------------------------------------------
|
||||||
return self.halted
|
|
||||||
|
|
||||||
def step(self) -> Dict[str, int | str | dict | list]:
|
def structure(self) -> Dict[int, Dict[str, Any]]:
|
||||||
if self.halted or self.p_prog not in self.prog:
|
return {i: {"call": call, "macros": []} for i, call in sorted(self.prog.items())}
|
||||||
# if macro ended, return to caller
|
|
||||||
if self.call_stack:
|
|
||||||
self.prog, self.p_prog, macro_name = self.call_stack.pop()
|
|
||||||
if self.in_macro_stack:
|
|
||||||
self.in_macro_stack.pop()
|
|
||||||
return self.step() # skip macro return entry
|
|
||||||
else:
|
|
||||||
self.halted = True
|
|
||||||
return self.config("halted")
|
|
||||||
|
|
||||||
call = self.prog[self.p_prog]
|
|
||||||
name, args = self.decode(call)
|
|
||||||
|
|
||||||
# Handle macro invocation with parameter substitution
|
|
||||||
if name in self.macros:
|
|
||||||
macro = self.macros[name]
|
|
||||||
formal_args = macro["args"]
|
|
||||||
actual_args = args if isinstance(args, list) else []
|
|
||||||
mapping = dict(zip(formal_args, actual_args))
|
|
||||||
|
|
||||||
expanded_prog = {}
|
|
||||||
for i, instr in macro["prog"].items():
|
|
||||||
# split into opcode and argument part for safe substitution
|
|
||||||
if "(" in instr:
|
|
||||||
instr_name, rest = instr.split("(", 1)
|
|
||||||
arg_text = rest[:-1]
|
|
||||||
if arg_text.strip() != "":
|
|
||||||
parts = [a.strip() for a in arg_text.split(",")]
|
|
||||||
resolved = []
|
|
||||||
for a in parts:
|
|
||||||
if a in mapping:
|
|
||||||
resolved.append(str(mapping[a]))
|
|
||||||
else:
|
|
||||||
resolved.append(a)
|
|
||||||
instr = f"{instr_name}({','.join(resolved)})"
|
|
||||||
else:
|
|
||||||
instr = f"{instr_name}()"
|
|
||||||
expanded_prog[i] = instr
|
|
||||||
|
|
||||||
# push current program context
|
|
||||||
self.call_stack.append((self.prog, self.p_prog + 1, name))
|
|
||||||
self.in_macro_stack.append(name)
|
|
||||||
self.prog = expanded_prog
|
|
||||||
self.p_prog = 0
|
|
||||||
return self.step() # directly continue without adding step
|
|
||||||
|
|
||||||
method = getattr(self, f"_{name}", None)
|
|
||||||
if method is None:
|
|
||||||
raise ValueError(f"Unknown instruction: {call}")
|
|
||||||
|
|
||||||
method(args)
|
|
||||||
self.steps += 1
|
|
||||||
return self.config(call)
|
|
||||||
|
|
||||||
# Return current configuration including macro nesting
|
|
||||||
def config(self, call: str) -> Dict[str, int | str | dict | list]:
|
|
||||||
return {
|
|
||||||
"step": self.steps,
|
|
||||||
"call": call,
|
|
||||||
"p_prog": self.p_prog,
|
|
||||||
"p_stack": self.p_stack,
|
|
||||||
"stack": dict(self.stack),
|
|
||||||
"in_macro": list(self.in_macro_stack), # first = outermost, last = innermost
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def decode(call: str) -> Tuple[str, Optional[List[int]]]:
|
def decode(call: str) -> Tuple[str, Optional[List[int]]]:
|
||||||
@@ -140,6 +44,33 @@ class MaMa:
|
|||||||
return name, args
|
return name, args
|
||||||
return call, None
|
return call, None
|
||||||
|
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
|
||||||
|
def config(self, call: str) -> Dict[str, int | str | dict | list]:
|
||||||
|
return {
|
||||||
|
"step": self.steps,
|
||||||
|
"call": call,
|
||||||
|
"p_prog": self.p_prog,
|
||||||
|
"p_stack": self.p_stack,
|
||||||
|
"stack": dict(self.stack),
|
||||||
|
}
|
||||||
|
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
|
||||||
|
def __step(self) -> Dict[str, int | str | dict | list]:
|
||||||
|
if self.halted or self.p_prog not in self.prog:
|
||||||
|
self.halted = True
|
||||||
|
return self.config("halted")
|
||||||
|
|
||||||
|
call = self.prog[self.p_prog]
|
||||||
|
name, args = MaMa.decode(call)
|
||||||
|
method = getattr(self, f"_{name}", None)
|
||||||
|
if method is None:
|
||||||
|
raise ValueError(f"Unknown instruction: {call}")
|
||||||
|
method(args)
|
||||||
|
self.steps += 1
|
||||||
|
return self.config(call)
|
||||||
|
|
||||||
# Stop execution
|
# Stop execution
|
||||||
def _stop(self, _: Optional[int]) -> None:
|
def _stop(self, _: Optional[int]) -> None:
|
||||||
self.halted = True
|
self.halted = True
|
||||||
|
|||||||
@@ -5,88 +5,106 @@ from MaMa import MaMa
|
|||||||
|
|
||||||
class MaMaGUI:
|
class MaMaGUI:
|
||||||
def __init__(self, mama: MaMa, delay: int = 400) -> None:
|
def __init__(self, mama: MaMa, delay: int = 400) -> None:
|
||||||
self.machine = mama
|
# Autoplay speed
|
||||||
self.delay = delay
|
self.delay = delay
|
||||||
self.index = 0
|
|
||||||
self.journal: List[Dict[str, object]] = []
|
|
||||||
|
|
||||||
# Tracks automatic running state
|
# Rather autoplay is activated
|
||||||
self.running = False
|
self.do_autoplay = False
|
||||||
|
|
||||||
# Run machine once and include initial configuration
|
# Run MaMa and create journal
|
||||||
self.journal = self.machine.run()
|
self.machine = mama
|
||||||
|
self.journal: List[Dict[str, object]] = self.machine.run()
|
||||||
if not self.journal:
|
if not self.journal:
|
||||||
raise ValueError("Journal is empty. Make sure MaMa executed successfully.")
|
raise ValueError("Journal is empty.")
|
||||||
print(self.journal)
|
self.journal_index = 0
|
||||||
|
|
||||||
|
# Bootstrap UI
|
||||||
self.root = tk.Tk()
|
self.root = tk.Tk()
|
||||||
self.root.title("MaMa GUI")
|
self.root.title("MaMa GUI")
|
||||||
|
|
||||||
# Prepare rows and columns
|
|
||||||
container = ttk.Frame(self.root, padding=10)
|
container = ttk.Frame(self.root, padding=10)
|
||||||
container.grid(sticky="nsew")
|
container.grid(sticky="nsew")
|
||||||
container.columnconfigure(0, weight=1)
|
container.columnconfigure((0, 1), weight=1)
|
||||||
container.columnconfigure(1, weight=1)
|
|
||||||
container.rowconfigure(0, weight=1)
|
container.rowconfigure(0, weight=1)
|
||||||
|
|
||||||
# Program display
|
# Program display
|
||||||
prog_frame = ttk.LabelFrame(container, text="Program", padding=5)
|
prog_frame = ttk.LabelFrame(container, text="Program", padding=5)
|
||||||
prog_frame.grid(row=0, column=0, sticky="nsew", padx=(0, 10))
|
prog_frame.grid(row=0, column=0, sticky="nsew", padx=(0, 10))
|
||||||
self.prog_list = tk.Listbox(prog_frame, width=30, height=22, font=("Consolas", 11))
|
self.prog_list = tk.Listbox(prog_frame, width=70, height=24, font=("Consolas", 11))
|
||||||
self.prog_list.pack(fill="both", expand=True)
|
self.prog_list.pack(fill="both", expand=True)
|
||||||
|
|
||||||
# Stack and configuration display
|
# Stack display
|
||||||
stack_frame = ttk.LabelFrame(container, text="Stack", padding=5)
|
stack_frame = ttk.LabelFrame(container, text="Stack", padding=5)
|
||||||
stack_frame.grid(row=0, column=1, sticky="nsew")
|
stack_frame.grid(row=0, column=1, sticky="nsew")
|
||||||
stack_frame.rowconfigure(0, weight=1)
|
stack_frame.rowconfigure(0, weight=1)
|
||||||
stack_frame.columnconfigure(0, weight=1)
|
self.stack_list = tk.Listbox(stack_frame, width=36, height=22, font=("Consolas", 11))
|
||||||
self.stack_list = tk.Listbox(stack_frame, width=32, height=20, font=("Consolas", 11))
|
|
||||||
self.stack_list.grid(row=0, column=0, sticky="nsew")
|
self.stack_list.grid(row=0, column=0, sticky="nsew")
|
||||||
|
|
||||||
# Configuration label
|
# Configuration display
|
||||||
self.conf_label = ttk.Label(stack_frame, text="(s, p, S) = (-, -, [])", font=("Consolas", 11), anchor="e")
|
self.conf_label = ttk.Label(stack_frame, text="(s, p, S) = (-, -, [])", font=("Consolas", 11), anchor="e")
|
||||||
self.conf_label.grid(row=1, column=0, sticky="ew", pady=(4, 0))
|
self.conf_label.grid(row=1, column=0, sticky="ew", pady=(4, 0))
|
||||||
|
|
||||||
# Init and bind controls
|
# Create and bind controls
|
||||||
control = ttk.Frame(self.root, padding=5)
|
control = ttk.Frame(self.root, padding=5)
|
||||||
control.grid(row=1, column=0, columnspan=2, sticky="ew")
|
control.grid(row=1, column=0, columnspan=2, sticky="ew")
|
||||||
|
btns = [
|
||||||
|
("▶ Start", self.__start),
|
||||||
|
("⏸ Stop", self.__stop),
|
||||||
|
("⏭ Next", self.__next_step),
|
||||||
|
("↩ Prev", self.__prev_step),
|
||||||
|
("⟲ Reset", self.__reset)
|
||||||
|
]
|
||||||
|
|
||||||
ttk.Button(control, text="▶ Start", command=self.start).pack(side="left", padx=5)
|
for text, cmd in btns:
|
||||||
ttk.Button(control, text="⏸ Stop", command=self.stop).pack(side="left", padx=5)
|
ttk.Button(control, text=text, command=cmd).pack(side="left", padx=5)
|
||||||
ttk.Button(control, text="⏭ Next", command=self.next_step).pack(side="left", padx=5)
|
|
||||||
ttk.Button(control, text="↩ Prev", command=self.prev_step).pack(side="left", padx=5)
|
|
||||||
ttk.Button(control, text="⟲ Reset", command=self.reset).pack(side="left", padx=5)
|
|
||||||
|
|
||||||
ttk.Label(control, text="Speed:").pack(side="left", padx=5)
|
ttk.Label(control, text="Speed:").pack(side="left", padx=5)
|
||||||
self.speed_scale = ttk.Scale(control, from_=2000, to=100, orient="horizontal", command=self.__update_speed)
|
self.speed_scale = ttk.Scale(control, from_=2000, to=100, orient="horizontal", command=self.__update_speed)
|
||||||
self.speed_scale.set(self.delay)
|
self.speed_scale.set(self.delay)
|
||||||
self.speed_scale.pack(side="left", padx=5)
|
self.speed_scale.pack(side="left", padx=5)
|
||||||
|
|
||||||
# Status bar
|
# Global status bar
|
||||||
self.status = ttk.Label(self.root, text="Ready", padding=5, anchor="w")
|
self.status = ttk.Label(self.root, text="Ready", padding=5, anchor="w")
|
||||||
self.status.grid(row=2, column=0, columnspan=2, sticky="ew")
|
self.status.grid(row=2, column=0, columnspan=2, sticky="ew")
|
||||||
|
|
||||||
# Initial update
|
|
||||||
self.__update()
|
self.__update()
|
||||||
|
|
||||||
def __update(self) -> None:
|
def __update(self) -> None:
|
||||||
state = self.journal[self.index]
|
# Load current journal entry
|
||||||
prog = self.machine.prog
|
state = self.journal[self.journal_index]
|
||||||
p_prog = state["p_prog"]
|
stack = dict(state["stack"])
|
||||||
p_stack = state["p_stack"]
|
p_prog, p_stack = int(state["p_prog"]), int(state["p_stack"])
|
||||||
stack = state["stack"]
|
step, call = int(state["step"]), str(state["call"])
|
||||||
step = state["step"]
|
|
||||||
call = state["call"]
|
|
||||||
|
|
||||||
# Program display
|
# Load code structure
|
||||||
|
structure = self.machine.structure()
|
||||||
self.prog_list.delete(0, tk.END)
|
self.prog_list.delete(0, tk.END)
|
||||||
for addr, instr in prog.items():
|
opened_macros: List[str] = []
|
||||||
|
macro_offset = 4
|
||||||
|
|
||||||
|
# Display code lines and unpack macros
|
||||||
|
for addr, info in structure.items():
|
||||||
|
macros = info.get("macros", [])
|
||||||
|
depth = len(macros)
|
||||||
|
|
||||||
|
# Align macro headers at parent's instruction column
|
||||||
|
if len(macros) > len(opened_macros):
|
||||||
|
parent_depth = len(macros) - 1
|
||||||
|
header_indent = " " * parent_depth + " " * macro_offset
|
||||||
|
self.prog_list.insert(tk.END, f"{header_indent}[{macros[-1]}]")
|
||||||
|
self.prog_list.itemconfig(tk.END, {"bg": "#e6e6e6"})
|
||||||
|
|
||||||
|
instr_indent = " " * depth
|
||||||
prefix = ">> " if addr == p_prog else " "
|
prefix = ">> " if addr == p_prog else " "
|
||||||
self.prog_list.insert(tk.END, f"{prefix}{addr:>3}: {instr}")
|
line = f"{prefix}{instr_indent}{addr:>3}: {info['call']}"
|
||||||
|
self.prog_list.insert(tk.END, line)
|
||||||
|
opened_macros = macros
|
||||||
|
|
||||||
|
# Highlight current program line
|
||||||
if addr == p_prog:
|
if addr == p_prog:
|
||||||
self.prog_list.itemconfig(tk.END, {"bg": "#ffd966"})
|
self.prog_list.itemconfig(tk.END, {"bg": "#ffd966"})
|
||||||
|
|
||||||
# Stack display
|
# Visualize current stack
|
||||||
self.stack_list.delete(0, tk.END)
|
self.stack_list.delete(0, tk.END)
|
||||||
if stack:
|
if stack:
|
||||||
for i in range(p_stack, -1, -1):
|
for i in range(p_stack, -1, -1):
|
||||||
@@ -96,50 +114,52 @@ class MaMaGUI:
|
|||||||
if i == p_stack:
|
if i == p_stack:
|
||||||
self.stack_list.itemconfig(tk.END, {"bg": "#cfe2f3"})
|
self.stack_list.itemconfig(tk.END, {"bg": "#cfe2f3"})
|
||||||
else:
|
else:
|
||||||
self.stack_list.insert(tk.END, "(empty)")
|
self.stack_list.insert(tk.END, "Empty")
|
||||||
|
|
||||||
# Configuration line
|
# Update configuration and global stack
|
||||||
conf_str = f"({p_stack}, {p_prog}, {list(stack.values())})"
|
self.conf_label.config(text=f"({p_stack}, {p_prog}, {list(stack.values())})")
|
||||||
self.conf_label.config(text=conf_str)
|
self.status.config(text=f"Step {step}/{len(self.journal)-1} | PC={p_prog} | SP={p_stack} | Call: {call}")
|
||||||
|
|
||||||
# Status update
|
|
||||||
status = f"Step {step}/{len(self.journal)-1} | PC={p_prog} | SP={p_stack} | Last call: {call}"
|
|
||||||
self.status.config(text=status)
|
|
||||||
|
|
||||||
|
# Configure auto step speed
|
||||||
def __update_speed(self, value: str) -> None:
|
def __update_speed(self, value: str) -> None:
|
||||||
self.delay = int(float(value))
|
self.delay = int(float(value))
|
||||||
|
|
||||||
def start(self) -> None:
|
# Start autoplay
|
||||||
if not self.running:
|
def __start(self) -> None:
|
||||||
self.running = True
|
if not self.do_autoplay:
|
||||||
|
self.do_autoplay = True
|
||||||
self.__auto_step()
|
self.__auto_step()
|
||||||
|
|
||||||
def stop(self) -> None:
|
# Stop autoplay
|
||||||
self.running = False
|
def __stop(self) -> None:
|
||||||
|
self.do_autoplay = False
|
||||||
|
|
||||||
|
# Play an autoplay step
|
||||||
def __auto_step(self) -> None:
|
def __auto_step(self) -> None:
|
||||||
if self.running and self.index < len(self.journal) - 1:
|
if self.do_autoplay and self.journal_index < len(self.journal) - 1:
|
||||||
self.index += 1
|
self.journal_index += 1
|
||||||
self.__update()
|
self.__update()
|
||||||
self.root.after(self.delay, self.__auto_step)
|
self.root.after(self.delay, self.__auto_step)
|
||||||
else:
|
else:
|
||||||
self.running = False
|
self.do_autoplay = False
|
||||||
|
|
||||||
def next_step(self) -> None:
|
# Play next step
|
||||||
if self.index < len(self.journal) - 1:
|
def __next_step(self) -> None:
|
||||||
self.index += 1
|
if self.journal_index < len(self.journal) - 1:
|
||||||
|
self.journal_index += 1
|
||||||
self.__update()
|
self.__update()
|
||||||
|
|
||||||
def prev_step(self) -> None:
|
# Play previous step
|
||||||
if self.index > 0:
|
def __prev_step(self) -> None:
|
||||||
self.index -= 1
|
if self.journal_index > 0:
|
||||||
|
self.journal_index -= 1
|
||||||
self.__update()
|
self.__update()
|
||||||
|
|
||||||
def reset(self) -> None:
|
# Reset machine
|
||||||
self.machine.reload()
|
def __reset(self) -> None:
|
||||||
self.journal = self.machine.run()
|
self.journal_index = 0
|
||||||
self.index = 0
|
|
||||||
self.__update()
|
self.__update()
|
||||||
|
|
||||||
|
# Run main loop
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
self.root.mainloop()
|
self.root.mainloop()
|
||||||
|
|||||||
42
Uebung-01/MaMaMa.py
Normal file
42
Uebung-01/MaMaMa.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
from typing import Dict, Optional, List, Any, Tuple
|
||||||
|
from MaMa import MaMa
|
||||||
|
|
||||||
|
class MaMaMa(MaMa):
|
||||||
|
def __init__(self, prog, stack=None) -> None:
|
||||||
|
self.macros: Dict[str, Dict[str, Any]] = {}
|
||||||
|
self.initial_macros: Dict[str, Dict[str, Any]] = {}
|
||||||
|
self._macro_trace: Dict[int, List[str]] = {}
|
||||||
|
super().__init__(prog, stack)
|
||||||
|
|
||||||
|
def add_macro(self, name: str, prog: List[str] | Dict[int, str], args: List[str] = None) -> None:
|
||||||
|
if isinstance(prog, list):
|
||||||
|
prog = {i: instr for i, instr in enumerate(prog)}
|
||||||
|
self.macros[name] = {"prog": prog, "args": args}
|
||||||
|
self.initial_macros[name] = dict(self.macros[name])
|
||||||
|
|
||||||
|
def run(self, max_steps: int = 1000):
|
||||||
|
# automatically flatten macros before execution
|
||||||
|
self._expand_macros_into_prog()
|
||||||
|
return super().run(max_steps)
|
||||||
|
|
||||||
|
# --- flatten macros recursively before execution ---
|
||||||
|
def _expand_macros_into_prog(self) -> None:
|
||||||
|
def expand(prog: Dict[int, str], stack: List[str]) -> List[Tuple[str, List[str]]]:
|
||||||
|
out: List[Tuple[str, List[str]]] = []
|
||||||
|
for _, call in sorted(prog.items()):
|
||||||
|
name, args = self.decode(call)
|
||||||
|
if name in self.macros:
|
||||||
|
out.extend(expand(self.macros[name]["prog"], stack + [name]))
|
||||||
|
else:
|
||||||
|
out.append((call, list(stack)))
|
||||||
|
return out
|
||||||
|
|
||||||
|
expanded = expand(self.prog, [])
|
||||||
|
self.prog = {i: call for i, (call, _) in enumerate(expanded)}
|
||||||
|
self._macro_trace = {i: macros for i, (_, macros) in enumerate(expanded)}
|
||||||
|
|
||||||
|
def structure(self) -> Dict[int, Dict[str, Any]]:
|
||||||
|
return {
|
||||||
|
i: {"call": call, "macros": self._macro_trace.get(i, []), "p_prog": self.p_prog}
|
||||||
|
for i, call in sorted(self.prog.items())
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
from MaMaGUI import MaMaGUI
|
from MaMaGUI import MaMaGUI
|
||||||
from MaMa import MaMa
|
from MaMaMa import MaMaMa
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
prog = {
|
prog = {
|
||||||
@@ -14,7 +14,7 @@ if __name__ == "__main__":
|
|||||||
8: 'leq(14)',
|
8: 'leq(14)',
|
||||||
9: 'ldo(-1)',
|
9: 'ldo(-1)',
|
||||||
10: 'ldo(-1)',
|
10: 'ldo(-1)',
|
||||||
11: 'sub',
|
11: 'subs',
|
||||||
12: 'sto(-2)',
|
12: 'sto(-2)',
|
||||||
13: 'ujp(6)',
|
13: 'ujp(6)',
|
||||||
14: 'ldo(-1)',
|
14: 'ldo(-1)',
|
||||||
@@ -27,7 +27,11 @@ if __name__ == "__main__":
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Create and execute MaMa instance
|
# Create and execute MaMa instance
|
||||||
machine = MaMa(prog, [4, 6])
|
machine = MaMaMa(prog, [4, 6])
|
||||||
|
|
||||||
|
machine.add_macro('subs', {
|
||||||
|
0: "sub",
|
||||||
|
})
|
||||||
|
|
||||||
# Visualize finished execution using journal
|
# Visualize finished execution using journal
|
||||||
gui = MaMaGUI(machine)
|
gui = MaMaGUI(machine)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from MaMaGUI import MaMaGUI
|
from MaMaGUI import MaMaGUI
|
||||||
from MaMa import MaMa
|
from MaMaMa import MaMaMa # ← use macro-capable class
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
prog = {
|
prog = {
|
||||||
@@ -7,7 +7,8 @@ if __name__ == "__main__":
|
|||||||
1: 'stop'
|
1: 'stop'
|
||||||
}
|
}
|
||||||
|
|
||||||
machine = MaMa(prog, [4, 6])
|
# use MaMaMa instead of MaMa
|
||||||
|
machine = MaMaMa(prog, [4, 6])
|
||||||
|
|
||||||
inner_prog = [
|
inner_prog = [
|
||||||
'push(1)',
|
'push(1)',
|
||||||
@@ -26,6 +27,5 @@ if __name__ == "__main__":
|
|||||||
machine.add_macro("inner", inner_prog, [])
|
machine.add_macro("inner", inner_prog, [])
|
||||||
machine.add_macro("outer", outer_prog, [])
|
machine.add_macro("outer", outer_prog, [])
|
||||||
|
|
||||||
# Run machine once for GUI visualization
|
|
||||||
gui = MaMaGUI(machine)
|
gui = MaMaGUI(machine)
|
||||||
gui.display()
|
gui.display()
|
||||||
|
|||||||
Reference in New Issue
Block a user