Homework progress

This commit is contained in:
Jan-Niclas Loosen
2025-10-18 15:35:07 +02:00
parent 081a7132fc
commit ee97bf1518
3 changed files with 99 additions and 36 deletions

View File

@@ -91,7 +91,13 @@ class MaMaGUI:
if len(macros) > len(opened_macros): if len(macros) > len(opened_macros):
parent_depth = len(macros) - 1 parent_depth = len(macros) - 1
header_indent = " " * parent_depth + " " * macro_offset header_indent = " " * parent_depth + " " * macro_offset
self.prog_list.insert(tk.END, f"{header_indent}[{macros[-1]}]") macro = macros[-1]
if isinstance(macro, dict):
params = ", ".join(f"{k}={v}" for k, v in macro.get("params", {}).items())
header = f"{macro['name']}({params})" if params else macro["name"]
else:
header = str(macro)
self.prog_list.insert(tk.END, f"{header_indent}[{header}]")
self.prog_list.itemconfig(tk.END, {"bg": "#e6e6e6"}) self.prog_list.itemconfig(tk.END, {"bg": "#e6e6e6"})
instr_indent = " " * depth instr_indent = " " * depth

View File

@@ -10,6 +10,7 @@ class MaMaMa(MaMa):
# Trace nested macros # 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)
self.initial_macros["__top__"] = dict(self.prog)
# Register a new macro, which is a name and a sequence of micros # 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:
@@ -18,22 +19,37 @@ class MaMaMa(MaMa):
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])
# Safely evaluate simple arithmetic expressions
def _eval_expr(self, expr: Any, env: Dict[str, Any]) -> Any:
if isinstance(expr, (int, float)):
return expr
if isinstance(expr, str):
# Replace variables in the expression with env values
safe_expr = expr
for k, v in env.items():
safe_expr = safe_expr.replace(str(k), str(v))
try:
return eval(safe_expr, {"__builtins__": {}})
except Exception:
return expr
return expr
# Automatically flatten macros and then execute # Automatically flatten macros and then execute
@override @override
def run(self, max_steps: int = 1000): def run(self, max_steps: int = 1000):
self.__flatten_macro() self.__flatten_macro()
return super().run(max_steps) return super().run(max_steps)
# Flatten macros recursively # Flatten macros recursively with expression support
def __flatten_macro(self) -> None: def __flatten_macro(self) -> None:
def expand(prog: Dict[int, str], stack: List[str], env: Dict[str, Any]) -> List[Tuple[str, List[str]]]: def expand(prog: Dict[int, str], stack: List[str], env: Dict[str, Any]) -> List[Tuple[str, List[str]]]:
out: List[Tuple[str, List[str]]] = [] out: List[Tuple[str, List[str]]] = []
for _, micro in sorted(prog.items()): for _, micro in sorted(prog.items()):
name, args = self.decode(micro) name, args = self.decode(micro)
# substitute arguments if defined in env # substitute arguments if defined in env and evaluate expressions
if args: if args:
args = [env.get(str(a), a) for a in args] args = [self._eval_expr(env.get(str(a), a), env) for a in args]
micro = f"{name}({','.join(map(str, args))})" micro = f"{name}({','.join(map(str, args))})"
if name in self.macros: if name in self.macros:
@@ -52,10 +68,32 @@ class MaMaMa(MaMa):
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 # Build program structure with parameter info (no change to _macro_trace)
@override @override
def structure(self) -> Dict[int, Dict[str, Any]]: def structure(self) -> Dict[int, Dict[str, Any]]:
return { struct: Dict[int, Dict[str, Any]] = {}
i: {"micro": micro, "macros": self._macro_trace.get(i, []), "p_prog": self.p_prog}
for i, micro in sorted(self.prog.items()) # extract macro calls with their argument values from original top-level prog
} top_calls: Dict[str, Dict[str, Any]] = {}
for _, micro in sorted(self.initial_macros.get("__top__", self.prog).items()):
name, args = self.decode(micro)
if name in self.macros:
macro = self.macros[name]
params = macro.get("args") or []
if args and params:
top_calls[name] = dict(zip(params, args))
# build structure
for i, micro in sorted(self.prog.items()):
entry = {"micro": micro, "macros": []}
for macro_name in self._macro_trace.get(i, []):
macro_info = {"name": macro_name, "params": {}}
if macro_name in self.macros:
param_names = self.macros[macro_name].get("args") or []
macro_info["params"] = {
p: top_calls.get(macro_name, {}).get(p, None)
for p in param_names
}
entry["macros"].append(macro_info)
struct[i] = entry
return struct

View File

@@ -2,37 +2,56 @@ from MaMaGUI import MaMaGUI
from MaMaMa import MaMaMa from MaMaMa import MaMaMa
if __name__ == "__main__": if __name__ == "__main__":
prog = { prog = [
0: 'ldo(-1)', 'cequal(26)',
1: 'push(0)', 'cleqR(11)',
2: 'equal(17)', 'csub(-1,0,-1)',
3: 'push(0)', 'ujp(15)',
4: 'ldo(-1)', 'csub(0,-1,0)',
5: 'equal(19)', 'nzero(-1,3)',
6: 'ldo(-1)', 'swp',
7: 'ldo(-1)', 'pop',
8: 'leq(14)', 'stop',
9: 'ldo(-1)', 'pop',
10: 'ldo(-1)', 'stop'
11: 'sub', ]
12: 'sto(-2)',
13: 'ujp(6)',
14: 'ldo(-1)',
15: 'sub',
16: 'ujp(3)',
17: 'sto(-1)',
18: 'stop',
19: 'pop',
20: 'stop'
}
# Create and execute MaMa instance # Create and execute MaMa instance
machine = MaMaMa(['equal0(3)', 'stop', 'push(10)', 'stop'], [4, 6, 0]) machine = MaMaMa(prog, [1, 1, 1, 4, 6])
machine.add_macro('equal0', [ machine.add_macro('nzero', [
'ldo(n)',
'ldo(0)',
'sub',
'push(0)', 'push(0)',
'equal(n)' 'equal(p)'
], ["n"]) ], ['n', 'p'])
machine.add_macro('cequal', [
'ldo(-1)',
'ldo(-1)',
'equal(p)'
], ["p"])
machine.add_macro('cleqR', [
'ldo(0)',
'ldo(-2)',
'leq(p)'
], ['p'])
machine.add_macro('csub', [
'ldo(n)',
'ldo(m-1)',
'sub',
'sto(s-1)'
], ['n', 'm', 's'])
machine.add_macro('swp', [
'ldo(-1)',
'ldo(-1)',
'sto(-2)',
'sto(-1)',
])
# Visualize finished execution using journal # Visualize finished execution using journal
gui = MaMaGUI(machine) gui = MaMaGUI(machine)