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\$
1
  • 1
    \$\begingroup\$ BTW: this is a compiler, not an interpreter. \$\endgroup\$ Commented Jul 31, 2015 at 11:19

1 Answer 1

5
\$\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\$
7
  • \$\begingroup\$ I'm not quite sure what you mean by "can you use constants with string interpolation?" \$\endgroup\$
    – anon
    Commented Jun 24, 2015 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
    Commented Jun 24, 2015 at 23:21
  • \$\begingroup\$ Oh, like "#{'test'} test"? Yes, that's possible. I don't see why you'd do it though. \$\endgroup\$
    – anon
    Commented Jun 24, 2015 at 23:22
  • 2
    \$\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
    Commented Jun 24, 2015 at 23:23
  • \$\begingroup\$ And when would I ever need to change it? \$\endgroup\$
    – anon
    Commented Jun 25, 2015 at 1:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.