User:Iconmaster/iscom.lua
Jump to navigation
Jump to search
This is an implementation of ISCOM in Lua.
-------------------------------------
--
-- ISCOM interpreter
-- Made by Joshua Robbins, 3/23/11
-- Interprets ISCOM src.
--
-------------------------------------
--Variable setup
bit = require("bit")
socket = require("socket")
mem = {}
ip = 1
numclass = "[%[%]0-9a-zA-Z%#%@%$%_]+"
opclass = "[%+%-%*%/%%%&%|%!%<%>%=%~%^%{%}]"
code = {}
const = {}
if arg then
while #arg ~= 0 do
c = table.remove(arg,1)
if c == "-f" then
src = io.open(table.remove(arg,1),"r"):read("*a")
elseif c == "-d" then
DEBUG = true
else
src = c
end
end
end
if not src then src = io.read("*l") end
function getmem(addr)
local nests,num,i
nests = #(addr:match("^%[*"))
num = addr:match("[0-9a-zA-Z#@$_]+")
if const[num] then num = const[num] end
if not num then return 0 end
num = num:gsub("_","-")
if num == "#" then num = ip end
if num == "@" then num = fin() end
if num == "$" then num = port end
num = tonumber(num)
if nests == 0 then return num end
for i=1,nests do
num = mem[num] or 0
end
return num
end
function setmem(addr,val)
local nests,num,i
nests = #(addr:match("^%[*"))
num = addr:match("[0-9#@$_A-Za-z]+")
if const[num] then num = const[num] end
num = num:gsub("_","-")
if num == "#" then ip = val - 1 return end
if num == "@" then fout(val) return end
if num == "$" then port=val fin=ins[port] fout=outs[port] return end
num = tonumber(num)
if nests == 0 then mem[num]=val end
for i=1,nests do
num = mem[num] or 0
end
mem[num]=val
end
-- the operator table.
ops = {}
ops["+"] = function(n1,n2) return n1 + n2 end
ops["-"] = function(n1,n2) return n1 - n2 end
ops["*"] = function(n1,n2) return n1 * n2 end
ops["/"] = function(n1,n2) return math.floor(n1 / n2) end
ops["%"] = function(n1,n2) return n1 % n2 end
ops["&"] = function(n1,n2) return bit.band(n1,n2) end
ops["|"] = function(n1,n2) return bit.bor(n1,n2) end
ops["!"] = function(n1) if n1~=0 then return 0 else return 1 end end
ops[":"] = function(n1) return bit.bnot(n1) end
ops["^"] = function(n1,n2) return bit.bxor(n1,n2) end
ops["="] = function(n1,n2) if n1 == n2 then return 1 else return 0 end end
ops["~"] = function(n1,n2) if n1 ~= n2 then return 1 else return 0 end end
ops["<"] = function(n1,n2) if n1 < n2 then return 1 else return 0 end end
ops[">"] = function(n1,n2) if n1 > n2 then return 1 else return 0 end end
ops["{"] = function(n1,n2) return bit.rol(n1,n2) end
ops["}"] = function(n1,n2) return bit.ror(n1,n2) end
--The Default Port Table.
ins = {}
outs = {}
port = 0
cfn = ""
socport = 0
socstate = 0
socaddr = ""
sendbuf = ""
randmax = 100
lbls = {}
ins[0] = function()
local ret
if bfr then
ret = bfr:sub(1,1)
bfr = bfr:sub(2)
if bfr == "" then bfr = nil end
return ret:byte()
else
bfr = io.read("*l") .. "\n"
ret = bfr:sub(1,1)
bfr = bfr:sub(2)
if bfr == "" then bfr = nil end
return ret:byte()
end
end
outs[0]= function(n) io.write(string.char(n)) end
ins[1] = function() return io.read("*n") end
outs[1]= function(n) io.write(tostring(n)) end
ins[2] = function() return #cfn end
outs[2]= function(n) if cfn == 10 then cfn = "" else cfn = cfn .. string.char(n) end cfile = io.open(cfn,"r+") end
ins[3] = function() if cfn then return cfile:seek() else return 0 end end
outs[3]= function(n) if cfn then cfile:seek("set",n) end end
ins[4] = function() if not cfile then cfile = io.open(cfn,"w+") end c = cfile:read(1) if c then return c:byte() else return -1 end end
outs[4]= function(n) if not cfile then cfile = io.open(cfn,"w+") end cfile:write(string.char(n)) end
ins[5] = function() if not cfile then cfile = io.open(cfn,"w+") end c = cfile:read("*n") return c or -1 end
outs[5]= function(n) if not cfile then cfile = io.open(cfn,"w+") end cfile:write(tostring(n)) end
ins[6] = function() return socstate end
outs[6]= function(n)
socstate = n
if socstate == 0 and soc then
soc:close()
soc = nil
if cli then cli:close() cli = nil end
elseif socstate == 1 then
soc = socket.connect(socaddr,socport)
elseif socstate == 2 then
soc = socket.bind(socaddr,socport)
cli = soc:accept()
end
end
ins[7] = function() return #socaddr end
outs[7]= function(n) if n == 10 then socaddr = "" else socaddr = socaddr .. string.char(n) end end
ins[8] = function() return socport end
outs[8]= function(n) socport = n end
ins[9] = function()
if socstate == 1 then --client
if not soc then return -1 end
c = soc:receive(1)
if c then return c:byte() else return -1 end
elseif socstate == 2 then --server
if not cli then return -1 end
c = cli:receive(1)
if c then return c:byte() else return -1 end
end
end
outs[9]= function(n)
if socstate == 1 then --client
if not soc then return end
if n == -1 then soc:send(sendbuf) sendbuf = "" return end
sendbuf = sendbuf .. string.char(n)
elseif socstate == 2 then --server
if not cli then return end
if n == -1 then cli:send(sendbuf) sendbuf = "" return end
sendbuf = sendbuf .. string.char(n)
end
end
ins[10] = function() return socket.gettime() end
outs[10]= function(n) socket.sleep(n) end
ins[11] = function() return math.random(randmax) end
outs[11]= function(n) randmax = n end
fin = ins[0]
fout=outs[0]
--parse src
function parse(src)
local code,ocode = {},{}
local ii,src2,i,v
src = src:gsub("\"([^\"]*)\"",function(t)
local c,s
s = ""
for c in t:gmatch(".") do
s = s .. " @='" .. c .. " "
end
return s
end,nil)
src = src:gsub("%b()","")
src = src:gsub("\'(.)",function(m) return tostring(m:byte()) end)
ii = 0
src2 = src
for i in src2:gmatch("%S+") do
if i:match("^;;") then
if i:match("=") then
src = src:gsub(i,"")
a,b = i:match(";;([^=]*)=(.*)")
const[a] = b
else
src = src:gsub(i,"")
const[i:sub(3)] = tostring(ii + 1)
lbls[ii] = i
end
else
ii = ii + 1
end
end
ii = nil
src2 = nil
ocode = {}
for i in src:gmatch("%S+") do
table.insert(code,i)
table.insert(ocode,i)
end
for i,v in ipairs(code) do
if v:sub(1,1)=="?" then
code[i] = {"?",v:match("("..numclass..")("..opclass..")("..numclass..")")}
else
cellto = v:match("^"..numclass)
if cellto then
v = v:sub(#cellto+2)
op = v:match("^"..opclass)
if op then
code[i] = {"+",cellto,{op,v:match(numclass)}}
v = v:sub(2)
for op,num in v:gmatch("("..opclass..")("..numclass..")") do
table.insert(code[i],{op,num})
end
else
code[i] = {"=",cellto,v:match(numclass)}
end
end
end
end
return code,ocode
end
code,ocode = parse(src)
function step()
if ip>#code then return false end
cmd = code[ip]
if cmd[1]=="+" then
num = getmem("["..cmd[2])
for i,v in ipairs(cmd) do
if type(v)=="table" then
num = ops[v[1]](num,getmem(v[2]))
end
end
setmem(cmd[2],num)
elseif cmd[1]=="=" then
setmem(cmd[2],getmem(cmd[3]))
elseif cmd[1]=="?" then
if ops[cmd[3]](getmem(cmd[2]),getmem(cmd[4]))==0 then ip = ip + 1 end
end
ip=ip+1
return true
end
if DEBUG then
tracking = {}
function track()
io.write("#: " .. ip .. " $: " .. port .. " [#]: " .. (ocode[ip] or "nil") .. " " .. (lbls[ip-1] or "") .. " ")
for i,v in pairs(tracking) do
io.write(i .. ": " .. getmem(v) .. " ")
end
io.write("\n")
end
while true do
io.write(">>")
dc = io.read("*l")
dcmd = {}
for s in dc:gmatch("%S+") do
table.insert(dcmd,s)
end
if #dcmd == 0 then
if not step() then
print("program done.")
else
if verbose then track() end
end
elseif ops[dcmd[1]] then
print(ops[dcmd[1]](getmem(dcmd[2]),getmem(dcmd[3])))
elseif getmem(dcmd[1]) and dcmd[2] and getmem(dcmd[2]) then
for i=getmem(dcmd[1]),getmem(dcmd[2]) do
io.write((mem[i] or 0) .. " ")
end
io.write("\n")
elseif getmem(dcmd[1]) then
print(mem[getmem(dcmd[1])] or 0)
elseif dcmd[1] == "r" then
track()
elseif dcmd[1] == "j" then
ip = getmem(dcmd[2])
elseif dcmd[1] == "p" then
port = getmem(dcmd[2])
fin = ins[port]
fout = outs[port]
elseif dcmd[1] == "s" then
setmem(dcmd[2],getmem(dcmd[3]))
elseif dcmd[1] == "l" then
if dcmd[2] and dcmd[3] then
for i=getmem(dcmd[2]),getmem(dcmd[3]) do
print(i .. ": " .. ocode[i] .. " " .. (lbls[i-1] or ""))
end
elseif dcmd[2] then
print(getmem(dcmd[2]) .. ": " .. ocode[getmem(dcmd[2])] .. " " .. (lbls[getmem(dcmd[2])-1] or ""))
else
for i=1,#code do
print(i .. ": " .. ocode[i] .. " " .. (lbls[i-1] or ""))
end
end
elseif dcmd[1] == "c" then
if dcmd[2] and dcmd[3] then
const[dcmd[2]] = dcmd[3]
elseif dcmd[2] then
print(const[dcmd[2]])
else
for i,v in pairs(const) do
print(i.."="..v)
end
end
elseif dcmd[1] == "g" then
if dcmd[2] == nil then dcmd[2] = #code else dcmd[2] = getmem(dcmd[2]) end
while ip <= dcmd[2] do
if not step() then
print("program done.")
break
else
if verbose then track() end
end
end
print("Finished executing segment.")
elseif dcmd[1] == "w" then
ncode,nocode = parse(table.concat(dcmd," ",2))
t = {}
for i,v in ipairs(code) do
table.insert(t,v)
end
for i,v in ipairs(ncode) do
table.insert(t,v)
end
code = t
t = {}
for i,v in ipairs(ocode) do
table.insert(t,v)
end
for i,v in ipairs(nocode) do
table.insert(t,v)
end
ocode = t
elseif dcmd[1] == "i" then
dcmd[2] = getmem(dcmd[2])
ncode,nocode = parse(table.concat(dcmd," ",3))
t = {}
for i,v in ipairs(code) do
table.insert(t,v)
end
for i,v in ipairs(ncode) do
table.insert(t,dcmd[2],v)
end
code = t
t = {}
for i,v in ipairs(ocode) do
table.insert(t,v)
end
for i,v in ipairs(nocode) do
table.insert(t,dcmd[2],v)
end
ocode = t
elseif dcmd[1] == "d" then
for i=1,getmem(dcmd[3]) do
table.remove(code,getmem(dcmd[2]))
table.remove(ocode,getmem(dcmd[2]))
end
elseif dcmd[1] == "q" then
os.exit()
elseif dcmd[1] == "b" then
mem = {}
ip = 1
port = 0
fin = ins[0]
fout=outs[0]
cfn = ""
socport = 0
socstate = 0
socaddr = ""
sendbuf = ""
randmax = 100
elseif dcmd[1] == "v" then
verbose = not verbose
elseif dcmd[1] == "t" then
if dcmd[2] and dcmd[3] then
tracking[dcmd[2]] = dcmd[3]
elseif dcmd[2] then
tracking[dcmd[2]] = nil
else
tracking = {}
end
end
end
else
while step() do
end
end