325 lines
6.2 KiB
Ruby
Executable File
325 lines
6.2 KiB
Ruby
Executable File
$debug=true
|
|
$pfdebug=true
|
|
$fdebug=true
|
|
$mname="the initialization code"
|
|
$arg=[]
|
|
$local=[]
|
|
$static=[]
|
|
$pointer=[nil,nil]
|
|
$temp=[nil,nil,nil,nil,nil,nil,nil,nil]
|
|
$heap=[]
|
|
$stack=[]
|
|
$labels={}
|
|
$gstack=[]
|
|
$funcs={}
|
|
def runvmcommand(cmd,lno)
|
|
def putsd(arg)
|
|
if $debug
|
|
puts arg
|
|
end
|
|
end
|
|
def putspfd(arg)
|
|
if $pfdebug or $debug
|
|
puts arg
|
|
end
|
|
end
|
|
def putsdf(arg)
|
|
if $fdebug
|
|
puts arg
|
|
end
|
|
end
|
|
def raised(etype,arg=nil)
|
|
if arg==nil
|
|
raise etype
|
|
else
|
|
raise etype,arg
|
|
end
|
|
end
|
|
def checklistbounds(lname,list,index,lno=nil)
|
|
if index > list.length-1
|
|
if lno
|
|
raised "Line #{lno}: Index #{index} is out of bounds for #{lname}"
|
|
else
|
|
raised "Index #{index} is out of bounds for #{lname}"
|
|
end
|
|
exit
|
|
end
|
|
end
|
|
oldstack=$stack
|
|
funcdef=false
|
|
pflowc=false
|
|
cmd=cmd.split(" ")
|
|
op=cmd.shift
|
|
putsd "#{op} "+cmd.join(" ") unless op == "function" or op==nil or op=="#"
|
|
case op
|
|
when "add"
|
|
$stack.push($stack.pop+$stack.pop)
|
|
when "sub"
|
|
second=$stack.pop
|
|
first=$stack.pop
|
|
$stack.push(first-second)
|
|
when "neg"
|
|
$stack.push(-$stack.pop)
|
|
when "push"
|
|
cmd[1]=cmd[1].to_i
|
|
case cmd[0]
|
|
when "argument"
|
|
checklistbounds("arg",$arg,cmd[1],lno)
|
|
$stack.push($arg[cmd[1]])
|
|
when "local"
|
|
checklistbounds("local",$local,cmd[1],lno)
|
|
$stack.push($local[cmd[1]])
|
|
when "static"
|
|
$stack.push($static[cmd[1]])
|
|
when "constant"
|
|
$stack.push(cmd[1])
|
|
when "this"
|
|
$stack.push($heap[$pointer[0]+cmd[1]])
|
|
when "that"
|
|
$stack.push($heap[$pointer[1]+cmd[1]])
|
|
when "temp"
|
|
checklistbounds("temp",$temp,cmd[1],lno)
|
|
$stack.push($temp[cmd[1]])
|
|
when "pointer"
|
|
checklistbounds("pointer",$pointer,cmd[1],lno)
|
|
$stack.push($pointer[cmd[1]])
|
|
end
|
|
when "pop"
|
|
cmd[1]=cmd[1].to_i
|
|
case cmd[0]
|
|
when "local"
|
|
checklistbounds("local",$local,cmd[1],lno)
|
|
$local[cmd[1]]=$stack.pop
|
|
putsd "New local:#{$local}"
|
|
when "static"
|
|
$static[cmd[1]]=$stack.pop
|
|
putsd "New static:#{$static}"
|
|
when "this"
|
|
$heap[$pointer[0]+cmd[1]]=$stack.pop
|
|
putsd "New heap:#{$heap}"
|
|
when "that"
|
|
$heap[$pointer[1]+cmd[1]]=$stack.pop
|
|
putsd "New heap:#{$heap}"
|
|
when "pointer"
|
|
checklistbounds("pointer",$pointer,cmd[1],lno)
|
|
$pointer[cmd[1]]=$stack.pop
|
|
putsd "New pointer:#{$pointer}"
|
|
when "temp"
|
|
checklistbounds("temp",$temp,cmd[1],lno)
|
|
$temp[cmd[1]]=$stack.pop
|
|
putsd "New temp:#{$temp}"
|
|
end
|
|
when "label"
|
|
$labels[cmd[0]]=lno+1
|
|
putsd "New labels:#{$labels}"
|
|
when "goto"
|
|
pflowc=true
|
|
nlno=$labels[cmd[0]]
|
|
when "if-goto"
|
|
pflowc=true
|
|
if $stack.pop == 0
|
|
nlno=$labels[cmd[1]]
|
|
end
|
|
when "call"
|
|
if $funcs[cmd[0]]==nil
|
|
puts "Line #{lno}: Function #{cmd[0]} is undefined"
|
|
exit
|
|
end
|
|
pflowc=true
|
|
args=[]
|
|
i=cmd[1].to_i-1
|
|
if i == -1
|
|
i=0
|
|
else
|
|
while i >= 0
|
|
args[i]=$stack.pop
|
|
i-=1
|
|
end
|
|
end
|
|
hash={"local"=>$local,"arg"=>$arg,"pointer"=>$pointer,"stack"=>$stack,"ret"=>lno+1,"mname"=>$mname}
|
|
$gstack.push(hash)
|
|
$arg=args
|
|
$local=Array.new($funcs[cmd[0]][1])
|
|
nlno=$funcs[cmd[0]][0]
|
|
$mname=cmd[0]
|
|
puts "Transferring control from #{hash["mname"]} to #{$mname}"
|
|
putsd "New arg:#{$arg}"
|
|
putsd "New local:#{$local}"
|
|
putsd "Stack is now cleared"
|
|
when "function"
|
|
funcdef=true
|
|
$funcs[cmd[0]]=[lno+1,cmd[1].to_i]
|
|
putsdf "New funcs:#{$funcs}"
|
|
when "return"
|
|
pflowc=true
|
|
hash=$gstack.pop
|
|
putspfd "Transferring control from #{$mname} to method #{hash["mname"]}"
|
|
ostack=$stack
|
|
$stack=hash["stack"]
|
|
rval=ostack.pop
|
|
unless rval == nil
|
|
$stack.push(rval)
|
|
end
|
|
$local=hash["local"]
|
|
$arg=hash["arg"]
|
|
$pointer=hash["pointer"]
|
|
nlno=hash["ret"]
|
|
$mname=hash["mname"]
|
|
putsd "New arg:#{$arg}"
|
|
putsd "New local:#{$local}"
|
|
putsd "New pointer:#{$pointer}"
|
|
when "halt"
|
|
return lno,funcdef,true
|
|
end
|
|
unless pflowc
|
|
nlno=lno+1
|
|
end
|
|
putsd "New stack:#{$stack}" unless op=="function" or op=="call" or (oldstack==[] and $stack==[])
|
|
undef checklistbounds
|
|
undef raised
|
|
undef putsd
|
|
undef putspfd
|
|
undef putsdf
|
|
return nlno,funcdef,false
|
|
end
|
|
def runprog(prog)
|
|
prog=prog.split("\n")
|
|
i=1
|
|
temp={}
|
|
prog.each do |line|
|
|
temp[i]=line
|
|
i+=1
|
|
end
|
|
prog=temp
|
|
lno=1
|
|
while lno <= prog.length
|
|
lno,funcdef,halt=runvmcommand(prog[lno],lno)
|
|
break if halt
|
|
if funcdef
|
|
i=lno
|
|
while i <= prog.length
|
|
if prog[i]=="return"
|
|
lno=i+1
|
|
break
|
|
end
|
|
i+=1
|
|
end
|
|
end
|
|
end
|
|
puts "Program halted. Heap:#{$heap} "
|
|
if $stack[0]
|
|
puts "Return value:#{$stack[0]}"
|
|
end
|
|
end
|
|
prog=<<-END
|
|
# Memory class
|
|
|
|
function Memory.alloc 1
|
|
push static 0
|
|
pop local 0
|
|
push static 0
|
|
push argument 0
|
|
add
|
|
pop static 0
|
|
push local 0
|
|
return
|
|
|
|
# Array class
|
|
|
|
function Array.set 0
|
|
push argument 0
|
|
push argument 1
|
|
add
|
|
pop pointer 0
|
|
push argument 2
|
|
pop this 0
|
|
return
|
|
|
|
function Array.get 0
|
|
push argument 0
|
|
push argument 1
|
|
add
|
|
pop pointer 0
|
|
push this 0
|
|
return
|
|
|
|
# Test class
|
|
function Test.new 0
|
|
# this=Memory.alloc(2)
|
|
push constant 1
|
|
call Memory.alloc 1
|
|
pop pointer 0
|
|
# this.var=0
|
|
push constant 0
|
|
pop this 0
|
|
# this.var2=0
|
|
push constant 0
|
|
pop this 1
|
|
# push return value
|
|
push pointer 0
|
|
return
|
|
function Test.var= 0
|
|
push argument 0
|
|
pop pointer 0
|
|
push argument 1
|
|
pop this 0
|
|
return
|
|
|
|
function Test.var 0
|
|
push argument 0
|
|
pop pointer 0
|
|
push this 0
|
|
return
|
|
function Test.var2= 0
|
|
push argument 0
|
|
pop pointer 0
|
|
push argument 1
|
|
pop this 1
|
|
return
|
|
|
|
function Test.var2 0
|
|
push argument 0
|
|
pop pointer 0
|
|
push this 1
|
|
return
|
|
|
|
# Main class
|
|
function Main.main 1
|
|
# t=Test.new
|
|
call Test.new 0
|
|
pop local 0
|
|
# t.var=10
|
|
push local 0
|
|
push constant 10
|
|
call Test.var= 2
|
|
# t.var2=11
|
|
push local 0
|
|
push constant 11
|
|
call Test.var2= 2
|
|
return
|
|
|
|
# Sys class
|
|
function Sys.init 0
|
|
call Main.main
|
|
return
|
|
# Init code
|
|
push constant 0
|
|
pop static 0
|
|
call Sys.init 0
|
|
halt
|
|
END
|
|
boundtest=<<-END
|
|
pop pointer 2
|
|
END
|
|
|
|
testing=<<-END
|
|
function main 2
|
|
push constant 10
|
|
pop local 0
|
|
push constant 10
|
|
pop local 1
|
|
return
|
|
call main 0
|
|
END
|
|
runprog(testing)
|