Created first prototype

This commit is contained in:
2024-01-08 13:34:12 +01:00
parent 12ba86cb19
commit 40a27ef29d

147
src/RAM.py Normal file
View File

@@ -0,0 +1,147 @@
from pathlib import Path
import re
class Expression:
def __init__(self):
self.register = r"R\[(?:\d+|R\[\d+])\]"
self.un_exp = f"(?:{self.register}|\\d+)"
self.bi_exp = f"{self.un_exp}(\\+|-|div|\\*|!=|==|<|>|<=|>=){self.un_exp}"
self.named_bi_exp = f"(?P<lexp>{self.un_exp})(?P<op>\\+|-|div|\\*|!=|==|<|>|<=|>=)(?P<rexp>{self.un_exp})"
def _eval_unary(self, exp: str, mem: dict) -> int:
try:
return int(exp)
except Exception:
pass
p = r"R\[(?:(?P<rd>\d+)|R\[(?P<rrd>\d+)])\]"
m = re.match(p, exp)
if not m: raise Exception("no valid expression")
rd, rrd = m.group("rd", "rrd")
if rd: return mem[int(rd)]
elif rrd: return mem[mem[int(rrd)]]
else: raise Exception("no valid expression")
def eval(self, exp: str, mem: dict) -> int:
m = re.match(self.named_bi_exp, exp)
if m:
lexp, rexp, op = m.group("lexp", "rexp", "op")
vl = self._eval_unary(lexp, mem)
vr = self._eval_unary(rexp, mem)
if op == "==": return vl == vr
if op == "!=": return vl != vr
if op == "<=": return vl <= vr
if op == ">=": return vl >= vr
if op == "<": return vl < vr
if op == ">": return vl > vr
if op == "-": return vl - vr
if op == "+": return vl + vr
if op == "*": return vl * vr
if op == "div": return vl // vr
raise Exception("no valid expression")
else:
return self._eval_unary(exp, mem)
def pattern(self) -> str:
# Order in regex is important!
return f"({self.bi_exp}|{self.un_exp})"
class Assignment:
def __init__(self):
self.exp = Expression()
self.pattern = f"^R\\[(?P<write_addr>\\d+|R\\[\\d+]|out)\\]:=(?P<e>{self.exp.pattern()})$"
def exec(self, exp: str, mem: dict) -> dict:
m = re.match(self.pattern, exp)
if not m: raise Exception("not a expression")
e, write_addr = m.group("e", "write_addr")
# Look up Register
if write_addr[0] == "R": write_addr = mem[int(write_addr[2:-1])]
# Evaluate the expression in the if statement
result = self.exp.eval(e, mem)
# Write to memory
if write_addr == "out": mem["out"] = result
else: mem[int(write_addr)] = result
# Set the programm counter
mem["pc"] += 1
return mem
class Condition:
def __init__(self):
self.exp = Expression()
self.pattern = f"if(?P<e>{self.exp.pattern()})goto(?P<line>\\d+)"
pass
def exec(self, exp: str, mem: dict) -> dict:
m = re.match(self.pattern, exp)
if not m: raise Exception("not a expression")
e, line = m.group("e", "line")
# Evaluate the expression in the if statement
result = self.exp.eval(e, mem)
# Set the programm counter
if result != 0: mem["pc"] = int(line) - 1
else: mem["pc"] += 1
return mem
class RAM:
def __init__(self, path: str):
self.load_file(Path(path))
print(self.instructions)
self.mem = {}
self.mem["pc"] = 0
print(self.run())
def load_file(self, path: Path) -> dict:
with open(path, "r") as f:
raw_src_text = "".join(f.readlines())
# Sanitize input
raw_src_text = re.sub(r"\\", "", raw_src_text, flags=re.MULTILINE)
# Remove whitespace, mark empty lines
raw_src_text = re.sub("(#[^\n]*)?\n", r"\\", raw_src_text, flags=re.MULTILINE)
raw_src_text = re.sub(r"\s", "", raw_src_text, flags=re.MULTILINE)
self.instructions = { l:i for l, i in enumerate(raw_src_text.split("\\")) }
def run(self) -> int:
while "out" not in self.mem.keys(): self.eval()
return self.mem["out"]
def eval(self):
# Get current instruction
current = self.instructions[self.mem["pc"]]
# Check for empty line
if current == "":
self.mem["pc"] += 1
return
asg = Assignment()
con = Condition()
if current[0] == "R":
asg.exec(current, self.mem)
elif current[0] == "i":
con.exec(current, self.mem)
else:
raise Exception(f"Syntax error in line {self.mem['pc']}")
if __name__ == "__main__":
RAM("../examples/test.ram")