Мария обнови решението на 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
, още повече като се вземе предвид имплементацията на тези методи. Направи нещо по въпроса.