基础知识
Python3中的双向队列(deque)是一个能够从两端进行操作的序列容器。它的特点是可以高效地在两端进行元素的插入和删除操作,而不像列表(list)那样在头部插入或删除元素时会导致整个序列的复制和移动。Python的标准库collections中提供了deque的实现,使用方法和列表类似,可以通过append、appendleft、pop和popleft等方法进行操作。在这里介绍了deque的常用语法。
Brainfuck是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。它只有8种关键字,是一个极小化的语言。虽然语言比较小和简单,但是它是图灵完备的,于是经常用于计算理论中相关论题的验证。
BrainFuck执行器实现
计算模型:定义Table
类,定义一个双向无限长的寄存器空间,仅在指针指向的位置可存取值。每一个寄存器内初始值为0。指针初始指向的位置为0. 支持指针的移动,读写指针位置值及字节操作(增减)。
双向队列在处理一些需要同时从头尾操作的场合非常有用,,所以在这里用一个双向队列及指向这个队列中位置的指针实现我们定义的计算模型。在实现中,保证指针的下标始终不小于0.
import collections
class Table:
def __init__(self):
self.register = collections.deque([0])
self.ptr = 0
def ptr_l(self):
if self.ptr == 0:
self.register.appendleft(0)
else:
self.ptr -= 1
def ptr_r(self):
self.ptr += 1
if self.ptr == len(self.register):
self.register.append(0)
def add1(self):
self.register[self.ptr] += 1
def sub1(self):
self.register[self.ptr] -= 1
def set(self, value):
self.register[self.ptr] = value
def get(self):
return self.register[self.ptr]
解释器:定义Env
类,包含一个计算模型和指令的读取、执行方法。这个类通过process
方法执行指令,从代码段code
读取指令,从输入缓冲区inp
读取输入,在self.table
执行指令,写输出到输出缓冲区outp
,最终一起输出outp
的内容。
class Env:
def __init__(self):
self.table = Table()
def process(self, code, inp):
num_ins, ptr_ins = 0, 0
ptr_inp = 0
outp = ""
while ptr_ins < len(code):
if code[ptr_ins] == '>':
self.table.ptr_l()
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
elif code[ptr_ins] == '<':
self.table.ptr_r()
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
elif code[ptr_ins] == '+':
self.table.add1()
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
elif code[ptr_ins] == '-':
self.table.sub1()
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
elif code[ptr_ins] == '.':
outp += chr(self.table.get())
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
elif code[ptr_ins] == ',':
if ptr_inp < len(inp):
self.table.set(ord(inp[ptr_inp]))
ptr_inp += 1
else:
raise ValueError('Input exhausted')
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
elif code[ptr_ins] == '[':
if self.table.get() == 0:
while ptr_ins < len(code) and code[ptr_ins] != ']':
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
elif code[ptr_ins] == ']':
if self.table.get() != 0:
while ptr_ins >= 0 and code[ptr_ins] != '[':
num_ins, ptr_ins = num_ins + 1, ptr_ins - 1
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
else:
num_ins, ptr_ins = num_ins + 1, ptr_ins + 1
return outp
测试:将代码段和输入缓冲区的内容作为参数传入interpreter
,从interpreter.process
获得输出。
if __name__ == '__main__':
interpreter = Env()
# hello world
hello_world_code = '>++++++++[ < +++++++++ > -] < . > ++++[ < +++++++ > -] < +.+++++++..+++.>>++++++[ < +++++++ > -] < ++.------------. > ++++++[ < +++++++++ > -] < +. < .+++.------.--------.>> > ++++[ < ++++++++ > -] < +.'
print(interpreter.process(hello_world_code, None))
# toUpper
toUpper_code = ', ----------[----------------------., ----------]'
print(interpreter.process(toUpper_code, 'hello\n'))