4
\$\begingroup\$

Previous iteration.

I think this is about as good as it's gonna get, but just for kicks, let's do one more round of iterations.

As before, it's a very simple substitution from Brainfuck to Ruby, with fancy things like joining duplicate lines into one and indentation.

Some things that bug me:

  • The regex (/\++|-+|<+|>+|[.,\[\]]/) feels like it can be simplified, but I can't figure out how.
  • I feel like the map can be simplified, but I can't figure out how.
  • The constant repetition of #{' ' * indent_level} bugs me, but I can't see how to get rid of it.
  • indent_level being declared outside of the scope of each feels like an anti-pattern, but AFAICT there's no better way to do it.
input_file, output_file = ARGV
code = IO.read(input_file).delete('^+-<>.,[]')

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|
        case string[0]
          when '+' #String of "+"
            next "#{'  ' * indent_level}data[pointer] += #{string.length}"
          when '-' #String of "-"
            next "#{'  ' * indent_level}data[pointer] -= #{string.length}"
          when '<' #String of "<"
            next "#{'  ' * indent_level}pointer -= #{string.length}"
          when '>' #String of ">"
            next "#{'  ' * indent_level}pointer += #{string.length}"
          when '[' #Single "["
            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 ']' #Single "]"
            indent_level -= 1
            next "#{'  ' * indent_level}end"
          when ',' #Single ","
            next "#{'  ' * indent_level}data[pointer] = $stdin.readbyte"
          when '.' #Single "."
            next "#{'  ' * indent_level}putc data[pointer]"
        end
      end.each { |line| output.puts(line) }
end
\$\endgroup\$
  • \$\begingroup\$ BTW: this is a compiler, not an interpreter. \$\endgroup\$ – Jörg W Mittag Jul 31 '15 at 11:19
4
\$\begingroup\$

I'm not 100% sure this works in Ruby, but can you use constants with string interpolation? This string is repeated a lot. I doubt it will ever change, but if it does, it would be nice to only have to change it once.

"#{'  ' * indent_level}data[pointer]"

Could be #{' ' * indent_level}#{DATA}.

\$\endgroup\$
  • \$\begingroup\$ I'm not quite sure what you mean by "can you use constants with string interpolation?" \$\endgroup\$ – Nic Hartley Jun 24 '15 at 23:19
  • \$\begingroup\$ Can you inject a constant string value into another string using interpolation? I'm sure you can. I'm just not sure you can. \$\endgroup\$ – RubberDuck Jun 24 '15 at 23:21
  • \$\begingroup\$ Oh, like "#{'test'} test"? Yes, that's possible. I don't see why you'd do it though. \$\endgroup\$ – Nic Hartley Jun 24 '15 at 23:22
  • 1
    \$\begingroup\$ Because this string (data[pointer]) is repeated several times. If you would ever have a reason to change it. You'd only have to change it once. \$\endgroup\$ – RubberDuck Jun 24 '15 at 23:23
  • \$\begingroup\$ And when would I ever need to change it? \$\endgroup\$ – Nic Hartley Jun 25 '15 at 1:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.