Skip to main content
replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link
Tweeted twitter.com/#!/StackCodeReview/status/613689342691803137
Source Link
anon
anon

Brainf**k to Ruby converter -- v2

Previous iteration.

You know, I think this is the fastest I've ever pushed out an update to anything. This is Version 2 of my Brainf**k to Ruby converter, and the generated code looks... Well, like Brainf**k, converted directly to Ruby, with no attempt at making it more readable.

I'm looking for any tips on making things more idiomatic, both in the generator and generated code. The nest if/cases really bug me, but I'm not quite sure how to get rid of them, especially since just two characters are blindly replaced. I'd also like advice on making it run faster.

###bf_to_ruby.rb

input_file, output_file = ARGV
code = IO.read(input_file).tr('^+-<>.,[]', '')

open(output_file, File::CREAT | File::WRONLY) do |output|
  output.puts <<-END.gsub(/^[ \t]*\||\s*#@.*$/, '')
    |#!/usr/bin/env ruby
    |class Mem < Hash #@ `Hash` because it's more memory-efficient and allows negative values.
    |  def initialize; super(0); end
    |  def []=(i, val); super(i, val & 255); end
    |end
    |data = Mem.new
    |pointer = 0
  END
  indent_level = 0
  code.scan(/(\++)|(\-+)|(<+)|(>+)|([.,\[\]])/)
      .map do |string|
        if string[0]
          next "#{'  ' * indent_level}data[pointer] += #{string[0].length}"
        elsif string[1]
          next "#{'  ' * indent_level}data[pointer] -= #{string[1].length}"
        elsif string[2]
          next "#{'  ' * indent_level}pointer -= #{string[2].length}"
        elsif string[3]
          next "#{'  ' * indent_level}pointer += #{string[3].length}"
        elsif string[4]
          case string[4]
            when '['
              ret = "#{'  ' * indent_level}until data[pointer] == 0"
              indent_level += 1
              next ret #Split it so that it's clear that indent is increased *after* the line
            when ']'
              indent_level -= 1
              next "#{'  ' * indent_level}end"
            when ','
              next "#{'  ' * indent_level}data[pointer] = $stdin.readbyte"
            when '.'
              next "#{'  ' * indent_level}putc data[pointer]"
          end
        end
      end.each { |line| output.puts(line) }
end

###Demo

Input:

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

Output:

#!/usr/bin/env ruby
class Mem < Hash
  def initialize; super(0); end
  def []=(i, val); super(i, val & 255); end
end
data = Mem.new
pointer = 0
data[pointer] += 8
until data[pointer] == 0
  pointer += 1
  data[pointer] += 4
  until data[pointer] == 0
    pointer += 1
    data[pointer] += 2
    pointer += 1
    data[pointer] += 3
    pointer += 1
    data[pointer] += 3
    pointer += 1
    data[pointer] += 1
    pointer -= 4
    data[pointer] -= 1
  end
  pointer += 1
  data[pointer] += 1
  pointer += 1
  data[pointer] += 1
  pointer += 1
  data[pointer] -= 1
  pointer += 2
  data[pointer] += 1
  until data[pointer] == 0
    pointer -= 1
  end
  pointer -= 1
  data[pointer] -= 1
end
pointer += 2
putc data[pointer]
pointer += 1
data[pointer] -= 3
putc data[pointer]
data[pointer] += 7
putc data[pointer]
putc data[pointer]
data[pointer] += 3
putc data[pointer]
pointer += 2
putc data[pointer]
pointer -= 1
data[pointer] -= 1
putc data[pointer]
pointer -= 1
putc data[pointer]
data[pointer] += 3
putc data[pointer]
data[pointer] -= 6
putc data[pointer]
data[pointer] -= 8
putc data[pointer]
pointer += 2
data[pointer] += 1
putc data[pointer]
pointer += 1
data[pointer] += 2
putc data[pointer]

You'll notice that the generated code is nearly the same as the last version's generated code, but with a lot of duplicate lines merged and indenting.