Języki ezoteryczne

28.12.2009 - Marek Materzok
TrudnośćTrudność

INTERCAL, czyli jak się to wszystko zaczęło

Język INTERCAL został stworzony w roku 1972 przez dwójkę studentów Uniwersytetu Princeton, Donalda Woodsa i Jamesa Lyona. Jak podają sami autorzy, rozwinięciem skrótu INTERCAL jest "Compiler Language With No Pronounceable Acronym", czyli "Kompilowany Język Bez Wymawialnego Skrótu", a jedną z głównych cech języka jest jego niewyczerpana zdolność zadziwiania znajomych programistów, zdobywania przyjaciół i wpływania na ludzi. Język parodiuje popularne w chwili jego powstania języki FORTRAN i COBOL. Opisuje go napisany w żartobliwy sposób, ponad 40-stronicowy dokument - "The INTERCAL programming language - revised reference manual". Zachęcam do jego przeczytania.

Cechą charakterystyczną języka są występujące w nim dziwaczne instrukcje. Każda instrukcja musi być poprzedzona słowem DO, PLEASE ("proszę") lub PLEASE DO ("proszę, zrób") - słowa te można używać zamiennie. Oto moim zdaniem najciekawsze instrukcje języka INTERCAL:

COME FROM

Zamiast popularnej niegdyś instrukcji GOTO, przekazującej sterowanie do podanej linii programu, w języku INTERCAL pojawia się COME FROM - oznaczająca, że po wykonaniu podanej linii następną instrukcją ma być ta następująca po COME FROM! Można sobie wyobrazić, jak bardzo można w ten sposób zamydlić strukturę programu. Dla przykładu, w następującym (schematycznym) programie:

(1) DO instrukcja1
(2) DO instrukcja2
(3) DO COME FROM (1)
(4) DO instrukcja3

Wykonana zostanie instrukcja instrukcja1, a następnie instrukcja3 - instrukcja2 zostanie pominięta.

IGNORE i REMEMBER

Instrukcja IGNORE powoduje, że wszystkie instrukcje piszące do podanej zmiennej przestają być wykonywane. Natomiast instrukcja REMEMBER kończy działanie IGNORE - ponownie pozwala na zapisywanie do danej zmiennej. W następującym programie:

DO .1 <- #2
PLEASE IGNORE .1
DO .1 <- #0
PLEASE REMEMBER .1
DO .1 <- .V1

Wykonana zostanie linijka pierwsza, trzecia i piąta, zaś nie zostanie wykonana linijka trzecia - i tym samym wynikiem programu jest 3. (Znaczenie literki V w kodzie omówię później.)

ABSTAIN i REINSTATE

Instrukcja ABSTAIN pozwala na zrezygnowanie z wykonywania wybranych instrukcji w programie. Podobnie, jak poprzednio, istnieje też instrukcja o przeciwnym działaniu, czyli REINSTATE. Instrukcje te mają dwie formy. W pierwszej z nich rezygnuje się z wykonywania wszystkich instrukcji wybranego rodzaju. Dla przykładu, instrukcja DO ABSTAIN FROM IGNORING powoduje, że instrukcje IGNORE nie będą wykonywane - a przynajmniej do momentu pojawienia się instrukcji DO REINSTATE IGNORING. Jak najbardziej poprawne są instrukcje DO ABSTAIN FROM ABSTAINING, a nawet DO ABSTAIN FROM REINSTATING - choć ta druga jest dość niebezpieczna, bo powoduje, że efekt ABSTAIN staje się trwały!

Instrukcje ABSTAIN i REINSTATE mogą też działać na pojedynczych instrukcjach. Dla przykładu, w poniższym programie:

PLEASE ABSTAIN FROM (1)
DO COME FROM (2)
(1) DO .1 <- #1
(2) PLEASE REINSTATE (1)

Instrukcja w linii o numerze 1 za pierwszym razem się nie wykona, po czym program zapętli się, a w pętli instrukcja ta będzie wykonywana.

Warto też wspomnieć, że instrukcje mogą być domyślnie w stanie takim, jak po użyciu ABSTAIN, jeśli poprzedzi się je słowem DON'T. Tym samym, instrukcja:

(1)PLEASE DON'T .1 <- #2

Wykona się tylko wtedy, gdy wcześniej zostanie wykonana instrukcja PLEASE REINSTATE (1).

Ciekawostka - instrukcję zakończenia pracy programu, GIVE UP, można również poprzedzić DON'T, otrzymując nic nie robiącą instrukcję DON'T GIVE UP - "nie poddawaj się".

Przypisanie

Wydawałoby się znajoma instrukcja przypisania w języku INTERCAL również nie jest zupełnie zwyczajna, a to ze względu na nietypowość występujących w języku operatorów. INTERCAL posiada trzy operatory binarne i dwa unarne. Operatory unarne wykonują operacje bitowe AND (<), OR (V) oraz XOR (?) na parach sąsiadujących bitów, zapisując wynik w drugim bicie z każdej pary. Pierwszy i ostatni bit również liczą się jako para. Dla przykładu, mając wartość #77 (1001101 binarnie), wyniki operacji są takie: #&77 to 4 (100 binarnie), #V77 to 32879 (1000000001101111), zaś #?77 to 32785 (1000000001101011).

Dwie operacje binarne języka INTERCAL to mingle ("pomieszaj") zapisywany $, oraz select ("wybierz") zapisywany ~. Operacja mingle polega na wybraniu z dwóch 16-bitowych wartości bitów na przemian z pierwszego i drugiego - na przykład, wynik #65535$#0 zapisany binarnie ma postać 10101010...1010. Natomiast operacja select wybiera z lewego argumentu te bity, których odpowiedniki w prawym argumencie mają wartość 1, i układa je w szeregu jeden obok drugiego, wypełniając zerami. Przykładowo, #179~#201 (10110011~11001001 binarnie) wybiera bity 1001, co daje wartość 9.

Jak widać, w języku INTERCAL zupełnie brakuje znanych operacji arytmetycznych. Programując w INTERCALu koniecznym jest zaimplementować je samemu, używając tylko operacji wymienionych powyżej.

Hello World

W Wariancie C-INTERCAL program Hello World wygląda następująco:

DO ,1 <- #13
PLEASE DO ,1 SUB #1 <- #238
DO ,1 SUB #2 <- #108
DO ,1 SUB #3 <- #112
DO ,1 SUB #4 <- #0
DO ,1 SUB #5 <- #64
DO ,1 SUB #6 <- #194
DO ,1 SUB #7 <- #48
PLEASE DO ,1 SUB #8 <- #22
DO ,1 SUB #9 <- #248
DO ,1 SUB #10 <- #168
DO ,1 SUB #11 <- #24
DO ,1 SUB #12 <- #16
DO ,1 SUB #13 <- #162
PLEASE READ OUT ,1
PLEASE GIVE UP

Powyższy program wpisuje kody ASCII słowa "Hello World" do tablicy, po czym wypisuje jej zawartość na ekran.

Brainf**k: osiem instrukcji i taśma

Język Brainf**k został opracowany przez Urbana Müllera w roku 1993. Jego intencją było stworzenie języka, który byłby bardzo prosty w kompilacji. Cel rzeczywiście zrealizował - istnieją kompilatory Brainf**ka krótsze od 200 bajtów! Ponadto, jak wskazuje nazwa, programowanie w tym języku jest wyjątkowo trudne. Dlaczego - niedługo się okaże.

Programy w języku Brainf**k wykonują się w pamięci ("taśmie") złożonej z bajtów, na którą wskazuje pojedynczy wskaźnik - "głowica". W zależności od wersji, przyjmuje się albo że pamięć jest cykliczna i ma ograniczony rozmiar (najczęściej 30000 bajtów), albo że jest (teoretycznie) nieograniczona z prawej strony. Program w Brainf**ku jest ciągiem znaków ASCII, z których każdy albo oznacza jakąś instrukcję, albo jest ignorowany. Język zawiera tylko osiem instrukcji:

Ciekawostka: Brainf**k jest praktyczną realizacją teoretycznego języka P'', opracowanego przez Corrado Böhma w roku 1964. Już wtedy pokazano, że język ten jest kompletny obliczeniowo!

  • > - przesuń głowicę o 1 w prawo
  • < - przesuń głowicę o 1 w lewo
  • + - dodaj 1 do bajtu pod głowicą
  • - - odejmij 1 od bajtu pod głowicą
  • [ - jeśli pod głowicą jest wartość różna od 0, wykonaj kolejną instrukcję; w przeciwnym wypadku wykonaj instrukcję po odpowiadającym ]
  • ] - jeśli pod głowicą jest wartość różna od 0, wykonaj instrukcję następującą po odpowiadającym [; w przeciwnym wypadku wykonaj kolejną instrukcję
  • , - wczytaj jeden bajt z wejścia i zapisz pod głowicą
  • . - wypisz bajt pod głowicą na wyjście

Instrukcje [ i ] muszą być dopasowane do siebie tak, jak nawiasy w wyrażeniach arytmetycznych.

I to wszystko! Mimo tak ograniczonego zasobu instrukcji, język ten jest kompletny obliczeniowo - można w nim policzyć dowolną funkcję, którą można policzyć w jakimkolwiek innym języku programowania. Wydaje się to zaskakujące, ale jest to prawda. Można to zademonstrować na papierze, przeprowadzając matematyczny dowód (nie będziemy się wgłębiać w to, jak taki dowód wygląda), albo w komputerze, pisząc kompilator - program tłumaczący kod w innym języku do języka Brainf**k.

Oto przykładowy kod "Hello World":

++++++++++
[>+++++++>++++++++++>+++>+<<<<-]
>++.
>+.
+++++++.
.
+++.
>++.
<<+++++++++++++++.
>.
+++.
------.
--------.
>+.
>.

Autor powyższego programu starał się zmniejszyć wielkość programu, używając wielokrotnie wartości zapisanych w kilku komórkach. Pierwsze dwie linijki zapisują w czterech kolejnych komórkach pamięci wartości 70, 100, 30 i 10, kolejne zaś poprawiają je do pożądanych kodów ASCII i wypisują na wyjście.

5
Twoja ocena: Brak Ocena: 5 (1 ocena)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com