Scrivi un interprete 0815


26

Mi piace il concetto di 0815 , tranne l'interprete sul sito del creatore restituisce un errore 404. Quindi ho deciso di chiedere a tutti di aiutare!

Le basi

0815 si basa su tre (3) registri e una coda. I registri sono denominati X, Y e Z, con X come sola scrittura, Z come sola lettura e Y come registro "helper" a cui non è possibile accedere direttamente. Tutti i registri iniziano impostati su 0. Tutti i numeri sono in formato esadecimale.

Istruzioni

Nota: alcune istruzioni accettano parametri che sono formattati come }:hello:dove :hello:è il parametro. Altra nota: alcune delle descrizioni delle istruzioni non sono chiare, quindi ho preso alcune libertà con loro. (Istruzioni originali qui )

~ significa che il parametro è obbligatorio

----------|---|--------------------------------------------
  ~Move   | < | <:8: will write 8 to X (parameter required) 
----------|---|--------------------------------------------
   Swap   | x | Swap X and Y
----------|---|--------------------------------------------
  ~Label  | } | }:hello: makes a label called 'hello'
----------|---|--------------------------------------------
  Input   | | | Set X to an integer from input in 
 Number   |   | hexadecimal greedily (regex: [0-9A-F]+)
----------|---|--------------------------------------------
  Input   | ! | Set X to the ASCII code of one ASCII
  ASCII   |   | character in the input
----------|---|--------------------------------------------
  Print   | % | Prints an integer stored in Z 
  number  |   | (hexadecimal base)
----------|---|--------------------------------------------
  Print   | $ | Prints an ASCII char stored in Z
  ASCII   |   |
----------|---|--------------------------------------------
  Roll    |   | Rolls all registers to the left
Registers | ~ | X <- Y <- Z <- X
  Left    |   | After roll: X = Y, Y = Z and Z = X
----------|---|--------------------------------------------
  Roll    |   | Rolls all registers to the right
Registers | = | X -> Y -> Z -> X
  Right   |   | After roll: Y = X, Z = Y and X = Z
----------|---|--------------------------------------------
 ~Jump if | ^ | ^:loop: Jumps to the label 'loop' if Z is
 not zero |   | not zero
----------|---|--------------------------------------------
 ~Jump if | # | #:loop: Jumps to the label 'loop' if Z is
   zero   |   | zero
----------|---|--------------------------------------------

Istruzioni per la coda

----------|---|--------------------------------------------
   Clear  | ? | Clears the queue
----------|---|--------------------------------------------
  Enqueue | > | Enqueue the number stored in Z
----------|---|--------------------------------------------
  Dequeue | { | Dequeue a number into X
----------|---|--------------------------------------------
          |   | Rolls the queue to the left, wrapping as
   Roll   |   | necessary. The first number becomes the 
   Queue  | @ | last; second becomes first and so on. Can  
   Left   |   | take a parameter to roll a certain number
          |   | of times. @:b: rolls 11 times.
----------|---|--------------------------------------------
   Roll   |   | 
   Queue  | & | The opposite of @
   Right  |   | 
----------|---|--------------------------------------------

Istruzioni aritmetiche

----------|---|--------------------------------------------  
   Add    | + | Z = X + Y
----------|---|--------------------------------------------
 Subtract | - | Z = X - Y
----------|---|--------------------------------------------
 Multiply | * | Z = X * Y
----------|---|--------------------------------------------
  Divide  | / | Z = X / Y
          |   | Y = remainder
----------|---|--------------------------------------------

Programmi di esempio

Ciao mondo: (Leggermente golfato)

<:48:~$<:65:~$<:6C:~$$><:6F:~$>@<:2C:~$<:20:~$<:57:~${~$<:72:~${~$<:64:~$

Gatto:

}:_t:!~$^:_t:

Macchina della verità:

|~}:i:%^:i:

Questo è , quindi vince l'invio con il minor numero di byte!


3
Qual è la distinzione tra ~e ~nei comandi "roll registers"? Hai un programma di esempio che le persone possono usare per testare?
AdmBorkBork,

3
Qualche esempio che potresti darci?
Conor O'Brien,

1
@DanTheMan Sto vedendo "Hello, Wlrod" quando eseguo il tuo esempio Hello World usando la mia implementazione (ancora WIP) ... Non sono sicuro che si tratti di un bug nel mio codice o dell'esempio stesso
Ruslan

2
@DanTheMan Sì, ma cambiando il collegamento si ottiene l'interprete. :-)
Sven scrive il codice

1
@usandfriends Fixed!
DanTheMan il

Risposte:


8

seme , 321 262 248 byte

Accorciato notevolmente usando eval e alcuni trucchi per la complessità di Kolmogorov.

a@:`.(:.*?:)?`z:Y0w:2**64W++v<#a{UnpWa@v^':;V("Yp57Syi7UybWb^@(b@?`[^0-9A-F]|$`)Yy57Y APOb7OzTB167O Cz7SyzSyi7SyiSyz7I2I!2l:[]7lPBz7Y3B3UDQl7z:(y+4-4*4//i)i:y%i"R2`zv:a@?"}:".p.':7`R3"POl7Lp?p5olP"R4"i)%w7z:(y"R5"FB16%w"^7"<x|!%$~=^#?>{@&+-*/"@?n)}

Provalo online! (L'esempio è il programma di numeri Collatz / hailstone dal sito Web dell'autore della lingua.)

Gli appunti:

  • Prende il codice 0815 come primo argomento della riga di comando e l'input come secondo. Sì, è un po 'imbarazzante (molto meno su TIO, dove ottieni caselle di testo separate), ma Pip non è così bravo a leggere tutto lo stdin.
  • I numeri in input devono usare cifre esadecimali maiuscole (come da OP: corrispondente alla regex [0-9A-F]+). Se, in |un'istruzione, il carattere successivo di input non lo è0-9A-F , la lettura fallisce e provoca comportamenti potenzialmente strani. Ciò significa che il programma pari-dispari dell'autore non funziona come scritto ... Non sono sicuro di come si aspettasse che funzionassero più letture di numeri, ma ho implementato solo in base a ciò che dicevano le specifiche.
  • Se un'etichetta viene duplicata, un salto passa alla prima. Se non esiste un'etichetta, un salto termina il programma.

La mia versione non golfata con commenti:

;;; INITIALIZATION ;;;

; a is the code, analyzed with regex into a list of instructions
a @: `.(:.*?:)?`
; b is the input
; x, y, z are registers (initially three 0s)
x:y:z:0
; l is the queue (initially empty list)
; v is the instruction pointer (initially -1, but gets incremented at top of loop)
; w represents the width of the registers
w:2**64

;;; MAIN LOOP ;;;

; Loop while IP hasn't gone past last instruction
W ++v<#a {
 ; Unify n with first char of current iNstruction, p with the parameter (or nil)
 U np W a@v ^ ':

 ; If n eQuals "<": move p value into x
 InQ'<
  ; Convert p from hex and truncate to register width
  x : pFB16%w
 ; Swap x and y
 InQ'x
  Sxy
 ; Input number (in hex, uppercase only)
 InQ'| {
  ; Find index of first non-hex character in b and split at that index
  ; Unify left half with x and right with b
  U xb W b^@(b @? `[^0-9A-F]|$`)
  ; Convert x from hex and truncate to register width
  x : xFB16%w
 }
 ; Input ASCII
 InQ'!
  ; Pop 1st char of b and get ASCII code
  x : A POb
 ; Print number (in hex)
 InQ'%
  ; Output z converted to hex
  O zTB16
 ; Print ASCII
 InQ'$
  ; Output chr(z)
  O Cz
 ; Roll registers left
 InQ'~ {
  ; With three registers, a roll is just two swaps
  Sxz
  Sxy
 }
 ; Roll registers right
 InQ'= {
  Sxy
  Sxz
 }
 ; Jump (combines if-nonzero and if-zero cases)
 I nQ'^ & z | nQ'# & !z
  ; Construct the corresponding label, find its index in a, and set IP to that
  v : a @? "}:".p.':
  ; If the label doesn't exist, v becomes nil, which makes the loop condition nil,
  ; which (being falsy) exits the loop and terminates the program

 ; Clear queue
 InQ'?
  l:[]
 ; Enqueue
 InQ'>
  ; Push z to back of l
  lPBz
 ; Dequeue
 InQ'{
  ; Pop l and assign to x
  x:POl
 ; Roll queue left
 ; NOTE: doesn't work if 0 is a valid parameter for roll operation
 ; If we want to handle that case, use #p?... instead of p?... for +1 byte
 InQ'@
  ; Loop specified number of times (converted from hex), or 1 if not specified
  L p ? pFB16 1
   ; Pop (front of) l and push that value to the back of l
   l PB POl
 ; Roll queue right
 InQ'&
  L p ? pFB16 1
   ; Dequeue from back of l and push that value to (the front of) l
   l PU DQl

 ; Add (truncating as needed)
 InQ'+
  z:(x+y)%w
 ; Subtract (truncating as needed)
 InQ'-
  z:(x-y)%w
 ; Multiply (truncating as needed)
 InQ'*
  z:x*y%w
 ; Divide (truncating not needed)
 InQ'/ {
  z:x//y
  y:x%y
 }
}

7

haxe, 987 byte

class Main{static function main(){var c=sys.io.File.getContent(Sys.args()[0]).split(""),i=0,x=0,y=0,z=0,t=0,m=0,g=Sys.getChar.bind(false),f=String.fromCharCode,b="",B="",l="",A=[];while(i<c.length)switch(l=c[i++]){case"<"|"}"|"^"|"#":b=l=="<"?"0x":"";if(c[i++]==":")while((B=c[i++])!=":")b+=B;if(l=="<")x=Std.parseInt(b);else if(l!="}"&&(z==0)==(l=="#")){t=0;while(t!=(m=(i+t++)%c.length)){if(c[m]==":")t+=c.indexOf(":",m+1)-m;else if(c[m]=="}"){l="";if(c[++m]==":")while((B=c[++m])!=":")l+=B;if(b==l){i=m;break;}}}return;}case"x":t=x;x=y;y=t;case"|":b="0x";while(((t=g())>47&&t<58)||(t>96&&t<103))b+=f(t);x=Std.parseInt(b);case"!":x=g();x=x<0?0:x;case"%"|"$":Sys.print(l=="%"?[for(j in 0...8){"0123456789abcdef".split("")[z>>((7-j)*4)&15];}].join(""):f(z));case"?":A=[];case">":A.push(z);case"{":x=A.shift();case"@":A.push(A.shift());case"&":A.unshift(A.pop());case"+":z=x+y;case"-":z=x-y;case"*":z=x*y;case"~":t=x;x=y;y=z;z=t;case"=":t=x;x=z;z=y;y=t;case"/":z=Math.floor(x/y);y=x%y;}}}

o con alcuni spazi bianchi:

class Main{static function main(){
var c=sys.io.File.getContent(Sys.args()[0]).split(""),
    i=0,
    x=0,
    y=0,
    z=0,
    t=0,
    m=0,
    g=Sys.getChar.bind(false),
    f=String.fromCharCode,
    b="",
    B="",
    l="",
    A=[];
while(i<c.length)switch(l=c[i++]){
    case"<"|"}"|"^"|"#":
        b=l=="<"?"0x":"";
        if(c[i++]==":")
            while((B=c[i++])!=":")
                b+=B;
        if(l=="<")
            x=Std.parseInt(b);
        else if(l!="}"&&(z==0)==(l=="#")){
            t=0;
            while(t!=(m=(i+t++)%c.length)){
                if(c[m]==":")
                    t+=c.indexOf(":",m+1)-m;
                else if(c[m]=="}"){
                    l="";
                    if(c[++m]==":")
                        while((B=c[++m])!=":")
                            l+=B;
                        if(b==l){
                            i=m;
                            break;
                        }
                }
            }
            return;
        }
    case"x":
        t=x;x=y;y=t;
    case"|":
        b="0x";
        while(((t=g())>47&&t<58)||(t>96&&t<103))
            b+=f(t);
        x=Std.parseInt(b);
    case"!":
        x=g();
        x=x<0?0:x;
    case"%"|"$":
        Sys.print(l=="%"?[
            for(j in 0...8){
                "0123456789abcdef".split("")[z>>((7-j)*4)&15];
            }
        ].join(""):f(z));
    case"?":
        A=[];
    case">":
        A.push(z);
    case"{":
        x=A.shift();
    case"@":
        A.push(A.shift());
    case"&":
        A.unshift(A.pop());
    case"+":
        z=x+y;
    case"-":
        z=x-y;
    case"*":
        z=x*y;
    case"~":
        t=x;x=y;y=z;z=t;
    case"=":
        t=x;x=z;z=y;y=t;
    case"/":
        z=Math.floor(x/y);
        y=x%y;
}}}

Hai giocato a golf con haxe? Wow.


1
+1 per Haxe, la risposta più breve in uno dei langs meno golfistici
cat

1
Sai, se lo compilassi per JS, sarebbe più breve? allora potresti farlo ES6 / ES7
cat

5

Python 3, 1320 byte

La versione ungolfed, così come l'analisi dei programmi di test (e, se necessario, le versioni di corretti), si possono trovare in questo Gist .

Decisioni di progettazione:

  • Più definizioni di etichette vengono ignorate. Viene utilizzata solo la prima definizione di un'etichetta. (In precedenza sarebbe stata utilizzata la definizione vista più di recente, ma è stata eliminata.)
  • L'input è conforme alle specifiche del PO: l'input numerico legge avidamente i caratteri esadecimali. (Inizialmente leggeva fino a newline ed errore quando venivano letti caratteri non esadecimali.)
  • L'ingresso "ASCII" viene considerato come ingresso "orientato al byte". (Inizialmente aveva il pieno supporto Unicode, che richiedeva meno codice grazie all'essere Python 3 ... ma incontrare il prossimo punto elenco significava che leggere byte per byte era ora più breve.)
  • I parametri in cui non sono previsti parametri vengono ignorati; quindi, sono utilizzabili come commenti.

Ci sono problemi con i programmi di esempio che usano CR da solo come loro nuova riga (a volte), il che rende la mia shell sovrascrivere la linea corrente piuttosto che avviarne una nuova. Ciò influisce sui programmi Sequenza di Fibonacci e 99 Bottiglie di birra. Anche l'ultimo verso di 99 Bottiglie di birra non viene stampato correttamente e sto ancora indagando sul perché.

import sys as y
import sys as y
b=y.stdin.buffer
I=int
g=getattr
X=2**64
R=lambda a:property(lambda s:g(s,a)-[X,0][0<=g(s,a)<X/2],lambda s,v:setattr(s,a,I(v)&X-1))
M,*Q=':<}^#@&xX|!%$~=?>{+-*/'
class A:
 x,y,z=map(R,'uvw')
 def R(s,p):
  s.p,s.s,*s.q=p,3,;s.x=s.y=s.z=s.i=0
  while s.s<4:
   t='';p=s.s=i=0
   while s.s<3:
    k=s.p[s.i];s.i+=1
    if s.s==1:
     if k==M:
      if p==2:s.t=s.i;g(s,s.I[i])(t);s.s=max(s.s,3)
     else:t+=k
    elif k==M:p,s.s=s.s,1
    elif k in Q:
     i=k;m=M==s.p[s.i]
     if k in Q[:6]and m:s.s=2
     elif k in Q[6:]or k in'@&'and m<1:g(s,s.I[i])()
 def B(s,v):s.x=I(v,16)
 def C(s):s.x,s.y=s.y,s.x
 def D(s,l):0
 def E(s):
  s.x=0
  try:
   while 1:s.x=s.x*16+I(b.peek()[:1],16);b.read(1)
  except:0
 def F(s):s.x=b.read(1)[0]
 def G(s):print(format(s.z,'x'),end='')
 def H(s):print(chr(s.z),end='')
 def J(s):s.x,s.y,s.z=s.y,s.z,s.x
 def K(s):s.J();s.J()
 def j(s,l):
  a=s.p.find('}:'+l+M)
  if a<0:s.s=4
  else:s.i=a
 def L(s,l):
  if s.z:s.j(l)
 def T(s,l):
  if s.z==0:s.j(l)
 def U(s):s.q=[]
 def V(s):s.q+=s.z,
 def W(s):s.x,*s.q=s.q
 def Y(s,d='1'):d=I(d,16);s.q=s.q[d:]+s.q[:d]
 def Z(s,d='1'):Y('-'+d)
 def a(s):s.z=s.x+s.y
 def b(s):s.z=s.x-s.y
 def c(s):s.z=s.x*s.y
 def d(s):s.z,s.y=divmod(s.x,s.y)
 I=dict(zip(Q,'BDLTYZCCEFGHJKUVWabcd'))
try:A().R(open(y.argv[1]).read())
except:0

4

Scala, 3.123 2.844 2.626 2.540 byte

Oltre ai vincoli delineati nell'interrogazione, questo interprete è stato scritto per orientarsi il più possibile verso i principi del PQ. In particolare:

  • Solo strutture immutabili
  • Tutte le funzioni sono pure

Ciò è stato realizzato, ad eccezione delle quattro righe di codice che guidano il ciclo principale dell'interprete. Le strutture immutabili erano molto difficili da utilizzare qui perché lo stato dei registri guida il flusso di controllo del loop (in particolare le due istruzioni GOTO). Sto ancora pensando a come convertirlo per usare strutture pure e immutabili, ma questo è irrilevante per la sfida del codice golf.

import java.util.Scanner
import scala.util._
object Z extends App{type K=Long
type G=List[K]
type I=String
type E=Boolean
val(f,t,ф,д,б)=(false,true,(z:G)=>z(0),(z:G)=>z.tail,(q:K,w:K,e:K)=>q::w::e::Nil)
trait O{def h(z:I)=BigInt(z,16).longValue()}
trait S extends O
trait B extends S with P{def apply(r:G):E}
trait R extends O{def a(r:G):G}
trait T extends O{def a(r:G,s:G):(G,G)}
trait P{def p:I}
case class L(p:I)extends S with P
case class U(p:I)extends B{def apply(r:G):E=r(2)==0}
case class J(p:I)extends B{def apply(r:G):E=r(2)!=0}
case class M(p:I)extends R with P{def a(r:G):G=h(p)::д(r)}
class Y extends R{def a(r:G):G=б(r(0),r(0)%r(1),r(0)/r(1))}
case class Q(p:I)extends T with P{def r(q:G,i:Int):G={val s=д(q):+ф(q)
if(i>0)r(s,i-1)else s}
def a(e:G,t:G)=e->r(t,Try(p.toInt).getOrElse(1))}
case class N(p:I)extends T with P{def r(q:G,i:Int):G={
val s=q.last::q.iterator.sliding(2).map(_(0)).toList
if(i>0)r(s,i-1)else s}
def a(e:G,t:G)=e->r(t,Try(p.toInt).getOrElse(1))}
case class A(n:Array[O], l:Map[I,Int]){def e={var (r,t,x)=(List(0L,0,0),List[K](),0)
while(x<n.length){x=n(x)match{case i:B=>if(i(r))l(i.p)else x+1
case i:R=>r=i.a(r);x+1
case i:T=>val(y,u)=i.a(r,t);r=y;t=u;x+1
case _=>x+1}}}}
object A{def apply(i:Seq[O]):A={A(n=i.toArray,l=Map(i.zipWithIndex.flatMap{case(e:L,i)=>Some(e.p->i)
case _=>None}.toList:_*))}}
object X{def v(y:(Char, Option[Z.I]))=y._2.getOrElse("");val F=Map('x->new R{def a(t:G)=б(t(1),t(0),t(2))},'|'->new R{def a(r:G)=h(new Scanner(System.in).next("[0-9a-fA-F]+"))::д(r)},'!'->new R{def a(r:G)=(System.in.read match{case i if i== -1=>0;case i=>i})::д(r)},'%'->new R{def a(r:G)={print(Integer.toHexString(r(2).toInt));r}},'$'->new R{def a(r:G)={print(r(2).toChar);r}},'~'->new R{def a(r:G)=д(r):+ф(r)},'='->new R{def a(r:G)=б(r(2),r(0),r(1))},'?'->new T{def a(r:G,s:G)=r->List()},'>'->new T{def a(r:G,s:G)=r->(r(2)::s)},'{'->new T{def a(r:G, s:G)=(ф(s)::д(r))->д(s)},'+'->new R{def a(r:G)=б(r(0),r(1),r(0)+r(1))},'-'->new R{def a(r:G)=б(r(0),r(1),r(0)-r(1))},'*'->new R{def a(r:G)=б(r(0),r(1),r(0)*r(1))},'/'->new Y);def apply(i:I)={(i+" ").foldLeft((List[(Char,Option[I])](),None:Option[Char],"",f))((a,n)=>{n match{case i if i==':'=>if(a._4)(a._1:+(a._2.get->Some(a._3)),None,"",f)else(a._1,a._2,"",t)
case i if a._4=>(a._1,a._2,a._3+i,t)
case i if a._2.isEmpty=>(a._1,Some(i),"",f)
case i=>(a._1:+(a._2.get->None),Some(i),"",f)}})._1.map(x=>x._1 match{
case'<'=>M(v(x))
case'}'=>L(v(x))
case'^'=>J(v(x))
case'#'=>U(v(x))
case'@'=>Q(v(x))
case'&'=>N(v(x))
case c=>F(c)})}}
A(X(args(0))).e}

Pubblicherò la versione non golfata su Github e fornirò un link quando lo farò. Per ora, posterò la versione originale qui:

import java.util.Scanner
import scala.util.Try

trait Operation {
  def hexToLong(hex:String):Long = BigInt(hex, 16).longValue()
}

trait Parameter {
  def param:String
}


trait RegisterOperation extends Operation { def apply(registers:List[Long]):List[Long] }
trait StackOperation extends Operation { def apply(registers:List[Long], stack:List[Long]):(List[Long], List[Long]) }
trait SpecialOperation extends Operation
trait SpecialRegisterOperation extends SpecialOperation with Parameter  { def apply(registers:List[Long]):Boolean }

class Move(val param:String) extends RegisterOperation with Parameter { override def apply(registers:List[Long]): List[Long] = hexToLong(param) :: registers.tail }
class Swap extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers(1) :: registers(0) :: registers(2) :: Nil }
class InputNumber extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = hexToLong(new Scanner(System.in).next("[0-9a-fA-F]+")) :: registers.tail }
class InputAscii extends RegisterOperation {
  override def apply(registers:List[Long]): List[Long] = (System.in.read() match {
  case i if i == -1 => 0
  case i => i}) :: registers.tail }

class PrintNumber extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = { print(Integer.toHexString(registers(2).toInt)); registers } }
class PrintAscii extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = { print(registers(2).toChar); registers } }
class RegisterRollLeft extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers.tail :+ registers.head }
class RegisterRollRight extends RegisterOperation { override def apply(registers:List[Long]): List[Long] = registers(2) :: registers(0) :: registers(1) :: Nil }

class Add extends RegisterOperation { override def apply(registers:List[Long]): List[Long] =  registers(0) :: registers(1) :: (registers(0) + registers(1)) :: Nil }
class Subtract extends RegisterOperation { override def apply(registers:List[Long]): List[Long] =  registers(0) :: registers(1) :: (registers(0) - registers(1)) :: Nil }
class Multiply extends RegisterOperation { override def apply(registers:List[Long]): List[Long] =  registers(0) :: registers(1) :: (registers(0) * registers(1)) :: Nil }
class Divide extends RegisterOperation { override def apply(registers:List[Long]): List[Long] =  registers(0) :: (registers(0) % registers(1)) :: (registers(0) / registers(1)) :: Nil }

class Clear extends StackOperation { override def apply(registers:List[Long], stack:List[Long]) = registers -> List() }
class Enqueue extends StackOperation { override def apply(registers:List[Long], stack:List[Long]) = registers -> (registers(2) :: stack) }
class Dequeue extends StackOperation { override def apply(registers:List[Long], stack:List[Long]) = (stack.head :: registers.tail) -> stack.tail }
class QueueRollLeft(val param:String) extends StackOperation with Parameter {
  def roll(stack:List[Long], i:Int):List[Long] = {
    val s = stack.tail :+ stack.head
    if (i > 0) roll(s, i-1) else s
  }

  override def apply(registers:List[Long], stack:List[Long]) = registers -> roll(stack, Try(param.toInt).toOption.getOrElse(1))
}

class QueueRollRight(val param:String) extends StackOperation with Parameter {
  def roll(stack:List[Long], i:Int):List[Long] = {
    val s = stack.last :: stack.iterator.sliding(2).map(_.head).toList
    if (i > 0) roll(s, i-1) else s
  }

  override def apply(registers:List[Long], stack:List[Long]) = registers -> roll(stack, Try(param.toInt).toOption.getOrElse(1))
}

class SetLabel(val param:String) extends SpecialOperation with Parameter
class JumpLabelIfZero(val param:String) extends SpecialRegisterOperation { override def apply(registers: List[Long]): Boolean = registers(2) == 0 }
class JumpLabelIfNotZero(val param:String) extends SpecialRegisterOperation { override def apply(registers: List[Long]): Boolean = registers(2) != 0 }

class Script(val instructions:Array[Operation],
             val labels:Map[String, Int]) {
  def execute() = {
    var registers = List[Long](0, 0, 0)
    var stack = List[Long]()
    var idx = 0;

    while(idx < instructions.length) {
      idx = instructions(idx) match {
        case i: SpecialRegisterOperation => if(i(registers)) labels(i.param) else idx + 1
        case i: RegisterOperation => { registers = i(registers); idx + 1 }
        case i: StackOperation => { val (zregisters, zstack) = i(registers, stack); registers = zregisters; stack = zstack; idx + 1 }
        case _ => idx + 1
      }
    }
  }
}

object Script {
  def apply(instructions: Seq[Operation]):Script = {
    new Script(instructions = instructions.toArray, labels = Map(instructions.zipWithIndex.flatMap {
      case (e:SetLabel, i) => Some(e.param -> i)
      case _ => None
    }.toList:_*))
  }
}

object Parser {
  def apply(input:String): Seq[Operation] = {
    case class Accumulator(val list: List[(Char, Option[String])] = List(), val char:Option[Char] = None, val str:String = "", val parsingVar:Boolean = false)

    (input + " ").foldLeft(Accumulator())((acc, next) => {
      next match {
        case i if i == ':' => if(acc.parsingVar) Accumulator(acc.list :+ (acc.char.get -> Some(acc.str)), None, "", false) else Accumulator(acc.list, acc.char, "", true)
        case i if acc.parsingVar => Accumulator(acc.list, acc.char, acc.str + i, true)
        case i if !acc.char.isDefined => Accumulator(acc.list, Some(i), "", false)
        case i => Accumulator(acc.list :+ (acc.char.get -> None), Some(i), "", false)
      }
    }).list.map(x => x._1 match {
      case '<' => new Move(x._2.getOrElse(""))
      case 'x' => new Swap
      case '}' => new SetLabel(x._2.getOrElse(""))
      case '|' => new InputNumber
      case '!' => new InputAscii
      case '%' => new PrintNumber
      case '$' => new PrintAscii
      case '~' => new RegisterRollLeft
      case '=' => new RegisterRollRight
      case '^' => new JumpLabelIfNotZero(x._2.getOrElse(""))
      case '#' => new JumpLabelIfZero(x._2.getOrElse(""))
      case '?' => new Clear
      case '>' => new Enqueue
      case '{' => new Dequeue
      case '@' => new QueueRollLeft(x._2.getOrElse(""))
      case '&' => new QueueRollRight(x._2.getOrElse(""))
      case '+' => new Add
      case '-' => new Subtract
      case '*' => new Multiply
      case '/' => new Divide
    })
  }
}

object Go extends App {
  Script(Parser(args(0))).execute()
}

2

Flex / C ++, 848 838 byte

%{
#include<map>
#include<deque>
using namespace std;typedef uint64_t I;I X,Y,Z,P,T,i;map<string,I>L;deque<I>Q;
#define YY_USER_ACTION P+=yyleng;
#define A for(i=0;i<(yyleng>2?stoull(yytext+2,0,16):1);++i
#define B fseek(yyin,L.at(yytext+1),0),yyrestart(yyin);
%}
H :[0-9A-F]+:
B :[0-9a-zA-Z_]+:
%x E
%%
<E>\}{B} L[yytext+1]=P;
<E>.|\n
\<{H} X=stoull(yytext+2,0,16);
x T=X;X=Y;Y=T;
\}{B}
\| scanf("%lx",&X);
! X=getchar();
% printf("%lx",Z);
\$ putchar(Z);
~ T=X;X=Y;Y=Z;Z=T;
= T=Y;Y=X;X=Z;Z=T;
\^{B} if(Z)B
#{B} if(!Z)B
\? Q.clear();
> Q.push_back(Z);
\{ X=Q.front();Q.pop_front();
@{H}? A)T=Q.front(),Q.pop_front(),Q.push_back(T);
&{H}? A)T=Q.back(),Q.pop_back(),Q.push_front(T);
\+ Z=X+Y;
- Z=X-Y;
\* Z=X*Y;
\/ Z=X/Y;Y=X%Y;
.|\n
%%
main(int,char**v){yyin=fopen(v[1],"r");BEGIN(E);yylex();rewind(yyin);yyrestart(yyin);BEGIN(0);yylex();}

Compilato con:

flex -o 0815.cpp 0815.ll
g++ -std=c++11 0815.cpp -o 0815 -ll

Potrebbe compilare anche con altri lexes, ma non ho verificato. Funziona in due passaggi, quindi i salti in avanti sono gestiti correttamente. I nomi delle etichette possono iniziare con una cifra, come accade più di una volta nei casi di test. I letterali esadecimali possono essere solo in maiuscolo, secondo le specifiche.

Supera tutti i casi di test, compresi quelli trovati sul Wiki di Esolangs e sulla pagina 0815. La gestione degli errori è inesistente e l'uscita su un'etichetta sconosciuta non è elegante, dopo tutto questo è code-golf.

Sto preparando l'interprete ungolf (e molto più simpatico) per una versione, in modo che OP possa continuare a armeggiare con 0815. Resta sintonizzato :)


Le 99 bottiglie di esempi di birra usano \rinvece \ncome nuova riga (Mac OS vecchia scuola?), Quindi se vuoi vedere qualcosa di stampato sullo schermo usa ./0815 99bb.0815 | tr "\r" "\n". Lo stesso per Fibonacci.
Stefano Sanfilippo,

2

Lisp comune, 1088 byte

(progn(defun r(s)(parse-integer s :radix 16))(defun h(k)(coerce(loop for c =(#7=read-char()())while(funcall k c)collect c finally(unread-char c))'string))(defun w(c)(find c"0123456789ABCDEFabcdef"))(defmacro c(s)(with-input-from-string(*standard-input* s)(labels((L()(intern(p #'u)))(o()(case(peek-char()())(#\:(r(q))(#7#))(t 1)))(q()(p #'w))(p(k)(prog2(#7#)(h k)(#7#)))(u(c)(char/= c #\:)))`(let((x 0)(y 0)(z 0)(q(list())))(labels((&(n)(q(nconc(last(car q)n)(butlast(car q)n))))(@(n)(q(nconc(nthcdr n(car q))(subseq(car q)0 n))))(q(x)(#3=setf q(cons x(last x)))))(prog(),@(loop for c =(#7#()())while c collect(case c(#\<`(#3#x,(r(q))))(#\x`(#5=rotatef x y))(#\}(L))(#\|`(#3#x(r(h'w))))(#\!`(#3#x(char-code(#7#))))(#\%`(format t"~x"z))(#\$`(princ(code-char z)))(#\~`(#5#x y z))(#\=`(#5#z y x))(#\^`(if(/= z 0)(go,(L))))(#\#`(if(= 0 z)(go,(L))))(#\?`(#3#q(q())))(#\>'(if(car q)(#3#(cddr q)(list z)(cdr q)(cddr q))(#3#(cdr q)(#3#(car q)(list z)))))(#\{'(#3#x(pop(car q))))(#\@`(@,(o)))(#\&`(&,(o)))(#\/'(#3#(values z y)(truncate x y)))(t`(#3#z(,(elt'(+ * -)(position c"+*-"))x y))))))))))))

Ungolfed

Con traccia opzionale in fase di esecuzione.

;;; Those auxiliary functions are needed both
;;; during macroexpansion and evaluation

(defun r(s)
  (parse-integer s :radix 16))

(defun h(k)
  (coerce (loop for c = (read-char nil nil)
                while (funcall k c)
                collect c
                finally (unread-char c))
          'string))

(defun w(c)
  (find c "0123456789ABCDEFabcdef"))


;;; C is a macro, it takes a string, replaces it by 
;;; code, which is then evaluated.

(defmacro C(s &optional tracep)
  (with-input-from-string(*standard-input* s)
    (labels((L()(intern(p #'u)))
            (d()(assert(eql #\:(read-char))))
            (o(d)(case (peek-char () () ())
                   (#\:(r(q))(d))
                   (t d)))
            (q()(p #'w))
            (p(k)(prog2(d)(h k)(d)))
            (u(c)(not(eql c #\:))))
      `(let((x 0)(y 0)(z 0)(q(list())))
         (labels((&(n)(q(append(last(car q)n)(butlast(car q)n))))
                 (@(n)(q(nconc(nthcdr n(car q))(subseq(car q)0 n))))
                 (q(x)(setf q(cons x(last x)))))
           (tagbody
              ,@(loop for c =(read-char nil ())
                      while c
                      when tracep
                        collect '(fresh-line)
                        and collect `(print (list :c ,c :x x :y y :z z :q q :s (map'string'code-char(car q))))
                      collect
                      (ecase c
                        (#\<`(setf x ,(r(q))))
                        (#\x`(rotatef x y))
                        (#\}(L))
                        (#\|`(setf x(r(h'w))))
                        (#\!`(setf x(char-code(read-char))))
                        (#\%`(format t"~x"z))
                        (#\$`(princ(code-char z)))
                        (#\~`(rotatef x y z))
                        (#\=`(rotatef z y x))
                        (#\^`(if(not(zerop z))(go,(L))))
                        (#\#`(if(zerop z)(go,(L))))
                        (#\?`(setf q(q())))
                        (#\>'(if(car q)(setf(cddr q)(list z)(cdr q)(cddr q))(setf(cdr q)(setf(car q)(list z)))))
                        (#\{'(setf x(pop(car q))))
                        (#\@`(@,(o 1)))
                        (#\&`(&,(o 1)))
                        (#\/'(multiple-value-setq(z y)(truncate x y)))
                        ((#\+ #\* #\-)`(,(intern(string c)"CL")x y)))
                      when tracep
                        collect `(print (list :c ,c :x x :y y :z z :q q :s (map'string'code-char(car q)))))))))))

Fibonacci

(c "%<:0A:>~$<:01:~%>=<:68a3dd8e61eccfbd:>~>}:_s:{x{={~$x+%{=>~>x~-x<:0A:~>~>~^:_s:?")

macroexpansion

(LET ((X 0) (Y 0) (Z 0) (Q (LIST NIL)))
  (LABELS ((& (N)
             (Q (NCONC (LAST (CAR Q) N) (BUTLAST (CAR Q) N))))
           (@ (N)
             (Q (NCONC (NTHCDR N (CAR Q)) (SUBSEQ (CAR Q) 0 N))))
           (Q (X)
             (SETF Q (CONS X (LAST X)))))
    (PROG ()
      (FORMAT T "~x" Z)
      (SETF X 10)
      (IF (CAR Q)
          (SETF (CDDR Q) (LIST Z)
                (CDR Q) (CDDR Q))
          (SETF (CDR Q) (SETF (CAR Q) (LIST Z))))
      (ROTATEF X Y Z)
      (PRINC (CODE-CHAR Z))
      (SETF X 1)
      (ROTATEF X Y Z)
      (FORMAT T "~x" Z)
      (IF (CAR Q)
          (SETF (CDDR Q) (LIST Z)
                (CDR Q) (CDDR Q))
          (SETF (CDR Q) (SETF (CAR Q) (LIST Z))))
      (ROTATEF Z Y X)
      (SETF X 7540113804746346429)
      (IF (CAR Q)
          (SETF (CDDR Q) (LIST Z)
                (CDR Q) (CDDR Q))
          (SETF (CDR Q) (SETF (CAR Q) (LIST Z))))
      (ROTATEF X Y Z)
      (IF (CAR Q)
          (SETF (CDDR Q) (LIST Z)
                (CDR Q) (CDDR Q))
          (SETF (CDR Q) (SETF (CAR Q) (LIST Z))))
     |_s|
      (SETF X (POP (CAR Q)))
      (ROTATEF X Y)
      (SETF X (POP (CAR Q)))
      (ROTATEF Z Y X)
      (SETF X (POP (CAR Q)))
      (ROTATEF X Y Z)
      (PRINC (CODE-CHAR Z))
      (ROTATEF X Y)
      (SETF Z (+ X Y))
      (FORMAT T "~x" Z)
      (SETF X (POP (CAR Q)))
      (ROTATEF Z Y X)
      (IF (CAR Q)
          (SETF (CDDR Q) (LIST Z)
                (CDR Q) (CDDR Q))
          (SETF (CDR Q) (SETF (CAR Q) (LIST Z))))
      (ROTATEF X Y Z)
      (IF (CAR Q)
          (SETF (CDDR Q) (LIST Z)
                (CDR Q) (CDDR Q))
          (SETF (CDR Q) (SETF (CAR Q) (LIST Z))))
      (ROTATEF X Y)
      (ROTATEF X Y Z)
      (SETF Z (- X Y))
      (ROTATEF X Y)
      (SETF X 10)
      (ROTATEF X Y Z)
      (IF (CAR Q)
          (SETF (CDDR Q) (LIST Z)
                (CDR Q) (CDDR Q))
          (SETF (CDR Q) (SETF (CAR Q) (LIST Z))))
      (ROTATEF X Y Z)
      (IF (CAR Q)
          (SETF (CDDR Q) (LIST Z)
                (CDR Q) (CDDR Q))
          (SETF (CDR Q) (SETF (CAR Q) (LIST Z))))
      (ROTATEF X Y Z)
      (IF (/= Z 0)
          (GO |_s|))
      (SETF Q (Q NIL)))))

Produzione

0
1
1
2
3
5
8
D
15
22
37
59
90
...
5D4D629E80D5489
96F75D79B354522
F444C01834299AB
18B3C1D91E77DECD
27F80DDAA1BA7878
40ABCFB3C0325745
68A3DD8E61ECCFBD

Forse più spiegazioni dopo


1

Python 3, 1573 , 1499 byte

Esegue i programmi di esempio su http://paulo-jorente.de/poncho/esolang/0815/ e implementa tutte le istruzioni (anche scriverne, secondo le specifiche originali).

Esegue il file di origine passato sulla riga di comando.

import sys
from collections import deque
class w:
    q=deque()
    X=Y=Z=c=0
    def __init__(k):k.s=open(sys.argv[1],'r').read()
    def a(k,l):
        i=k.s.find("}:"+l+":")
        if (i<0):sys.exit()
        return i
    def l(k):
        k.c+=1
        if k.s[k.c]!=":":sys.exit(":")
        k.c+=1
        return k.s[k.c:k.c+k.s[k.c:].find(":")]
    def u(k):
        k.c+=1
        if k.s[k.c]!=":":sys.exit(":")
        k.c+=1
        h=k.s[k.c:k.c+k.s[k.c:].find(":")]
        k.c+=len(h)
        return h
    def b(k):
        g=range
        j=input
        z=len
        w=sys.stdout.write
        o=k.s[k.c]
        y=k.q.rotate
        if o=='<':k.X=int(k.u(),16)
        elif o=='x':t=k.X;k.X=k.Y;k.Y=t
        elif o=='=':t=k.X;k.X=k.Z;v=k.Y;k.Y=t;k.Z=v;
        elif o=='$':
            if (k.Z==0x0d):w('\n')
            else:w(str(chr(k.Z%256)))
        elif o=='%':w(str(k.Z))
        elif o=='~':t=k.X;v=k.Y;k.X=v;k.Y=k.Z;k.Z=t;
        elif o=='?':k.q.clear()
        elif o=='>':k.q.append(k.Z)
        elif o=='{':k.X=k.q.popleft()
        elif o=='@':
            if k.s[k.c+1]==':':
                t=k.u()
                for i in g(0,int(t,16)):y(-1)
            else:
                y(-1)
        elif o=='&':
            if k.s[k.c+1]==':':
                t=k.u()
                for i in g(0,int(t,16)):y(1)
            else:
                y(1)
        elif o=='}':
            k.c+=z(k.l())
        elif o=='#':
            l=k.l()
            if (k.Z==0):
                k.c=k.a(l)-1
            else:
                k.c+=z(l)
        elif o=='^':
            l=k.l()
            if (k.Z!=0):
                k.c=k.a(l)-1
            else:
                k.c+=z(l)
        elif o=='|':k.X=int(j("?"),16)
        elif o=='!':k.X=ord(j(">")[0])
        elif o=='+':k.Z=k.X+k.Y
        elif o=='-':k.Z=k.X-k.Y
        elif o=='*':k.Z=k.X*k.Y
        elif o=='/':
            k.Z=int(k.X/k.Y)
            k.Y=k.X%k.Y
        k.c+=1
    def x(k):
        while k.c<len(k.s):k.b()
w().x()

2
" Funziona con alcuni bug " di solito non è una risposta accettabile.
fase

@phase: ora è stato risolto.
Gabriele D'Antona,

1
Questo è codice golf, amico! perché tutto lo spazio bianco? perché tutti i nomi delle variabili a 2 byte?
Quintopia,

Ciò potrebbe essere dovuto al fatto che lo sto eseguendo in Python 3 (che funziona, tra l'altro, dopo essere passato j=raw_inputa j=input), ma non funziona per me nel programma "99 Bottiglie di birra". Un campione ("//" per newline): "0x63 // 0x63tles di birra sul muro // 0x62 uno in basso e passalo intorno // 0x62tles di birra sul muro // 0x62tles di birra sul muro // 0x61 uno giù e
passalo

@TimPederick: hai ragione. Sei riuscito a eseguire l'interprete originale (.exe)? Qual è il risultato atteso?
Gabriele D'Antona,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.