6
\$\begingroup\$

I recently created Copy, an esoteric language, and wrote an implementation in Ruby.

The language has only 7 instructions:

  • copy <a> <b> <c> Copy the code block from a to b at c
  • remove <a> <b> Remove the code block from a to b
  • skip <value> Skip the next instruction if value is not 0
  • add <var> <value> Add value to var
  • negate <var> Negate var
  • print <value> Print value as an ASCII character
  • getch <var> Read a character and store it character code in var

All addresses are relative and values can be variables or signed integers,

require "io/console"
class Copy
 def initialize(code)
 @code = code.lines.map &:chomp
 @len = @code.length*2
 @i = 0
 @vars = {}
 end
 def value(s)
 if s =~ /-?\d+/
 s.to_i
 else
 @vars[s] or 0
 end
 end
 def step
 while @code.length > @len do
 @code.shift
 @i -= 1
 end
 line = @code[@i].split " "
 case line[0]
 when "copy"
 @code.insert(
 @i + value(line[3]),
 *@code.slice((@i + value(line[1]))..(@i + value(line[2])))
 )
 when "remove"
 @code.slice!((@i + value(line[1]))..(@i + value(line[2])))
 when "skip"
 if value(line[1]) != 0
 @i += 1
 end
 when "add"
 @vars[line[1]] = (@vars[line[1]] or 0) + value(line[2])
 when "negate"
 @vars[line[1]] *= -1
 when "print"
 STDOUT.write value(line[1]).chr
 when "getch"
 @vars[line[1]] = STDIN.getch.ord
 end
 @i += 1
 end
 def run
 while @i < @code.length
 step
 end
 end
end
if __FILE__ == 0ドル
 unless ARGV[0]
 puts "Copy interpreter in Ruby"
 puts "Usage: #{0ドル} <file>"
 end
 c = Copy.new File.read(ARGV[0])
 c.run
end

Truth machine (If the input is 0, print 0 and exit, if the input is 1, print 1 in an infinite loop):

getch a
add b a
add b -48
print a
skip b
skip 1
copy -4 0 1

I am not really good at Ruby, can someone review this?

chicks
2,8593 gold badges18 silver badges30 bronze badges
asked Sep 25, 2016 at 9:59
\$\endgroup\$
1
  • \$\begingroup\$ I personally would change step to self.step to increase readability. \$\endgroup\$ Commented Sep 25, 2016 at 16:36

1 Answer 1

3
\$\begingroup\$

I would suggest refactoring the switch. This would make scaling easier

 def remove_callback
 @code.slice!((@i + value(line[1]))..(@i + value(line[2])))
 end
 ...
 line = @code[@i].split " "
 self.send("#{line[0]}_callback")
answered Sep 25, 2016 at 13:23
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.