阿婆主脑容量不够,ぜんぜん不能在大脑中运行 Brainfuck 程序,而且发现连运行过程都想不出来啊, 然而就这么几个字符完全可以自己写解释器嘛,并且可以打印出运行过程,而且可以试试看做成playground 的形式呢,想想还是挺有趣的。
项目地址:Code CSDN
Git地址:Git on CSDN
Brainfuck
Brainfuck是一种图灵完备的语言,他可以做到任何事情,他的编译器是世界上最小的,他共有8个操作符:
Operator | Function |
---|---|
> | increment the data pointer (to point to the next cell to the right). |
< | decrement the data pointer (to point to the next cell to the left). |
+ | increment (increase by one) the byte at the data pointer. |
- | decrement (decrease by one) the byte at the data pointer. |
. | output the byte at the data pointer. |
, | accept one byte of input, storing its value in the byte at the data pointer. |
[ | if the byte at the data pointer is zero, then instead of moving the instruction pointer forward to the next command, jump it forward to the command after the matching ] command. |
] | if the byte at the data pointer is nonzero, then instead of moving the instruction pointer forward to the next command, jump it back to the command after the matching [ command. |
基本就是对内存直接操作的语言,他的『Hello World!』是这样的:
“++++++++[>++++[>++>+++>+++>+««-]>+>+>-»+[<]<-]».>—.+++++++..+++.».<-.<.+++.——.——–.»+.>++.”
WTF!!!!!!
需求点
1、基本功能
- 解释裸BF程序
- 打印内存信息
- 分开输出以及集体输出
2、调试功能
- 设置断点
- 单步执行
- 查看内存
3、playground功能
- 做命令行模式(加参数可选)
- 窗口分割
- 实时解释
基本功能实现
Brainfuck基本解释使用class BF()来实现
数据部分
class BF()中数据由两部分组成:
- Brainfuck程序
- 内存
BF直接对内存进行操作,所以这边可以很简单的用list模拟出来,这样我们就有了一个无限长的内存,并用BF.position来指明正在操作的内存,相当于一个指针(实际是list index)。另外一个就是代码存储区,代码由string类型的BF.code保存,同样有个代码指针BF.codePosition指明目前正在解释的操作符.
def __init__(self):
self.codeInit()
self.ifRuntime = True
def memoryInit(self):
self.dirty = False # if memory have been wroten
self.memory = [0] # memory
self.position = 0 # pointer to memory which byte now operating
self.codePosition = 0 # pointer to code which operator now parsing
self.result = '' # store whole program output
def codeInit(self, code = None):
if None == code: # for object init without BF code
self.code = ''
self.code = code
self.memoryInit()
操作符动作
操作符没有一点难度,按照wiki来解释。
def getChar(self):
return self.memory[self.position]
'''operators'''
def printChar(self):
print "echo: ",
print chr(self.memory[self.position]) # turn to ASCII char
self.result += chr(self.memory[self.position]) # store output
def inputChar(self):
print "put in: ",
self.memory[self.position] = ord(sys.stdin.read(1))
def increment(self):
self.memory[self.position] += 1
def decrement(self):
self.memory[self.position] -= 1
def next(self):
self.position += 1
if len(self.memory) <= self.position:
self.memory.append(0)
def previous(self):
self.position -= 1
if 0 > self.position:
print 'error: position is %d'%self.position
print printMemory()
循环实现
循环实现比较麻烦,本来只简单地想到一对括号的情况,后面发现了多对括号的问题,就先使用direction来保存括号在代码中的位子。并且用stack来先记录左括号。
首先在loopParser()中记录成对的括号位置,同时意味着循环开始结束地址也被记录了下来。在这个函数中,首先使用stack来登记未配对左括号地址,并在出现右括号时,弹出一个左括号地址,与右括号地址配对,写入loopMap这个direction**中,同样这个地址配对记录需要返回给主解析流程的。
在主流程中,通过loopParser()获得loopMap后,就开始对整个BF代码进行解释。此时根据wiki中的操作符作用,遇到**[时检查当前指针内容是否为0,为0则不进入循环,直接跳到对应的]地址上,遇到]时,当前指针内容不为0,则跳回到对应[**代码地址,继续循环。
def loopParser(self, code):
'''parse loop operator, recode the position of code'''
loopMap = {}
leftStack = []
codePosition = 0
leftNum = 0
rightNum = 0
for operator in code:
if operator == '[':
leftStack.append(codePosition)
leftNum += 1
elif operator == ']':
leftPosition = leftStack.pop()
rightPosition = codePosition
loopMap[leftPosition] = rightPosition
loopMap[rightPosition] = leftPosition
rightNum += 1
codePosition += 1
if 0 != len(leftStack):
print "error: there are %d '[' but %d ']'"
loopMap = None
return loopMap
def parser(self, code = None):
'''parse code'''
if None == code:
code = self.code
self.memoryInit()
loopMap = self.loopParser(code)
if None == loopMap:
return
if None == code:
code = self.code
while self.codePosition < len(code):
operator = code[self.codePosition]
if operator == ">":
self.next()
elif operator == "<":
self.previous()
elif operator == "+":
self.increment()
elif operator == "-":
self.decrement()
elif operator == ".":
self.printChar()
elif operator == ",":
self.inputChar()
elif operator == "[" and self.getChar() == 0:
self.codePosition = loopMap[self.codePosition]
elif operator == "]" and self.getChar() != 0:
self.codePosition = loopMap[self.codePosition]
self.runtime()
self.codePosition += 1
打印runtime
做这个解释器的主要原因就是,看不懂Brainfuck每一步为什么要这样做,所以解释器的重点就在于打印每一步的数据内存和代码内存,并且标出目前运行到哪里了。
Global function:
def printChar(char, point = False):
if point:
char = '\033[31m%s\033[0m' %char # print red chars on Unix
sys.stdout.write(char + ' ')
BF() method:
def printData(self, data, position):
'''print linear data and point the position now point'''
point = False
for nowPosition in xrange(0, len(data)):
if nowPosition == position:
point = True
printChar(str(data[nowPosition]), point)
point = False
print "" # printChar don't print '\n'
def runtime(self):
'''print runtime memory and code'''
if self.ifRuntime:
self.printData(self.code, self.codePosition)
self.printData(self.memory, self.position)
基本功能运行结果
未完待续。。。或者。。。