HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyMinor

Brainf**k to Ruby converter, written in Ruby -- v1.0

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
converterwrittenbrainfruby

Problem

I've seen a lot of Brainfk interpreters in various languages. I decided that actually interpreting Brainfk is too hard, so instead of that, I wrote a 'compiler' in Ruby that directly transcribes BF to Ruby code. This is Version 1.0, and I'm looking for any tips on how to make it more efficient.

There are a few things that really bug me:

  • replacements feels like it's messed up somehow, but I can't put my finger on how.



  • $stdin.readbyte feels entirely too long, but I can't find an alternative that's shorter.



  • Should I be using $stdin at all?



input_file = $ARGV[0]
output_file = $ARGV[1]
start = ', replacement: 'pointer += 1'                    },
    { replacing: '<', replacement: 'pointer -= 1'                    },
    { replacing: '.', replacement: 'putc data[pointer]'              },
    { replacing: ',', replacement: 'data[pointer] = $stdin.readbyte' },
    { replacing: '[', replacement: 'until data[pointer] == 0'        },
    { replacing: ']', replacement: 'end'                             },
]

output = open(output_file, File::CREAT | File::WRONLY)
output.puts(start)

open(input_file, File::RDONLY) do |input|
  input.each_char do |char|
    replacements.each do |data|
      if data[:replacing] == char
        output.puts(data[:replacement])
      end
    end
  end
end


Demo

Input:

++++++++[>++++[>++>+++>+++>++>+>->>+[>.>---.+++++++..+++.>>.>+.>++.


Output:

`# Automatically generated by bf_to_ruby.rb
# Source available at GitHub
data = Hash.new(0)
pointer = 0
data[pointer] += 1
data[pointer] += 1
data[pointer] += 1
data[pointer] += 1
data[pointer] += 1
data[pointer] += 1
data[pointer] += 1
data[pointer] += 1
until data[pointer] == 0
pointer += 1
data[pointer] += 1
data[pointer] += 1
data[pointer] += 1
data[pointer] += 1
until data[pointer] == 0
pointer += 1
data[pointer] += 1
data[pointer] += 1
pointer += 1
data[pointer] += 1
data[pointer] += 1
data[pointer] += 1
pointer += 1
data[pointer] += 1
data[pointer] += 1
data[pointer

Solution

You should open the input file before the output file, so that if the input file is unreadable, no file is created at all. File opening should be done using blocks for automatic closure and cleanup.

This is too complicated:

replacements.each do |data|
  if data[:replacing] == char
    output.puts(data[:replacement])
  end
end


replacements would be better as a Hash:

replacements = {
    '+' => 'data[pointer] += 1',
    '-' => 'data[pointer] -= 1',
    '>' => 'pointer += 1',
    ' 'pointer -= 1',
    '.' => 'putc data[pointer]',
    ',' => 'data[pointer] = $stdin.readbyte',
    '[' => 'until data[pointer] == 0',
    ']' => 'end',
}

open(input_file, File::RDONLY) do |input|
  open(output_file, File::CREAT | File::WRONLY) do |output|
    output.puts(start)
    output.puts(input.each_char.map { |c| replacements[c] }.compact.join("\n"))
  end
end


One big puts should be faster than many indivual puts.

Code Snippets

replacements.each do |data|
  if data[:replacing] == char
    output.puts(data[:replacement])
  end
end
replacements = {
    '+' => 'data[pointer] += 1',
    '-' => 'data[pointer] -= 1',
    '>' => 'pointer += 1',
    '<' => 'pointer -= 1',
    '.' => 'putc data[pointer]',
    ',' => 'data[pointer] = $stdin.readbyte',
    '[' => 'until data[pointer] == 0',
    ']' => 'end',
}

open(input_file, File::RDONLY) do |input|
  open(output_file, File::CREAT | File::WRONLY) do |output|
    output.puts(start)
    output.puts(input.each_char.map { |c| replacements[c] }.compact.join("\n"))
  end
end

Context

StackExchange Code Review Q#94489, answer score: 6

Revisions (0)

No revisions yet.