I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

Execute SNUSP

From Rosetta Code
(Redirected from RCSNUSP)
Task
Execute SNUSP
You are encouraged to solve this task according to the task description, using any language you may know.
Execute SNUSP is an implementation of SNUSP. Other implementations of SNUSP.
RCSNUSP is a set of SNUSP compilers and interpreters written for Rosetta Code in a variety of languages. Below are links to each of the versions of RCSNUSP.

An implementation need only properly implement the Core SNUSP instructions ('$', '\', '/', '+', '-', '<', '>', ',', '.', '!', and '?'). Modular SNUSP ('#', '@') and Bloated SNUSP (':', ';', '%', and '&') are also allowed, but not required. Any extra characters that you implement should be noted in the description of your implementation. Any cell size is allowed, EOF support is optional, as is whether you have bounded or unbounded memory.

11l[edit]

Translation of: Python
V HW = ‘
/++++!/===========?\>++.>+.+++++++..+++\
\+++\ | /+>+++++++>/ /++++++++++<<.++>./
$+++/ | \+++++++++>\ \+++++.>.+++.-----\
\==-<<<<+>+++/ /=.>.+>.--------.-/’
 
F snusp(store, code)
V ds = [Byte(0)] * store
V dp = 0
V cs = code.split("\n")
V ipr = 0
V ipc = 0
 
L(row) cs
ipc = row.findi(‘$’)
I ipc != -1
ipr = L.index
L.break
 
V id = 0
 
F step()
I @id [&] 1
@ipr += 1 - (@id [&] 2)
E
@ipc += 1 - (@id [&] 2)
 
L ipr >= 0 & ipr < cs.len & ipc >= 0 & ipc < cs[ipr].len
S cs[ipr][ipc]
‘>’
dp++
‘<’
dp--
‘+’
ds[dp]++
‘-’
ds[dp]--
‘.’
 :stdout.write(Char(code' ds[dp]))
‘,’
ds[dp] = Byte(:stdin.read(1).code)
‘/’
id = (-)id
‘\’
id (+)= 1
‘!’
step()
‘?’
I !(ds[dp])
step()
step()
 
snusp(5, HW)
Output:
Hello World!

Ada[edit]

See Execute SNUSP/Ada.

AutoHotkey[edit]

See RCSNUSP/AutoHotkey.

C[edit]

See RCSNUSP/C.

C++[edit]

See RCSNUSP/C++.

COBOL[edit]

See RCSNUSP/COBOL.

D[edit]

See RCSNUSP/D.

F#[edit]

See RCSNUSP/F Sharp.

Factor[edit]

See RCSNUSP/Factor.

Go[edit]

See RCSNUSP/Go.

Haskell[edit]

See RCSNUSP/Haskell.

Icon and Unicon[edit]

#
# snusp.icn, A Modular SNUSP interpreter
#
 
$define VERSION 0.6
 
# allow a couple of cli options
link options
 
# directions
$define DRIGHT 1
$define DLEFT 2
$define DUP 3
$define DDOWN 4
 
record position(row, col)
global dir, ip, ram
 
procedure main(argv)
local ch, codespace, col, dp, fn, line
local row := 1
local wid := 0
local dirs := []
local ips := []
local opts, verbose, debug
 
opts := options(argv, "-h! -v! -d!", errorproc)
\opts["v"] & verbose := 1
\opts["h"] & show_help(verbose)
\opts["d"] & debug := 1
 
ip := position(1,1)
 
# initial direction
dir := DRIGHT
 
# prepare initial memory
ram := list(1, 0)
 
# prepare code field
codespace := []
 
fn := open(argv[1], "r") | &input
if (fn === &input) & \opts["h"] then return
 
while line := read(fn) do {
put(codespace, line)
wid := max(*line, wid)
}
if *codespace = 0 then return
every line := !codespace do {
codespace[row] := left(codespace[row], wid)
# track starting indicator
if /col := find("$", codespace[row]) then {
ip.row := row
ip.col := col
}
row +:= 1
}
 
if \verbose then {
write("Starting at ", ip.row, ", ", ip.col, " with codespace:")
every write(!codespace)
}
 
dp := 1
repeat {
if not (ch := codespace[ip.row][ip.col]) then break
if \debug then {
write(&errout, "dir: ", dir, " ch: ", ch, " [", ord(ch), "]",
" row: ", ip.row, " col: ", ip.col,
" dp: ", dp, " ram[dp]: ", ram[dp])
}
case ch of {
# six of the bf instructions
"+": ram[dp] +:= 1
"-": ram[dp] -:= 1
">": resize(dp +:= 1)
"<": dp -:= 1
".": writes(char(ram[dp]) | char(0))
",": ram[dp] := getche()
# direction change, LURD, RULD, SKIP, SKIPZ
"\\": { # LURD
case dir of {
DRIGHT: dir := DDOWN
DLEFT: dir := DUP
DUP: dir := DLEFT
DDOWN: dir := DRIGHT
}
}
"/": { # RULD
case dir of {
DRIGHT: dir := DUP
DLEFT: dir := DDOWN
DUP: dir := DRIGHT
DDOWN: dir := DLEFT
}
}
"!": step()
"?": { # skipz
if ram[dp] = 0 then {
step()
}
}
# modular SNUSP
"@": { # Enter
push(dirs, dir)
push(ips, copy(ip))
}
"#": { # Leave
if *dirs < 1 then break
dir := pop(dirs)
ip := pop(ips)
step()
}
}
step()
}
end
 
# advance the ip depending on direction
procedure step()
case dir of {
DRIGHT: ip.col +:= 1
DLEFT: ip.col -:= 1
DUP: ip.row -:= 1
DDOWN: ip.row +:= 1
}
end
 
# enlarge memory when needed
procedure resize(elements)
until *ram >= elements do put(ram, 0)
end
 
# quick help or verbose help
procedure show_help(verbose)
write("SNUSP interpeter in Unicon, version ", VERSION)
write("CORE and MODULAR, not yet BLOATED")
write()
write("Usage: unicon snusp.icn -x [filename] [-h|-v|-d]")
write(" -h, help")
write(" -v, verbose (and verbose help")
write(" -d, debug (step tracer)")
if \verbose then {
write()
write("Instructions:")
write(" + INCR, Increment current memory location")
write(" - DECR, Decrement current memory location")
write(" > RIGHT, Advance memory pointer")
write(" < LEFT, Retreat memory pointer")
write(" . WRITE, Output contents of current memory cell, in ASCII")
write(" , READ, Accept key and place byte value in current memory cell")
write(" \\ LURD, If going:")
write(" left, go up")
write(" up, go left")
write(" right, go down")
write(" down, go right")
write(" / RULD, If going:")
write(" right, go up")
write(" up, go right")
write(" left, go down")
write(" down, go left")
write(" !, SKIP, Move forward one step in current direction")
write(" ?, SKIPZ, If current memory cell is zero then SKIP")
write("Modular SNUSP adds:")
write(" @, ENTER, Push direction and instruction pointer")
write(" #, LEAVE, Pop direction and instruction pointer and SKIP")
write()
write("All other characters are NOOP, explicitly includes =,|,spc")
write(" $, can set the starting location; first one found")
write()
write("Hello world examples:")
write()
write("CORE SNUSP:")
write("/++++!/===========?\\>++.>+.+++++++..+++\\")
write("\\+++\\ | /+>+++++++>/ /++++++++++<<.++>./")
write("$+++/ | \\+++++++++>\\ \\+++++.>.+++.-----\\")
write(" \\==-<<<<+>+++/ /=.>.+>.--------.-/")
write()
write("Modular SNUSP:")
write(" /@@@@++++# #[email protected]@\ #[email protected]@@\\n")
write("[email protected]\\[email protected]/e.+++++++l.l.+++o.>>++++.< .<@/[email protected]\\[email protected]\\[email protected]\\d.>[email protected]/.#")
write(" \\@@@@=>++++>+++++<<@+++++# #[email protected]@/!=========/!==/")
write()
}
end
Output:

Using the Modular SNUSP sample

prompt$ unicon -s snusp.icn -x hello.snusp
Hello, world!

J[edit]

This program places no limits on the program or data size. Perhaps I'll revisit and write a tacit version of the SNUSP interpreter.

 
Note 'snusp'
 
Without $ character the program counter starts at top left (0 0) moving to the right (0 1)
 
> increment the pointer (to point to the next cell to the right).
< decrement the pointer (to point to the next cell to the left).
+ increment (increase by one) the cell at the pointer.
- decrement (decrease by one) the cell at the pointer.
. output the value of the cell at the pointer as a character.
, accept one character of input, storing its value in the cell at the pointer.
\/ mirrors
 ? skip if memory pointer is 0
 ! skip
$ optional start program here (also heading to the right)
 
)

 
smoutput 'Toroidal programs run forever. Use ^C to interrupt.'
 
main =: 3 : 0 NB. use: main 'program.snusp'
PROGRAM =: [;._2 LF ,~ 1!:1 boxopen y
SHAPE =: $PROGRAM
PC =: SHAPE#:(,PROGRAM) i.'$'
PCSTEP =: 0 1
CELL =: 0
CELLS =: ,0
while. 1 do. NB. for_i. i.400 do.
INSTRUCTION =: (<PC) { PROGRAM
STEP =: PCSTEP
select. INSTRUCTION
case. '<' do.
CELL =: <: CELL
if. CELL < 0 do.
CELL =: 0
CELLS =: 0 , CELLS
end.
case. '>' do.
CELL =: >: CELL
if. CELL >: # CELLS do.
CELLS =: CELLS , 0
end.
case. ;/'-+' do. CELLS =: CELL ((<:'- +'i.INSTRUCTION)+{)`[`]} CELLS
case. '.' do. 1!:2&4 (CELL{CELLS){a.
case. ',' do. CELLS =: (1!:1<1) CELL } CELLS
fcase. '/' do. STEP =: - STEP
case. '\' do. STEP =: PCSTEP =: |. STEP
case. '?' do. STEP =: +:^:(0 = CELL{CELLS) STEP
case. '!' do. STEP =: +: STEP
end.
PC =: (| (PC + STEP + ])) SHAPE NB. toroidal
NB. smoutput PC;CELL;CELLS NB. debug
end.
)
 
Store
\      display  JJ and linefeed, then loop forever
\ +++++++++++++++++++++++++++++++++++++\
 ! /+++++++++++++++++++++++++++++++++++++/
/ \..<+++++\
\ . +++++/
 
as J.snusp
   load'snusp.ijs'  NB. the j code above
Toroidal programs run forever.  Use ^C to interrupt.
   
   main'J.snusp'
JJ
^C
|attention interrupt: main
   

Java[edit]

See RCSNUSP/Java

JavaScript[edit]

See RCSNUSP/JavaScript.

Julia[edit]

This Modular SNUSP interpreter uses modular calls to echo the first 2 characters entered. Try typing "Hi" at the prompt.

const echo2 =  raw"""
/==!/======ECHO==,==.==#
| |
$==>[email protected]/[email protected]/==<==#"""
 
@enum Direction left up right down
 
function snusp(datalength, progstring)
stack = Vector{Tuple{Int, Int, Direction}}()
data = zeros(datalength)
dp = ipx = ipy = 1
direction = right # default to go to right at beginning
 
lines = split(progstring, "\n")
lmax = maximum(map(length, lines))
lines = map(x -> rpad(x, lmax), lines)
for (y, li) in enumerate(lines)
if (x = findfirst("\$", li)) != nothing
(ipx, ipy) = (x[1], y)
end
end
 
instruction = Dict([('>', ()-> dp += 1),
('<', ()-> (dp -= 1; if dp < 0 running = false end)), ('+', ()-> data[dp] += 1),
('-', ()-> data[dp] -= 1), (',', ()-> (data[dp] = read(stdin, UInt8))),
('.', ()->print(Char(data[dp]))),
('/', ()-> (d = Int(direction); d += (iseven(d) ? 3 : 5); direction = Direction(d % 4))),
('\\', ()-> (d = Int(direction); d += (iseven(d) ? 1 : -1); direction = Direction(d))),
('!', () -> ipnext()), ('?', ()-> if data[dp] == 0 ipnext() end),
('@', ()-> push!(stack, (ipx, ipy, direction))),
('#', ()-> if length(stack) > 0 (ipx, ipy, direction) = pop!(stack) end),
('\n', ()-> (running = false))])
 
inboundsx(plus) = (plus ? (ipx < lmax) : (ipx > 1)) ? true : exit(data[dp])
inboundsy(plus) = (plus ? (ipy < length(lines)) : (ipy > 1)) ? true : exit(data[dp])
function ipnext()
if direction == right && inboundsx(true) ipx += 1
elseif direction == left && inboundsx(false) ipx -= 1
elseif direction == down && inboundsy(true) ipy += 1
elseif direction == up && inboundsy(false) ipy -= 1
end
end
 
running = true
while running
cmdcode = lines[ipy][ipx]
if haskey(instruction, cmdcode)
instruction[cmdcode]()
end
ipnext()
end
exit(data[dp])
end
 
snusp(100, echo2)
Output:

> Hi
Hi
>

Kotlin[edit]

Translation of: Go
// version 1.1.2
 
// requires 5 chars (10 bytes) of data store
const val hw = """
/++++!/===========?\>++.>+.+++++++..+++\
\+++\ | /+>+++++++>/ /++++++++++<<.++>./
$+++/ | \+++++++++>\ \+++++.>.+++.-----\
\==-<<<<+>+++/ /=.>.+>.--------.-/"
""
 
// input is a multi-line string.
fun snusp(dlen: Int, raw: String) {
val ds = CharArray(dlen) // data store
var dp = 0 // data pointer
var s = raw
 
// remove leading '\n' from string if present
s = s.trimStart('\n')
 
// make 2 dimensional instruction store and declare instruction pointers
val cs = s.split('\n')
var ipr = 0
var ipc = 0
 
// look for starting instruction
findStart@ for ((r, row) in cs.withIndex()) {
for ((i, c) in row.withIndex()) {
if (c == '$') {
ipr = r
ipc = i
break@findStart
}
}
}
 
var id = 0
val step = fun() {
if (id and 1 == 0)
ipc += 1 - (id and 2)
else
ipr += 1 - (id and 2)
}
 
// execute
while ((ipr in 0 until cs.size) && (ipc in 0 until cs[ipr].length)) {
when (cs[ipr][ipc]) {
'>' -> dp++
'<' -> dp--
'+' -> ds[dp]++
'-' -> ds[dp]--
'.' -> print(ds[dp])
',' -> ds[dp] = readLine()!![0]
'/' -> id = id.inv()
'\\' -> id = id xor 1
'!' -> step()
'?' -> if (ds[dp] == '\u0000') step()
}
step()
}
}
 
fun main(args: Array<String>) {
snusp(5, hw)
}
Output:
Hello World!

Lua[edit]

See RCSNUSP/Lua.

Mathematica[edit]

See RCSNUSP/Mathematica.

OCaml[edit]

See RCSNUSP/OCaml.

Perl[edit]

See RCSNUSP/Perl.

Phix[edit]

Translation of: Go
integer id = 0, ipr = 1, ipc = 1
 
procedure step()
if and_bits(id,1) == 0 then
ipc += 1 - and_bits(id,2)
else
ipr += 1 - and_bits(id,2)
end if
end procedure
 
procedure snusp(integer dlen, string s)
sequence ds = repeat(0,dlen) -- data store
integer dp = 1 -- data pointer
 
-- remove leading '\n' from string if present
s = trim_head(s,'\n')
 
-- make 2 dimensional instruction store and set instruction pointers
sequence cs = split(s,'\n')
ipr = 1
ipc = 1
 
-- look for starting instruction
for i=1 to length(cs) do
ipc = find('$',cs[i])
if ipc then
ipr = i
exit
end if
end for
 
id = 0
 
-- execute
while ipr>=1 and ipr<=length(cs)
and ipc>=1 and ipc<=length(cs[ipr]) do
integer op = cs[ipr][ipc]
switch op do
case '>' : dp += 1
case '<' : dp -= 1
case '+' : ds[dp] += 1
case '-' : ds[dp] -= 1
case '.' : puts(1,ds[dp])
case ',' : ds[dp] = getc(0)
case '/' : id = not_bits(id)
case '\\': id = xor_bits(id,1)
case '!' : step()
case '?' : if ds[dp]=0 then step() end if
end switch
step()
end while
end procedure
 
constant hw = """
/++++!/===========?\>++.>+.+++++++..+++\
\+++\ | /+>+++++++>/ /++++++++++<<.++>./
$+++/ | \+++++++++>\ \+++++.>.+++.-----\
\==-<<<<+>+++/ /=.>.+>.--------.-/"""
 
snusp(5, hw)
Output:
Hello World!

PicoLisp[edit]

See RCSNUSP/PicoLisp.

Python[edit]

Translation of: Go
#!/usr/bin/env python3
 
HW = r'''
/++++!/===========?\>++.>+.+++++++..+++\
\+++\ | /+>+++++++>/ /++++++++++<<.++>./
$+++/ | \+++++++++>\ \+++++.>.+++.-----\
\==-<<<<+>+++/ /=.>.+>.--------.-/'''

 
def snusp(store, code):
ds = bytearray(store) # data store
dp = 0 # data pointer
cs = code.splitlines() # 2 dimensional code store
ipr, ipc = 0, 0 # instruction pointers in row and column
for r, row in enumerate(cs):
try:
ipc = row.index('$')
ipr = r
break
except ValueError:
pass
rt, dn, lt, up = range(4)
id = rt # instruction direction. starting direction is always rt
def step():
nonlocal ipr, ipc
if id&1:
ipr += 1 - (id&2)
else:
ipc += 1 - (id&2)
while ipr >= 0 and ipr < len(cs) and ipc >= 0 and ipc < len(cs[ipr]):
op = cs[ipr][ipc]
if op == '>':
dp += 1
elif op == '<':
dp -= 1
elif op == '+':
ds[dp] += 1
elif op == '-':
ds[dp] -= 1
elif op == '.':
print(chr(ds[dp]), end='')
elif op == ',':
ds[dp] = input()
elif op == '/':
id = ~id
elif op == '\\':
id ^= 1
elif op == '!':
step()
elif op == '?':
if not ds[dp]:
step()
step()
 
if __name__ == '__main__':
snusp(5, HW)
Output:
Hello World!

Racket[edit]

See RCSNUSP/Racket.

Raku[edit]

(formerly Perl 6)

Works with: Rakudo version 2017.02

Implementation of modular SNUSP.

class SNUSP {
 
has @!inst-pointer;
has @!call-stack;
has @!direction;
has @!memory;
has $!mem-pointer;
 
method run ($code) {
init();
my @code = pad( |$code.lines );
for @code.kv -> $r, @l {
my $index = @l.grep( /'$'/, :k );
if $index {
@!inst-pointer = $r, $index;
last
}
}
 
loop {
my $instruction = @code[@!inst-pointer[0]; @!inst-pointer[1]];
given $instruction {
when '>' { $!mem-pointer++ }
when '<' { $!mem-pointer-- }
when '+' { @!memory[$!mem-pointer]++ }
when '-' { @!memory[$!mem-pointer]-- }
when '.' { print @!memory[$!mem-pointer].chr }
when ',' { @!memory[$!mem-pointer] = $*IN.getc.ord }
when '/' { @!direction = @!direction.reverse «*» -1 }
when '\\' { @!direction = @!direction.reverse }
when '!' { nexti() }
when '?' { nexti() unless @!memory[$!mem-pointer] }
when '@' { @!call-stack.push: @!inst-pointer.Array }
when '#' {
last unless +@!call-stack;
@!inst-pointer = |@!call-stack.pop;
nexti();
}
}
nexti();
last if @!inst-pointer[0] > +@code or
@!inst-pointer[1] > +@code[0];
}
 
sub init () {
@!inst-pointer = 0, 0;
@!direction = 0, 1;
$!mem-pointer = 0;
@!memory = ()
}
 
sub nexti () { @!inst-pointer Z+= @!direction }
 
sub pad ( *@lines ) {
my $max = max @lines».chars;
my @pad = @lines.map: $max - *.chars;
map -> $i { flat @lines[$i].comb, ' ' xx @pad[$i] }, ^@lines;
}
}
}
 
# TESTING
my $hw = q:to/END/;
/++++!/===========?\>++.>+.+++++++..+++\
\+++\ | /+>+++++++>/ /++++++++++<<.++>./
$+++/ | \+++++++++>\ \+++++.>.+++.-----\
\==-<<<<+>+++/ /=.>.+>.--------.-/
END
 
my $snusp = SNUSP.new;
$snusp.run($hw)
Output:
Hello World!

Ruby[edit]

See RCSNUSP/Ruby.

Seed7[edit]

The interpreter below implements Core SNUSP:

$ include "seed7_05.s7i";
 
const proc: snusp (in string: sourceCode, in integer: memSize, inout file: input, inout file: output) is func
local
var array string: instructions is 0 times "";
var array char: memory is 0 times ' ';
var integer: dataPointer is 1;
var integer: instrPtrRow is 0;
var integer: instrPtrColumn is 0;
var integer: rowDir is 0;
var integer: columnDir is 1;
var integer: helpDir is 0;
var integer: row is 0;
begin
instructions := split(sourceCode, "\n");
memory := memSize times '\0;';
 
for key row range instructions do
if pos(instructions[row], '$') <> 0 then
instrPtrRow := row;
instrPtrColumn := pos(instructions[row], '$');
end if;
end for;
 
while instrPtrRow >= 1 and instrPtrRow <= length(instructions) and
instrPtrColumn >= 1 and instrPtrColumn <= length(instructions[instrPtrRow]) do
case instructions[instrPtrRow][instrPtrColumn] of
when {'>'}: incr(dataPointer);
when {'<'}: decr(dataPointer);
when {'+'}: incr(memory[dataPointer]);
when {'-'}: decr(memory[dataPointer]);
when {'.'}: write(output, memory[dataPointer]);
when {','}: memory[dataPointer] := getc(input);
when {'/'}: helpDir := rowDir;
rowDir := -columnDir;
columnDir := -helpDir;
when {'\\'}: helpDir := rowDir;
rowDir := columnDir;
columnDir := helpDir;
when {'!'}: instrPtrRow +:= rowDir;
instrPtrColumn +:= columnDir;
when {'?'}: if memory[dataPointer] = '\0;' then
instrPtrRow +:= rowDir;
instrPtrColumn +:= columnDir;
end if;
end case;
instrPtrRow +:= rowDir;
instrPtrColumn +:= columnDir;
end while;
end func;
 
# SNUSP implementation of Hello World.
const string: helloWorld is "/++++!/===========?\\>++.>+.+++++++..+++\\\n\
\\\+++\\ | /+>+++++++>/ /++++++++++<<.++>./\n\
\$+++/ | \\+++++++++>\\ \\+++++.>.+++.-----\\\n\
\ \\==-<<<<+>+++/ /=.>.+>.--------.-/";
 
const proc: main is func
begin
snusp(helloWorld, 5, IN, OUT);
end func;
Output:
Hello World!

Tcl[edit]

See RCSNUSP/Tcl.