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

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

Към профила на Красимира Божанова

Резултати

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

Код

module Asm
def self.asm(&block)
parser = BlockParser.new
parser.instance_eval &block
EvaluateAssembler.new(parser.block_array, parser.labels).get_registers
end
class BlockParser
attr_reader :block_array, :labels
ASSEMBLER_METHODS = [:mov, :inc, :dec, :cmp, :jmp, :je, :jne, :jg, :jge, :jle, :jl]
ASSEMBLER_METHODS.each do |method_name|
define_method method_name do |*args|
@block_array << [method_name, *args]
end
end
def initialize
@block_array = []
@labels = {}
end
def label(label_name)
@labels[label_name] = @block_array.size
end
def method_missing(method_name, *args, &block)
method_name.to_sym
end
end
class EvaluateAssembler
attr_accessor :register_ax, :register_bx, :register_cx, :register_dx
METHODS_JUMP = {
je: :==,
jne: :!=,
jl: :<,
jle: :<=,
jg: :>,
jge: :>=,
}
METHODS_MODIFY = {
inc: :+,
dec: :-,
}
METHODS_JUMP.each do |method_name, operation|
define_method method_name do |where|
if @last_comparing.send operation, 0
jmp where
end
end
end
METHODS_MODIFY.each do |method_name, operation|
define_method method_name do |destination_register, value|
destination_register_value = send "register_" + destination_register.to_s
modify_with = destination_register_value.send operation, get_value(value)
send "register_" + "#{destination_register}=", modify_with
end
end
def initialize(block_array, labels)
@register_ax, @register_bx, @register_cx, @register_dx = 0, 0, 0, 0
@commands = block_array
@labels = labels
@current_command = 0
@last_comparing = 0
evaluate
end
def evaluate
while @current_command < @commands.size
send *@commands[@current_command]
@current_command = @current_command + 1
end
end
def get_registers
[@register_ax, @register_bx, @register_cx, @register_dx]
end
def mov(destination_register, source)
send "register_" + "#{destination_register}=", get_value(source)
end
def cmp(register, value)
@last_comparing = (send "register_" + register.to_s) <=> get_value(value)
end
def jmp(where)
if where.is_a?(Numeric)
@current_command = where - 1
else
@current_command = @labels[where] - 1
end
end
def get_value(value)
value.is_a?(Symbol) ? (send "register_" + value.to_s) : value
end
private :get_value, :evaluate
end
end

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

..FF..F.

Failures:

  1) Asm.asm implements INC
     Failure/Error: Asm.asm do
     ArgumentError:
       wrong number of arguments (1 for 2)
     # /tmp/d20140115-8451-60cqap/solution.rb:59:in `block (2 levels) in <class:EvaluateAssembler>'
     # /tmp/d20140115-8451-60cqap/solution.rb:77:in `evaluate'
     # /tmp/d20140115-8451-60cqap/solution.rb:72:in `initialize'
     # /tmp/d20140115-8451-60cqap/solution.rb:5:in `new'
     # /tmp/d20140115-8451-60cqap/solution.rb:5:in `asm'
     # /tmp/d20140115-8451-60cqap/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-60cqap/solution.rb:59:in `block (2 levels) in <class:EvaluateAssembler>'
     # /tmp/d20140115-8451-60cqap/solution.rb:77:in `evaluate'
     # /tmp/d20140115-8451-60cqap/solution.rb:72:in `initialize'
     # /tmp/d20140115-8451-60cqap/solution.rb:5:in `new'
     # /tmp/d20140115-8451-60cqap/solution.rb:5:in `asm'
     # /tmp/d20140115-8451-60cqap/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 LABEL
     Failure/Error: Asm.asm do
     ArgumentError:
       wrong number of arguments (1 for 2)
     # /tmp/d20140115-8451-60cqap/solution.rb:59:in `block (2 levels) in <class:EvaluateAssembler>'
     # /tmp/d20140115-8451-60cqap/solution.rb:77:in `evaluate'
     # /tmp/d20140115-8451-60cqap/solution.rb:72:in `initialize'
     # /tmp/d20140115-8451-60cqap/solution.rb:5:in `new'
     # /tmp/d20140115-8451-60cqap/solution.rb:5:in `asm'
     # /tmp/d20140115-8451-60cqap/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.00952 seconds
8 examples, 3 failures

Failed examples:

rspec /tmp/d20140115-8451-60cqap/spec.rb:14 # Asm.asm implements INC
rspec /tmp/d20140115-8451-60cqap/spec.rb:22 # Asm.asm implements DEC
rspec /tmp/d20140115-8451-60cqap/spec.rb:77 # Asm.asm implements LABEL

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

Красимира обнови решението на 15.01.2014 10:52 (преди почти 11 години)

+module Asm
+ def self.asm(&block)
+ parser = BlockParser.new
+ parser.instance_eval &block
+ EvaluateAssembler.new(parser.block_array, parser.labels).get_registers
+ end
+
+ class BlockParser
+ attr_reader :block_array, :labels
+
+ ASSEMBLER_METHODS = [:mov, :inc, :dec, :cmp, :jmp, :je, :jne, :jg, :jge, :jle, :jl]
+
+ ASSEMBLER_METHODS.each do |method_name|
+ define_method method_name do |*args|
+ @block_array << [method_name, *args]
+ end
+ end
+
+ def initialize
+ @block_array = []
+ @labels = {}
+ end
+
+ def label(label_name)
+ @labels[label_name] = @block_array.size
+ end
+
+ def method_missing(method_name, *args, &block)
+ method_name.to_sym
+ end
+ end
+
+ class EvaluateAssembler
+ attr_accessor :register_ax, :register_bx, :register_cx, :register_dx
+
+ METHODS_JUMP = {
+ je: :==,
+ jne: :!=,
+ jl: :<,
+ jle: :<=,
+ jg: :>,
+ jge: :>=,
+ }
+
+ METHODS_MODIFY = {
+ inc: :+,
+ dec: :-,
+ }
+
+ METHODS_JUMP.each do |method_name, operation|
+ define_method method_name do |where|
+ if @last_comparing.send operation, 0
+ jmp where
+ end
+ end
+ end
+
+ METHODS_MODIFY.each do |method_name, operation|
+ define_method method_name do |destination_register, value|
+ destination_register_value = send "register_" + destination_register.to_s
+ modify_with = destination_register_value.send operation, get_value(value)
+ send "register_" + "#{destination_register}=", modify_with
+ end
+ end
+
+ def initialize(block_array, labels)
+ @register_ax, @register_bx, @register_cx, @register_dx = 0, 0, 0, 0
+ @commands = block_array
+ @labels = labels
+ @current_command = 0
+ @last_comparing = 0
+ evaluate
+ end
+
+ def evaluate
+ while @current_command < @commands.size
+ send *@commands[@current_command]
+ @current_command = @current_command + 1
+ end
+ end
+
+ def get_registers
+ [@register_ax, @register_bx, @register_cx, @register_dx]
+ end
+
+ def mov(destination_register, source)
+ send "register_" + "#{destination_register}=", get_value(source)
+ end
+
+ def cmp(register, value)
+ @last_comparing = (send "register_" + register.to_s) <=> get_value(value)
+ end
+
+ def jmp(where)
+ if where.is_a?(Numeric)
+ @current_command = where - 1
+ else
+ @current_command = @labels[where] - 1
+ end
+ end
+
+ def get_value(value)
+ value.is_a?(Symbol) ? (send "register_" + value.to_s) : value
+ end
+
+ private :get_value, :evaluate
+ end
+end

Харесва ми името на класа EvaluateAssembler и как го ползваш.

Употребата на private в него не е много канонична. Щеше да е по-добре да сложиш дефиницията на двата такива метода под private декларация, както си му е редът.

Като цяло, решението изглежда добре. Ще видим с тестовете :)