好久没更新了,最近有人委托我做了一个单纸带 图灵机的模型,我就用python写了一个简易的。写完之后想了一想,其实这东西本质上就是一个仿汇编指令语法的程序编译器。虽然是一个比较精简的实现,但我个人认为还是比较有参考价值的,因此我把代码开源给大家。
完整代码在我的github上:https://github.com/Eathoublu/EathouTuringMachine
我设计的是一个单纸带图灵机,拥有1024的个可分配内存地址。采取的是一个仿汇编语言的指令集。
废话不多说,下面放图灵机的源码:
# coding:utf8
# author: Yixiao Lan
class Memory(object):
def __init__(self, length):
self.space = [None for _ in range(length)]
self.length = length
def malloc(self):
for idx in range(self.length):
if self.space[idx] is None:
return idx
raise Exception('MemoryError', 'Out if space.')
def set_memory(self, addr, value):
if addr >= self.length:
raise Exception('MemoryError', 'Address > Memory max address.')
self.space[addr] = value
return
def clear_memory(self, addr):
if addr >= self.length:
raise Exception('MemoryError', 'Address > Memory max address.')
self.space[addr] = None
return
def read_memory(self, addr):
if addr >= self.length:
raise Exception('MemoryError', 'Address > Memory max address.')
return self.space[addr]
class Controller(object):
def __init__(self):
self.cursor = 0
self.input_sequence = None
self.memory = Memory(length=1000)
self.arithmetic_logic_unit = ArithmeticLogicUnit(self.memory)
def set_operates(self, operation_sequence_input):
self.input_sequence = operation_sequence_input
return
@staticmethod
def turn_operation_into_tuple(operation):
opt_arg = operation.split(' ')
if len(opt_arg) == 1:
return opt_arg
args = opt_arg[1].split(',')
return opt_arg[0], args
def run(self):
while True:
operation = self.input_sequence[self.cursor]
operation_tuple = self.turn_operation_into_tuple(operation)
self.cursor = self.arithmetic_logic_unit.operate(operation_tuple, self.cursor)
if self.cursor == -1:
break
# self.watch_memory()
def watch_memory(self):
print('Memory state is as follow:\n{}'.format(self.memory.space))
class ArithmeticLogicUnit(object):
def __init__(self, bond_memory):
self.bond_memory = bond_memory
def detect(self, value):
if str(value)[0] == '@':
return self.bond_memory.read_memory(int(str(value)[1:])) if self.bond_memory.read_memory(int(str(value)[1:])) else 0
return int(value)
@staticmethod
def get_cursor(value):
if str(value)[0] != '@':
return int(value)
return int(str(value)[1:])
def watch_memory(self):
print('Memory state is as follow:\n{}'.format(self.bond_memory.space))
def operate(self, operation_tuple, pc):
opt = operation_tuple[0]
if len(operation_tuple) != 1:
args = operation_tuple[1]
if opt == 'MOV':
self.bond_memory.set_memory(addr=self.get_cursor(args[0]), value=self.detect(args[1]))
return pc + 1
if opt == 'ADD':
register = self.detect(args[0])
if not register:
register = 0
register += self.detect(args[1])
self.bond_memory.set_memory(addr=self.get_cursor(args[0]), value=register)
return pc + 1
if opt == 'DEC':
register = self.detect(args[0])
if not register:
register = 0
register -= self.detect(args[1])
self.bond_memory.set_memory(addr=self.get_cursor(args[0]), value=register)
return pc + 1
if opt == 'MUL':
register = self.detect(args[0])
if not register:
register = 0
register *= self.detect(args[1])
self.bond_memory.set_memory(addr=self.get_cursor(args[0]), value=register)
return pc + 1
if opt == 'DIV':
register = self.detect(args[0])
if not register:
register = 0
register /= self.detect(args[1])
self.bond_memory.set_memory(addr=args[0], value=register)
return pc + 1
if opt == 'EQU':
if self.detect(args[0]) == self.detect(args[1]):
return self.get_cursor(args[3])
return pc + 1
if opt == 'NEQ':
if self.detect(args[0]) != self.detect(args[1]):
return self.get_cursor(args[3])
return pc + 1
if opt == 'BGT':
if self.detect(args[0]) >= self.detect(args[1]):
return int(args[3])
return pc + 1
if opt == 'SMT':
if self.detect(args[0]) <= self.detect(args[1]):
return int(args[3])
return pc + 1
if opt == 'ANB':
if self.detect(args[0]) and self.detect(args[1]):
return int(args[3])
return pc + 1
if opt == 'ORB':
if self.detect(args[0]) or self.detect(args[1]):
return int(args[3])
return pc + 1
if opt == 'JMP':
return int(args[0])
if opt == 'END':
return -1
if opt == 'DEL':
self.bond_memory.clear_memory(addr=self.get_cursor(args[0]))
return pc + 1
if opt == 'MLC':
pass
return pc + 1
if opt == 'VAR':
pass
return pc + 1
if opt == 'PRT':
print(self.detect(args[0]))
return pc + 1
if opt == 'PRTM':
self.watch_memory()
return pc + 1
raise Exception('Syntax Error', 'No such opt code : {}'.format(opt))
def parser(seq, spl=';'):
seq = seq.replace('\n', '')
return seq.split(spl)
if __name__ == '__main__':
with open('tape.trl', 'r') as f:
content = f.read()
parsed_content = parser(content)
controller = Controller()
controller.set_operates(parsed_content)
controller.run()
测试程序放在tape.trl中,(trl是一个我自己定义的语言名称,其实只是个文件名而已啦)。
MOV @1,2;
MUL @1,2;
PRT @1;
DEL @1;
PRT @1;
END;
输出结果:
0
4
附上语法说明(完整readme可以去我的github看):
1. MOV @1,2 @1<-2
2. ADD @1,2 @1<-@1+2
3. DEC @1,2 @1<-@1-2
4. MUL @1,2 @1<-@1*2
5. DIV @1,2 @1<-@1/2
6. EQU 1,2,4 1=2?pc<-4:pc<-pc+1
7. NEQ 1,1,4 1!=2?pc<-4:pc<-pc+1
8. BGT 1,2,4 1>2?pc<-4:pc<-pc+1
9. SMT 1,2,4 1<2?pc<-4:pc<-pc+1
10. ANB 1,2,4 1&2?pc<-4:pc<-pc+1
11. ORB 1,2,4 1|2?pc<-4:pc<-pc+1
12. DEL @1 @1<-NULL
13. PRT @1 PRINT TO TERMINAL<-@1
14. PRTM PRINT COMPLETE MEMORY TO TERMINAL
15. END QUIT PROCESS
其中,@XX指的是内存地址
正如大家所见,这个图灵机模型尚为一个极其简易的模型,如果大家有兴趣,我们可以共同完善这个项目,欢迎大家到我的github:
https://github.com/Eathoublu/EathouTuringMachine 上fork这个项目,嘻嘻。
本人联系邮箱:yixiaolan@foxmail.com