Homework progress
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user