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
|
call.function.return_type
|
||||||
end
|
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 mov( :fp , 0 )
|
||||||
|
entry.do_add call( context.function.entry )
|
||||||
|
entry
|
||||||
end
|
end
|
||||||
def main_exit exit
|
def main_exit context
|
||||||
|
exit = Vm::Block.new("main_exit",nil,nil)
|
||||||
syscall(exit , 1)
|
syscall(exit , 1)
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
def function_entry block, f_name
|
def function_entry block, f_name
|
||||||
block.do_add push( [:lr] )
|
block.do_add push( [:lr] )
|
||||||
|
block
|
||||||
end
|
end
|
||||||
def function_exit entry , f_name
|
def function_exit entry , f_name
|
||||||
entry.do_add pop( [:pc] )
|
entry.do_add pop( [:pc] )
|
||||||
|
entry
|
||||||
end
|
end
|
||||||
|
|
||||||
# assumes string in r0 and r1 and moves them along for the syscall
|
# 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
|
# the number (a Vm::integer) is (itself) divided by 10, ie overwritten by the result
|
||||||
# and the remainder is overwritten (ie an out argument)
|
# and the remainder is overwritten (ie an out argument)
|
||||||
# not really a function, more a macro,
|
# 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
|
# 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
|
# 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
|
# 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( remainder , number , 10 )
|
||||||
sub( number , number , number , shift_lsr: 2)
|
sub( number , number , number , shift_lsr: 2)
|
||||||
add( number , number , number , shift_lsr: 4)
|
add( number , number , number , shift_lsr: 4)
|
||||||
|
@ -28,7 +28,6 @@ module Ast
|
|||||||
context.locals = locals
|
context.locals = locals
|
||||||
context.function = function
|
context.function = function
|
||||||
|
|
||||||
into = function.body
|
|
||||||
last_compiled = nil
|
last_compiled = nil
|
||||||
body.each do |b|
|
body.each do |b|
|
||||||
puts "compiling in function #{b}"
|
puts "compiling in function #{b}"
|
||||||
@ -38,9 +37,9 @@ module Ast
|
|||||||
|
|
||||||
return_reg = Vm::Integer.new(Vm::RegisterMachine.instance.return_register)
|
return_reg = Vm::Integer.new(Vm::RegisterMachine.instance.return_register)
|
||||||
if last_compiled.is_a?(Vm::IntegerConstant) or last_compiled.is_a?(Vm::ObjectConstant)
|
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
|
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
|
end
|
||||||
function.set_return return_reg
|
function.set_return return_reg
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ module Ast
|
|||||||
class ReturnExpression < Expression
|
class ReturnExpression < Expression
|
||||||
# attr_reader :expression
|
# attr_reader :expression
|
||||||
def compile context
|
def compile context
|
||||||
|
into = context.function
|
||||||
puts "compiling return expression #{expression}, now return in return_regsiter"
|
puts "compiling return expression #{expression}, now return in return_regsiter"
|
||||||
expression_value = expression.compile(context)
|
expression_value = expression.compile(context)
|
||||||
# copied from function expression: TODO make function
|
# copied from function expression: TODO make function
|
||||||
|
@ -4,12 +4,13 @@ module Ast
|
|||||||
def compile context
|
def compile context
|
||||||
into = context.function
|
into = context.function
|
||||||
while_block = into.new_block "while"
|
while_block = into.new_block "while"
|
||||||
ret = while_block.new_block "return"
|
ret = into.new_block "return"
|
||||||
into.insert_at while_block
|
into.insert_at while_block
|
||||||
|
|
||||||
puts "compiling while condition #{condition}"
|
puts "compiling while condition #{condition}"
|
||||||
cond_val = condition.compile(context)
|
cond_val = condition.compile(context)
|
||||||
while_block.b ret , condition_code: cond_val.not_operator
|
into.b ret , condition_code: cond_val.not_operator
|
||||||
while_block.branch = ret
|
into.insertion_point.branch = ret
|
||||||
|
|
||||||
last = nil
|
last = nil
|
||||||
|
|
||||||
@ -17,7 +18,9 @@ module Ast
|
|||||||
puts "compiling in while #{part}"
|
puts "compiling in while #{part}"
|
||||||
last = part.compile(context)
|
last = part.compile(context)
|
||||||
end
|
end
|
||||||
while_block.b while_block
|
into.b while_block
|
||||||
|
into.insertion_point.branch = while_block
|
||||||
|
|
||||||
puts "compile while end"
|
puts "compile while end"
|
||||||
into.insert_at ret
|
into.insert_at ret
|
||||||
return last
|
return last
|
||||||
|
@ -4,22 +4,6 @@ module Core
|
|||||||
#there are no Kernel instances, only class methods.
|
#there are no Kernel instances, only class methods.
|
||||||
# We use this module syntax to avoid the (ugly) self (also eases searching).
|
# We use this module syntax to avoid the (ugly) self (also eases searching).
|
||||||
module ClassMethods
|
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
|
#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
|
# while all other methods add their code into some block. --> kernel
|
||||||
@ -39,19 +23,20 @@ module Core
|
|||||||
int = putint_function.receiver
|
int = putint_function.receiver
|
||||||
moved_int = putint_function.new_local
|
moved_int = putint_function.new_local
|
||||||
utoa = context.object_space.get_or_create_class(:Object).get_or_create_function(:utoa)
|
utoa = context.object_space.get_or_create_class(:Object).get_or_create_function(:utoa)
|
||||||
body = putint_function.body
|
putint_function.instance_eval do
|
||||||
body.mov( moved_int , int ) #move arg up
|
mov( moved_int , int ) #move arg up
|
||||||
#body.a buffer => int # string to write to
|
#body.a buffer => int # string to write to
|
||||||
|
|
||||||
body.add( int , buffer ,nil ) # string to write to
|
add( int , buffer ,nil ) # string to write to
|
||||||
body.add(int , int , buffer.length - 3)
|
add(int , int , buffer.length - 3)
|
||||||
body.call( utoa )
|
call( utoa )
|
||||||
after = body.new_block("#{body.name}_a")
|
after = new_block("#{body.name}_a")
|
||||||
body.insert_at after
|
insert_at after
|
||||||
# And now we "just" have to print it, using the write_stdout
|
# And now we "just" have to print it, using the write_stdout
|
||||||
after.add( int , buffer , nil ) # string to write to
|
add( int , buffer , nil ) # string to write to
|
||||||
after.mov( moved_int , buffer.length )
|
mov( moved_int , buffer.length )
|
||||||
Vm::RegisterMachine.instance.write_stdout(after)
|
Vm::RegisterMachine.instance.write_stdout(after)
|
||||||
|
end
|
||||||
putint_function
|
putint_function
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -65,14 +50,15 @@ module Core
|
|||||||
str_addr = utoa_function.receiver
|
str_addr = utoa_function.receiver
|
||||||
number = utoa_function.args.first
|
number = utoa_function.args.first
|
||||||
remainder = utoa_function.new_local
|
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"
|
# make char out of digit (by using ascii encoding) 48 == "0"
|
||||||
body = utoa_function.body
|
utoa_function.instance_eval do
|
||||||
body.add(remainder , remainder , 48)
|
add( remainder , remainder , 48)
|
||||||
body.strb( remainder, str_addr )
|
strb( remainder, str_addr )
|
||||||
body.sub( str_addr, str_addr , 1 )
|
sub( str_addr, str_addr , 1 )
|
||||||
body.cmp( number , 0 )
|
cmp( number , 0 )
|
||||||
body.callne( utoa_function )
|
callne( utoa_function )
|
||||||
|
end
|
||||||
return utoa_function
|
return utoa_function
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -87,25 +73,29 @@ module Core
|
|||||||
count = fibo_function.new_local
|
count = fibo_function.new_local
|
||||||
f1 = fibo_function.new_local
|
f1 = fibo_function.new_local
|
||||||
f2 = fibo_function.new_local
|
f2 = fibo_function.new_local
|
||||||
body = fibo_function.body
|
fibo_function.instance_eval do
|
||||||
|
|
||||||
body.cmp int , 1
|
cmp int , 1
|
||||||
body.mov( result, int , condition_code: :le)
|
mov( result, int , condition_code: :le)
|
||||||
body.mov( :pc , :lr , condition_code: :le)
|
mov( :pc , :lr , condition_code: :le)
|
||||||
body.push [ count , f1 , f2 , :lr]
|
push [ count , f1 , f2 , :lr]
|
||||||
body.mov f1 , 1
|
mov f1 , 1
|
||||||
body.mov f2 , 0
|
mov f2 , 0
|
||||||
body.sub count , int , 2
|
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
|
fibo_function.instance_eval do
|
||||||
l.sub f2 , f1 , f2
|
add f1 , f1 , f2
|
||||||
l.sub count , count , 1 , set_update_status: 1
|
sub f2 , f1 , f2
|
||||||
l.bpl( l )
|
sub count , count , 1 , set_update_status: 1
|
||||||
l.mov( result , f1 )
|
bpl( l )
|
||||||
|
mov( result , f1 )
|
||||||
|
pop [ count , f1 , f2 , :pc]
|
||||||
|
end
|
||||||
fibo_function.set_return result
|
fibo_function.set_return result
|
||||||
l.pop [ count , f1 , f2 , :pc]
|
|
||||||
fibo_function
|
fibo_function
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -35,8 +35,7 @@ module Vm
|
|||||||
attr_reader :name , :next , :codes , :function , :assigns , :uses
|
attr_reader :name , :next , :codes , :function , :assigns , :uses
|
||||||
attr_accessor :branch
|
attr_accessor :branch
|
||||||
|
|
||||||
def reachable
|
def reachable ret = []
|
||||||
ret = []
|
|
||||||
add_next ret
|
add_next ret
|
||||||
add_branch ret
|
add_branch ret
|
||||||
ret
|
ret
|
||||||
@ -98,14 +97,14 @@ module Vm
|
|||||||
return if @next.nil?
|
return if @next.nil?
|
||||||
return if ret.include? @next
|
return if ret.include? @next
|
||||||
ret << @next
|
ret << @next
|
||||||
ret + @next.reachable
|
@next.reachable ret
|
||||||
end
|
end
|
||||||
# helper for determining reachable blocks
|
# helper for determining reachable blocks
|
||||||
def add_branch ret
|
def add_branch ret
|
||||||
return if @branch.nil?
|
return if @branch.nil?
|
||||||
return if ret.include? @branch
|
return if ret.include? @branch
|
||||||
ret << @branch
|
ret << @branch
|
||||||
ret + @branch.reachable
|
@branch.reachable ret
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -13,7 +13,7 @@ module Vm
|
|||||||
@super_class = super_class
|
@super_class = super_class
|
||||||
@meta_class = MetaClass.new(self)
|
@meta_class = MetaClass.new(self)
|
||||||
end
|
end
|
||||||
attr_reader :name , :functions , :meta_class
|
attr_reader :name , :functions , :meta_class , :context
|
||||||
|
|
||||||
def add_function function
|
def add_function function
|
||||||
raise "not a function #{function}" unless function.is_a? Function
|
raise "not a function #{function}" unless function.is_a? Function
|
||||||
|
@ -31,12 +31,13 @@ module Vm
|
|||||||
@classes = {}
|
@classes = {}
|
||||||
@context = Context.new(self)
|
@context = Context.new(self)
|
||||||
@context.current_class = get_or_create_class :Object
|
@context.current_class = get_or_create_class :Object
|
||||||
|
@main = Function.new("main")
|
||||||
|
@context.function = @main
|
||||||
#global objects (data)
|
#global objects (data)
|
||||||
@objects = []
|
@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 gets executed between entry and exit
|
||||||
@main = Block.new("main",nil,nil)
|
@exit = RegisterMachine.instance.main_exit @context
|
||||||
@exit = Core::Kernel::main_exit Vm::Block.new("main_exit",nil,nil)
|
|
||||||
boot_classes
|
boot_classes
|
||||||
end
|
end
|
||||||
attr_reader :context , :main , :classes , :entry , :exit
|
attr_reader :context , :main , :classes , :entry , :exit
|
||||||
|
@ -48,11 +48,11 @@ module Vm
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
set_return return_type
|
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)
|
@return = Block.new("return", self , @exit)
|
||||||
@body = Block.new("body", self , @return)
|
@body = Block.new("body", self , @return)
|
||||||
@insert_at = @body
|
@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 = []
|
@locals = []
|
||||||
@linked = false # incase link is called twice, we only calculate locals once
|
@linked = false # incase link is called twice, we only calculate locals once
|
||||||
end
|
end
|
||||||
@ -153,7 +153,6 @@ module Vm
|
|||||||
# to the current block
|
# to the current block
|
||||||
# also symbols are supported and wrapped as register usages (for bare metal programming)
|
# also symbols are supported and wrapped as register usages (for bare metal programming)
|
||||||
def method_missing(meth, *args, &block)
|
def method_missing(meth, *args, &block)
|
||||||
puts "passing #{meth} , #{args.length} #{args}"
|
|
||||||
add_code RegisterMachine.instance.send(meth , *args)
|
add_code RegisterMachine.instance.send(meth , *args)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -169,7 +168,7 @@ module Vm
|
|||||||
if push = b.call_block?
|
if push = b.call_block?
|
||||||
locals = locals_at b
|
locals = locals_at b
|
||||||
if(locals.empty?)
|
if(locals.empty?)
|
||||||
puts "Empty #{b}"
|
puts "Empty #{b.name}"
|
||||||
else
|
else
|
||||||
puts "PUSH #{push}"
|
puts "PUSH #{push}"
|
||||||
push.set_registers(locals)
|
push.set_registers(locals)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user