Skip to content

Instantly share code, notes, and snippets.

@Vftdan
Created November 8, 2018 09:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Vftdan/0e582d07d82489846e2134e1a1d1fbb4 to your computer and use it in GitHub Desktop.
Save Vftdan/0e582d07d82489846e2134e1a1d1fbb4 to your computer and use it in GitHub Desktop.
Turing machine interpreter. Usage: `python turingm.py program.tsv inputs.txt`
import sys
class ParsingException(BaseException):
pass
class TuringException(BaseException):
pass
header = None
data = dict()
dataptr = 0
states = dict()
stateptr = None
stateinit = None
stepnum = 0
MAX_STEPNUM = 3000
DEBUG = False
def log(*args, **kwargs):
if DEBUG:
print(*args, **kwargs)
def norm_line(ln):
if ln[0] == '\ufeff':
ln = ln[1:]
while ln[-1] in '\r\n':
ln = ln[:-1]
if len(ln) == 0:
return ln
return ln
def parse_prog_line(ln):
global stateinit
ln = norm_line(ln).split('\t')
p = dict()
for i in range(len(ln)):
col = header[i]
if len(col) == 1 and ln[i] != 'halt':
p[col] = ln[i].split(' ')
else:
p[col] = ln[i]
name = p['Q\\A']
if name in states:
raise ParsingException('State "{0}" already exists!'.format(name))
states[name] = p
if stateinit == None:
stateinit = name
def run_step():
global dataptr, stateptr, stepnum
stepnum += 1
if stepnum > MAX_STEPNUM:
raise TuringException('Step limit!')
value = data.get(dataptr, '_')
log('<', stateptr, ',', value, '>')
if value == ' ':
value = '_'
if value not in header:
raise TuringException('Invalid input!')
st = states.get(stateptr, None)
if st == None:
raise TuringException('State "{0}" is not defined!'.format(stateptr))
act = st.get(value)
if act != 'halt' and len(act) != 3:
raise TuringException('State "{0}" cannot proceed value "{1}"!'.format(stateptr, value))
if len(act) == 3:
if act[0] == value and act[1] == 'n' and act[2] == stateptr:
act = 'halt'
if act == 'halt':
return False
outp, direct, target = act
if len(outp) != 1 or outp not in header:
raise ParsingException('Value "{0}" is not valid!'.format(outp))
data[dataptr] = outp
if direct == 'l':
dataptr -= 1
elif direct == 'r':
dataptr += 1
elif direct != 'n':
raise ParsingException('Direction "{0}" is not valid!'.format(direct))
stateptr = target
return True
def print_data():
k = list(sorted(data.keys()))
try:
while data[k[0]] == '_':
k = k[1:]
while data[k[-1]] == '_':
k = k[:-1]
except IndexError:
print('_\n^')
return
for i in range(k[0], k[-1] + 1):
print(data.get(i, '_'), end='')
sp = dataptr - k[0]
if sp < 0:
sp = 0
print('\n' + ' ' * sp + '^')
def run(inp):
global dataptr, stateptr, stepnum
for il in inp:
ilt = tuple(il)
data.clear()
dataptr = 0
stateptr = stateinit
stepnum = 0
for i in range(len(ilt)):
data[i] = ilt[i]
try:
while run_step():
pass
print('Input:', il, 'Output:', sep='\n')
print_data()
except BaseException as e:
print('Error! Current data:')
print_data()
print('State = "{0}"'.format(stateptr))
raise e
prog = map(norm_line, open(sys.argv[1], 'r').readlines())
inp = map(norm_line, open(sys.argv[2], 'r').readlines())
header = tuple(next(prog).split('\t'))
tuple(map(parse_prog_line, prog))
run(inp)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment