2
\$\begingroup\$

For a while now, I've wanted to write a stack-based "Turing-tarpit". This is the perfect excuse to learn Ruby, which I have never used before, so I wrote Brain-flak.

The language only uses these characters, ()[]{}<> in various contexts. Here is the interpreter:

class Stack
  def initialize(name)
    @name = name
    @data = []
  end

  def pop
    if @data.length != 0 then
      return @data.pop
    else
      return 0
    end
  end

  def push(current_value)
    @data.push(current_value)
  end

  def peek
    return @data.last || 0
  end

  def print
    while @data.length > 0 do
        puts pop
    end
  end

  def talk
    puts @name
  end
end

def is_opening_bracket?(b)
  return '([{<'.include? b
end

def is_closing_bracket?(b)
  return ')]}>'.include? b
end

def brackets_match?(b1, b2)
  s = [b1, b2].join('')
  return ['()', '[]', '{}', '<>'].include? s
end

def read_until_stack_end(s, start)
  stack_height = 0
  s[start + 1..s.length].each_char.with_index(1) do |c, i|
    case c
    when '{' then stack_height += 1
    when '}' then
      stack_height -= 1
      if stack_height == -1 then
        return i
      end
    end
  end
  return nil
end

left = Stack.new('Left')
right = Stack.new('Right')
main_stack = Stack.new('Main')
active = left

source_index = 0
current_value = 0
error = false

if ARGV.length < 1 then
  puts "Welcome to Brain-Flak!"\
       "\nUsage:"\
       "brain_flak source_file"\
       "brain_flak source_file args\n"
  exit
end

source_path = ARGV[0]
source_file = File.open(source_path, 'r')
source = source_file.read
source_length = source.length

ARGV[1..-1].each do|a|
  active.push(a.to_i)
end

while true do
  current_symbol = source[source_index..source_index+1] or source[source_index]
  if source_index >= source.length then
    break
  end

  if ['()', '[]', '{}', '<>'].include? current_symbol 
    case current_symbol
      when '()' then current_value += 1
      when '[]' then current_value -= 1
      when '{}' then current_value += active.pop
      when '<>' then active = active == left ? right : left
      else
        error = true
        break
    end
    source_index += 2

  else
    current_symbol = current_symbol[0]
    if is_opening_bracket?(current_symbol) then
      if current_symbol == '{' and active.peek == 0 then
        new_index = read_until_stack_end(source, source_index)
        if new_index == nil then
          error = true
          break
        else
          source_index = new_index
        end
      else
        main_stack.push([current_symbol, current_value, source_index])
      end
      current_value = 0

    elsif is_closing_bracket?(current_symbol) then
      data = main_stack.pop
      if not brackets_match?(data[0], current_symbol) then
        error = true
        break
      end

      case current_symbol
        when ')' then active.push(current_value)
        when ']' then puts current_value
        when '>' then current_value = 0
        when '}' then source_index = data[2] - 1 if active.peek != 0
        end
    end
    source_index += 1
  end

  if source_index >= source_length then
    break
  end

end

if error then
  puts 'Invalid character in source file!'
  exit
end

active.print

Does this follow the best practices of Ruby? Is it easy to understand? Like I said, this is the first thing I've written in Ruby, so there are probably lots of things that I'm doing in the roundabout/less convenient way. For example, there are so many then keywords! I don't know if or where these are necessary.

\$\endgroup\$
1
  • \$\begingroup\$ In terms of style, I suggest that you start by reading this guide: github.com/bbatsov/ruby-style-guide . It covers pretty much all cases, and will help you make your code look more "Ruby-ish". \$\endgroup\$ Commented May 17, 2016 at 9:41

0

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.