Created
January 19, 2010 05:53
-
-
Save dydx/280705 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
# 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