Created
October 5, 2011 04:46
-
-
Save pcostesi/1263655 to your computer and use it in GitHub Desktop.
S Interpreter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" This is a simple and experimental version of an interpreter for the | |
S language. It doesn't aim to be complete, just correct. | |
""" | |
from collections import defaultdict | |
import re | |
TAG = r"\s*(\[\s*(?P<tag>[a-eA-E]\d+)\s*\])?\s*" | |
NXT = r"(?P<nxt>[a-eA-E]\d+)" | |
VAR = r"([XZ]\d+)|Y" | |
ADD = re.compile(TAG + "(?P<var>" + VAR + r")\s*<-\s*(" + VAR + r")\s*\+\s*1") | |
REM = re.compile(TAG + "(?P<var>" + VAR + r")\s*<-\s*(" + VAR + r")\s*-\*1") | |
JNZ = re.compile(TAG + r"IF\s+(?P<var>" + VAR + r")\s*!=\s*0\s*GOTO\s*" + NXT) | |
def extract(operations, line): | |
for operation in operations: | |
statement = re.match(operation, line) | |
if statement: | |
d = statement.groupdict() | |
return d.get('tag', None), operation, d['var'], d.get('nxt', None), line | |
class State(object): | |
def __init__(self, Y=0, **kwargs): | |
self.vars = defaultdict(lambda: 0) | |
self.vars["Y"] = Y | |
self.vars.update(kwargs) | |
self.ptr = 1 #instruction pointer | |
def add(self, var): | |
self.vars[var] += 1 | |
def rem(self, var): | |
value = self.vars[var] - 1 | |
if value < 0: | |
value = 0 | |
self.vars[var] = value | |
def jnz(self, var): | |
return self.vars[var] == 0 | |
def __str__(self): | |
pairs = ("\t- %s:\t%s" % (k, v) for k, v in sorted(self.vars.iteritems())) | |
return "State:\n" + '\n'.join(pairs) | |
class Interpreter(object): | |
def __init__(self, f): | |
self.f = f | |
self.operations = [ADD, REM, JNZ] | |
self.program = list(Interpreter.__parse(f, self.operations)) | |
@staticmethod | |
def __parse(f, operations): | |
for line in f: | |
i = extract(operations, line) | |
if i is not None: | |
yield i | |
def __jump(self, nxt): | |
for i in xrange(len(self.program)): | |
if self.program[i][0] == nxt: | |
return i | |
return len(self.program) + 1 | |
def execute(self, state=None): | |
if state is None: | |
state = State() | |
while True: | |
if state.ptr - 1 >= len(self.program): | |
break | |
tag, op, var, nxt, line = self.program[state.ptr - 1] | |
if op == ADD: | |
state.add(var) | |
if op == REM: | |
state.rem(var) | |
if op == JNZ: | |
if state.jnz(var): | |
state.ptr = self.__jump(nxt) | |
print state | |
continue | |
print state | |
state.ptr += 1 | |
return state.vars["Y"] | |
if __name__ == "__main__": | |
import sys | |
with open(sys.argv[1]) as f: | |
i = Interpreter(f) | |
input_values = dict(("X%d" % (d + 1), int(v)) for d, v in enumerate(sys.argv[2:])) | |
print i.execute(State(**input_values)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment