Produce xed

This commit is contained in:
Juhani Krekelä 2018-07-12 17:34:24 +03:00
parent e510661d9c
commit 09977f8fed
2 changed files with 148 additions and 2 deletions

12
README
View File

@ -1 +1,11 @@
Project to translate smallfuck (with infinite tape) to xed
Project to translate smallfuck (with unbounded to the right tape) to xed.
The command created by bf2xed.py produces a replacement command that advances
the program execution by one step each time it is executed.
To produce a tape usable by the step command, input your tape in the form:
0 0 ^0 1 0
Which says there is a tape with 5 cells, second from right being 1 and all
others being 0, and the tape head is in the middle of this tape

138
sf2xed.py
View File

@ -138,11 +138,147 @@ def reachability(start, states):
return processed
def string_id(state, value, processed):
def intlog(num, base):
# This is floor(log_{base} num)
assert num > 0
result = 0
while num > base - 1:
num = num // base
result += 1
return result
assert value == 0 or value == 1
assert state is None or 0 <= state < len(processed)
# One for each (cell value, state) combination and one for the cell values without a state
max_num = 2 * len(processed) + 2 - 1
# Base 62 because we have 0-9A-Za-y, +1 because the intlog is one less than the digits needed
width = intlog(max_num, 61) + 1
if state is not None:
num = 2 * (state + 1) + value
else:
num = value
digits = []
while num > 0:
digit = num % 61
num = num // 61
if digit < 10:
digits.append(chr(ord('0') + digit))
elif digit < 36:
digits.append(chr(ord('A') + digit - 10))
else:
digits.append(chr(ord('a') + digit - 36))
string = ''.join(reversed(digits))
# Pad to width
string = '0' * (width - len(string)) + string
return string
def create_replacements(processed):
replacements = []
for index in range(len(processed)):
state = processed[index]
if state.action == actions.nothing:
for value in [0, 1]:
if state.reachable[value]:
start = string_id(index, value, processed)
end = string_id(state.transitions[value], value, processed)
replacements.append((start, end))
elif state.action == actions.change:
for original_value in [0, 1]:
if state.reachable[original_value]:
changed_value = original_value ^ 1
start = string_id(index, original_value, processed)
end = string_id(state.transitions[changed_value], changed_value, processed)
replacements.append((start, end))
elif state.action == actions.left:
for this_value in [0, 1]:
if state.reachable[this_value]:
for left_value in [0, 1]:
this_start = string_id(index, this_value, processed)
left_start = string_id(None, left_value, processed)
start = '%s %s' % (left_start, this_start)
this_end = string_id(None, this_value, processed)
left_end = string_id(state.transitions[left_value], left_value, processed)
end = '%s %s' % (left_end, this_end)
replacements.append((start, end))
elif state.action == actions.right:
for this_value in [0, 1]:
if state.reachable[this_value]:
for right_value in [0, 1, None]:
this_start = string_id(index, this_value, processed)
if right_value is not None:
right_start = string_id(None, right_value, processed)
else:
right_start = 'z'
start = '%s %s' % (this_start, right_start)
this_end = string_id(None, this_value, processed)
if right_value is not None:
right_end = string_id(state.transitions[right_value], right_value, processed)
else:
right_end = string_id(state.transitions[0], 0, processed) + ' z'
end = '%s %s' % (this_end, right_end)
replacements.append((start, end))
else:
assert not "Unreachable"
return replacements
def xedify(replacements):
replaced = '|'.join(start for start, end in replacements)
replacement = '|'.join(end for start, end in replacements)
return 'x/%s/%s/' % (replaced, replacement)
def process_tape(tape, processed):
assert all(i in ['0', '1', '^0', '^1'] for i in tape)
processed_tape = []
for i in tape:
if i == '0':
processed_tape.append(string_id(None, 0, processed))
elif i == '1':
processed_tape.append(string_id(None, 1, processed))
elif i == '^0':
processed_tape.append(string_id(0, 0, processed))
elif i == '^1':
processed_tape.append(string_id(0, 1, processed))
else:
assert not "Unreachable"
return ' '.join(processed_tape) + ' z'
def main():
program = input('program: ')
start_noreachability, states_noreachability = turingify(parse_smallfuck(program))
processed = reachability(start_noreachability, states_noreachability)
prettyprint_states(processed)
replacements = create_replacements(processed)
print(xedify(replacements))
print('\nSend empty to exit. ^0/^1 for initial tape head position')
while True:
tape = input('tape: ')
if tape == '': break
tape = tape.split(' ')
print(process_tape(tape, processed))
if __name__ == '__main__':
main()