diff --git a/Uebung-01/MaMaGUI.py b/Uebung-01/MaMaGUI.py index fefd492..34a1cce 100644 --- a/Uebung-01/MaMaGUI.py +++ b/Uebung-01/MaMaGUI.py @@ -91,7 +91,13 @@ class MaMaGUI: 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]}]") + 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"}) instr_indent = " " * depth diff --git a/Uebung-01/MaMaMa.py b/Uebung-01/MaMaMa.py index e661e32..b5236fe 100644 --- a/Uebung-01/MaMaMa.py +++ b/Uebung-01/MaMaMa.py @@ -10,6 +10,7 @@ class MaMaMa(MaMa): # Trace nested macros self._macro_trace: Dict[int, List[str]] = {} super().__init__(prog, stack) + self.initial_macros["__top__"] = dict(self.prog) # 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: @@ -18,22 +19,37 @@ class MaMaMa(MaMa): self.macros[name] = {"prog": prog, "args": args} 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 @override def run(self, max_steps: int = 1000): self.__flatten_macro() return super().run(max_steps) - # Flatten macros recursively + # Flatten macros recursively with expression support def __flatten_macro(self) -> None: def expand(prog: Dict[int, str], stack: List[str], env: Dict[str, Any]) -> List[Tuple[str, List[str]]]: out: List[Tuple[str, List[str]]] = [] for _, micro in sorted(prog.items()): name, args = self.decode(micro) - # substitute arguments if defined in env + # substitute arguments if defined in env and evaluate expressions 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))})" if name in self.macros: @@ -52,10 +68,32 @@ class MaMaMa(MaMa): self.prog = {i: call for i, (call, _) 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 def structure(self) -> Dict[int, Dict[str, Any]]: - return { - i: {"micro": micro, "macros": self._macro_trace.get(i, []), "p_prog": self.p_prog} - for i, micro in sorted(self.prog.items()) - } + struct: Dict[int, Dict[str, Any]] = {} + + # 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 diff --git a/Uebung-01/ggt.py b/Uebung-01/ggt.py index fb2faa9..286743b 100644 --- a/Uebung-01/ggt.py +++ b/Uebung-01/ggt.py @@ -2,37 +2,56 @@ from MaMaGUI import MaMaGUI from MaMaMa import MaMaMa if __name__ == "__main__": - prog = { - 0: 'ldo(-1)', - 1: 'push(0)', - 2: 'equal(17)', - 3: 'push(0)', - 4: 'ldo(-1)', - 5: 'equal(19)', - 6: 'ldo(-1)', - 7: 'ldo(-1)', - 8: 'leq(14)', - 9: 'ldo(-1)', - 10: 'ldo(-1)', - 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' - } + prog = [ + 'cequal(26)', + 'cleqR(11)', + 'csub(-1,0,-1)', + 'ujp(15)', + 'csub(0,-1,0)', + 'nzero(-1,3)', + 'swp', + 'pop', + 'stop', + 'pop', + 'stop' + ] # 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)', - 'equal(n)' - ], ["n"]) + 'equal(p)' + ], ['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 gui = MaMaGUI(machine)