rubyx/lib/register/instruction.rb
Torsten Ruger 229f5896c6 update to use new ast
soml was updated to have a typed ast layer to make programatic creation
easier
this brings LOTS of syntax change with it, that does not really mean
anything at all
All tests pass again so back to the same
2016-03-07 11:55:28 +02:00

132 lines
3.8 KiB
Ruby

module Register
# the register machine has at least 8 registers, named r0-r5 , :lr and :pc (for historical reasons)
# we can load and store their contents and
# access (get/set) memory at a constant offset from a register
# while the vm works with objects, the register machine has registers,
# but we keep the names for better understanding, r4/5 are temporary/scratch
# there is no direct memory access, only through registers
# constants can/must be loaded into registers before use
# Instructions form a graph.
# Linear instructions form a linked list
# Branches fan out, Labels collect
# Labels are the only valid branch targets
class Instruction
include Positioned
def initialize source , nekst = nil
@source = source
@next = nekst
return unless source
raise "Source must be string or ast node, not #{source.class}" unless source.is_a?(String) or source.is_a?(Soml::Code)
end
attr_reader :source
# set the next instruction (also aliased as <<)
# throw an error if that is set, use insert for that use case
# return the instruction, so chaining works as one wants (not backwards)
def set_next nekst
raise "Next already set #{@next}" if @next
@next = nekst
nekst
end
alias :<< :set_next
# during translation we replace one by one
def replace_next nekst
old = @next
@next = nekst
@next.append old.next if old
end
# get the next instruction (without arg given )
# when given an interger, advance along the line that many time and return.
def next( amount = 1)
(amount == 1) ? @next : @next.next(amount-1)
end
# set the give instruction as the next, while moving any existing
# instruction along to the given ones's next.
# ie insert into the linked list that the instructions form
def insert instruction
instruction.set_next @next
@next = instruction
end
# return last set instruction. ie follow the linked list until it stops
def last
code = self
code = code.next while( code.next )
return code
end
# set next for the last (see last)
# so append the given code to the linked list at the end
def append code
last.set_next code
end
def length labels = []
ret = 1
ret += self.next.length( labels ) if self.next
ret
end
def to_ac labels = []
ret = [self.class]
ret += self.next.to_ac(labels) if self.next
ret
end
# derived classes must provide a byte_length
def byte_length
raise "Abstract called on #{self}"
end
def assemble_all io , labels = []
self.assemble(io)
self.next.assemble_all(io, labels) if self.next
end
def assemble io
raise "Abstract called on #{self}"
end
def total_byte_length labels = []
ret = self.byte_length
ret += self.next.total_byte_length(labels) if self.next
#puts "#{self.class.name} return #{ret}"
ret
end
def set_position position , labels = []
self.position = position
position += byte_length
if self.next
self.next.set_position(position , labels)
else
position
end
end
def each_label labels =[] , &block
self.next.each_label(labels , &block) if self.next
end
end
end
require_relative "instructions/set_slot"
require_relative "instructions/get_slot"
require_relative "instructions/set_byte"
require_relative "instructions/get_byte"
require_relative "instructions/load_constant"
require_relative "instructions/syscall"
require_relative "instructions/function_call"
require_relative "instructions/function_return"
require_relative "instructions/register_transfer"
require_relative "instructions/label"
require_relative "instructions/branch"
require_relative "instructions/operator_instruction"