Napisz tłumacza 0815

26

Podoba mi się koncepcja 0815 , z wyjątkiem tłumacza na stronie twórcy zwraca błąd 404. Postanowiłem więc poprosić was wszystkich o pomoc!

Podstawy

0815 opiera się na trzech (3) rejestrach i kolejce. Rejestry noszą nazwy X, Y i Z, przy czym X jest tylko do zapisu, Z jest tylko do odczytu, a Y jest rejestrem „pomocniczym”, do którego nie można uzyskać bezpośredniego dostępu. Wszystkie rejestry zaczynają się od zera. Wszystkie liczby są w systemie szesnastkowym.

Instrukcje

Uwaga: niektóre instrukcje pobierają parametry, które są sformatowane tak, jak }:hello:gdzie :hello:jest parametr. Inna uwaga: niektóre opisy instrukcji są niejasne, więc zabrałem ze sobą pewne swobody. (Oryginalne instrukcje tutaj )

~ oznacza, że ​​parametr jest wymagany

----------|---|--------------------------------------------
  ~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
----------|---|--------------------------------------------

Instrukcje kolejki

----------|---|--------------------------------------------
   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  |   | 
----------|---|--------------------------------------------

Instrukcje arytmetyczne

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

Przykładowe programy

Witaj, świecie: (lekko golfowy)

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

Kot:

}:_t:!~$^:_t:

Maszyna Prawdy:

|~}:i:%^:i:

To jest , więc wygrywa zgłoszenie z najmniejszą liczbą bajtów!

DanTheMan
źródło
3
Jaka jest różnica między ~i ~w swoim „roll rejestry” poleceń? Czy masz przykładowy program, którego ludzie mogą używać do testowania?
AdmBorkBork,
3
Jakieś przykłady, które możesz nam podać?
Conor O'Brien,
1
@DanTheMan Widzę „Hello, Wlrod”, gdy uruchamiam Twój przykład Hello World przy użyciu mojej implementacji (wciąż WIP) ... Nie jestem pewien, czy to błąd w moim kodzie, czy sam przykład
Ruslan
2
@DanTheMan Tak, ale zmiana linku daje tłumacza. :-)
Sven pisze kod
1
@usandfriends Naprawiono!
DanTheMan

Odpowiedzi:

8

Pypeć , 321 262 248 bajtów

Znacznie skrócone za pomocą eval i niektórych sztuczek złożoności Kołmogorowa.

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)}

Wypróbuj online!(Przykładem jest program Collatz / hailstone numbers z witryny autora języka).

Uwagi:

  • Pobiera kod 0815 jako pierwszy argument wiersza poleceń, a dane wejściowe jako drugi. Tak, jest to trochę niezręczne (o wiele mniej tak w TIO, gdzie masz oddzielne pola tekstowe), ale Pip nie jest świetny w czytaniu wszystkich standardowych.
  • Liczby na wejściu muszą zawierać duże cyfry szesnastkowe (zgodnie z OP: dopasowanie wyrażenia regularnego [0-9A-F]+). Jeśli, zgodnie z |instrukcją, kolejnym znakiem wejściowym nie jest0-9A-F , odczyt kończy się niepowodzeniem i powoduje potencjalnie dziwne zachowanie. Oznacza to, że parzysty nieparzysty program autora nie działa tak, jak napisano ... Nie jestem pewien, jak oczekiwał odczytywania wielu odczytów liczb, ale po prostu zaimplementowałem zgodnie z tym, co podano w specyfikacji.
  • Jeśli etykieta jest zduplikowana, skok przechodzi do pierwszej. Jeśli etykieta nie istnieje, skok kończy działanie programu.

Moja nie golfowa wersja z komentarzami:

;;; 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
 }
}
DLosc
źródło
7

haxe, 987 bajtów

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;}}}

lub z pewnymi odstępami:

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;
}}}

Udało ci się zagrać w golfa z haxe? Łał.

Aurel Bílý
źródło
1
+1 dla Haxe, najkrótsza odpowiedź w jednym z najmniej golfowych języków
kot
1
Czy wiesz, jeśli skompilowałbyś to w JS, czy byłby krótszy? wtedy możesz zrobić to ES6 / ES7
kot
5

Python 3, 1320 bajtów

Wersja bez golfa, a także analiza (i, w razie potrzeby, poprawionych wersji) programów testowych, można znaleźć w tej treści .

Decyzje projektowe:

  • Wiele definicji etykiet jest ignorowanych. Używana jest tylko pierwsza definicja etykiety. (Poprzednio używana byłaby ostatnio widziana definicja, ale to się rozegrało).
  • Dane wejściowe są zgodne ze specyfikacją PO: dane liczbowe odczytują zachłannie znaki szesnastkowe. (Początkowo był czytany do nowej linii i występował błąd, gdy czytano znaki inne niż szesnastkowe).
  • Wejście „ASCII” oznacza wejście „zorientowane na bajty”. (Początkowo miał pełną obsługę Unicode, która wymagała mniej kodu dzięki byciu Python 3 ... ale spełnienie następnego punktu oznaczało, że czytanie bajt po bajcie było teraz krótsze.)
  • Parametry, w których nie oczekuje się żadnych parametrów, są ignorowane; stąd są użyteczne jako komentarze.

Występują problemy z przykładowymi programami używającymi CR jako nowej linii (czasami), co powoduje, że moja powłoka zastępuje bieżącą linię, zamiast uruchamiać nową. Wpływa to na programy Sekwencji Fibonacciego i 99 Butelek Piwa. Ostatni wiersz 99 butelek piwa również nie jest drukowany poprawnie, a ja wciąż badam, dlaczego.

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
Tim Pederick
źródło
4

Scala, 3,123 2.844 2.626 2,540 bajtów

Oprócz ograniczeń przedstawionych w pytaniu, ten tłumacz został napisany tak, aby w jak największym stopniu kierować się zasadami PR. Konkretnie:

  • Tylko niezmienne konstrukcje
  • Wszystkie funkcje są czyste

Dokonano tego, z wyjątkiem czterech linii kodu, które sterują główną pętlą interpretera. Niezmienne struktury były tutaj bardzo trudne do wykorzystania, ponieważ stan rejestrów steruje przepływem sterowania pętli (konkretnie dwie instrukcje GOTO). Nadal zastanawiam się, jak przekonwertować go, aby używał czystych i niezmiennych struktur, ale nie ma to znaczenia dla wyzwania golfowego.

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}

Zamieszczę wersję niegolfowaną na Github i podam link, kiedy to zrobię. Na razie opublikuję oryginalną wersję tutaj:

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()
}
Ruslan
źródło
2

Flex / C ++, 848 838 bajtów

%{
#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();}

Kompilowany z:

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

Może się również kompilować z innymi lexes, ale nie sprawdziłem. Działa w dwóch krokach, więc skoki do przodu są obsługiwane poprawnie. Nazwy etykiet mogą zaczynać się od cyfry, ponieważ zdarza się to więcej niż jeden raz w przypadkach testowych. Hex literały mogą być pisane tylko wielkimi literami, zgodnie ze specyfikacją.

Przechodzi wszystkie przypadki testowe, w tym te znalezione na Wiki Esolangs i na stronie 0815. Obsługa błędów nie istnieje, a wyjście na nieznanej etykiecie nie jest taktowne, w końcu to jest golf golfowy.

Przygotowuję niefunkcjonalnego (i znacznie ładniejszego) interpretera do wydania, aby OP mógł ciągle majstrować przy 0815. Bądź na bieżąco :)

Stefano Sanfilippo
źródło
99 butelek przykładów piwa używa \rzamiast \nnowej linii (oldschoolowy Mac OS?), Więc jeśli chcesz zobaczyć coś wydrukowanego na ekranie, użyj ./0815 99bb.0815 | tr "\r" "\n". To samo dotyczy Fibonacciego.
Stefano Sanfilippo,
2

Common Lisp, 1088 bajtów

(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))))))))))))

Nie golfił

Z opcjonalnym śledzeniem w czasie wykonywania.

;;; 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)))))))))))

Fibonnaci

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

Makroekspansja

(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)))))

Wydajność

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

Może później więcej wyjaśnień

rdzeń rdzeniowy
źródło
1

Python 3, 1573 , 1499 bajtów

Uruchamia przykładowe programy na stronie http://paulo-jorente.de/poncho/esolang/0815/ i implementuje wszystkie instrukcje (nawet napisz te, zgodnie z oryginalną specyfikacją).

Wykonuje plik źródłowy przekazany w wierszu polecenia.

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()
Gabriele D'Antona
źródło
2
Działa z pewnymi błędamizwykle nie jest akceptowalną odpowiedzią.
faza
@phase: teraz naprawione.
Gabriele D'Antona,
1
To jest kod golfowy, stary! dlaczego wszystkie białe znaki? dlaczego wszystkie 2-bajtowe nazwy zmiennych?
kwintopia
Może to być spowodowane tym, że uruchamiam go w Pythonie 3 (który, nawiasem mówiąc, działa po zmianie j=raw_inputna j=input), ale nie działa dla mnie w programie „99 butelek piwa”. Próbka („//” dla nowego wiersza): „0x63 // 0x63t piwa na ścianie // 0x62 jeden w dół i podaj go wokół // 0x62tles piwa na ścianie // 0x62tles piwa na ścianie // 0x61 jeden i
przekażcie
@TimPederick: masz rację. Czy udało Ci się uruchomić oryginalny interpreter (.exe)? Jaki jest oczekiwany wynik?
Gabriele D'Antona,