Created
April 14, 2009 12:47
-
-
Save kuzux/95165 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
class Brainfuck | |
# Ruby Brainfuck interpreter | |
# (C) Scott Olson <scott@scott-olson.org> | |
# MIT License | |
attr_accessor :script, :stdin, :stdout | |
@@allowed = '<>+-.,[]#' | |
# script is the brainfuck program | |
# stdin and stdout are the input and output, respectively | |
# they can be String, IO, or something else that accepts putc/getc | |
def initialize(script, stdout=nil, stdin=nil) | |
@script = script | |
@stdout = stdout || '' | |
@stdin = stdin || '' | |
end | |
def run | |
ptr = 0 | |
stack = [0] | |
script = @script.split('') | |
script_ptr = 0 | |
while script_ptr < script.length | |
debug_msg = "%0#{script.length.to_s.length}i: (#{ptr}=#{stack[ptr]}) #{script[script_ptr]}" % script_ptr | |
case script[script_ptr] | |
when '>' | |
ptr += 1 | |
stack[ptr] ||= 0 # set the cell to 0 if it is nil | |
when '<' | |
ptr -= 1 | |
stack[ptr] ||= 0 # set the cell to 0 if it is nil | |
when '+' | |
stack[ptr] += 1 | |
when '-' | |
stack[ptr] -= 1 | |
when '.' | |
debug_msg << " outputting #{stack[ptr].chr.inspect}" | |
case @stdout | |
when String | |
@stdout << stack[ptr] | |
else | |
@stdout.putc stack[ptr] | |
end | |
when ',' | |
case @stdin | |
when String | |
stack[ptr] = (/^1\.8/ === RUBY_VERSION ? @stdin.first[0] : @stdin.first.ord) # grab first char as int | |
@stdin[0] = '' # remove the char from the string | |
else | |
stack[ptr] = @stdin.getc | |
stack[ptr] ||= 0 # our EOF if @stdin is at the end | |
end | |
when '[' | |
came_from = script_ptr # never forget where you came from | |
# this code jumps to the next ']' if our current byte is 0 | |
script_ptr += script[script_ptr..-1].index(']') if stack[ptr] == 0 | |
when ']' | |
raise "unmatched ] encountered" unless defined? :came_from | |
script_ptr = came_from - 1 # go back to the start of the loop | |
when '#' | |
debug_msg << " dumping info for debugging purposes\n" | |
stack_dump = [] | |
stack.each_with_index do |v,i| | |
stack_dump << "*#{i}=#{v}" && next if ptr == i # put a * next to the cell the pointer is at | |
stack_dump << "#{i}=#{v}" | |
end | |
debug_msg << "[" << stack_dump.join(', ') << "]\n" | |
else # not a brainfuck character; treated as a comment | |
comment ||= [script_ptr] | |
comment[1] = script_ptr | |
end | |
if @@allowed.include?(script[script_ptr]) and comment | |
debug_msg = ("%0#{script.length.to_s.length}i-%0#{script.length.to_s.length}i: comments\n" % [comment[0], comment[1]]) + debug_msg | |
comment = nil | |
end | |
script_ptr += 1 | |
$stderr.puts debug_msg if @@debug unless comment | |
end | |
end | |
@@debug = false | |
def self.debug=(val) | |
@@debug = val | |
end | |
end | |
class BSP | |
def call(env) | |
#Brainfuck.debug = true | |
req = Rack::Request.new env | |
headers = {"Content-Type" => "text/html"} | |
filename = env["PATH_INFO"][1..-1] | |
input = req.params.map{|k,v|"#{k}=#{v}"}.join("&") | |
output = "" | |
Brainfuck.new(File.read(filename), output, input).run | |
headers["Content-Length"] = output.length.to_s | |
[200,headers,output] | |
end | |
end | |
run BSP.new |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment