still recoving from previous block - function change. no more exceptions at least
This commit is contained in:
parent
e9519d4f05
commit
7cca50cd3a
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user