Решение на Четвърта задача от Иван Латунов

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

Към профила на Иван Латунов

Резултати

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

Код

class Asm
attr_reader :operations, :labels
[:ax, :bx, :cx, :dx].each {|x| define_method x do x.to_s end}
@@methods = %w(mov inc dec cmp jmp je jne jl jle jg jge)
def initialize
@line = -1
@labels = {}
@operations = []
end
def label(name)
@labels[name.to_s] = @line + 1
end
def method_missing(name, *args)
if @@methods.include? name.to_s
@labels[@line += 1] = @line
@operations << [name, *args]
else
name.to_s
end
end
class Jumper
def initialize(evaluator)
@evaluator = evaluator
end
operations = {
e: :==,
ne: '!=',
l: :<,
le: :<=,
g: :>,
ge: :>=
}
def jmp(label, _)
@evaluator.execute_operations @evaluator.labels[label]
end
operations.each do |name, symbol|
define_method 'j' + name.to_s do |label, current_line|
jump_with_compare(label, current_line, symbol)
end
end
private
def jump_with_compare(label, current_line, symbol)
if @evaluator.last_cmp.send(symbol, 0)
@evaluator.execute_operations(@evaluator.labels[label])
else
@evaluator.execute_operations current_line + 1
end
end
end
class Evaluator
attr_accessor :ax, :bx, :cx, :dx, :last_cmp, :labels
@@jumps = %w(jmp je jne jl jle jg jge)
def initialize(operations, labels)
@ax, @bx, @cx, @dx = 0, 0, 0, 0
@operations = operations
@operations << [:cmp, 0, 0]
@last_cmp = 0
@line_number = -1
@labels = labels
@jumper = Jumper.new self
end
def mov(register, source)
send "#{register}=", value_of(source)
end
def inc(register, source = 1)
send "#{register}=", value_of(register) + value_of(source)
end
def dec(register, source = 1)
inc register, -value_of(source)
end
def cmp(register, source)
@last_cmp = value_of(register) <=> value_of(source)
end
def execute_operations(from_line = 0)
@operations[from_line..-1].each_with_index do |command, index|
if @@jumps.include? command[0].to_s
@jumper.send(command[0], *command[1..-1], index + from_line)
break
else
send(command[0], *command[1..-1])
end
end
return [@ax, @bx, @cx, @dx]
end
private
def value_of(var)
(var.class == Fixnum ? var : instance_variable_get("@#{var}"))
end
end
def self.asm(&block)
assembler = Asm.new
assembler.instance_eval &block
e = Evaluator.new assembler.operations, assembler.labels
e.execute_operations
end
end

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

........

Finished in 0.00839 seconds
8 examples, 0 failures

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

Иван обнови решението на 13.01.2014 01:42 (преди почти 11 години)

+class Asm
+ attr_reader :operations, :labels
+ [:ax, :bx, :cx, :dx].each {|x| define_method x do x.to_s end}
+
+ def initialize
+ @line = -1
+ @labels = {}
+ @operations = []
+ end
+
+ def label(name)
+ @labels[name] = @lines + 1
+ end
+
+ def method_missing(name, *args)
+ @line += 1
+ @operations << [name, *args]
+ end
+
+ class Evaluator
+ attr_accessor :ax, :bx, :cx, :dx
+
+ def initialize(operations, labels)
+ @ax, @bx, @cx, @dx = 0, 0, 0, 0
+ @operations = operations
+ @last_cmp = 0
+ @line_number = -1
+ @labels = labels
+ end
+
+ def mov(register, source)
+ send "#{register}=", value_of(source)
+ end
+
+ def inc(register, source = 1)
+ send "#{register}=", value_of(register) + value_of(source)
+ end
+
+ def dec(register, source = 1)
+ inc register, -value_of(source)
+ end
+
+ def cmp(register, source)
+ value_of(register) <=> value_of(source)
+ end
+
+ def execute_operations
+ @operations.each do |command|
+ send(command.shift, *command)
+ end
+ [@ax, @bx, @cx, @dx]
+ end
+
+ private
+
+ def value_of(var)
+ (var.class == Fixnum ? var : instance_variable_get("@#{var}"))
+ end
+
+ def increment_line
+ @line_number += 1
+ end
+ end
+
+ def Asm.asm(&block)
+ assembler = Asm.new
+ assembler.instance_eval &block
+ e = Evaluator.new assembler.operations, assembler.labels
+ e.execute_operations
+ end
+end

Дотук добре. Само трябва да се добавят jump-овете. Освен това:

  • def Asm.asm -> def self.asm. Не е добра идея да повтаряш името на модула. Това е малък пример за нарушение на DRY принципа. Този принцип обхваща не само повторението на код, но и повторението на имена. Вярно е, че във всички редактори има search&replace, но избягването на повторения винаги е от полза.
  • execute_operations не спазма style guide-а. Последният ред трябва да е отделен с празен ред, ако се връща стойност.

Иван обнови решението на 13.01.2014 20:14 (преди почти 11 години)

class Asm
attr_reader :operations, :labels
[:ax, :bx, :cx, :dx].each {|x| define_method x do x.to_s end}
-
+ @@methods = %w(mov inc dec cmp jmp je jne jl jle jg jge)
def initialize
@line = -1
@labels = {}
@operations = []
end
def label(name)
- @labels[name] = @lines + 1
+ @labels[name.to_s] = @line + 1
end
def method_missing(name, *args)
- @line += 1
- @operations << [name, *args]
+ if @@methods.include? name.to_s
+ @labels[@line += 1] = @line
+ @operations << [name, *args]
+ else
+ name.to_s
+ end
end
+ class Jumper
+
+ def initialize(evaluator)
+ @evaluator = evaluator
+ end
+ operations = {
+ e: :==,
+ ne: '!=',
+ l: :<,
+ le: :<=,
+ g: :>,
+ ge: :>=
+ }
+ def jmp(label, _)
+ @evaluator.execute_operations @evaluator.labels[label]
+ end
+
+ operations.each do |name, symbol|
+ define_method 'j' + name.to_s do |label, current_line|
+ jump_with_compare(label, current_line, symbol)
+ end
+ end
+
+ private
+ def jump_with_compare(label, current_line, symbol)
+ if @evaluator.last_cmp.send(symbol, 0)
+ @evaluator.execute_operations(@evaluator.labels[label])
+ else
+ @evaluator.execute_operations current_line + 1
+ end
+ end
+ end
+
class Evaluator
- attr_accessor :ax, :bx, :cx, :dx
+ attr_accessor :ax, :bx, :cx, :dx, :last_cmp, :labels
+ @@jumps = %w(jmp je jne jl jle jg jge)
def initialize(operations, labels)
@ax, @bx, @cx, @dx = 0, 0, 0, 0
@operations = operations
+ @operations << [:cmp, 0, 0]
@last_cmp = 0
@line_number = -1
@labels = labels
+ @jumper = Jumper.new self
end
def mov(register, source)
send "#{register}=", value_of(source)
end
def inc(register, source = 1)
send "#{register}=", value_of(register) + value_of(source)
end
def dec(register, source = 1)
inc register, -value_of(source)
end
def cmp(register, source)
- value_of(register) <=> value_of(source)
+ @last_cmp = value_of(register) <=> value_of(source)
end
- def execute_operations
- @operations.each do |command|
- send(command.shift, *command)
+ def execute_operations(from_line = 0)
+
+ @operations[from_line..-1].each_with_index do |command, index|
+ if @@jumps.include? command[0].to_s
+ @jumper.send(command[0], *command[1..-1], index + from_line)
+ break
+ else
+ send(command[0], *command[1..-1])
+ end
+
end
- [@ax, @bx, @cx, @dx]
+
+ return [@ax, @bx, @cx, @dx]
end
private
def value_of(var)
(var.class == Fixnum ? var : instance_variable_get("@#{var}"))
end
-
- def increment_line
- @line_number += 1
- end
end
- def Asm.asm(&block)
+ def self.asm(&block)
assembler = Asm.new
assembler.instance_eval &block
e = Evaluator.new assembler.operations, assembler.labels
e.execute_operations
end
-end
+end
+
+q = Asm.asm do
+ mov ax, 40
+ mov bx, 32
+ label cycle
+ cmp ax, bx
+ je finish
+ jl asmaller
+ dec ax, bx
+ jmp cycle
+ label asmaller
+ dec bx, ax
+ jmp cycle
+ label finish
+end # => [8, 8, 0, 0]
+
+p q

Иван обнови решението на 14.01.2014 00:26 (преди почти 11 години)

class Asm
attr_reader :operations, :labels
[:ax, :bx, :cx, :dx].each {|x| define_method x do x.to_s end}
@@methods = %w(mov inc dec cmp jmp je jne jl jle jg jge)
def initialize
@line = -1
@labels = {}
@operations = []
end
def label(name)
@labels[name.to_s] = @line + 1
end
def method_missing(name, *args)
if @@methods.include? name.to_s
@labels[@line += 1] = @line
@operations << [name, *args]
else
name.to_s
end
end
class Jumper
def initialize(evaluator)
@evaluator = evaluator
end
operations = {
e: :==,
ne: '!=',
l: :<,
le: :<=,
g: :>,
ge: :>=
}
def jmp(label, _)
@evaluator.execute_operations @evaluator.labels[label]
end
operations.each do |name, symbol|
define_method 'j' + name.to_s do |label, current_line|
jump_with_compare(label, current_line, symbol)
end
end
private
def jump_with_compare(label, current_line, symbol)
if @evaluator.last_cmp.send(symbol, 0)
@evaluator.execute_operations(@evaluator.labels[label])
else
@evaluator.execute_operations current_line + 1
end
end
end
class Evaluator
attr_accessor :ax, :bx, :cx, :dx, :last_cmp, :labels
@@jumps = %w(jmp je jne jl jle jg jge)
def initialize(operations, labels)
@ax, @bx, @cx, @dx = 0, 0, 0, 0
@operations = operations
@operations << [:cmp, 0, 0]
@last_cmp = 0
@line_number = -1
@labels = labels
@jumper = Jumper.new self
end
def mov(register, source)
send "#{register}=", value_of(source)
end
def inc(register, source = 1)
send "#{register}=", value_of(register) + value_of(source)
end
def dec(register, source = 1)
inc register, -value_of(source)
end
def cmp(register, source)
@last_cmp = value_of(register) <=> value_of(source)
end
def execute_operations(from_line = 0)
@operations[from_line..-1].each_with_index do |command, index|
if @@jumps.include? command[0].to_s
@jumper.send(command[0], *command[1..-1], index + from_line)
break
else
send(command[0], *command[1..-1])
end
end
return [@ax, @bx, @cx, @dx]
end
private
def value_of(var)
(var.class == Fixnum ? var : instance_variable_get("@#{var}"))
end
end
def self.asm(&block)
assembler = Asm.new
assembler.instance_eval &block
e = Evaluator.new assembler.operations, assembler.labels
+
e.execute_operations
end
end
-
-q = Asm.asm do
- mov ax, 40
- mov bx, 32
- label cycle
- cmp ax, bx
- je finish
- jl asmaller
- dec ax, bx
- jmp cycle
- label asmaller
- dec bx, ax
- jmp cycle
- label finish
-end # => [8, 8, 0, 0]
-
-p q