Решение на Четвърта задача от Мария Терзиева

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

Към профила на Мария Терзиева

Резултати

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

Код

module Asm
def self.asm(&block)
Evaluator.new.evaluate &block
end
module Jumps
def execute_jmp(where)
from = where.is_a?(Symbol) ? send(where) : where
@current_instruction = from - 1
end
def execute_je(where)
execute_jmp where if @flag == 0
end
def execute_jne(where)
execute_jmp where if @flag != 0
end
def execute_jl(where)
execute_jmp where if @flag < 0
end
def execute_jle(where)
execute_jmp where if @flag <= 0
end
def execute_jg(where)
execute_jmp where if @flag > 0
end
def execute_jge(where)
execute_jmp where if @flag >= 0
end
end
module Instructions
include Jumps
def execute_mov(destination_register, source)
if source.is_a? Fixnum
@registers[destination_register] = source
else
@registers[destination_register] = @registers[source]
end
end
def execute_inc(destination_register, value=1)
if value.is_a? Fixnum
@registers[destination_register] += value
else
@registers[destination_register] += @registers[value]
end
end
def execute_dec(destination_register, value=1)
if value.is_a? Fixnum
@registers[destination_register] -= value
else
@registers[destination_register] -= @registers[value]
end
end
def execute_cmp(register, value)
if value.is_a? Fixnum
@flag = @registers[register] <=> value
else
@flag = @registers[register] <=> @registers[value]
end
end
end
class Evaluator
include Instructions
functions = [:mov, :inc, :dec, :cmp, :jmp, :je, :jne, :jl, :jle, :jg, :jge]
functions.each do |function|
define_method function do |*args|
@instructions << [function, *args]
end
end
def initialize
@registers = {ax: 0, bx: 0, cx: 0, dx: 0}
@flag = 0
@instructions = []
@current_instruction = 0
end
def label(label_name)
next_instruction = @instructions.size
singleton_class.class_eval do
define_method(label_name) { next_instruction }
end
end
def evaluate(&block)
instance_eval &block
until @current_instruction == @instructions.size
name, *args = @instructions[@current_instruction]
send "execute_#{name}".to_sym, *args
@current_instruction += 1
end
@registers.values
end
def method_missing(method, *args, &block)
singleton_class.class_eval do
define_method(method) { __method__ }
end
end
end
end

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

........

Finished in 0.00759 seconds
8 examples, 0 failures

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

Мария обнови решението на 13.01.2014 13:12 (преди почти 11 години)

+module Asm
+ def self.asm(&block)
+ Evaluator.new.evaluate &block
+ end
+
+ module Jumps
+ def execute_jmp(where)
+ from = where.is_a?(Symbol) ? send(where) : where
+ @current_instruction = from - 1
+ end
+
+ def execute_je(where)
+ if @flags == 0
+ execute_jmp where
+ end
+ end
+
+ def execute_jne(where)
+ if @flags != 0
+ execute_jmp where
+ end
+ end
+
+ def execute_jl(where)
+ if @flags < 0
+ execute_jmp where
+ end
+ end
+
+ def execute_jle(where)
+ if @flags <= 0
+ execute_jmp where
+ end
+ end
+
+ def execute_jg(where)
+ if @flags > 0
+ execute_jmp where
+ end
+ end
+
+ def execute_jge(where)
+ if @flags >= 0
+ execute_jmp where
+ end
+ end
+ end
+
+
+ module Instructions
+ include Jumps
+
+ def execute_mov(destination_register, source)
+ if source.is_a? Fixnum
+ @registers[destination_register] = source
+ else
+ @registers[destination_register] = @registers[source]
+ end
+ end
+
+ def execute_inc(destination_register, value=1)
+ if value.is_a? Fixnum
+ @registers[destination_register] += value
+ else
+ @registers[destination_register] += @registers[value]
+ end
+ end
+
+ def execute_dec(destination_register, value=1)
+ if value.is_a? Fixnum
+ @registers[destination_register] -= value
+ else
+ @registers[destination_register] -= @registers[value]
+ end
+ end
+
+ def execute_cmp(register, value)
+ if value.is_a? Fixnum
+ @flags = @registers[register] <=> value
+ else
+ @flags = @registers[register] <=> @registers[value]
+ end
+ end
+ end
+
+
+ class Evaluator
+ include Instructions
+
+ functions = [:mov, :inc, :dec, :cmp, :jmp, :je, :jne, :jl, :jle, :jg, :jge]
+ functions.each do |function|
+ define_method function do |*args|
+ @instructions << [function, *args]
+ end
+ end
+
+ def initialize
+ @registers = {ax: 0, bx: 0, cx: 0, dx: 0}
+ @flags = 0
+ @instructions = []
+ @current_instruction = 0
+ end
+
+ def label(label_name)
+ next_instruction = @instructions.size
+ singleton_class.class_eval do
+ define_method(label_name) { next_instruction }
+ end
+ end
+
+ def evaluate(&block)
+ instance_eval &block
+ until @current_instruction == @instructions.size
+ name, *args = @instructions[@current_instruction]
+ send "execute_#{name}".to_sym, *args
+ @current_instruction += 1
+ end
+ @registers.values
+ end
+
+ def method_missing(method, *args, &block)
+ singleton_class.class_eval do
+ define_method(method) { __method__ }
+ end
+ end
+ end
+end

Мария Терезиева:

  • Можеш да направиш if-овете в Jumps едноредови, например: execute_jmp where if @flags >= 0. Помисли също така доколко са DRY (виж по-долу).
  • @flags не е колекция от неща => трябва да се казва @flag
  • Има прекалено много повторения в методите на модула Instructions. Това е code smell и нарушава DRY принципа. Абстрахирай if-овете в помощен метод.
  • Не е добра идея да дефинираш нов метод за всеки label в method_missing, още повече като се вземе предвид имплементацията на тези методи. Направи нещо по въпроса.

Мария обнови решението на 14.01.2014 13:50 (преди почти 11 години)

module Asm
def self.asm(&block)
Evaluator.new.evaluate &block
end
module Jumps
def execute_jmp(where)
from = where.is_a?(Symbol) ? send(where) : where
@current_instruction = from - 1
end
def execute_je(where)
- if @flags == 0
- execute_jmp where
- end
+ execute_jmp where if @flag == 0
end
def execute_jne(where)
- if @flags != 0
- execute_jmp where
- end
+ execute_jmp where if @flag != 0
end
def execute_jl(where)
- if @flags < 0
- execute_jmp where
- end
+ execute_jmp where if @flag < 0
end
def execute_jle(where)
- if @flags <= 0
- execute_jmp where
- end
+ execute_jmp where if @flag <= 0
end
def execute_jg(where)
- if @flags > 0
- execute_jmp where
- end
+ execute_jmp where if @flag > 0
end
def execute_jge(where)
- if @flags >= 0
- execute_jmp where
- end
+ execute_jmp where if @flag >= 0
end
end
module Instructions
include Jumps
def execute_mov(destination_register, source)
if source.is_a? Fixnum
@registers[destination_register] = source
else
@registers[destination_register] = @registers[source]
end
end
def execute_inc(destination_register, value=1)
if value.is_a? Fixnum
@registers[destination_register] += value
else
@registers[destination_register] += @registers[value]
end
end
def execute_dec(destination_register, value=1)
if value.is_a? Fixnum
@registers[destination_register] -= value
else
@registers[destination_register] -= @registers[value]
end
end
def execute_cmp(register, value)
if value.is_a? Fixnum
- @flags = @registers[register] <=> value
+ @flag = @registers[register] <=> value
else
- @flags = @registers[register] <=> @registers[value]
+ @flag = @registers[register] <=> @registers[value]
end
end
end
class Evaluator
include Instructions
functions = [:mov, :inc, :dec, :cmp, :jmp, :je, :jne, :jl, :jle, :jg, :jge]
functions.each do |function|
define_method function do |*args|
@instructions << [function, *args]
end
end
def initialize
@registers = {ax: 0, bx: 0, cx: 0, dx: 0}
- @flags = 0
+ @flag = 0
@instructions = []
@current_instruction = 0
end
def label(label_name)
next_instruction = @instructions.size
singleton_class.class_eval do
define_method(label_name) { next_instruction }
end
end
def evaluate(&block)
instance_eval &block
until @current_instruction == @instructions.size
name, *args = @instructions[@current_instruction]
send "execute_#{name}".to_sym, *args
@current_instruction += 1
end
@registers.values
end
def method_missing(method, *args, &block)
singleton_class.class_eval do
define_method(method) { __method__ }
end
end
end
-end
+end

Благодаря за feedback-a!

  • Оправих @flags и направих jump-овете на по един ред.
  • Относно method_missing знам, че не е добра идея, но не ми хрумва нищо друго.
  • Относно DRY, когато се опитах да направя нещо такова:

      module Instructions
        include Jumps
    
        def instruction(register, source, initial_value=0, operation)
          fixnum_source = source.is_a?(Fixnum) ? source : @registers[source]
          if register.is_a?(Fixnum)
            register = initial_value.send(operation, fixnum_source)
          else
            @registers[register] = initial_value.send(operation, fixnum_source)
          end
        end
    
        def execute_mov(destination_register, source)
          instruction(destination_register, source, :+)
        end
    
        def execute_inc(destination_register, value=1)
          instruction(destination_register, value, @registers[destination_register], :+)
        end
    
        def execute_dec(destination_register, value=1)
          instruction(destination_register, value, @registers[destination_register], :-)
        end
    
        def execute_cmp(register, value)
          instruction(@flag, value, @registers[register], :<=>)
        end
      end
    

    кодът ми се счупи.

  • Ако ми остане време, ще поработя още по тези неща.