diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/Construction-of-Compilers.iml b/.idea/Construction-of-Compilers.iml
new file mode 100644
index 0000000..24ef2ea
--- /dev/null
+++ b/.idea/Construction-of-Compilers.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml
new file mode 100644
index 0000000..d335fa7
--- /dev/null
+++ b/.idea/dictionaries/project.xml
@@ -0,0 +1,7 @@
+
+
+
+ ldsp
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..a794ecf
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..f7274d5
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..dfd6964
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..8306744
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Uebung-01/MaMa.py b/Uebung-01/MaMa.py
new file mode 100644
index 0000000..c2ea282
--- /dev/null
+++ b/Uebung-01/MaMa.py
@@ -0,0 +1,169 @@
+from typing import Dict, Optional, Tuple, List
+
+class MaMa:
+ def __init__(self, prog: Dict[int, str] | List[str], stack: Dict[int, int] | List[int] | None = None) -> None:
+ # Execution state
+ self.steps = 0
+
+ # 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
+
+ # Stack memory and pointer
+ self.stack: Dict[int, int] = {}
+ self.p_stack = -1
+ self.initial_stack: Dict[int, int] = {}
+ if stack is not None:
+ self.reload(stack)
+
+ # Machine halted flag
+ self.halted = False
+
+
+ # 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):
+ self.stack.update({i: v for i, v in enumerate(stack)})
+ else:
+ self.stack.update(stack)
+
+ self.p_prog = 0
+ self.p_stack = max(self.stack.keys(), default=-1)
+ self.halted = False
+ self.steps = 0
+
+ def run(self, max_steps: int = 1000) -> List[Dict[str, int|str|dict]]:
+ steps = 0
+ journal = [self.config('init')]
+ while not self.halted and steps < max_steps:
+ journal.append(self.step())
+ steps += 1
+ return journal
+
+ def is_halted(self) -> bool:
+ return self.halted
+
+ def step(self) -> Dict[str, int|str|dict]:
+ 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, arg = self.decode(call)
+ method = getattr(self, f"_{name}", None)
+ if method is None:
+ raise ValueError(f"Unknown instruction: {call}")
+
+ method(arg)
+ self.steps += 1
+ return self.config(call)
+
+ def config(self, call: str) -> Dict[str, int|str|dict]:
+ return {
+ "step": self.steps,
+ "call": call,
+ "p_prog": self.p_prog,
+ "p_stack": self.p_stack,
+ "stack": dict(self.stack),
+ }
+
+ @staticmethod
+ def decode(call: str) -> Tuple[str, Optional[int]]:
+ if "(" in call:
+ name, arg = call.split("(")
+ return name, int(arg[:-1])
+ return call, None
+
+ # Stop execution
+ def _stop(self, _: Optional[int]) -> None:
+ self.halted = True
+
+ # Remove top element from stack
+ def _pop(self, _: Optional[int]) -> None:
+ self.p_stack -= 1
+ self.p_prog += 1
+
+ # Load stack pointer value onto stack
+ def _ldsp(self, _: Optional[int]) -> None:
+ self.p_stack += 1
+ self.stack[self.p_stack] = self.p_stack
+ self.p_prog += 1
+
+ # Push constant n onto stack
+ def _push(self, n: Optional[int]) -> None:
+ assert n is not None
+ self.p_stack += 1
+ self.stack[self.p_stack] = n
+ self.p_prog += 1
+
+ # Add top two stack elements
+ def _add(self, _: Optional[int]) -> None:
+ self.stack[self.p_stack - 1] += self.stack[self.p_stack]
+ self.p_stack -= 1
+ self.p_prog += 1
+
+ # Subtract top element from second-top element
+ def _sub(self, _: Optional[int]) -> None:
+ self.stack[self.p_stack - 1] -= self.stack[self.p_stack]
+ self.p_stack -= 1
+ self.p_prog += 1
+
+ # Multiply top two stack elements
+ def _mult(self, _: Optional[int]) -> None:
+ self.stack[self.p_stack - 1] *= self.stack[self.p_stack]
+ self.p_stack -= 1
+ self.p_prog += 1
+
+ # Integer division of second-top by top stack element
+ def _div(self, _: Optional[int]) -> None:
+ self.stack[self.p_stack - 1] //= self.stack[self.p_stack]
+ self.p_stack -= 1
+ self.p_prog += 1
+
+ # Load value from relative address n in stack
+ def _ldo(self, n: Optional[int]) -> None:
+ assert n is not None
+ old_sp = self.p_stack
+ self.p_stack += 1
+ self.stack[self.p_stack] = self.stack[old_sp + n]
+ self.p_prog += 1
+
+ # Store top value to relative address n in stack
+ def _sto(self, n: Optional[int]) -> None:
+ assert n is not None
+ self.stack[self.p_stack + n] = self.stack[self.p_stack]
+ self.p_stack -= 1
+ self.p_prog += 1
+
+ # Unconditional jump to address a
+ def _ujp(self, a: Optional[int]) -> None:
+ assert a is not None
+ self.p_prog = a
+
+ # Conditional jump if top two elements are equal
+ def _equal(self, a: Optional[int]) -> None:
+ assert a is not None
+ if self.stack[self.p_stack - 1] == self.stack[self.p_stack]:
+ self.p_stack -= 2
+ self.p_prog = a
+ else:
+ self.p_stack -= 2
+ self.p_prog += 1
+
+ # Conditional jump if second-top ≤ top element
+ def _leq(self, a: Optional[int]) -> None:
+ assert a is not None
+ if self.stack[self.p_stack - 1] <= self.stack[self.p_stack]:
+ self.p_stack -= 2
+ self.p_prog = a
+ else:
+ self.p_stack -= 2
+ self.p_prog += 1
diff --git a/Uebung-01/MaMaGUI.py b/Uebung-01/MaMaGUI.py
new file mode 100644
index 0000000..0f787e8
--- /dev/null
+++ b/Uebung-01/MaMaGUI.py
@@ -0,0 +1,145 @@
+import tkinter as tk
+from tkinter import ttk
+from typing import Dict, List
+from MaMa import MaMa
+
+class MaMaGUI:
+ def __init__(self, mama: MaMa, delay: int = 400) -> None:
+ self.machine = mama
+ self.delay = delay
+ self.index = 0
+ self.journal: List[Dict[str, object]] = []
+
+ # Tracks automatic running state
+ self.running = False
+
+ # Run machine once and include initial configuration
+ self.journal = self.machine.run()
+ if not self.journal:
+ raise ValueError("Journal is empty. Make sure MaMa executed successfully.")
+ print(self.journal)
+
+ self.root = tk.Tk()
+ self.root.title("MaMa GUI")
+
+ # Prepare rows and columns
+ container = ttk.Frame(self.root, padding=10)
+ container.grid(sticky="nsew")
+ container.columnconfigure(0, weight=1)
+ container.columnconfigure(1, weight=1)
+ container.rowconfigure(0, weight=1)
+
+ # Program display
+ prog_frame = ttk.LabelFrame(container, text="Program", padding=5)
+ 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.pack(fill="both", expand=True)
+
+ # Stack and configuration display
+ stack_frame = ttk.LabelFrame(container, text="Stack", padding=5)
+ stack_frame.grid(row=0, column=1, sticky="nsew")
+ stack_frame.rowconfigure(0, weight=1)
+ stack_frame.columnconfigure(0, weight=1)
+ self.stack_list = tk.Listbox(stack_frame, width=32, height=20, font=("Consolas", 11))
+ self.stack_list.grid(row=0, column=0, sticky="nsew")
+
+ # Configuration label
+ 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))
+
+ # Init and bind controls
+ control = ttk.Frame(self.root, padding=5)
+ control.grid(row=1, column=0, columnspan=2, sticky="ew")
+
+ ttk.Button(control, text="▶ Start", command=self.start).pack(side="left", padx=5)
+ ttk.Button(control, text="⏸ Stop", command=self.stop).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)
+ 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.pack(side="left", padx=5)
+
+ # Status bar
+ self.status = ttk.Label(self.root, text="Ready", padding=5, anchor="w")
+ self.status.grid(row=2, column=0, columnspan=2, sticky="ew")
+
+ # Initial update
+ self.__update()
+
+ def __update(self) -> None:
+ state = self.journal[self.index]
+ prog = self.machine.prog
+ p_prog = state["p_prog"]
+ p_stack = state["p_stack"]
+ stack = state["stack"]
+ step = state["step"]
+ call = state["call"]
+
+ # Program display
+ self.prog_list.delete(0, tk.END)
+ for addr, instr in prog.items():
+ prefix = ">> " if addr == p_prog else " "
+ self.prog_list.insert(tk.END, f"{prefix}{addr:>3}: {instr}")
+ if addr == p_prog:
+ self.prog_list.itemconfig(tk.END, {"bg": "#ffd966"})
+
+ # Stack display
+ self.stack_list.delete(0, tk.END)
+ if stack:
+ for i in range(p_stack, -1, -1):
+ val = stack.get(i, 0)
+ mark = "<-- top" if i == p_stack else ""
+ self.stack_list.insert(tk.END, f"[{i:>2}] {val:>6} {mark}")
+ if i == p_stack:
+ self.stack_list.itemconfig(tk.END, {"bg": "#cfe2f3"})
+ else:
+ self.stack_list.insert(tk.END, "(empty)")
+
+ # Configuration line
+ conf_str = f"({p_stack}, {p_prog}, {list(stack.values())})"
+ self.conf_label.config(text=conf_str)
+
+ # Status update
+ status = f"Step {step}/{len(self.journal)-1} | PC={p_prog} | SP={p_stack} | Last call: {call}"
+ self.status.config(text=status)
+
+ def __update_speed(self, value: str) -> None:
+ self.delay = int(float(value))
+
+ def start(self) -> None:
+ if not self.running:
+ self.running = True
+ self.__auto_step()
+
+ def stop(self) -> None:
+ self.running = False
+
+ def __auto_step(self) -> None:
+ if self.running and self.index < len(self.journal) - 1:
+ self.index += 1
+ self.__update()
+ self.root.after(self.delay, self.__auto_step)
+ else:
+ self.running = False
+
+ def next_step(self) -> None:
+ if self.index < len(self.journal) - 1:
+ self.index += 1
+ self.__update()
+
+ def prev_step(self) -> None:
+ if self.index > 0:
+ self.index -= 1
+ self.__update()
+
+ def reset(self) -> None:
+ self.machine.reload()
+ self.journal = self.machine.run()
+ self.index = 0
+ self.__update()
+
+ def display(self) -> None:
+ self.root.mainloop()
diff --git a/Uebung-01/ggt.py b/Uebung-01/ggt.py
new file mode 100644
index 0000000..99e0b1d
--- /dev/null
+++ b/Uebung-01/ggt.py
@@ -0,0 +1,34 @@
+from MaMaGUI import MaMaGUI
+from MaMa import MaMa
+
+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'
+ }
+
+ # Create and execute MaMa instance
+ machine = MaMa(prog, [4, 6])
+
+ # Visualize finished execution using journal
+ gui = MaMaGUI(machine)
+ gui.display()