Иван обнови решението на 15.01.2014 16:46 (преди почти 11 години)
+module Asm
+ class Register
+ include Comparable
+ attr_reader :value
+
+ def initialize (value=0)
+ @value = value
+ end
+
+ def +(other)
+ @value += other.to_i
+ self
+ end
+
+ def -(other)
+ @value -= other.to_i
+ self
+ end
+
+ def assign(value)
+ @value = value.to_i
+ end
+
+ def to_i
+ @value
+ end
+
+ def <=>(other)
+ to_i <=> other.to_i
+ end
+ end
+
+ module Arithmetics
+ attr_reader :arithmetic_flag
+
+ def inc (destination, value=1)
+ destination += value
+ end
+
+ def dec (destination, value=1)
+ destination -= value
+ end
+
+ def mov (destination, source)
+ destination.assign source
+ end
+
+ def cmp (register, value)
+ @arithmetic_flag = register <=> value
+ end
+ end
+
+ module Registers
+ attr_reader :ax, :bx, :cx, :dx
+ end
+
+ module Locator
+ attr_reader :labels, :ip
+
+ def jmp (label)
+ @ip = label.is_a?(Numeric) ? label - 1 : labels[[label]]
+ end
+
+ def label (name)
+ end
+
+ def je (label)
+ jmp label if @arithmetic_flag.zero?
+ end
+
+ def jne (label)
+ jmp label if @arithmetic_flag.nonzero?
+ end
+
+ def jl (label)
+ jmp label if @arithmetic_flag < 0
+ end
+
+ def jle (label)
+ jmp label if @arithmetic_flag <= 0
+ end
+
+ def jg (label)
+ jmp label if @arithmetic_flag > 0
+ end
+
+ def jge (label)
+ jmp label if @arithmetic_flag >= 0
+ end
+ end
+
+ class Assembler
+ include Arithmetics
+ include Registers
+ include Locator
+
+ @registerSet = Registers.instance_methods
+ @instructionSet = Arithmetics.instance_methods + Locator.instance_methods
+
+ class << self
+ attr_accessor :instructionSet, :registerSet
+ end
+
+ def get_registers
+ [@ax.to_i, @bx.to_i, @cx.to_i, @dx.to_i]
+ end
+
+ def initialize
+ @ip = 0
+ @labels = {}
+ @ax, @bx, @cx, @dx = Register.new, Register.new, Register.new, Register.new
+ @arithmetic_flag = 0
+ end
+
+ def initialize_labels (instructions)
+ instructions.each do |instruction|
+ if instruction.name == :label
+ @labels[instruction.args] = instructions.index(instruction)
+ end
+ end
+ end
+
+ def execute (instructions)
+ unless instructions.empty?
+ initialize_labels instructions
+ begin
+ send(instructions[@ip].name, *instructions[@ip].args)
+ @ip+=1
+ end until @ip == instructions.size
+ end
+ get_registers
+ end
+ end
+
+ class Instruction
+ attr_accessor :name, :args
+
+ def initialize(name="", args=[])
+ @name, @args = name, args
+ end
+ end
+
+ class Evaluator
+ attr_reader :instructions
+
+ def initialize (assembler)
+ @instructions = []
+ @assembler = assembler
+ end
+
+ def method_missing(name, *args, &block)
+ if Assembler.instructionSet.include?(name)
+ return @instructions << (Instruction.new name, args)
+ elsif Assembler.registerSet.include?(name)
+ return @assembler.send(name)
+ end
+ name
+ end
+
+ end
+
+ def self.asm(&block)
+ assembler = Assembler.new
+ evaluator = Evaluator.new(assembler)
+ evaluator.instance_eval &block
+ assembler.execute evaluator.instructions
+ end
+end
Имаш разни дребни стилистични проблеми:
- Не оставяй интервал преди отварящата скоба при дефиниция/извикване на метод:
def jg (label)
. Освен това го правиш неконсистентно (не навсякъде си оставял интервал там). - Трябва да има интервали около оператори като
+=
,=
и прочее. - Не трябва да има празен ред на ред 159.