Clean up codes

This commit is contained in:
Jan-Niclas Loosen
2025-10-18 13:16:52 +02:00
parent eab6386b83
commit 64061d8b79
3 changed files with 55 additions and 41 deletions

View File

@@ -1,14 +1,22 @@
from typing import Dict, Optional, Tuple, List, Any from typing import Dict, Optional, Tuple, List, Any
class MaMa: class MaMa:
def __init__(self, prog: Dict[int, str] | List[str], def __init__(self, prog: Dict[int, str] | List[str], stack: Dict[int, int] | List[int] | None = None) -> None:
stack: Dict[int, int] | List[int] | None = None) -> None: self.step_counter = 0
self.steps = 0
self.prog = {i: instr for i, instr in enumerate(prog)} if isinstance(prog, list) else prog
self.p_prog = 0
self.stack: Dict[int, int] = {}
self.p_stack = -1
self.halted = False self.halted = False
# Init prog from list or dict
self.p_prog = 0
if isinstance(prog, list):
self.prog = {i: micro for i, micro in enumerate(prog)}
else:
self.prog = prog
# Default stack
self.p_stack = -1
self.stack: Dict[int, int] = {}
# Init custom stack from list or dict
if stack is not None: if stack is not None:
if isinstance(stack, list): if isinstance(stack, list):
self.stack = {i: v for i, v in enumerate(stack)} self.stack = {i: v for i, v in enumerate(stack)}
@@ -17,8 +25,7 @@ class MaMa:
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.initial_stack = dict(self.stack)
# ------------------------------------------------------------- # Runs the machine and returns execution journal
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 # always insert init configuration as step 0
@@ -28,48 +35,48 @@ class MaMa:
steps += 1 steps += 1
return journal return journal
# ------------------------------------------------------------- # Returns the full program
def structure(self) -> Dict[int, Dict[str, Any]]: def structure(self) -> Dict[int, Dict[str, Any]]:
return {i: {"call": call, "macros": []} for i, call in sorted(self.prog.items())} return {i: {"micro": micro, "macros": []} for i, micro in sorted(self.prog.items())}
# Decodes string MaMa instructions to function callables
@staticmethod @staticmethod
def decode(call: str) -> Tuple[str, Optional[List[int]]]: def decode(micro: str) -> Tuple[str, Optional[List[int]]]:
if "(" in call: if "(" in micro:
name, rest = call.split("(", 1) name, rest = micro.split("(", 1)
args_str = rest[:-1] args_str = rest[:-1]
if args_str.strip() == "": if args_str.strip() == "":
return name, [] return name, []
args = [int(a.strip()) for a in args_str.split(",")] args = [int(a.strip()) for a in args_str.split(",")]
return name, args return name, args
return call, None return micro, None
# ------------------------------------------------------------- # Generates journal entry for a step
def config(self, micro: str) -> Dict[str, int | str | dict | list]:
def config(self, call: str) -> Dict[str, int | str | dict | list]:
return { return {
"step": self.steps, "step": self.step_counter,
"call": call, "micro": micro,
"p_prog": self.p_prog, "p_prog": self.p_prog,
"p_stack": self.p_stack, "p_stack": self.p_stack,
"stack": dict(self.stack), "stack": dict(self.stack),
} }
# ------------------------------------------------------------- # Executes one step of the machine
def __step(self) -> Dict[str, int | str | dict | list]: def __step(self) -> Dict[str, int | str | dict | list]:
if self.halted or self.p_prog not in self.prog: if self.halted or self.p_prog not in self.prog:
self.halted = True self.halted = True
return self.config("halted") return self.config("halted")
call = self.prog[self.p_prog] micro = self.prog[self.p_prog]
name, args = MaMa.decode(call) name, args = MaMa.decode(micro)
method = getattr(self, f"_{name}", None) method = getattr(self, f"_{name}", None)
if method is None: if method is None:
raise ValueError(f"Unknown instruction: {call}") raise ValueError(f"Unknown instruction: {micro}")
method(args) method(args)
self.steps += 1 self.step_counter += 1
return self.config(call) return self.config(micro)
# DEFINE MaMa Micros
# Stop execution # Stop execution
def _stop(self, _: Optional[int]) -> None: def _stop(self, _: Optional[int]) -> None:

View File

@@ -74,7 +74,7 @@ class MaMaGUI:
state = self.journal[self.journal_index] state = self.journal[self.journal_index]
stack = dict(state["stack"]) stack = dict(state["stack"])
p_prog, p_stack = int(state["p_prog"]), int(state["p_stack"]) p_prog, p_stack = int(state["p_prog"]), int(state["p_stack"])
step, call = int(state["step"]), str(state["call"]) step, micro = int(state["step"]), str(state["micro"])
# Load code structure # Load code structure
structure = self.machine.structure() structure = self.machine.structure()
@@ -96,7 +96,7 @@ class MaMaGUI:
instr_indent = " " * depth instr_indent = " " * depth
prefix = ">> " if addr == p_prog else " " prefix = ">> " if addr == p_prog else " "
line = f"{prefix}{instr_indent}{addr:>3}: {info['call']}" line = f"{prefix}{instr_indent}{addr:>3}: {info['micro']}"
self.prog_list.insert(tk.END, line) self.prog_list.insert(tk.END, line)
opened_macros = macros opened_macros = macros
@@ -118,7 +118,7 @@ class MaMaGUI:
# Update configuration and global stack # Update configuration and global stack
self.conf_label.config(text=f"({p_stack}, {p_prog}, {list(stack.values())})") self.conf_label.config(text=f"({p_stack}, {p_prog}, {list(stack.values())})")
self.status.config(text=f"Step {step}/{len(self.journal)-1} | PC={p_prog} | SP={p_stack} | Call: {call}") self.status.config(text=f"Step {step}/{len(self.journal)-1} | PC={p_prog} | SP={p_stack} | Micro: {micro}")
# Configure auto step speed # Configure auto step speed
def __update_speed(self, value: str) -> None: def __update_speed(self, value: str) -> None:

View File

@@ -1,42 +1,49 @@
from typing import Dict, Optional, List, Any, Tuple from typing import Dict, Optional, List, Any, Tuple, override
from MaMa import MaMa from MaMa import MaMa
class MaMaMa(MaMa): class MaMaMa(MaMa):
def __init__(self, prog, stack=None) -> None: def __init__(self, prog, stack=None) -> None:
# Store macros
self.macros: Dict[str, Dict[str, Any]] = {} self.macros: Dict[str, Dict[str, Any]] = {}
self.initial_macros: Dict[str, Dict[str, Any]] = {} self.initial_macros: Dict[str, Dict[str, Any]] = {}
# Trace nested macros
self._macro_trace: Dict[int, List[str]] = {} self._macro_trace: Dict[int, List[str]] = {}
super().__init__(prog, stack) super().__init__(prog, stack)
# Register a new macro, which is a name and a sequence of micros
def add_macro(self, name: str, prog: List[str] | Dict[int, str], args: List[str] = None) -> None: def add_macro(self, name: str, prog: List[str] | Dict[int, str], args: List[str] = None) -> None:
if isinstance(prog, list): if isinstance(prog, list):
prog = {i: instr for i, instr in enumerate(prog)} prog = {i: instr for i, instr in enumerate(prog)}
self.macros[name] = {"prog": prog, "args": args} self.macros[name] = {"prog": prog, "args": args}
self.initial_macros[name] = dict(self.macros[name]) self.initial_macros[name] = dict(self.macros[name])
# Automatically flatten macros and then execute
@override
def run(self, max_steps: int = 1000): def run(self, max_steps: int = 1000):
# automatically flatten macros before execution self.__flatten_macro()
self._expand_macros_into_prog()
return super().run(max_steps) return super().run(max_steps)
# --- flatten macros recursively before execution --- # Flatten macros recursively
def _expand_macros_into_prog(self) -> None: def __flatten_macro(self) -> None:
def expand(prog: Dict[int, str], stack: List[str]) -> List[Tuple[str, List[str]]]: def expand(prog: Dict[int, str], stack: List[str]) -> List[Tuple[str, List[str]]]:
out: List[Tuple[str, List[str]]] = [] out: List[Tuple[str, List[str]]] = []
for _, call in sorted(prog.items()): for _, micro in sorted(prog.items()):
name, args = self.decode(call) name, args = self.decode(micro)
if name in self.macros: if name in self.macros:
out.extend(expand(self.macros[name]["prog"], stack + [name])) out.extend(expand(self.macros[name]["prog"], stack + [name]))
else: else:
out.append((call, list(stack))) out.append((micro, list(stack)))
return out return out
expanded = expand(self.prog, []) expanded = expand(self.prog, [])
self.prog = {i: call for i, (call, _) in enumerate(expanded)} self.prog = {i: call for i, (call, _) in enumerate(expanded)}
self._macro_trace = {i: macros for i, (_, macros) in enumerate(expanded)} self._macro_trace = {i: macros for i, (_, macros) in enumerate(expanded)}
# Add macros to structure
@override
def structure(self) -> Dict[int, Dict[str, Any]]: def structure(self) -> Dict[int, Dict[str, Any]]:
return { return {
i: {"call": call, "macros": self._macro_trace.get(i, []), "p_prog": self.p_prog} i: {"micro": micro, "macros": self._macro_trace.get(i, []), "p_prog": self.p_prog}
for i, call in sorted(self.prog.items()) for i, micro in sorted(self.prog.items())
} }