Execute SNUSP/D: Difference between revisions

m
Fixed syntax highlighting.
m (re-implemented)
m (Fixed syntax highlighting.)
 
(7 intermediate revisions by 5 users not shown)
Line 1:
{{implementation|SNUSP}}{{collection|RCSNUSP}}[[Category:D]]
 
This [[D]] implementation supports commands from all the three SNUSP variants, as described on the [http[eso://esolangs.org/wiki/SNUSP |Esolang SNUSP page]], plus an extended mode, '''SUPERNATURAL'''.
 
'''SUPERNATURAL Mode''':
Line 7:
#Read the char in current code pointer as input, assign it to memory currently pointed to by memory pointer.
*'''* : join and wait tasks''' (telepathy):
#A task ishas initializeda asstate property of free-state/join/wait;
#A task is by default initialized as free-state;
#The splited new thread inherites free/join/wait-state from the old thread;
#When a free-state task first executes this '''*''' command, the task enters into a join-state;
#Then if a join-state task executes another '''*''' command, the task enters into a wait-state;
#A wait-state task stops its execution, and waits until all alive join-state tasks are inturning into a wait-state, which then all these wait-state tasks are return to free-state;
#This command enables global synchronization of the tasks.
#Difference to original specification:
::*The original specification does not require threads execution in a specific order. For this command to be useful, the order of execution of tasks(threads) becomes important;
::*In this implementation, the order of execution is first-created-first-executed;
::*The original specification specifies that ''(&)SPLIT''-ed old thread skips the immediate code (see below 1a->2b->3c->4d example), which may lead to anti-intuition codes (which is good for an esoteric language :). This implementation retain old-thread-skips-immediate-code behavior in ''BLOATED'' mode, but new-thread-skips-immediate-code in ''SUPERNATURAL'' mode ( A->B->C->D example). 1->2->...->8 is thread creation order in ''SUPERNATURAL'' mode.
:::<codett style="line-height: 1em;">$*&\&nbsp;&nbsp;==&\:&\:&\:=\<br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;~&nbsp;&nbsp;~&nbsp;&nbsp;~&nbsp;&nbsp;~&nbsp;&\=>&nbsp;new(B)<br>&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;A&nbsp;&nbsp;B&nbsp;2A&nbsp;C3B&nbsp;4C&nbsp;D5D&nbsp;&nbsp;\=>&nbsp;old(A)<br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;\=!\=!\=!\===**.~&nbsp;.=.#<br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;/=!/=!/=!/===**.=.=.#<br>&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;2&nbsp;&nbsp;3&nbsp;1b&nbsp;46c&nbsp;7d&nbsp;18a&nbsp;&\=>&nbsp;old(1a)<br>&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;~&nbsp;&nbsp;~&nbsp;&nbsp;~&nbsp;&nbsp;~&nbsp;&nbsp;\=>&nbsp;new(2b)<br>&nbsp;&nbsp;\&nbsp;&nbsp;\==&/;&/;&/;=/&nbsp;&nbsp;<br></codett>
*'''^ : wrapwarp''' (teleport):
#The code pointer will bounce back to the code space boundary in its reverse direction;
#then forward and stop after the first '''^''' it encounter in normal direction.
#Example :
<d>module snud ;
:::==a^A&lt;=cp==B^==&lt;=C^==
private import std.string, std.random ;
::when the code pointer cp heading into A's^, next turn, the code pointer will be in C. if no such ^ in the reverse direction, the code pointer will be in ''a'' next turn.
<syntaxhighlight lang="d">module snud ;
private import std.string, std.random ;
 
// io interface, which has to be defined in another module
Line 32 ⟶ 37:
 
int rnd(int b) { return b < 0 ? (-rand()) % (-b + 1) : rand() % (b + 1) ; }
// simple stack template
void push(T)(inout T[] stk, T value) { stk ~= value ; }
T pop(T)(inout T[] stk, bool discard = true) {
T top = stk[$-1] ;
if(discard) stk.length = stk.length - 1 ;
return top ;
}
 
// a 2x tuple type
struct X(U,V = U) {
U x ; V y ;
void to(ref U a, ref V b) { a = x ; b = y ; }
void from(U a, V b) { x = a ; y = b ; }
}
alias X!(int) I2 ; // intxint, used as code pointer, memory pointer & direction
alias X!(I2) ST ; // (intxint)x(intxint), used as cpu state [cp,dp]
 
enum Mode : uint {CORE = 1, MODULAR, BLOATED, SUPERNATURAL } ;
Line 72 ⟶ 77:
void opIndexAssign(int value, I2 key) { cells[key] = value ; }
int opIndex(I2 key) {
int* vp = key in cells ; // get value pointer of the key, null if no such key
if(vp is null) { cells[key] = 0 ; return 0 ; } // initialize the value/key pair
return *vp ; // return the already existed value
Line 80 ⟶ 85:
final class CPU {
final class Task {
enum {FREE, JOINED, WAITING }
const int id ;
I2 cp, dp, mp ;
int join = FREE ;
bool quit = false ;
private ST[] stack ;
private char curCode ;
 
this(I2 Cp, I2 Dp, I2 Mp, int joinstate = FREE) {
{ cp = Cp ; dp = Dp ; mp = Mp ; id = Id++ ; }
if((join = joinstate) == JOINED) joinwait++ ;
}
 
private void fwd(int step = 1) { with(cp) from(x + dp.x*step, y + dp.y*step) ; }
private void rfx(int dir) { with(dp) from(dir*y, dir*x) ; }
// _outer_ is D keyword for an inner class to ref outer class
private bool hasCode() { return this.outer.hasCode(cp) ; }
char getCode() { return this.outer.getCode(cp) ; }
Task execute() {
curCode = getCode ;
Line 118 ⟶ 125:
case '#' :
if(stack.length > 0) // return from subroutine
{ stack.pop().to(cp,dp) ; fwd ; break ; }
case '\0': // else process as \0, = quit
quit = true ; goto RET ;
case '&' :
if(tasksMode == Mode.BLOATED) // old task skip immediate code
{ fwd ; queued ~= new Task(cp, dp, mp, join) ; break ; }
else // new task skip immediate code
{ fwd(2) ; queued ~= new Task(cp, dp, mp, join) ; fwd(-2) ; break ; }
case '~' : fwd ; m[mp] = getCode ; break ; // read next code as input
case '*' : // join/wait threads
Line 146 ⟶ 153:
if(quit && join == JOINED) joinwait-- ;
return this ;
}
}
 
this(IIO inputoutput) { m = new Memory ; io = inputoutput ; }
 
bool hasCode(I2 codePtr)
{ with(codePtr) return !(x < 0 || y < 0 || x >= width || y >= lines) ; }
char getCode(I2 codePtr)
{ with(codePtr) return hasCode(codePtr) ? src[y][x] : '\0' ; }
string program() { if(prog is null) prog = join(src,"\n") ; return prog ; }
CPU load(string codes) {
src = splitlines(codes) ; width = 0 ; lines = src.length ; prog = null ;
foreach(k,l; src)
{ if ((src[k] = stripr(tr(l,"\0"," "))).length > width) width = src[k].length ; }
foreach(k,l; src) src[k] = l ~ repeat(" ", width - l.length) ;
debugInput = pfind(&start, src, "debug[", "]debug") ;
pfind(&start, src, "$") ;
if(start.x < 0) start = I2(0,0) ; else start.x++ ;
return this ;
Line 175 ⟶ 182:
}
int run(string codes,Mode mode = Mode.SUPERNATURAL, bool useDebugInput = true)
{ return load(codes).initialize(mode, useDebugInput).run() ; }
int run() { while(nTaskLeft) run1Tick ; return m[lastmp] ; }
bool run1Tick() {
if(nTaskLeft > 0) {
nTaskLeft = 0 ; tick++ ;
foreach(tsk ; tasks) // execute & update task
if((tasks[nTaskLeft] = tsk.execute).quit == false)
nTaskLeft++ ;
tasks.length = nTaskLeft ;
Line 189 ⟶ 196:
return nTaskLeft > 0 ;
}
 
static const string[] command = ["<>+-,.!?/\\\0","@#",":;&%","~*^"] ;
 
Memory m ;
IIO io ;
 
string prog, debugInput ;
Mode tasksMode ;
Line 203 ⟶ 210:
private char[char] acceptCmd ;
private uint Id = 0 ;
}</dsyntaxhighlight>
Sample SNUSP using a console io :
<syntaxhighlight lang="d">module rcsnusp ;
import snud ;
import std.stdio, std.file, std.conv ;
Line 256 ⟶ 263:
 
return result ;
}</dsyntaxhighlight>
9,476

edits