Interpretuj Kipple!

12

Wprowadzenie

Kipple to ezoteryczny język programowania oparty na stosach, opracowany przez Rune Berg w marcu 2003 roku.

Kipple ma 27 stosów, 4 operatorów i strukturę kontrolną.

Półki na książki

Stosy są nazywane a- zi zawierają 32-bitowe liczby całkowite ze znakiem. Istnieje również specjalny stos @, aby ułatwić wyprowadzanie liczb. Kiedy liczba jest wypychana na @, wartości ASCII cyfr tego numeru są w rzeczywistości wypychane. (Na przykład, jeśli naciśniesz 12 do @, popchnie 49, a następnie 50 do @.)

Dane wejściowe są wypychane na stos wejściowy iprzed uruchomieniem programu. Interpretator poprosi o zapisanie wartości iprzed wykonaniem. Po zakończeniu wykonywania wszystko na stosie wyjściowym ojest wyskakujące na wyjście jako znak ASCII. Ponieważ jest to jedyny mechanizm IO Kipple, interakcja z programem Kipple jest niemożliwa.

Operatorzy

Operand jest albo identyfikatorem stosu, albo 32-bitową liczbą całkowitą ze znakiem.

Naciśnij: >lub<

Składnia: Operand>StackIndentifierlubStackIndentifier<Operand

Operator Push przenosi operand w lewo i wypycha go na określony stos. Na przykład 12>awypchnie wartość 12 na stos a. a>bwyskoczy najwyższą wartość ze stosu ai wrzuci ją na stos b. Stuknięcie pustego stosu zawsze zwraca 0. a<bjest równoważne z b>a. a<b>cwyskakuje najwyższa wartość z bi popycha do obu ci a.

Dodaj: +

Składnia: StackIndentifier+Operand

Operator Add wypycha sumę najwyższego elementu ze stosu i operandu na stos. Jeśli operand jest stosem, wartość jest z niego wyskakująca. Na przykład, jeśli najwyższą wartością stosu ajest 1, wówczas a+2popchnie na niego 3. Jeśli ajest pusty, wówczas a+2popchnie 2 na niego. Jeśli najwyższe wartości stosu ai bwynoszą 1 i 2, wówczas a+bwyskakuje wartość 2 ze stosu bi wypycha 3 na stos a.

Odejmować: -

Składnia: StackIndentifier-Operand

Operator Subtract działa dokładnie tak samo, jak operator Add, z tym wyjątkiem, że odejmuje zamiast dodawać.

Jasny: ?

Składnia: StackIndentifier?

Operator Clear opróżnia stos, jeśli jego najwyższy element to 0.

Interpreter ignoruje wszystko, co nie jest obok operatora, więc następujący program będzie działać: a+2 this will be ignored c<i. Jednak właściwym sposobem dodawania komentarzy jest użycie #znaku. #Przed wykonaniem usuwane jest wszystko od znaku do końca wiersza. Znak ASCII # 10 jest zdefiniowany jako koniec linii w Kipple.

Operandy mogą być współużytkowane przez dwóch operatorów, np. a>b c>b c?Mogą być zapisane jako a>b<c?.

Program 1>a<2 a+abędzie azawierał wartości [1 4](od dołu do góry), a nie [1 3]. Podobnie dla -operatora.

Struktura kontroli

W Kipple jest tylko jedna struktura kontrolna: pętla.

Składnia: (StackIndentifier code )

Dopóki określony stos nie jest pusty, kod w pasujących nawiasach będzie powtarzany. Pętle mogą zawierać inne pętle. Na przykład (a a>b)przeniesie wszystkie wartości stosu ana stos b, chociaż kolejność zostanie odwrócona . Funkcjonalnie identyczny, ale bardziej elegancki sposób to zrobić (a>b).

Przykłady

100>@ (@>o)

To wyjdzie 100

33>o 100>o 108>o 114>o 111>o 87>o 32>o 111>o 108>o 108>o 101>o 72>o

To zostanie wydrukowane "Hello World!". Kiedy ostos jest wyprowadzany, zaczyna wyrywać znaki od góry stosu do dołu.

#prime.k by Jannis Harder
u<200
#change 200


k<2>m
u-2
(u-1 u>t u>z u<t
  (k>e e+0 e>r)
  (e>k)
  m+1
  m>t
  m>z
  m<t
  t<0>z? t?
  1>g
  (r>b
    m+0 m>a
    b+0 b>w
    (a-1 
      b+0 b>j
      j?
      1>s
      (j<0>s j?)
      s?
      (s<0 w+0 w>b s?)
      a>t
      a>z
      t>a
      b-1
      b>t
      b>z
      t>b
      z<0>t? z?
    a?)
    b?
    1>p
    (b<0 b? 0>p)
    p?
    (p 0>r? 0>p? 0>g)
  )
  g?
  (g m+0 m>k 0>g?)
u?)
(k>@
  10>o
  (@>o)
)

Jest to generator liczb pierwszych, ale nie jestem pewien, jak to działa.

Zasady

  • Musisz napisać program / funkcję, która interpretuje Kipple. Ten program / funkcja może uzyskać program Kipple za pośrednictwem pliku źródłowego lub uzyskać go za pośrednictwem STDIN bezpośrednio od użytkownika. Jeśli STDIN nie jest dostępny, musi pobrać go z klawiatury i kontynuować wprowadzanie, dopóki nie zostanie wprowadzony określony znak niedrukowalny. Na przykład, jeśli interpreter jest napisany w kodzie maszynowym x86, pobierze znak programu Kipple po znaku z klawiatury i będzie to robił do momentu escnaciśnięcia (lub dowolnego innego klawisza, który nie emituje znaku drukowalnego).

  • Jeśli wystąpi błąd, np. Błąd składniowy lub przepełnienie stosu, musi w jakiś sposób potwierdzić to, na przykład zwracając 10 zamiast 0 lub komunikaty o błędach generowane przez interpreter / kompilator, ALE NIE WIADOMOŚCI O BŁĘDACH .

  • Do tego wyzwania obowiązują wszelkie inne regularne zasady gry w golfa kodowego.

  • Twój kod zostanie przetestowany z niektórymi przykładami w archiwum próbek Kipple

To jest . Wygra najkrótszy kod w bajtach. Powodzenia!


Zauważ, że w Kipple istnieje opcjonalny operator ", ale nie jest on częścią specyfikacji, a jedynie dodatkową funkcją w oficjalnym tłumaczu. Nie wspomniałem o tym tutaj, więc nie musi być poparty w twoim zgłoszeniu.

Jeśli masz jakiekolwiek wątpliwości co do jakiejkolwiek części specyfikacji, możesz to sprawdzić za pomocą oficjalnego tłumacza napisanego w Javie . Spowoduje to pobranie pliku zip zawierającego skompilowany program i kod źródłowy. Jest licencjonowany na licencji GPL.


źródło
1
Czy możemy mieć do wykorzystania 32-bitowej liczby całkowite lub możemy iść z naturalnego typu całkowitego wdrożenia przyjmującego? (Najważniejsze przypadki to prawdopodobnie 32-bitowe liczby całkowite bez znaku, 8-bitowe liczby całkowite ze znakiem lub liczby całkowite bez znaku).
Martin Ender
cóż, to znalazłem na esotric wiki. tak, ponieważ twój tłumacz może być niekompatybilny z innymi programami kipple, których mechanizm opiera się na tej funkcji
Czy możesz bardziej szczegółowo określić zachowanie w przypadku błędów? Możemy więc zwrócić niepoprawną odpowiedź lub wyemitować błąd, ale nie możemy wydrukować błędu?
Alex A.,
@Alex A. Tak, ponieważ można go traktować jako wynik programu i można utworzyć program kipple, który może mieć takie same wyniki jak komunikat o błędzie. Również „taniej” (zużywa mniej znaków) nie mieć funkcji / instrukcji, która wypisuje komunikat o błędzie.
3
Jakie białe znaki mogą wystąpić w programie źródłowym? Jak mogę poprosić o dane wejściowe, ijeśli pobieram program źródłowy ze standardowego wejścia?
orlp

Odpowiedzi:

6

C, 709 702 bajtów

Wynik w bajtach został usunięty z nowej linii (którą można usunąć), ale dla ułatwienia czytania zamieszczam ją tutaj z nową linią:

#define R return
#define C ;break;case
c[999]={};*P=c;*S[28];M[99999]={};t;*T;
u(s,v){S[s]+=28;*S[s]=v;
if(s>26){for(t=v/10;t;t/=10)S[s]+=28;T=S[s];do{*T=48+v%10;T-=28;}while(v/=10);}}
o(s){t=S[s]-M>27;S[s]-=28*t;R S[s][28]*t;}
I(s){R s<65?27:s-97;}
O(int*p){if(!isdigit(*p))R o(I(*p));
for(;isdigit(p[-1]);--p);for(t=0;isdigit(*p);t*=10,t+=*p++-48);R t;}

main(i,a){for(i=0;i<28;++i)S[i]=M+i;
for(;~(*++P=getchar()););P=c+1;
for(;;){i=I(P[-1]);switch(*P++){
case 35:for(;*P++!=10;)
C'<':u(i,O(P))
C'>':u(I(*P),O(P-2))
C'+':u(i,*S[i]+O(P))
C'-':u(i,*S[i]-O(P))
C'?':if(!*S[i])S[i]=M+i
C'(':for(i=1,T=P;i;++T)i+=(*T==40)-(*T==41);if(S[I(*P)]-M<28)P=T;else u(26,P-c)
C')':P=c+o(26)-1
C-1:for(;i=o(14);)putchar(i); R 0;}}}

Kompiluj z gcc -w golf.c( -wwycisza ostrzeżenia dla twojego zdrowia psychicznego).

Obsługuje wszystko oprócz idanych wejściowych, ponieważ pytający nie odpowiedział jeszcze na moje pytanie, jak to zrobić, jeśli weźmiesz kod ze standardowego wejścia. Nie zgłasza błędów składniowych.

orlp
źródło
Odpowiedziałem na twoje pytanie dotyczące stosu „i” w komentarzach głównego postu.
btw jak to czyta programy Kipple? za pomocą argumentów poleceń? jak powinienem tego użyć?
@GLASSIC Oczekuje, że program uruchomi się na standardowym wejściu.
orlp
Do kiedy ? Jak rozpocząć wycięcie?
@GLASSIC Wystarczy przekazać program na standardowe wejście. Np ./a.out < prime.k.
orlp
3

Rubinowy, 718 bajtów (obecnie niekonkurencyjny)

jestem bardzo zmęczony

Plik jest ładowany jako argument wiersza poleceń, a dane wejściowe są przesyłane przez STDIN. Alternatywnie, potokuj plik do STDIN, jeśli nie potrzebujesz danych wejściowych do irejestru.

Z powodu pewnych nieporozumień dotyczących specyfikacji bieżąca wersja nie obsługuje się a<b>cpoprawnie, a zatem nie jest konkurencyjna, dopóki nie zostanie naprawiona.

a<b>cjest teraz naprawiony. Jednak nadal zwraca zły wynik podczas uruchamiania funkcji liczb pierwszych, więc nadal pozostaje odpowiedzią niekonkurencyjną.

(f=$<.read.gsub(/#.*?\n|\s[^+-<>#()?]*\s/m,' ').tr ?@,?`
t=Array.new(27){[]}
t[9]=STDIN.read.bytes
k=s=2**32-1
r=->c{c=c[0];c[0]==?(?(s[c[1..-2]]while[]!=t[c[1].ord-96]):(c=c.sub(/^(.)<(\D)>(.)/){$1+"<#{t[$2.ord-96].pop||0}>"+$3}.sub(/(\d+|.)(\W)(\d+|.)?/){_,x,y,z=*$~
a=x.ord-96
b=(z||?|).ord-96
q=->i,j=z{j[/\d/]?j.to_i: (t[i]||[]).pop||0}
l=t[a]
y<?-?(x==z ?l[-1]*=2:l<<(l.pop||0)+q[b]
l[-1]-=k while l[-1]>k/2):y<?.?(x==z ?l[-1]=0:l<<(l.pop||0)-q[b]
l[-1]+=k while l[-1]<-k/2-1):y<?>?t[a]+=a<1?q[b].to_s.bytes: [q[b]]:y<???
(t[b]+=b<1?q[a,x].to_s.bytes: [q[a,x]]): l[-1]==0?t[a]=[]:0
z||x}while c !~/^(\d+|.)$/)}
s=->c{(z=c.scan(/(\((\g<1>|\s)+\)|[^()\s]+)/m)).map &r}
s[f]
$><<t[15].reverse.map(&:chr)*'')rescue 0
Wartość tuszu
źródło
W każdym razie +1. Czy próbowałeś programu Fibonacciego?
edc65
@ edc65 Program sekwencyjny Fibbonacciego również drukuje niewłaściwą rzecz: 0 1 1 2 4 8 16...Zastanawiam się, czy to błąd specyfikacji
Wartość Ink
Nie, program Fibonacciego to bzdura, na przykład linia a+0jest nonsensowna
edc65
Myślę, że problem z liczbami pierwszymi polega na tym, że nie obsługuje zagnieżdżonych struktur kontrolnych, ale niewiele wiem o ruby, wątpię, czy moje przypuszczenia są prawidłowe.
Ten program powinien poprawnie obsługiwać zagnieżdżone zestawy parenów z powodu rekurencyjnego dopasowania wyrażenia regularnego /(\((\g<1>|\s)+\)|[^()\s]+)/m, którego używa do dzielenia na tokeny i grupy tokenów. ( Przetestuj na regex101 ). Prawdopodobnie jest to błąd w pozostałej części parsowania, ale nie wiem gdzie.
Wartość tuszu