still recoving from previous block - function change. no more exceptions at least

This commit is contained in:
Torsten Ruger 2014-06-11 00:38:46 +03:00
parent e9519d4f05
commit 7cca50cd3a
9 changed files with 72 additions and 74 deletions

View File

@ -73,18 +73,24 @@ module Arm
call.function.return_type
end
def main_start entry
def main_start context
entry = Vm::Block.new("main_entry",nil,nil)
entry.do_add mov( :fp , 0 )
entry.do_add call( context.function.entry )
entry
end
def main_exit exit
def main_exit context
exit = Vm::Block.new("main_exit",nil,nil)
syscall(exit , 1)
exit
end
def function_entry block, f_name
block.do_add push( [:lr] )
block
end
def function_exit entry , f_name
entry.do_add pop( [:pc] )
entry
end
# assumes string in r0 and r1 and moves them along for the syscall
@ -98,11 +104,11 @@ module Arm
# the number (a Vm::integer) is (itself) divided by 10, ie overwritten by the result
# and the remainder is overwritten (ie an out argument)
# not really a function, more a macro,
def div10 block, number , remainder
def div10 function, number , remainder
# Note about division: devision is MUCH more expensive than one would have thought
# And coding it is a bit of a mind leap: it's all about finding a a result that gets the
# remainder smaller than an int. i'll post some links sometime. This is from the arm manual
block.instance_eval do
function.instance_eval do
sub( remainder , number , 10 )
sub( number , number , number , shift_lsr: 2)
add( number , number , number , shift_lsr: 4)

View File

@ -28,7 +28,6 @@ module Ast
context.locals = locals
context.function = function
into = function.body
last_compiled = nil
body.each do |b|
puts "compiling in function #{b}"
@ -38,9 +37,9 @@ module Ast
return_reg = Vm::Integer.new(Vm::RegisterMachine.instance.return_register)
if last_compiled.is_a?(Vm::IntegerConstant) or last_compiled.is_a?(Vm::ObjectConstant)
return_reg.load into , last_compiled if last_compiled.register_symbol != return_reg.register_symbol
return_reg.load function , last_compiled if last_compiled.register_symbol != return_reg.register_symbol
else
return_reg.move( into, last_compiled ) if last_compiled.register_symbol != return_reg.register_symbol
return_reg.move( function, last_compiled ) if last_compiled.register_symbol != return_reg.register_symbol
end
function.set_return return_reg

View File

@ -2,6 +2,7 @@ module Ast
class ReturnExpression < Expression
# attr_reader :expression
def compile context
into = context.function
puts "compiling return expression #{expression}, now return in return_regsiter"
expression_value = expression.compile(context)
# copied from function expression: TODO make function

View File

@ -4,12 +4,13 @@ module Ast
def compile context
into = context.function
while_block = into.new_block "while"
ret = while_block.new_block "return"
ret = into.new_block "return"
into.insert_at while_block
puts "compiling while condition #{condition}"
cond_val = condition.compile(context)
while_block.b ret , condition_code: cond_val.not_operator
while_block.branch = ret
into.b ret , condition_code: cond_val.not_operator
into.insertion_point.branch = ret
last = nil
@ -17,7 +18,9 @@ module Ast
puts "compiling in while #{part}"
last = part.compile(context)
end
while_block.b while_block
into.b while_block
into.insertion_point.branch = while_block
puts "compile while end"
into.insert_at ret
return last

View File

@ -4,22 +4,6 @@ module Core
#there are no Kernel instances, only class methods.
# We use this module syntax to avoid the (ugly) self (also eases searching).
module ClassMethods
def main_start block
#TODO extract args into array of strings
Vm::RegisterMachine.instance.main_start block
block
end
def main_exit block
# Machine.exit mov r7 , 0 + swi 0
Vm::RegisterMachine.instance.main_exit block
block
end
def function_entry block , f_name
Vm::RegisterMachine.instance.function_entry block , f_name
end
def function_exit block , f_name
Vm::RegisterMachine.instance.function_exit block , f_name
end
#TODO this is in the wrong place. It is a function that returns a function object
# while all other methods add their code into some block. --> kernel
@ -39,19 +23,20 @@ module Core
int = putint_function.receiver
moved_int = putint_function.new_local
utoa = context.object_space.get_or_create_class(:Object).get_or_create_function(:utoa)
body = putint_function.body
body.mov( moved_int , int ) #move arg up
#body.a buffer => int # string to write to
body.add( int , buffer ,nil ) # string to write to
body.add(int , int , buffer.length - 3)
body.call( utoa )
after = body.new_block("#{body.name}_a")
body.insert_at after
# And now we "just" have to print it, using the write_stdout
after.add( int , buffer , nil ) # string to write to
after.mov( moved_int , buffer.length )
Vm::RegisterMachine.instance.write_stdout(after)
putint_function.instance_eval do
mov( moved_int , int ) #move arg up
#body.a buffer => int # string to write to
add( int , buffer ,nil ) # string to write to
add(int , int , buffer.length - 3)
call( utoa )
after = new_block("#{body.name}_a")
insert_at after
# And now we "just" have to print it, using the write_stdout
add( int , buffer , nil ) # string to write to
mov( moved_int , buffer.length )
Vm::RegisterMachine.instance.write_stdout(after)
end
putint_function
end
@ -65,14 +50,15 @@ module Core
str_addr = utoa_function.receiver
number = utoa_function.args.first
remainder = utoa_function.new_local
Vm::RegisterMachine.instance.div10( utoa_function.body , number , remainder )
Vm::RegisterMachine.instance.div10( utoa_function , number , remainder )
# make char out of digit (by using ascii encoding) 48 == "0"
body = utoa_function.body
body.add(remainder , remainder , 48)
body.strb( remainder, str_addr )
body.sub( str_addr, str_addr , 1 )
body.cmp( number , 0 )
body.callne( utoa_function )
utoa_function.instance_eval do
add( remainder , remainder , 48)
strb( remainder, str_addr )
sub( str_addr, str_addr , 1 )
cmp( number , 0 )
callne( utoa_function )
end
return utoa_function
end
@ -87,25 +73,29 @@ module Core
count = fibo_function.new_local
f1 = fibo_function.new_local
f2 = fibo_function.new_local
body = fibo_function.body
fibo_function.instance_eval do
body.cmp int , 1
body.mov( result, int , condition_code: :le)
body.mov( :pc , :lr , condition_code: :le)
body.push [ count , f1 , f2 , :lr]
body.mov f1 , 1
body.mov f2 , 0
body.sub count , int , 2
cmp int , 1
mov( result, int , condition_code: :le)
mov( :pc , :lr , condition_code: :le)
push [ count , f1 , f2 , :lr]
mov f1 , 1
mov f2 , 0
sub count , int , 2
end
l = fibo_function.body.new_block("loop")
l = fibo_function.new_block("loop")
fibo_function.insert_at l
l.add f1 , f1 , f2
l.sub f2 , f1 , f2
l.sub count , count , 1 , set_update_status: 1
l.bpl( l )
l.mov( result , f1 )
fibo_function.instance_eval do
add f1 , f1 , f2
sub f2 , f1 , f2
sub count , count , 1 , set_update_status: 1
bpl( l )
mov( result , f1 )
pop [ count , f1 , f2 , :pc]
end
fibo_function.set_return result
l.pop [ count , f1 , f2 , :pc]
fibo_function
end

View File

@ -35,8 +35,7 @@ module Vm
attr_reader :name , :next , :codes , :function , :assigns , :uses
attr_accessor :branch
def reachable
ret = []
def reachable ret = []
add_next ret
add_branch ret
ret
@ -98,14 +97,14 @@ module Vm
return if @next.nil?
return if ret.include? @next
ret << @next
ret + @next.reachable
@next.reachable ret
end
# helper for determining reachable blocks
def add_branch ret
return if @branch.nil?
return if ret.include? @branch
ret << @branch
ret + @branch.reachable
@branch.reachable ret
end
end
end

View File

@ -13,7 +13,7 @@ module Vm
@super_class = super_class
@meta_class = MetaClass.new(self)
end
attr_reader :name , :functions , :meta_class
attr_reader :name , :functions , :meta_class , :context
def add_function function
raise "not a function #{function}" unless function.is_a? Function

View File

@ -31,12 +31,13 @@ module Vm
@classes = {}
@context = Context.new(self)
@context.current_class = get_or_create_class :Object
@main = Function.new("main")
@context.function = @main
#global objects (data)
@objects = []
@entry = Core::Kernel::main_start Vm::Block.new("main_entry",nil,nil)
@entry = RegisterMachine.instance.main_start @context
#main gets executed between entry and exit
@main = Block.new("main",nil,nil)
@exit = Core::Kernel::main_exit Vm::Block.new("main_exit",nil,nil)
@exit = RegisterMachine.instance.main_exit @context
boot_classes
end
attr_reader :context , :main , :classes , :entry , :exit

View File

@ -48,11 +48,11 @@ module Vm
end
end
set_return return_type
@exit = Core::Kernel::function_exit( Vm::Block.new("exit" , self , nil) , name )
@exit = RegisterMachine.instance.function_exit( Vm::Block.new("exit" , self , nil) , name )
@return = Block.new("return", self , @exit)
@body = Block.new("body", self , @return)
@insert_at = @body
@entry = Core::Kernel::function_entry( Vm::Block.new("entry" , self , @body) ,name )
@entry = RegisterMachine.instance.function_entry( Vm::Block.new("entry" , self , @body) ,name )
@locals = []
@linked = false # incase link is called twice, we only calculate locals once
end
@ -153,7 +153,6 @@ module Vm
# to the current block
# also symbols are supported and wrapped as register usages (for bare metal programming)
def method_missing(meth, *args, &block)
puts "passing #{meth} , #{args.length} #{args}"
add_code RegisterMachine.instance.send(meth , *args)
end
@ -169,7 +168,7 @@ module Vm
if push = b.call_block?
locals = locals_at b
if(locals.empty?)
puts "Empty #{b}"
puts "Empty #{b.name}"
else
puts "PUSH #{push}"
push.set_registers(locals)