RosettaCodeData/Task/Compiler-virtual-machine-in.../Julia/compiler-virtual-machine-in...

104 lines
4.1 KiB
Plaintext

mutable struct VM32
code::Vector{UInt8}
stack::Vector{Int32}
data::Vector{Int32}
strings::Vector{String}
offsets::Vector{Int32}
lastargs::Vector{Int32}
ip::Int32
VM32() = new(Vector{UInt8}(), Vector{Int32}(), Vector{Int32}(),
Vector{String}(), Vector{Int32}(), Vector{Int32}(), 1)
end
halt, add, sub, mul, Div, mod, not, neg, and, or, lt, gt, le, ge, ne, eq, prts,
prti, prtc, store, Fetch, push, jmp, jz = UInt8.(collect(1:24))
function assemble(io)
vm = VM32()
header = readline(io)
datasize, nstrings = match(r"\w+:\s*(\d+)\s+\w+:\s*(\d+)", header).captures
vm.data = zeros(Int32, parse(Int, datasize) + 4)
for i in 1:parse(Int, nstrings)
line = replace(strip(readline(io), ['"', '\n']), r"\\." => x -> x[end] == 'n' ? "\n" : string(x[end]))
push!(vm.strings, line)
end
while !eof(io)
line = readline(io)
offset, op, arg1, arg2 = match(r"(\d+)\s+(\w+)\s*(\S+)?\s*(\S+)?", line).captures
op = op in ["fetch", "div"] ? uppercasefirst(op) : op
push!(vm.code, eval(Symbol(op)))
if arg1 != nothing
v = parse(Int32, strip(arg1, ['[', ']', '(', ')']))
foreach(x -> push!(vm.code, x), reinterpret(UInt8, [v]))
end
if arg2 != nothing
push!(vm.lastargs, (x = tryparse(Int32, arg2)) == nothing ? 0 : x)
end
push!(vm.offsets, parse(Int32, offset))
end
vm
end
function runvm(vm)
value() = (x = vm.ip; vm.ip += 4; reinterpret(Int32, vm.code[x:x+3])[1])
tobool(x) = (x != 0)
ops = Dict(
halt => () -> exit(),
add => () -> begin vm.stack[end-1] += vm.stack[end]; pop!(vm.stack); vm.stack[end] end,
sub => () -> begin vm.stack[end-1] -= vm.stack[end]; pop!(vm.stack); vm.stack[end] end,
mul => () -> begin vm.stack[end-1] *= vm.stack[end]; pop!(vm.stack); vm.stack[end] end,
Div => () -> begin vm.stack[end-1] /= vm.stack[end]; pop!(vm.stack); vm.stack[end] end,
mod => () -> begin vm.stack[end-1] %= vm.stack[1]; pop!(vm.stack); vm.stack[end] end,
not => () -> vm.stack[end] = vm.stack[end] ? 0 : 1,
neg => () -> vm.stack[end] = -vm.stack[end],
and => () -> begin vm.stack[end-1] = tobool(vm.stack[end-1]) && tobool(vm.stack[end]) ? 1 : 0; pop!(vm.stack); vm.stack[end] end,
or => () -> begin vm.stack[end-1] = tobool(vm.stack[end-1]) || tobool(vm.stack[end]) ? 1 : 0; pop!(vm.stack); vm.stack[end] end,
lt => () -> begin x = (vm.stack[end-1] < vm.stack[end] ? 1 : 0); pop!(vm.stack); vm.stack[end] = x end,
gt => () -> begin x = (vm.stack[end-1] > vm.stack[end] ? 1 : 0); pop!(vm.stack); vm.stack[end] = x end,
le => () -> begin x = (vm.stack[end-1] <= vm.stack[end] ? 1 : 0); pop!(vm.stack); vm.stack[end] = x end,
ge => () -> begin x = (vm.stack[end-1] >= vm.stack[end] ? 1 : 0); pop!(vm.stack); vm.stack[end] = x end,
ne => () -> begin x = (vm.stack[end-1] != vm.stack[end] ? 1 : 0); pop!(vm.stack); vm.stack[end] = x end,
eq => () -> begin x = (vm.stack[end-1] == vm.stack[end] ? 1 : 0); pop!(vm.stack); vm.stack[end] = x end,
prts => () -> print(vm.strings[pop!(vm.stack) + 1]),
prti => () -> print(pop!(vm.stack)),
prtc => () -> print(Char(pop!(vm.stack))),
store => () -> vm.data[value() + 1] = pop!(vm.stack),
Fetch => () -> push!(vm.stack, vm.data[value() + 1]),
push => () -> push!(vm.stack, value()),
jmp => () -> vm.ip += value(),
jz => () -> if pop!(vm.stack) == 0 vm.ip += value() else vm.ip += 4 end)
vm.ip = 1
while true
op = vm.code[vm.ip]
vm.ip += 1
ops[op]()
end
end
const testasm = """
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 """
const iob = IOBuffer(testasm)
const vm = assemble(iob)
runvm(vm)