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

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

Към профила на Марио Даскалов

Резултати

  • 3 точки от тестове
  • 0 бонус точки
  • 3 точки общо
  • 4 успешни тест(а)
  • 4 неуспешни тест(а)

Код

module Asm
class InstructionExecutorUnit
conditional_jumps = {
je: :==,
jne: :!=,
jl: :<,
jle: :<=,
jg: :>,
jge: :>=,
}
conditional_jumps.each do |instruction_name, operation|
define_method instruction_name do |argument|
jmp(argument) if get_value(:compare_flag).send(operation, 0)
end
end
def initialize(execution_unit)
@execution_unit = execution_unit
end
def mov(destination_register, source)
@execution_unit.registers[destination_register] = get_value(source)
end
def inc(destination_register, value)
mov destination_register, get_value(destination_register) + get_value(value)
end
def dec(destination_register, value)
inc destination_register, -get_value(value)
end
def cmp(register, value)
mov :compare_flag, get_value(register) <=> get_value(value)
end
def jmp(label)
@execution_unit.instruction_pointer = @execution_unit.labels[label]
end
private
def get_value(source)
if @execution_unit.registers.include? source
@execution_unit.registers[source]
else
source
end
end
end
class Parser < BasicObject
def initialize(labels, instruction_pipeline)
@labels = labels
@instruction_pipeline = instruction_pipeline
end
def label(name)
@labels[name] = @instruction_pipeline.size
end
def method_missing(name, *args)
if InstructionExecutorUnit.public_method_defined? name
@instruction_pipeline << [name, *args]
else
name
end
end
end
class ExecutionUnit
attr_reader :labels, :registers
attr_accessor :instruction_pointer
def initialize(&block)
@labels = {}
@instruction_pipeline = []
Parser.new(@labels, @instruction_pipeline).instance_eval &block
@instruction_executor_unit = InstructionExecutorUnit.new self
@registers = {ax: 0, bx: 0, cx: 0, dx: 0, compare_flag: 0}
@instruction_pointer = 0
end
def execute_next_instruction
@instruction_pointer += 1
instruction = @instruction_pipeline[@instruction_pointer.pred]
@instruction_executor_unit.public_send *instruction
end
def finished?
@instruction_pipeline.size <= @instruction_pointer
end
def execute_program
until finished?
execute_next_instruction
end
end
end
def self.asm(&block)
control_flow_unit = ExecutionUnit.new &block
control_flow_unit.execute_program
[:ax, :bx, :cx, :dx].map do |register_name|
control_flow_unit.registers[register_name]
end
end
end

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

..FFF.F.

Failures:

  1) Asm.asm implements INC
     Failure/Error: Asm.asm do
     ArgumentError:
       wrong number of arguments (1 for 2)
     # /tmp/d20140115-8451-175zm06/solution.rb:26:in `inc'
     # /tmp/d20140115-8451-175zm06/solution.rb:87:in `public_send'
     # /tmp/d20140115-8451-175zm06/solution.rb:87:in `execute_next_instruction'
     # /tmp/d20140115-8451-175zm06/solution.rb:96:in `execute_program'
     # /tmp/d20140115-8451-175zm06/solution.rb:103:in `asm'
     # /tmp/d20140115-8451-175zm06/spec.rb:15: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 implements DEC
     Failure/Error: Asm.asm do
     ArgumentError:
       wrong number of arguments (1 for 2)
     # /tmp/d20140115-8451-175zm06/solution.rb:30:in `dec'
     # /tmp/d20140115-8451-175zm06/solution.rb:87:in `public_send'
     # /tmp/d20140115-8451-175zm06/solution.rb:87:in `execute_next_instruction'
     # /tmp/d20140115-8451-175zm06/solution.rb:96:in `execute_program'
     # /tmp/d20140115-8451-175zm06/solution.rb:103:in `asm'
     # /tmp/d20140115-8451-175zm06/spec.rb:23: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)>'

  3) Asm.asm implements CMP
     Failure/Error: Asm.asm do
     ArgumentError:
       comparison of Fixnum with nil failed
     # /tmp/d20140115-8451-175zm06/solution.rb:91:in `<='
     # /tmp/d20140115-8451-175zm06/solution.rb:91:in `finished?'
     # /tmp/d20140115-8451-175zm06/solution.rb:95:in `execute_program'
     # /tmp/d20140115-8451-175zm06/solution.rb:103:in `asm'
     # /tmp/d20140115-8451-175zm06/spec.rb:34: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)>'

  4) Asm.asm implements LABEL
     Failure/Error: Asm.asm do
     ArgumentError:
       wrong number of arguments (1 for 2)
     # /tmp/d20140115-8451-175zm06/solution.rb:26:in `inc'
     # /tmp/d20140115-8451-175zm06/solution.rb:87:in `public_send'
     # /tmp/d20140115-8451-175zm06/solution.rb:87:in `execute_next_instruction'
     # /tmp/d20140115-8451-175zm06/solution.rb:96:in `execute_program'
     # /tmp/d20140115-8451-175zm06/solution.rb:103:in `asm'
     # /tmp/d20140115-8451-175zm06/spec.rb:78: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.00776 seconds
8 examples, 4 failures

Failed examples:

rspec /tmp/d20140115-8451-175zm06/spec.rb:14 # Asm.asm implements INC
rspec /tmp/d20140115-8451-175zm06/spec.rb:22 # Asm.asm implements DEC
rspec /tmp/d20140115-8451-175zm06/spec.rb:33 # Asm.asm implements CMP
rspec /tmp/d20140115-8451-175zm06/spec.rb:77 # Asm.asm implements LABEL

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

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

+module Asm
+ class InstructionExecutorUnit
+ conditional_jumps = {
+ je: :==,
+ jne: :!=,
+ jl: :<,
+ jle: :<=,
+ jg: :>,
+ jge: :>=,
+ }
+
+ conditional_jumps.each do |instruction_name, operation|
+ define_method instruction_name do |argument|
+ jmp(argument) if get_value(:compare_flag).send(operation, 0)
+ end
+ end
+
+ def initialize(execution_unit)
+ @execution_unit = execution_unit
+ end
+
+ def mov(destination_register, source)
+ @execution_unit.registers[destination_register] = get_value(source)
+ end
+
+ def inc(destination_register, value)
+ mov destination_register, get_value(destination_register) + get_value(value)
+ end
+
+ def dec(destination_register, value)
+ inc destination_register, -get_value(value)
+ end
+
+ def cmp(register, value)
+ mov :compare_flag, get_value(register) <=> get_value(value)
+ end
+
+ def jmp(label)
+ @execution_unit.instruction_pointer = @execution_unit.labels[label]
+ end
+
+ private
+ def get_value(source)
+ if @execution_unit.registers.include? source
+ @execution_unit.registers[source]
+ else
+ source
+ end
+ end
+ end
+
+ class Parser < BasicObject
+ def initialize(labels, instruction_pipeline)
+ @labels = labels
+ @instruction_pipeline = instruction_pipeline
+ end
+
+ def label(name)
+ @labels[name] = @instruction_pipeline.size
+ end
+
+ def method_missing(name, *args)
+ if InstructionExecutorUnit.public_method_defined? name
+ @instruction_pipeline << [name, *args]
+ else
+ name
+ end
+ end
+ end
+
+ class ExecutionUnit
+ attr_reader :labels, :registers
+ attr_accessor :instruction_pointer
+
+ def initialize(&block)
+ @labels = {}
+ @instruction_pipeline = []
+ Parser.new(@labels, @instruction_pipeline).instance_eval &block
+ @instruction_executor_unit = InstructionExecutorUnit.new self
+ @registers = {ax: 0, bx: 0, cx: 0, dx: 0, compare_flag: 0}
+ @instruction_pointer = 0
+ end
+
+ def execute_next_instruction
+ @instruction_pointer += 1
+ instruction = @instruction_pipeline[@instruction_pointer.pred]
+ @instruction_executor_unit.public_send *instruction
+ end
+
+ def finished?
+ @instruction_pipeline.size <= @instruction_pointer
+ end
+
+ def execute_program
+ until finished?
+ execute_next_instruction
+ end
+ end
+ end
+
+ def self.asm(&block)
+ control_flow_unit = ExecutionUnit.new &block
+ control_flow_unit.execute_program
+ [:ax, :bx, :cx, :dx].map do |register_name|
+ control_flow_unit.registers[register_name]
+ end
+ end
+end