Решение на Четвърта задача от Росен Рачев

Обратно към всички решения

Към профила на Росен Рачев

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 6 успешни тест(а)
  • 2 неуспешни тест(а)

Код

module Asm
module NumberOperations
def cmp(register, value)
@instructions << [:cmp, register, value]
end
def mov(destination_register, source)
@instructions << [:'=', destination_register, source]
end
def inc(destination_register, source = 1)
@instructions << [:'+', destination_register, source]
end
def dec(destination_register, source = 1)
@instructions << [:'-', destination_register, source]
end
end
module Jumps
def label(label_name)
@labels[label_name] = @instructions.length
end
def jmp(label)
@instructions << [:jmp, label]
end
def je(label)
@instructions << [:je, :==, label]
end
def jne(label)
@instructions << [:jne, :'!=', label]
end
def jl(label)
@instructions << [:jl, :<, label]
end
def jle(label)
@instructions << [:jle, :<=, label]
end
def jg(label)
@instructions << [:jg,:>, label]
end
def jge(label)
@instructions << [:jge, :>=, label]
end
end
class Assembler
include NumberOperations
include Jumps
def initialize
@compare_result = nil
@instructions = []
@labels = {}
@registers = {ax: 0, bx: 0, cx: 0, dx: 0}
end
def method_missing(method, *args)
method
end
def execute(label = 0)
@instructions.drop(label).each do |instruction, destination, source|
source = @registers[source] if @registers.keys.include?(source)
if instruction == :'='
@registers[destination] = source
else
perform_instruction(instruction, destination, source)
end
break if [:jmp, :je, :jne, :jl, :jle, :jg, :jge].include?(instruction)
end
@registers.to_a.map { |element| element.drop(1) }.flatten
end
private
def perform_instruction(instruction, destination, source)
case instruction
when :jmp
execute(@labels[destination] || destination)
when :cmp
@compare_result = @registers[destination] - source
when :je, :jne, :jl, :jle, :jg, :jge
execute(@labels[source] || source) if @compare_result.send(destination, 0)
else
@registers[destination] = @registers[destination].send(instruction, source)
end
end
end
def self.asm(&block)
program = Assembler.new
program.instance_eval(&block)
program.execute
end
end

Лог от изпълнението

....F..F

Failures:

  1) Asm.asm implements CMP
     Failure/Error: Asm.asm do
       
       expected: [0, 0, 1, 1]
            got: [0, 0, 0, 0]
       
       (compared using ==)
     # /tmp/d20140115-8451-17gq618/spec.rb:50:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) Asm.asm can be used to find GCD of two numbers
     Failure/Error: Asm.asm do
       
       expected: [8, 8, 0, 0]
            got: [40, 32, 0, 0]
       
       (compared using ==)
     # /tmp/d20140115-8451-17gq618/spec.rb:89:in `block (2 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/language/ruby/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.00797 seconds
8 examples, 2 failures

Failed examples:

rspec /tmp/d20140115-8451-17gq618/spec.rb:33 # Asm.asm implements CMP
rspec /tmp/d20140115-8451-17gq618/spec.rb:88 # Asm.asm can be used to find GCD of two numbers

История (2 версии и 2 коментара)

Росен обнови решението на 14.01.2014 22:06 (преди почти 11 години)

+module Asm
+ module NumberOperations
+ def cmp(register, value)
+ @instructions << [:cmp, register, value]
+ end
+
+ def mov(destination_register, source)
+ @instructions << [:'=', destination_register, source]
+ end
+
+ def inc(destination_register, source = 1)
+ @instructions << [:'+', destination_register, source]
+ end
+
+ def dec(destination_register, source = 1)
+ @instructions << [:'-', destination_register, source]
+ end
+ end
+
+ module Jumps
+ def label(label_name)
+ @labels[label_name] = @instructions.length
+ end
+
+ def jmp(label)
+ @instructions << [:jmp, label]
+ end
+
+ def je(label)
+ @instructions << [:je, :==, label]
+ end
+
+ def jne(label)
+ @instructions << [:jne, :'!=', label]
+ end
+
+ def jl(label)
+ @instructions << [:jl, :<, label]
+ end
+
+ def jle(label)
+ @instructions << [:jle, :<=, label]
+ end
+
+ def jg(label)
+ @instructions << [:jg,:>, label]
+ end
+
+ def jge(label)
+ @instructions << [:jge, :>=, label]
+ end
+ end
+
+ class Instructions
+ include NumberOperations
+ include Jumps
+
+ def initialize
+ @compare_result = nil
+ @instructions = []
+ @labels = {}
+ @registers = {:ax => 0, :bx => 0, :cx => 0, :dx => 0}
+ end
+
+ def method_missing(method, *args)
+ method
+ end
+
+ def execute(label = 0)
+ @instructions.drop(label).each do |instruction, destination, source|
+ source = @registers[source] if @registers.keys.include? source
+ if instruction == :'='
+ @registers[destination] = source
+ else
+ perform_instructions(instruction, destination, source)
+ end
+ break if [:jmp, :je, :jne, :jl, :jle, :jg, :jge].include? instruction
+ end
+ @registers.to_a.map { |element| element.drop(1) }.flatten
+ end
+
+ private
+
+ def perform_instructions(instruction, destination, source)
+ case instruction
+ when :jmp
+ execute(@labels[destination] || destination)
+ when :cmp
+ @compare_result = @registers[destination] - source
+ when :je, :jne, :jl, :jle, :jg, :jge
+ execute(@labels[source] || source) if @compare_result.send destination, 0
+ else
+ @registers[destination] = @registers[destination].send instruction, source
+ end
+ end
+ end
+
+ def self.asm(&block)
+ program = Instructions.new
+ program.instance_eval(&block)
+ program.execute
+ end
+end

Nice!

  • Ползвай новия синтаксис за хешове в Instructions#initialize
  • Някой имена може да се пипнат. Например perform_instructions взима само 1 инструкция, т.е. по-добре е да се казва perform_instruction. Самото име на класа Instructions също ми се струва странно, понеже той е повече от един контейнер за инструкции.
  • На някои места не си спазил конвенциите за форматиране, например в execute и perform_instructions.

Росен обнови решението на 15.01.2014 00:51 (преди почти 11 години)

module Asm
module NumberOperations
def cmp(register, value)
@instructions << [:cmp, register, value]
end
def mov(destination_register, source)
@instructions << [:'=', destination_register, source]
end
def inc(destination_register, source = 1)
@instructions << [:'+', destination_register, source]
end
def dec(destination_register, source = 1)
@instructions << [:'-', destination_register, source]
end
end
module Jumps
def label(label_name)
@labels[label_name] = @instructions.length
end
def jmp(label)
@instructions << [:jmp, label]
end
def je(label)
@instructions << [:je, :==, label]
end
def jne(label)
@instructions << [:jne, :'!=', label]
end
def jl(label)
@instructions << [:jl, :<, label]
end
def jle(label)
@instructions << [:jle, :<=, label]
end
def jg(label)
@instructions << [:jg,:>, label]
end
def jge(label)
@instructions << [:jge, :>=, label]
end
end
- class Instructions
+ class Assembler
include NumberOperations
include Jumps
def initialize
@compare_result = nil
@instructions = []
@labels = {}
- @registers = {:ax => 0, :bx => 0, :cx => 0, :dx => 0}
+ @registers = {ax: 0, bx: 0, cx: 0, dx: 0}
end
def method_missing(method, *args)
method
end
def execute(label = 0)
@instructions.drop(label).each do |instruction, destination, source|
- source = @registers[source] if @registers.keys.include? source
+ source = @registers[source] if @registers.keys.include?(source)
+
if instruction == :'='
@registers[destination] = source
else
- perform_instructions(instruction, destination, source)
+ perform_instruction(instruction, destination, source)
end
- break if [:jmp, :je, :jne, :jl, :jle, :jg, :jge].include? instruction
+
+ break if [:jmp, :je, :jne, :jl, :jle, :jg, :jge].include?(instruction)
end
@registers.to_a.map { |element| element.drop(1) }.flatten
end
private
- def perform_instructions(instruction, destination, source)
+ def perform_instruction(instruction, destination, source)
case instruction
when :jmp
execute(@labels[destination] || destination)
when :cmp
@compare_result = @registers[destination] - source
when :je, :jne, :jl, :jle, :jg, :jge
- execute(@labels[source] || source) if @compare_result.send destination, 0
+ execute(@labels[source] || source) if @compare_result.send(destination, 0)
else
- @registers[destination] = @registers[destination].send instruction, source
+ @registers[destination] = @registers[destination].send(instruction, source)
end
end
end
def self.asm(&block)
- program = Instructions.new
+ program = Assembler.new
program.instance_eval(&block)
program.execute
end
end