写一个brainfuck语言的解释器

Brainfuck 语法介绍

有一种很神奇的编程语言叫做brainfuck. 很多人都学过C++, Java, Python等主流的语言,总是会有一种“天哪,语法好复杂”的感觉,brainfuck的语法则超级简单:

字符命令含义
>指针右移一个单位
<指针左移一个单位
+当前数据加一
-当前数据减一
.输出当前数据
,读入一个字节并赋给当前数据
[如果当前数据是0,则跳到匹配的]指令后面;否则执行下一条指令
]如果当前的数据不是0,就跳到匹配的[的下一条指令;否则执行下一条指令

用C语言来翻译一下,就是:

字符命令等价的C语言
>++ptr
<--ptr
+++(*ptr)
---(*ptr)
.putchar(*ptr)
,*ptr = getchar()
[while (*ptr) {
]}

除了上面所列的8个字符之外的所有字符,都被视为程序的注释。

虽然brainfuck的语法如此之简单,但这种语言也满足图灵完全(Turing Completeness) 的性质,简单来说,所有可以用图灵机计算求解的问题都可以用brainfuck来求解。当然,用这种语言来编程必然是非常痛苦的。。

Brainfuck解释器

写一个brainfuck解释器,只需要分别实现8种操作命令就可以了,下面给出用ruby实现操作命令的几个例子。

比如,要实现>操作命令,自增指针就可以了:

def forward()
    @mem_ptr += 1
    if @mem_ptr >= @mem_limit
        print "Access Violation\n"
        exit 1
    end
    next_pc
end

next_pc函数是取下一条指令,pc程序计数器(Program Counter)的缩写。

要实现+操作命令,自增当前指针的数据就可以了:

def increment()
    @memory[@mem_ptr] = (@memory[@mem_ptr] + 1) % 256
    next_pc
end

下面给出完整可运行的代码实现:

class BrainfuckInt
    attr_accessor :code, :mem_limit, :memory, :buffer, :mem_ptr, :pc
    def initialize(path)
        @code = File.read(path).split('').select{|c| valid?(c)}
        if !bracket_match?
            print "Error: Unmatched brackets\n"
            exit 1
        end
        @mem_limit = 32 * 1024          # default memory size is 32KB
        @memory = Array.new(@mem_limit, 0)
        @pc = 0
        @mem_ptr = 0
        @buffer = ''
    end

    def parse()
        while @pc < @code.length
            if @code[@pc] == '+'
                increment
            elsif @code[@pc] == '-'
                decrement
            elsif @code[@pc] == '<'
                backward
            elsif @code[@pc] == '>'
                forward
            elsif @code[@pc] == '.'
                display
            elsif @code[@pc] == ','
                read
            elsif @code[@pc] == '['
                enter_loop
            elsif @code[@pc] == ']'
                exit_loop
            else
                print "Invalid character: " + @code[@pc] + "\n"
                exit 1
            end
        end
    end

private
    def increment()
        @memory[@mem_ptr] = (@memory[@mem_ptr] + 1) % 256
        next_pc
    end

    def decrement()
        @memory[@mem_ptr] = (@memory[@mem_ptr] - 1 + 256) % 256
        next_pc
    end

    def read()
        @memory[@mem_ptr] = get_char().ord
        next_pc
    end

    def display()
        print @memory[@mem_ptr].chr
        next_pc
    end

    def forward()
        @mem_ptr += 1
        if @mem_ptr >= @mem_limit
            print "Access Violation\n"
            exit 1
        end
        next_pc
    end

    def backward()
        @mem_ptr -= 1
        if @mem_ptr < 0
            print "Access Violation\n"
            exit 1
        end
        next_pc
    end

    def enter_loop()
        if @memory[@mem_ptr] == 0
            cnt = 1
            next_pc
            while cnt > 0
                if @code[@pc] == '['
                    cnt += 1
                elsif @code[@pc] == ']'
                    cnt -= 1
                    if cnt == 0
                        break
                    end
                end
                next_pc
            end
        end
        next_pc
    end

    def exit_loop()
        if @memory[@mem_ptr] != 0
            cnt = 1
            @pc -= 1
            while cnt > 0
                if @code[@pc] == ']'
                    cnt += 1
                elsif @code[@pc] == '['
                    cnt -= 1
                    if cnt == 0
                        break
                    end
                end
                @pc -= 1
            end
        end
        next_pc
    end

    def next_pc()
        @pc += 1
    end

    def valid?(ch)
        ['+', '-', '<', '>', '.', ',', '[', ']'].index(ch) != nil
    end

    def bracket_match?()
        cnt, i = 0, 0
        while i < @code.length
            if @code[i] == '['
                cnt += 1
            elsif @code[i] == ']'
                cnt -= 1
            end
            if cnt < 0
                return false
            end
            i += 1
        end
        true
    end

    def get_char()
        while @buffer == nil or @buffer.length == 0
            @buffer = STDIN.gets
        end
        next_char = @buffer[0]
        @buffer = @buffer[1, @buffer.length]
        next_char
    end
end

def help()
    print "Usage: \n\truby ./bf.rb example.bf\n"
end

if __FILE__ == $0
    if ARGV.length != 1
        help
        exit 1
    end
    path = ARGV[0]
    if not File.file?(path)
        print "Invalid path: " + path + "\n"
        exit 1
    end

    interpreter = BrainfuckInt.new(path)
    interpreter.parse
end

代码比较短,不用加注释也可以很容易读懂。

运行示例

运行命令很简单,比如有一个helloworld.bf的源文件:

ruby ./bf.rb helloworld.bf

就可以了

下面是一个可能版本的helloworld.bf实现:

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

在终端运行:

这里写图片描述

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值