RCSNUSP/Lua

From Rosetta Code

Lua

<lang lua> -- 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 </lang>