first interpreted tests, fix branch issues

whole branch logic wobbly
better syntax needed, but working(ish) for now
This commit is contained in:
Torsten Ruger 2015-10-19 14:46:12 +03:00
parent d767caf479
commit bdcd0f297d
12 changed files with 99 additions and 123 deletions

View File

@ -6,30 +6,23 @@ module Interpreter
# fire events for changed pc and register contents
include Eventable
# current instruction or pc
attr_reader :instruction
# current instruction or pc
attr_reader :clock
attr_reader :instruction # current instruction or pc
attr_reader :clock # current instruction or pc
# an (arm style) link register. store the return address to return to
attr_reader :link
# current executing block. since this is not a hardware simulator this is luxury
attr_reader :block
# the registers, 16
attr_reader :registers
# collect the output
attr_reader :stdout
attr_reader :state
attr_reader :registers # the registers, 16 (a hash, sym -> contents)
attr_reader :stdout # collect the output
attr_reader :state # running etc
attr_reader :flags # somewhat like the lags on a cpu, hash sym => bool (zero .. . )
def initialize
@state = "runnnig"
@stdout = ""
@registers = {}
@flags = { :zero => false , :positive => false ,
:negative=> false , :overflow => false }
@clock = 0
(0...12).each do |r|
set_register "r#{r}".to_sym , "r#{r}:unknown"
@ -65,6 +58,13 @@ module Interpreter
def set_register reg , val
old = get_register( reg ) # also ensures format
unless val.is_a? String
@flags[:zero] = (val == 0)
@flags[:positive] = (val > 0)
@flags[:negative] = (val < 0)
#puts "Set_flags #{val} :zero=#{@flags[:zero]}"
end
return if old === val
reg = reg.symbol if reg.is_a? Register::RegisterValue
@registers[reg] = val
@ -96,17 +96,21 @@ module Interpreter
end
# Instruction interpretation starts here
def execute_Branch
def execute_AlwaysBranch
target = @instruction.block
set_block target
false
end
def execute_IsZeroBranch
puts @instruction.inspect
target = @instruction.block
set_block target
false
#puts @instruction.inspect
if( @flags[:zero] )
target = @instruction.block
set_block target
return false
else
return true
end
end
def execute_LoadConstant
@ -192,18 +196,19 @@ module Interpreter
case @instruction.operator.to_s
when "+"
result = left + right
when "/"
result = left / right
when "-"
result = left - right
when "<"
result = left < right
when "/"
result = left / right
when "*"
#TODO set overflow, reduce result to int
result = left * right
when "=="
result = left == right
result = (left == right) ? 1 : 0
else
raise "unimplemented '#{@instruction.operator}' #{@instruction}"
end
#puts "#{@instruction} == #{result}"
#puts "#{@instruction} == #{result} (#{left}|#{right})"
right = set_register(@instruction.left , result)
true
end

View File

@ -11,9 +11,9 @@ module Register
attr_reader :block
def to_s
"Branch: #{block.name}"
"#{self.class.name}: #{block.name}"
end
alias :inspect :to_s
alias :inspect :to_s
end
class IsZeroBranch < Branch

View File

@ -118,7 +118,7 @@ module Virtual
def boot
boot_parfait!
@init = Block.new("init", :__init__ )
branch = Register::Branch.new( "__init__" , self.space.get_init.source.blocks.first )
branch = Register::AlwaysBranch.new( "__init__" , self.space.get_init.source.blocks.first )
@init.add_code branch
@booted = true
self

View File

@ -1,17 +0,0 @@
module CodeChecker
def check
machine = Virtual.machine.boot
machine.parse_and_compile @string_input
produced = Virtual.machine.space.get_main.source
assert @output , "No output given"
assert_equal @output.length , produced.blocks.length , "Block length"
produced.blocks.each_with_index do |b,i|
codes = @output[i]
assert codes , "No codes for block #{i}"
assert_equal b.codes.length , codes.length , "Code length for block #{i}"
b.codes.each_with_index do |c , ii |
assert_equal codes[ii] , c.class , "Block #{i} , code #{ii}"
end
end
end
end

View File

@ -1,54 +1,31 @@
require_relative '../../helper'
require "interpreter/interpreter"
# Fragments are small programs that we run through the interpreter and really only check
# - the no. of instructions processed
# - the stdout output
# simple tests to check parsing pworks and the first classes come out right.
#
# build up from small to check larger statements are correct
module Fragments
def setup
@stdout = ""
end
def check
machine = Virtual.machine.boot
machine.parse_and_compile @string_input
produced = Virtual.machine.space.get_main.source
assert @expect , "No output given"
assert_equal @expect.length , produced.blocks.length , "Block length"
produced.blocks.each_with_index do |b,i|
codes = @expect[i]
assert codes , "No codes for block #{i}"
assert_equal b.codes.length , codes.length , "Code length for block #{i+1}"
b.codes.each_with_index do |c , ii |
assert_equal codes[ii] , c.class , "Block #{i+1} , code #{ii+1}"
end
end
end
# helper to write the file
def write name
writer = Elf::ObjectWriter.new(@object_machine , Elf::Constants::TARGET_ARM)
assembly = writer.text
writer.save("#{name}.o")
function = @object_machine.classes[@target[0]]
assert function , "no class #{@target[0]}"
function = function.get_function(@target[1])
assert function , "no function #{@target[1]} for class #{@target[0]}"
io = StringIO.new
function.assemble io
assembly = io.string
# use this for getting the bytes to compare to :
puts bytes(assembly)
assembly.bytes.each_with_index do |byte , index|
is = @should[index]
assert_equal Fixnum , is.class , "@#{index.to_s(16)} = #{is}"
assert_equal byte , is , "@#{index.to_s(16)} #{byte.to_s(16)} != #{is.to_s(16)}"
end
if( RbConfig::CONFIG["build_cpu"] == "arm")
system "ld -N #{name}.o"
result = %x[./a.out]
assert_equal @output , result
end
end
def bytes string
"[" + string.bytes.collect{|b| "0x"+ b.to_s(16)}.join(",") + "]"
machine.collect
interpreter = Interpreter::Interpreter.new
interpreter.start machine.init
count = 0
begin
count += 1
#puts interpreter.instruction
interpreter.tick
end while( ! interpreter.instruction.nil?)
assert_equal @length , count
assert_equal @stdout , interpreter.stdout
end
end

View File

@ -1,9 +1,9 @@
require_relative "test_foo"
require_relative "test_if"
require_relative "test_hello"
require_relative "test_class"
require_relative "test_putint"
require_relative "test_functions"
require_relative "test_recursive_fibo"
require_relative "test_while_fibo"
#require_relative "test_foo"
#require_relative "test_hello"
#require_relative "test_class"
#require_relative "test_putint"
#require_relative "test_functions"
#require_relative "test_recursive_fibo"
#require_relative "test_while_fibo"

View File

@ -8,7 +8,7 @@ class TestIf < MiniTest::Test
class Object
int main()
int n = 10
if( n < 12)
if( n - 12)
return 3
else
return 4
@ -16,30 +16,32 @@ class Object
end
end
HERE
@expect = [[SaveReturn,Virtual::Set,Virtual::Set,Register::GetSlot,
Register::GetSlot,Register::OperatorInstruction,Register::IsZeroBranch] ,
[Virtual::Set,Register::AlwaysBranch] ,[Virtual::Set] ,[] ,[RegisterTransfer,GetSlot,FunctionReturn] ]
@length = 17
check
end
def test_return
def test_if_small
@string_input = <<HERE
class Object
int main()
return 5
int n = 10
if(8 - n )
"10".putstring()
end
end
end
HERE
@expect = [[SaveReturn,Virtual::Set] , [RegisterTransfer,GetSlot,FunctionReturn]]
@length = 33
@stdout = "10"
check
end
def test_if_function
def test_if_puts
@string_input = <<HERE
class Object
int itest(int n)
if( n < 12)
if( n - 12)
"then".putstring()
else
"else".putstring()
@ -51,8 +53,8 @@ class Object
end
end
HERE
@expect = [ [SaveReturn,Register::GetSlot,Virtual::Set,Virtual::Set,
Virtual::Set,Virtual::Set,RegisterTransfer,FunctionCall] ,[RegisterTransfer,GetSlot,FunctionReturn] ]
@length = 40
@stdout = "else"
check
end
end

View File

@ -2,4 +2,4 @@ require_relative "expressions/test_all"
require_relative "statements/test_all"
#require_relative "fragments/test_all"
require_relative "fragments/test_all"

View File

@ -16,7 +16,7 @@ module Ticker
error = nil
tick = 1
begin
while true and (classes.length < 100)
while true and (classes.length < 200)
cl = ticks(1).class
tick += 1
classes << cl

View File

@ -26,7 +26,7 @@ class AddTest < MiniTest::Test
def test_branch
was = @interpreter.block
assert_equal Register::Branch , ticks(1).class
assert_equal Register::AlwaysBranch , ticks(1).class
assert was != @interpreter.block
end
def test_load
@ -66,7 +66,7 @@ class AddTest < MiniTest::Test
def test_chain
#show_ticks # get output of what is
["Branch","LoadConstant","GetSlot","SetSlot","RegisterTransfer",
["AlwaysBranch","LoadConstant","GetSlot","SetSlot","RegisterTransfer",
"FunctionCall","SaveReturn","LoadConstant","LoadConstant","OperatorInstruction",
"RegisterTransfer","GetSlot","FunctionReturn","RegisterTransfer","Syscall",
"NilClass"].each_with_index do |name , index|

View File

@ -29,7 +29,7 @@ class Integer < Object
div = self / 10
int rest
rest = self - div
if( rest < 0)
if( rest - 0)
rest = self.digit( rest )
str = str + rest
else
@ -58,8 +58,8 @@ HERE
# Phisol::Compiler.compile( statements , Virtual.machine.space.get_main )
@interpreter = Interpreter::Interpreter.new
@interpreter.start Virtual.machine.init
#show_ticks # get output of what is
["Branch","LoadConstant","GetSlot","SetSlot","RegisterTransfer",
# show_ticks # get output of what is
["AlwaysBranch","LoadConstant","GetSlot","SetSlot","RegisterTransfer",
"FunctionCall","SaveReturn","GetSlot","LoadConstant","SetSlot",
"LoadConstant","SetSlot","RegisterTransfer","FunctionCall","SaveReturn",
"LoadConstant","GetSlot","SetSlot","GetSlot","GetSlot",
@ -68,14 +68,23 @@ HERE
"LoadConstant","OperatorInstruction","GetSlot","SetSlot","GetSlot",
"GetSlot","GetSlot","OperatorInstruction","GetSlot","SetSlot",
"GetSlot","GetSlot","LoadConstant","OperatorInstruction","IsZeroBranch",
"GetSlot","GetSlot","GetSlot","SetSlot","LoadConstant",
"SetSlot","GetSlot","SetSlot","RegisterTransfer","FunctionCall",
"SaveReturn","GetSlot","LoadConstant","OperatorInstruction","GetSlot",
"SetSlot","GetSlot","GetSlot","GetSlot","OperatorInstruction",
"GetSlot","SetSlot","GetSlot","GetSlot","LoadConstant",
"OperatorInstruction","IsZeroBranch","GetSlot","GetSlot","GetSlot",
"SetSlot","LoadConstant","SetSlot","GetSlot","SetSlot",
"RegisterTransfer","FunctionCall","SaveReturn","GetSlot","LoadConstant",
"OperatorInstruction","GetSlot","SetSlot","GetSlot","GetSlot",
"GetSlot","OperatorInstruction","GetSlot","SetSlot","GetSlot",
"GetSlot","LoadConstant","OperatorInstruction","IsZeroBranch","GetSlot",
"GetSlot","GetSlot","SetSlot","LoadConstant","SetSlot",
"GetSlot","GetSlot","SetSlot","RegisterTransfer","FunctionCall",
"SaveReturn","GetSlot","LoadConstant","OperatorInstruction","IsZeroBranch",
"LoadConstant","GetSlot","LoadConstant","OperatorInstruction","IsZeroBranch",
"LoadConstant","GetSlot","LoadConstant","OperatorInstruction","IsZeroBranch",
"LoadConstant","GetSlot","LoadConstant","OperatorInstruction","IsZeroBranch",
"LoadConstant","GetSlot","LoadConstant","OperatorInstruction","IsZeroBranch",
"LoadConstant","NilClass"].each_with_index do |name , index|
"GetSlot","SetSlot","RegisterTransfer","FunctionCall","SaveReturn",
"GetSlot","LoadConstant","OperatorInstruction","GetSlot","SetSlot",
"GetSlot","GetSlot","GetSlot","OperatorInstruction","GetSlot",
"SetSlot","GetSlot","GetSlot","LoadConstant","OperatorInstruction",
"IsZeroBranch","GetSlot","GetSlot","GetSlot"].each_with_index do |name , index|
got = ticks(1)
assert got.class.name.index(name) , "Wrong class for #{index+1}, expect #{name} , got #{got}"
end

View File

@ -26,7 +26,7 @@ class TestPuts < MiniTest::Test
def test_branch
was = @interpreter.block
assert_equal Register::Branch , ticks(1).class
assert_equal Register::AlwaysBranch , ticks(1).class
assert was != @interpreter.block
end
def test_load
@ -56,7 +56,7 @@ class TestPuts < MiniTest::Test
def test_chain
#show_ticks # get output of what is
["Branch","LoadConstant","GetSlot","SetSlot","RegisterTransfer",
["AlwaysBranch","LoadConstant","GetSlot","SetSlot","RegisterTransfer",
"FunctionCall","SaveReturn","GetSlot","LoadConstant","SetSlot",
"LoadConstant","SetSlot","RegisterTransfer","FunctionCall","SaveReturn",
"GetSlot","RegisterTransfer","Syscall","RegisterTransfer","RegisterTransfer",