148 lines
5.1 KiB
Text
148 lines
5.1 KiB
Text
Module Virtual_Machine_Interpreter (a$){
|
|
\\ function to extract string, replacing escape codes.
|
|
Function GetString$(a$) {
|
|
s=instr(a$, chr$(34))
|
|
m=rinstr(a$,chr$(34))-s
|
|
if m>1 then
|
|
\\ process escape codes
|
|
=format$(mid$(a$, s+1, m-1))
|
|
else
|
|
=""
|
|
end if
|
|
}
|
|
\\ module to print a string to console using codes, 13, 10, 9
|
|
Module printsrv (a$) {
|
|
for i=1 to len(a$)
|
|
select case chrcode(Mid$(a$,i,1))
|
|
case 13
|
|
cursor 0
|
|
case 10
|
|
cursor 0 : Print
|
|
case 9
|
|
cursor ((pos+tab) div tab)*tab
|
|
else case
|
|
{
|
|
m=pos :if pos>=width then Print : m=pos
|
|
Print Mid$(a$,i,1);
|
|
if m<=width then cursor m+1
|
|
}
|
|
end select
|
|
next i
|
|
}
|
|
const nl$=chr$(13)+chr$(10)
|
|
\\ we can set starting value to any number n where 0<=n<=232
|
|
enum op { halt_=232, add_, sub_, mul_, div_, mod_, not_, neg_, and_, or_, lt_,
|
|
gt_, le_, ge_, ne_, eq_, prts_, prti_, prtc_, store_, fetch_, push_,
|
|
jmp_, jz_
|
|
}
|
|
exit_now=false
|
|
Inventory func=halt_:=lambda->{exit_now=true}
|
|
Append func, push_:=lambda->{sp--:return stack_, sp:=eval(code_, pc as long):pc+=4}
|
|
Append func, jz_:=lambda->{
|
|
sp++: if eval(stack_, sp-1)=0 then pc=eval(code_, pc as long) else pc+=4
|
|
}
|
|
Append func, jmp_:=lambda->{pc=eval(code_, pc as long)}
|
|
Append func, fetch_:=lambda->{sp--:Return stack_, sp:=eval(stack_, eval(code_, pc as long)):pc+=4}
|
|
Append func, store_:=lambda->{Return stack_, eval(code_, pc as long):=eval(stack_, sp):sp++:pc+=4}
|
|
Append func, add_:=lambda->{Return stack_, sp+1:=uint(sint(eval(stack_, sp+1))+sint(eval(stack_, sp))):sp++}
|
|
Append func, sub_:=lambda->{Return stack_, sp+1:=uint(sint(eval(stack_, sp+1))-sint(eval(stack_, sp))):sp++}
|
|
Append func, mul_:=lambda->{Return stack_, sp+1:=uint(sint(eval(stack_, sp+1))*sint(eval(stack_, sp))):sp++}
|
|
Append func, div_:=lambda->{Return stack_, sp+1:=uint(sint(eval(stack_, sp+1)) div sint(eval(stack_, sp))):sp++}
|
|
Append func, mod_:=lambda->{Return stack_, sp+1:=uint(sint(eval(stack_, sp+1)) mod sint(eval(stack_, sp))) :sp++}
|
|
Append func, not_:=lambda->{Return stack_, sp:=if(eval(stack_, sp)=0->uint(-1),0)}
|
|
Append func, neg_:=lambda->{Return stack_, sp:=uint(-sint(eval(stack_, sp)))}
|
|
Append func, and_:=lambda->{Return stack_, sp+1:=binary.and(eval(stack_, sp+1),eval(stack_, sp)):sp++ }
|
|
Append func, or_:=lambda->{Return stack_, sp+1:=binary.or(eval(stack_, sp+1),eval(stack_, sp)):sp++ }
|
|
Append func, lt_:=lambda->{Return stack_, sp+1:=uint(if(sint(eval(stack_, sp+1))<sint(eval(stack_, sp))->-1, 0)):sp++}
|
|
Append func, gt_:=lambda->{Return stack_, sp+1:=uint(if(sint(eval(stack_, sp+1))>sint(eval(stack_, sp))->-1, 0)):sp++}
|
|
Append func, le_:=lambda->{Return stack_, sp+1:=uint(if(sint(eval(stack_, sp+1))<=sint(eval(stack_, sp))->-1, 0)):sp++}
|
|
Append func, ge_:=lambda->{Return stack_, sp+1:=uint(if(sint(eval(stack_, sp+1))>=sint(eval(stack_, sp))->-1, 0)):sp++}
|
|
Append func, ne_:=lambda->{Return stack_, sp+1:=uint(if(eval(stack_, sp+1)<>eval(stack_, sp)->-1, 0)):sp++}
|
|
Append func, eq_:=lambda->{Return stack_, sp+1:=uint(if(eval(stack_, sp+1)=eval(stack_, sp)->-1, 0)):sp++}
|
|
Append func, prts_:=lambda->{printsrv strings$(eval(stack_,sp)):sp++}
|
|
Append func, prti_:=lambda->{printsrv str$(sint(eval(stack_,sp)),0):sp++}
|
|
Append func, prtc_:=lambda->{printsrv chrcode$(eval(stack_,sp)):sp++}
|
|
Rem : Form 120, 60 ' change console width X height to run Ascii Mandlebrot examlpe
|
|
Report "Virtual Assembly Code:"+{
|
|
}+a$
|
|
Print "Prepare Byte Code"
|
|
|
|
\\ get datasize
|
|
a$=rightpart$(a$, "Datasize:")
|
|
m=0
|
|
data_size=val(a$, "int", m)
|
|
a$=mid$(a$, m)
|
|
\\ make stack
|
|
if data_size>0 then Buffer Clear stack_ as long*data_size
|
|
\\ dim or redim buffer append 1000 long as is.
|
|
Buffer stack_ as long*(1000+data_size)
|
|
\\ get strings
|
|
a$=rightpart$(a$, "Strings:")
|
|
m=0
|
|
strings=val(a$, "int", m)
|
|
a$=rightpart$(a$, nl$)
|
|
|
|
if strings>0 then
|
|
Dim strings$(strings)
|
|
for i=0 to strings-1
|
|
strings$(i)=GetString$(leftpart$(a$, nl$))
|
|
a$=rightpart$(a$, nl$)
|
|
Next i
|
|
End if
|
|
buffer clear code_ as byte*1000
|
|
do
|
|
m=0
|
|
offset=val(a$,"int", m)
|
|
if m<0 then exit
|
|
a$=mid$(a$,m)
|
|
line$=trim$(leftpart$(a$,nl$))
|
|
if line$="" then line$=trim$(a$) else a$=trim$(rightpart$(a$, nl$))
|
|
op$=if$(instr(line$," ")>0->leftpart$(line$," "), line$)
|
|
if not valid(eval(op$+"_")) then exit
|
|
opc=eval(op$+"_")
|
|
Return code_, offset:=opc
|
|
if opc>=store_ then
|
|
line$=rightpart$(line$," ")
|
|
select case opc
|
|
case store_, fetch_
|
|
Return code_, offset+1:=val(rightpart$(leftpart$(line$,"]"),"[")) as long : offset+=4
|
|
case push_
|
|
Return code_, offset+1:=uint(val(line$)) as long : offset+=4
|
|
case jz_, jmp_
|
|
Return code_, offset+1:=val(rightpart$(line$,")")) as long : offset+=4
|
|
end select
|
|
end if
|
|
Always
|
|
Print "Press any key" : Push key$ : Drop
|
|
\\ Prepare VM
|
|
let pc=0, sp=len(stack_) div 4
|
|
do
|
|
b=func(eval(code_, pc))
|
|
pc++
|
|
call local b()
|
|
until exit_now
|
|
Print "done"
|
|
}
|
|
Virtual_Machine_Interpreter {
|
|
Datasize: 1 Strings: 2
|
|
"count is: "
|
|
"\n"
|
|
0 push 1
|
|
5 store [0]
|
|
10 fetch [0]
|
|
15 push 10
|
|
20 lt
|
|
21 jz (43) 65
|
|
26 push 0
|
|
31 prts
|
|
32 fetch [0]
|
|
37 prti
|
|
38 push 1
|
|
43 prts
|
|
44 fetch [0]
|
|
49 push 1
|
|
54 add
|
|
55 store [0]
|
|
60 jmp (-51) 10
|
|
65 halt
|
|
}
|