RCSNUSP/Lua

From Rosetta Code

Lua[edit]

 
-- directions
UP, DOWN, LEFT, RIGHT = 1, 2, 4, 8
-- snusp
snIPC, snIPL, snMPT, snDIR, snMEMORY, snSTACK, snCODE = 1, 1, 1, RIGHT, {0}, {}, {}
 
-- stackframe
Stackframe = {}
function Stackframe:new()
local sf = { IPC, IPL, DIR = 0, 0, 0 }
self.__index = self
return setmetatable( sf, self )
end
 
function memStep( a )
snMPT = snMPT + a
if snMPT < 0 then return false end
if snMPT > #snMEMORY then
table.insert( snMEMORY, 0 )
end
return true
end
function changeDir( d )
if d == RIGHT then
if snDIR == RIGHT then snDIR = UP
elseif snDIR == LEFT then snDIR = DOWN
elseif snDIR == DOWN then snDIR = LEFT
else snDIR = RIGHT end
elseif d == LEFT then
if snDIR == RIGHT then snDIR = DOWN
elseif snDIR == LEFT then snDIR = UP
elseif snDIR == DOWN then snDIR = RIGHT
else snDIR = LEFT end
end
end
function step()
if snDIR == RIGHT then snIPC = snIPC + 1
elseif snDIR == LEFT then snIPC = snIPC - 1
elseif snDIR == DOWN then snIPL = snIPL + 1
elseif snDIR == UP then snIPL = snIPL - 1
end
if snIPL > #snCODE or snIPL < 1 then return false end
if snIPC > #snCODE[snIPL] or snIPC < 1 then return false end
return true
end
function pushFrame()
local sf = Stackframe:new(); sf.IPC = snIPC;
if snDIR == RIGHT then sf.IPC = sf.IPC + 1
elseif snDIR == LEFT then sf.IPC = sf.IPC - 1
end
sf.IPL = snIPL;
if snDIR == DOWN then sf.IPL = sf.IPL + 1
elseif snDIR == UP then sf.IPL = sf.IPL - 1
end
sf.DIR = snDIR
table.insert( snSTACK, 1, sf )
end
function popFrame()
if #snSTACK < 1 then return false end
local sf = table.remove( snSTACK, 1 )
snIPC = sf.IPC; snIPL = sf.IPL; snDIR = sf.DIR
sf = nil
return true
end
function exec( c )
local res = true
if c == "<" then res = memStep( -1 )
elseif c == ">" then res = memStep( 1 )
elseif c == "+" then snMEMORY[snMPT] = snMEMORY[snMPT] + 1
elseif c == "-" then snMEMORY[snMPT] = snMEMORY[snMPT] - 1
elseif c == "." then io.write( string.char( snMEMORY[snMPT] ) )
elseif c == "," then snMEMORY[snMPT] = string.byte( io.read() )
elseif c == "!" then res = step()
elseif c == "?" and snMEMORY[snMPT] == 0 then res = step()
elseif c == "@" then pushFrame()
elseif c == "#" then res = popFrame()
elseif c == "/" then changeDir( RIGHT )
elseif c == "\\" then changeDir( LEFT )
end
return res
end
function run( filename )
local i, lc = assert( io.open( filename, "rb" ) ), 1
for ln in io.lines( filename ) do
for c = 1, #ln do
if ln:sub( c, c ) == "$" then
snIPL = lc; snIPC = c
end
end
snCODE[#snCODE + 1] = ln
lc = lc + 1
end
repeat
if not exec( snCODE[snIPL]:sub( snIPC, snIPC ) ) then break end
until step() == false
end
-- [[ entry point ( argument = snusp program file name ) ]]--
if arg[1] ~= nil then run( arg[1] ) end