getting better, but somethings off
This commit is contained in:
parent
a61170942f
commit
7c0aa8ae7d
@ -30,11 +30,14 @@ module Arm
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def word_load value
|
def word_load value , reg
|
||||||
"word"
|
e = Vm::Block.new("load_#{value}")
|
||||||
|
e.add_code( MoveInstruction.new( :left => reg , :right => value ) )
|
||||||
end
|
end
|
||||||
def function_call call_value
|
def function_call call
|
||||||
"call"
|
raise "Not FunctionCall #{call.inspect}" unless call.is_a? Vm::FunctionCall
|
||||||
|
e = Vm::Block.new("call_#{call.name}")
|
||||||
|
e.add_code( bl( :function => call.function ))
|
||||||
end
|
end
|
||||||
|
|
||||||
def main_entry
|
def main_entry
|
||||||
@ -47,8 +50,8 @@ module Arm
|
|||||||
end
|
end
|
||||||
def syscall num
|
def syscall num
|
||||||
e = Vm::Block.new("syscall")
|
e = Vm::Block.new("syscall")
|
||||||
e.add_code( MoveInstruction.new( 7 , num ) )
|
e.add_code( MoveInstruction.new( :left => 7 , :right => num ) )
|
||||||
e.add_code( CallInstruction.new( :swi ) )
|
e.add_code( CallInstruction.new( :swi => 0 ) )
|
||||||
e
|
e
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,7 +7,7 @@ module Vm
|
|||||||
# Blocks must end in control instructions (jump/call/return).
|
# Blocks must end in control instructions (jump/call/return).
|
||||||
# And the only valid argument for a jump is a Block
|
# And the only valid argument for a jump is a Block
|
||||||
|
|
||||||
# Blocks for a double linked list so one can traverse back and forth
|
# Blocks form a linked list
|
||||||
|
|
||||||
# There are four ways for a block to get data (to work on)
|
# There are four ways for a block to get data (to work on)
|
||||||
# - hard coded constants (embedded in code)
|
# - hard coded constants (embedded in code)
|
||||||
@ -16,43 +16,70 @@ module Vm
|
|||||||
|
|
||||||
# See Value description on how to create code/instructions
|
# See Value description on how to create code/instructions
|
||||||
|
|
||||||
|
# Blocks have a list of expressions, that they compile into a list of codes
|
||||||
|
# Codes then get assembled into bytes (after positioning)
|
||||||
|
|
||||||
class Block < Code
|
class Block < Code
|
||||||
|
|
||||||
def initialize(name)
|
def initialize(name)
|
||||||
super()
|
super()
|
||||||
@name = name.to_sym
|
@name = name.to_sym
|
||||||
@next = nil
|
@next = nil
|
||||||
@previous = nil
|
@values = []
|
||||||
@codes = []
|
@codes = []
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :name , :previous , :next
|
attr_reader :name , :next , :codes , :values
|
||||||
|
|
||||||
def verify
|
def verify
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_value v
|
||||||
|
@values << v
|
||||||
|
end
|
||||||
|
def length
|
||||||
|
@codes.inject(0) {| sum , item | sum + item.length}
|
||||||
|
end
|
||||||
def add_code(kode)
|
def add_code(kode)
|
||||||
kode.at(@position)
|
kode.at(@position)
|
||||||
length = kode.length
|
length = kode.length
|
||||||
puts "length #{length}"
|
|
||||||
@position += length
|
@position += length
|
||||||
@codes << kode
|
@codes << kode
|
||||||
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def compile context
|
||||||
|
@values.each do |value|
|
||||||
|
value.compile(context)
|
||||||
|
end
|
||||||
|
end
|
||||||
def assemble(io)
|
def assemble(io)
|
||||||
@codes.each do |obj|
|
@codes.each do |obj|
|
||||||
obj.assemble io
|
obj.assemble io
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# all machine methods produce blocks so it's a unified interface. But often they are just linear
|
||||||
|
# code after linear code, so then they can be joined.
|
||||||
|
# The other block is useless after, all instructions move here
|
||||||
|
def join other
|
||||||
|
raise "block is chained already, can't join #{inspect}" if @next
|
||||||
|
other.codes.each do |code|
|
||||||
|
add_code code
|
||||||
|
end
|
||||||
|
other.values.each do |value|
|
||||||
|
add_value value
|
||||||
|
end
|
||||||
|
self
|
||||||
|
end
|
||||||
# set the next executed block after self.
|
# set the next executed block after self.
|
||||||
# why is this useful? if it's unconditional, why not merge them:
|
# why is this useful? if it's unconditional, why not merge them:
|
||||||
# So the second block can be used as a jump target. You standard loop needs a block to setup
|
# So the second block can be used as a jump target. You standard loop needs a block to setup
|
||||||
# and at least one to do the calculation
|
# and at least one to do the calculation
|
||||||
def next block
|
def next block
|
||||||
block.previous = self
|
@next = block
|
||||||
self.next = block
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
@ -13,9 +13,9 @@ module Vm
|
|||||||
# The first setting the position, the second assembling
|
# The first setting the position, the second assembling
|
||||||
class Code < Value
|
class Code < Value
|
||||||
|
|
||||||
# just sets position to nil, so we can sell that it has not been set
|
# set the position to zero, will have to reset later
|
||||||
def initialize
|
def initialize
|
||||||
@position = nil
|
@position = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
# the position in the stream. Think of it as an address if you want. The difference is small.
|
# the position in the stream. Think of it as an address if you want. The difference is small.
|
||||||
@ -35,7 +35,7 @@ module Vm
|
|||||||
|
|
||||||
# length for this code in bytes
|
# length for this code in bytes
|
||||||
def length
|
def length
|
||||||
throw "Not implemented #{self}"
|
raise "Not implemented #{self}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# so currently the interface passes the io (usually string_io) in for the code to assemble itself.
|
# so currently the interface passes the io (usually string_io) in for the code to assemble itself.
|
||||||
|
@ -14,7 +14,7 @@ module Vm
|
|||||||
FunctionCall.new( name , args.collect{ |a| a.to_value } )
|
FunctionCall.new( name , args.collect{ |a| a.to_value } )
|
||||||
end
|
end
|
||||||
def string_value
|
def string_value
|
||||||
ObjectReference.new( string )
|
ObjectReference.new( StringValue.new(string) )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -10,25 +10,25 @@ module Vm
|
|||||||
# but there is no branch created between them, this must be done by the programmer.
|
# but there is no branch created between them, this must be done by the programmer.
|
||||||
|
|
||||||
|
|
||||||
class Function < Value
|
class Function < Block
|
||||||
|
|
||||||
def initialize(name , args = [])
|
def initialize(name , args = [])
|
||||||
super()
|
super(name)
|
||||||
@name = name
|
|
||||||
@args = args
|
@args = args
|
||||||
@entry = Block.new("entry_#{name}")
|
@entry = Block.new("entry_#{name}")
|
||||||
@exit = Block.new("exit_#{name}")
|
@exit = Block.new("exit_#{name}")
|
||||||
end
|
end
|
||||||
attr_reader :name , :args , :entry , :exit
|
attr_reader :args , :entry , :exit
|
||||||
|
|
||||||
def arity
|
def arity
|
||||||
@args.length
|
@args.length
|
||||||
end
|
end
|
||||||
|
|
||||||
def compile function_expression , context
|
def length
|
||||||
arguments = function_expression.args.collect do |arg|
|
@entry.length + @exit.length + super
|
||||||
add_arg arg.to_value
|
end
|
||||||
end
|
|
||||||
|
def compile context
|
||||||
function = context.program.get_function(name)
|
function = context.program.get_function(name)
|
||||||
unless function
|
unless function
|
||||||
function = Vm::Kernel.send(name)
|
function = Vm::Kernel.send(name)
|
||||||
|
@ -2,31 +2,37 @@ module Vm
|
|||||||
|
|
||||||
# name and args , return
|
# name and args , return
|
||||||
|
|
||||||
class FunctionCall < Value
|
class FunctionCall < Block
|
||||||
|
|
||||||
def initialize(name , args)
|
def initialize(name , args)
|
||||||
|
super(name)
|
||||||
@name = name
|
@name = name
|
||||||
@args = args
|
@values = args
|
||||||
@function = nil
|
@function = nil
|
||||||
end
|
end
|
||||||
attr_reader :name , :args , :function
|
attr_reader :function
|
||||||
|
def args
|
||||||
|
values
|
||||||
|
end
|
||||||
|
|
||||||
def compile context
|
def compile context
|
||||||
@function = context.program.get_function @name
|
@function = context.program.get_function @name
|
||||||
if @function
|
if @function
|
||||||
raise "error #{self}" unless function.arity != @args.length
|
raise "error #{self}" unless @function.arity != @values.length
|
||||||
else
|
else
|
||||||
@function = context.program.get_or_create_function @name
|
@function = context.program.get_or_create_function @name
|
||||||
end
|
end
|
||||||
args.each_with_index do |arg , index|
|
args.each_with_index do |arg |
|
||||||
arg.load
|
|
||||||
arg.compile context
|
arg.compile context
|
||||||
end
|
end
|
||||||
|
args.each_with_index do |arg , index|
|
||||||
|
arg.load index
|
||||||
|
end
|
||||||
#puts "funcall #{self.inspect}"
|
#puts "funcall #{self.inspect}"
|
||||||
self.call
|
self.do_call
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def do_call
|
||||||
Machine.instance.function_call self
|
Machine.instance.function_call self
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -10,7 +10,7 @@ module Vm
|
|||||||
end
|
end
|
||||||
def self.puts string
|
def self.puts string
|
||||||
# should unwrap from string to char*
|
# should unwrap from string to char*
|
||||||
Machine.instance.puts
|
Machine.instance.puts string
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -25,19 +25,22 @@ module Vm
|
|||||||
Machine.instance = eval("#{machine}::#{machine}Machine").new
|
Machine.instance = eval("#{machine}::#{machine}Machine").new
|
||||||
|
|
||||||
@context = Context.new(self)
|
@context = Context.new(self)
|
||||||
@functions = []
|
|
||||||
@objects = []
|
@objects = []
|
||||||
@entry = Vm::Kernel::start
|
@entry = Vm::Kernel::start
|
||||||
@exit = Vm::Kernel::exit
|
@exit = Vm::Kernel::exit
|
||||||
end
|
end
|
||||||
attr_reader :context
|
attr_reader :context
|
||||||
|
|
||||||
|
def functions
|
||||||
|
@values
|
||||||
|
end
|
||||||
def add_object o
|
def add_object o
|
||||||
|
return if @objects.include? o
|
||||||
@objects << o # TODO check type , no basic values allowed (must be wrapped)
|
@objects << o # TODO check type , no basic values allowed (must be wrapped)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_function name
|
def get_function name
|
||||||
@functions.detect{ |f| f.name == name }
|
@values.detect{ |f| (f.name == name) && (f.class == Function) }
|
||||||
end
|
end
|
||||||
|
|
||||||
# preferred way of creating new functions (also forward declarations, will flag unresolved later)
|
# preferred way of creating new functions (also forward declarations, will flag unresolved later)
|
||||||
@ -45,21 +48,53 @@ module Vm
|
|||||||
fun = get_function name
|
fun = get_function name
|
||||||
unless fun
|
unless fun
|
||||||
fun = Function.new(name)
|
fun = Function.new(name)
|
||||||
@functions << fun
|
@values << fun
|
||||||
end
|
end
|
||||||
fun
|
fun
|
||||||
end
|
end
|
||||||
|
|
||||||
def compile
|
def compile(context)
|
||||||
super
|
@values.each do |function|
|
||||||
string_table
|
function.compile(context)
|
||||||
|
end
|
||||||
|
@entry.compile(context)
|
||||||
|
super(context)
|
||||||
|
@exit.compile(context)
|
||||||
|
#string_table
|
||||||
|
@objects.each do |o|
|
||||||
|
o.compile(context)
|
||||||
|
end
|
||||||
|
fix_positions
|
||||||
|
fix_positions # second time for forward references
|
||||||
end
|
end
|
||||||
|
|
||||||
def wrap_as_main value
|
def fix_positions
|
||||||
|
@position = 0
|
||||||
|
@entry.at( @position )
|
||||||
|
@position += @entry.length
|
||||||
|
@values.each do |function|
|
||||||
|
function.at(@position)
|
||||||
|
@position += function.length
|
||||||
|
end
|
||||||
|
@objects.each do |o|
|
||||||
|
o.at(@position)
|
||||||
|
@position += o.length
|
||||||
|
end
|
||||||
|
@exit.at( @position )
|
||||||
|
@position += @exit.length
|
||||||
|
end
|
||||||
|
|
||||||
|
def wrap_as_main block
|
||||||
|
# #blockify
|
||||||
|
unless block.is_a? Block
|
||||||
|
raise "No block, start coding torsten"
|
||||||
|
end
|
||||||
|
add_value block
|
||||||
|
@entry.next block
|
||||||
|
block.next @exit
|
||||||
end
|
end
|
||||||
def verify
|
def verify
|
||||||
@functions.each do |funct|
|
@values.each do |funct|
|
||||||
funct.verify
|
funct.verify
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -33,8 +33,11 @@ module Vm
|
|||||||
end
|
end
|
||||||
|
|
||||||
class Word < Value
|
class Word < Value
|
||||||
def load
|
def load reg
|
||||||
Machine.instance.word_load self
|
Machine.instance.word_load self , reg
|
||||||
|
end
|
||||||
|
def compile context
|
||||||
|
#nothing to do here
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -56,6 +59,21 @@ module Vm
|
|||||||
|
|
||||||
class Reference < Word
|
class Reference < Word
|
||||||
end
|
end
|
||||||
|
class StringValue < Value
|
||||||
|
def initialize string
|
||||||
|
@string = string
|
||||||
|
end
|
||||||
|
def at pos
|
||||||
|
@pos = pos
|
||||||
|
end
|
||||||
|
def length
|
||||||
|
@string.length + 3
|
||||||
|
end
|
||||||
|
def compile context
|
||||||
|
#nothing to do here
|
||||||
|
end
|
||||||
|
attr_reader :string
|
||||||
|
end
|
||||||
|
|
||||||
class MemoryReference < Reference
|
class MemoryReference < Reference
|
||||||
end
|
end
|
||||||
@ -67,7 +85,7 @@ module Vm
|
|||||||
attr_reader :object
|
attr_reader :object
|
||||||
|
|
||||||
def compile context
|
def compile context
|
||||||
if object.is_a? String
|
if object.is_a? StringValue
|
||||||
context.program.add_object object
|
context.program.add_object object
|
||||||
else
|
else
|
||||||
#TODO define object layout more generally and let objects lay themselves out
|
#TODO define object layout more generally and let objects lay themselves out
|
||||||
|
@ -22,13 +22,11 @@ class TestRunner < MiniTest::Test
|
|||||||
tree = Parser::Transform.new.apply(syntax)
|
tree = Parser::Transform.new.apply(syntax)
|
||||||
|
|
||||||
program = Vm::Program.new "Arm"
|
program = Vm::Program.new "Arm"
|
||||||
expression = tree.to_value
|
value = tree.to_value
|
||||||
compiled = expression.compile( program.context )
|
program.wrap_as_main value
|
||||||
# do some stuff with mains and what not ??
|
compiled = program.compile( program.context )
|
||||||
program.wrap_as_main compiled
|
|
||||||
puts program.to_yaml
|
|
||||||
program.verify
|
program.verify
|
||||||
# puts program.to_yaml
|
puts program.to_yaml
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
Loading…
Reference in New Issue
Block a user