Skip to content

Instantly share code, notes, and snippets.

@dydx
Created January 19, 2010 05:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dydx/280705 to your computer and use it in GitHub Desktop.
Save dydx/280705 to your computer and use it in GitHub Desktop.
# jbfc.rb - Josh Sandlin - 7:27PM - 1/18/2010
# Takes brainfuck source and compiles it to exe
# converts brainfuck code into C code
class BFToC
attr_accessor :source, :memory
def initialize( source, memory=30000 )
if !File.exists? source
abort "The supplied source file doesn't appear to exist."
else
@source_file = File.open( source )
@instructions = Array.new
@memory = memory
end
end
# takes BF program source and converts it
# into C instructions
private
def parse_to_c_instructions
instructions = Array.new
@source_file.each_byte do |byte|
case byte.chr
when "+"
# increment value of stack pointer
instructions += ['++*ptr;']
when "-"
# decrement value of stack pointer
instructions += ['--*ptr;']
when ">"
# increment index of stack pointer
instructions += ['++ptr;']
when "<"
# decrement index of stack pointer
instructions += ['--ptr;']
when "."
# value of stack pointer to stdout
instructions += ['putchar(*ptr);']
when ","
# value of stack pointer from stdin
instructions += ['*ptr = getchar();']
when "["
# begin `while' loop
instructions += ['while(*ptr) {']
when "]"
# end `while' loop
instructions += ['}']
else
# ignore instruction (comment, etc.)
end
end
instructions
end
# tacks on a valid header and the return statement.
private
def build_c_source
"#include <stdio.h>\n" +
"int main( void ) {\n" +
" unsigned char memory[#{@memory}];\n" +
" unsigned char *ptr = memory;\n" +
" #{parse_to_c_instructions.join('')}\n" +
" return 0;\n" +
"}\n"
end
# BFToC.new('bf_source.bf').to_c -> C source code
public
def to_c
build_c_source
end
end
# compiles brainfuck code into a binary via converting
# to C first and then compiling that.
class BFCompiler
attr_accessor :filename, :c_translation
def initialize( source_file, memory=30000 )
@filename = source_file.split('.')[0] # get name
@c_translation = BFToC.new( source_file ).to_c
end
def compile
# create C source file
if !File.exists? "#{@filename}.c"
File.open( "#{@filename}.c", 'w' ) do |f|
f << @c_translation
end
end
# compile C source file
if !File.exists? "#{@filename}"
system( "gcc #{@filename}.c -o #{@filename}" )
end
File.unlink( "#{@filename}.c" )
end
end
# `frontend' to the script. Allows the user to call the
# compiler from the command prompt and supply a file.
source_file = ARGV.shift
if source_file.split('.')[1] != 'bf'
puts "The supplied file was not a valid Brainfuck source file"
else
compiler = BFCompiler.new( source_file ).compile
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment