Copyright © 2006 Krzysztof Piecuch, Tomasz Jędrzejewski
Spis treści
Spis tabel
Spis przykładów
28 sierpnia 2006 roku do LO im. Stanisława Staszica w Lublinie zjechała się z całej Polski grupa młodych informatyków oraz matematyków, aby dzielić się między sobą własną wiedzą i doświadczeniem. Jeszcze przed samym rozpoczęciem zlotu rozmowa zeszła na ezoteryczne języki programowania, które poza nielicznymi wyjątkami nie oferowały nic ponad udziwnioną składnię. Na pierwszym z wykładów dwójka uczestników, Krzysztof Piecuch oraz Tomasz Jędrzejewski, postanowiła tchnąć nowe życie w tę gałąź informatyki, tworząc nowy język programowania oparty na rewolucyjnej idei działania. Tak narodził się projekt Revomer.
W przeciągu pięciu dni trwania zlotu, w spartańskich warunkach, powstawały równocześnie założenia projektowe oraz pierwszy interpreter języka. Prace prowadzone były w godzinach nocnych i porannych na laptopie ulokowanym na sali gimnastycznej, a pierwsza wersja niniejszej specyfikacji została napisana na kilkumetrowej wstędze szarego papieru toaletowego. 1 września o godzinie 10.04 po raz pierwszy udało uruchomić się program wypisujący "HI UNIVERSE".
Nazwa języka to pisane na odwrót angielskie słowo "remover". Odzwierciedla ona podstawowe idee leżące u jego podstaw, które można zawrzeć w prostym skrócie IN-IG (Is Negative-Is Good). Język samą swoją strukturą wymusza zastosowanie nowego punktu widzenia na wiele, zdałoby się, oczywistych i nieodłącznych konstrukcji programistycznych. Mamy głęboką nadzieję, że będzie on istotnym wkładem w rozwój światowej informatyki oraz że kupi go znany wszystkim monopolista z Redmond i zastosuje w swoich produktach.
W tej części wyjaśniamy podstawowe założenia języka programowania Revomer.
Podany poniżej program jest jednocześnie pierwszym, jaki udało się uruchomić na pierwszym interpreterze Revomera. Powoduje on wypisanie na ekranie napisu "HI UNIVERSE", po czym kończy swoją pracę.
Przykład 1.1. Program "HI UNIVERSE"
almukantarat~ nope~ null% almukantarat~ come here $1, $1, $3 gifs 3~ hide $3 gifs 29~ hide $2 gifs 29~ hide $1 pos $0~ gifs 69~ pos $0~ gifs 83~ pos $0~ gifs 82~ pos $0~ gifs 69~ pos $0~ gifs 86~ pos $0~ gifs 73~ pos $0~ gifs 78~ pos $0~ gifs 85~ pos $0~ gifs 32~ pos $0~ gifs 73~ pos $0~ gifs 72~ hide $0 %
Dokładna analiza kodu źródłowego jest przeprowadzona w dalszej części specyfikacji.
Szczegółowe założenia i koncepcje dotyczące Revomera to:
Środowisko, w którym pracują programy Revomera składa się z następujących elementów:
Spis treści
Wróćmy do naszego przykładu "HI UNIVERSE". Omówimy na jego przykładzie podstawowe koncepcje składni języka Revomer.
Przykład 2.1. Program "HI UNIVERSE"
almukantarat~ nope~ null% almukantarat~ come here $1, $1, $3 gifs 3~ hide $3 gifs 29~ hide $2 gifs 29~ hide $1 pos $0~ gifs 69~ pos $0~ gifs 83~ pos $0~ gifs 82~ pos $0~ gifs 69~ pos $0~ gifs 86~ pos $0~ gifs 73~ pos $0~ gifs 78~ pos $0~ gifs 85~ pos $0~ gifs 32~ pos $0~ gifs 73~ pos $0~ gifs 72~ hide $0 %
Pierwszą i najważniejszą zasadą, której trzeba się nauczyć, jest kierunek czytania listingów. W Revomerze każda linijka może zawierać tylko jeden rozkaz. Linijki numerowane są od początku pliku, ale cały kod wykonywany jest w tył, tj. z dołu do góry. Przy omawianiu poszczególnych komend dostępnych dla programisty będziemy używać pojęć "następna instrukcja" oraz "poprzednia instrukcja" zgodnie z kierunkiem wykonywania programu. Zatem zwrot "skasować następą instrukcję" oznacza, że interpreter skasuje następną instrukcję, jaka się wykona, czyli tę leżącą linijkę wyżej.
Cały kod podzielony jest na funkcje. Deklaracja funkcji rozpoczyna się znakiem %, przed którym
podana jest jej nazwa. Funkcja bez nazwy zwana jest funkcją zerową i od niej rozpoczyna się wykonywanie programu. Dopuszcza
się tworzenie wielu funkcji o identycznej nazwie - podczas ich wywoływania ta "właściwa" wybierana jest w sposób losowy. Funkcja
kończy pracę, gdy po napotkaniu deklaracji następnej funkcji lub komendy almukantarat stwierdzi, że nie zawiera
już żadnych rozkazów. W przeciwnym wypadku zaczyna wykonywać się od początku. Program kończy pracę w momencie skasowania z użytej
funkcji zerowej ostatniego rozkazu.
Jak wspomnieliśmy, formalnie funkcja kończy się w momencie deklaracji następnej funkcji lub końca listy rozkazów. Jednak
interpreter bardzo nie lubi, gdy programista każe mu tam dotrzeć i dlatego jej wykonywanie powinno się "przerywać" wcześniej
komendą almukantarat - uwaga, nie wlicza się ona do ostatecznej liczby rozkazów w danej funkcji. Oznacza
to, że jeśli w treści funkcji znajduje się np. operacja nope oraz almukantarat, to
dla interpretera tylko pierwsza z nich jest licząca się - zatem w funkcji mamy tylko jeden rozkaz i jego skasowanie wystarczy,
aby przerwać działanie.
Dalsze reguły dotyczące składni:
rope, która dopuszcza oba warianty.Rozdział ten opisuje komendy związane z tworzeniem, wywoływaniem i zarządzaniem funkcjami.
nazwa%
Rozpoczyna nową funkcję o podanej nazwie. Jeśli nazwa nie jest podana, tworzona jest funkcja zerowa. Jeżeli w trakcie wykonywania programu interpreter dotrze do takiej komendy, wykonuje identyczą czynność, jak almukantarat, jednak przedtem wykonuje także za karę operację rope.
Komenda nie jest zakończona tyldą.
almukantarat~
Jeżeli aktualnie wykonywana funkcja nie zawiera już żadnych innych instrukcji, przerywa jej wykonywanie i pozwala powrócić do miejsca wywołania. W przeciwnym wypadku rozpoczyna wykonywanie funkcji od początku. Nazwa tej komendy pochodzi z astronomii, gdzie oznacza koło na sferze niebieskiej, którego punkty leżą na tej samej wysokości nad horyzontem.
conffunkcja1,funkcja2~
Zamienia dwie podane funkcje nazwami. Operacja dotyczy także funkcji aktualnie wykonywanych i znajdujących się na stosie. Komenda musi być zakończona tyldą.
rf funkcja~
Usuwa z kodu wszystkie funkcje o podanej nazwie. Uwaga: jeżeli usuniemy w ten sposób funkcję zerową, nie spowodujemy przerwania wykonywania programu. Jeśli program nie zawiera funkcji zerowej, interpreter zaczyna w kółko wykonywać komendę rope w nadziei, że kiedyś uda mu się ją odtworzyć. Komenda musi być zakończona tyldą.
charm $1
Wywołuje funkcję. Nazwę funkcji do wywołania należy wprowadzić do kolejnych komórek pamięci (malejąco), a następnie podać tutaj jako argument adres komórki zawierającej pierwszą literę. Algorytm pobierania nazwy jest następujący:
Jeżeli osiągnięty zostanie w ten sposób koniec pamięci, interpreter wykonuje operację rope.
Przykład 2.3. Wywołanie funkcji "foo"
almukantarat~ nope~ foo% almukantarat~ charm $2 gifs 111~ hide $0 gifs 111~ hide $1 gifs 102~ hide $2 %
Rozdział ten opisuje operatory dostępne w języku Revomer.
????&$1,$2
Operator logiczny Logiki Revomerowej wykonuje operacje na bitach komórek $1 oraz $2,
a wynik zapisuje do pierwszej z nich. Tabelka logiczna:
Wartości inne niż Prawda i Fałsz Revomerowy są redukowane do takowych za pomocą Reduktora Standardowego.
in $1
Reduktor IN - jeżeli w podanej komórce pamięci znajduje się liczba ujemna, zapisuje tam Prawdę Revomerową (-1). Jeżeli nieujemna - Fałsz Revomerowy (0).
@&%^"$1,$2
Od pierwszego argumentu odejmuje drugi i wynik zapisuje w komórce pamięci podanej w drugim argumencie.
*?!$1,$2
Dzieli pierwszy argument przez drugi i wynik zapisuje w komórce pamięci podanej w pierwszym argumencie. W przypadku dzielenia przez zero wykonywana jest operacja rope.
~].?&*$1,$2~
Kopiuje zawartość pierwszej komórki do drugiej. W przykładzie poniżej wprowadzamy liczbę 52 do komórki $8, a następnie kopiujemy ją do komórki $9 i wyświetlamy.
Komenda musi być zakończona tyldą.
Rozdział ten opisuje komendy do zarządzania kodem źródłowym.
come here$1[,$2[,$3]]
Komenda pozwala przesuwać grupy komend w inne miejsce programu. Jej działanie różni się nieco w zależności od liczby argumentów:
$1 niżej i przenosi ją przed siebie.$1 nakazuje
się cofnąć X linijek w dół (początek zaznaczanego obszaru), a następnie od tego miejsca $1 linijek
do góry (koniec zaznaczanego obszaru). Obszar zostaje przeniesiony bezpośrednio przed komendę come here.come here
(ilość linijek liczona do góry).Uwaga: jeśli nowa lokalizacja bloku komend znajduje się wewnątrz tego bloku, kod źródłowy programu ulega defragmentacji
z powodu działania algorytmu przesuwania. Zachowanie wskaźnika programu jest następujące: docelowo jako następna ma się zawsze
wykonać instrukcja po come here. Jeżeli jednak come here zawarte jest wewnątrz przenoszonego
przez siebie bloku (czyt: instrukcja przenosi samą siebie), jako następna musi być wykonana instrukcja leżąca po przenoszonym bloku
(bierzemy pod uwagę sytuację SPRZED przeniesienia!).
unless}$1#
Instrukcja warunkowego usuwania kodu. Jeżeli w podanej komórce znajduje się wartość fałszywa, następna linijka kodu źródłowego jest z niego usuwana. Linijka ta wykona się tylko wtedy, gdy w komórce znajduje się Revomerowska Prawda Logiczna (-1).Adres komórki podawany jest w nawiasach.
if$1,$2~
Dołącza plik, którego nazwa zawarta jest między komórkami pamięci $1 oraz $2, a
znajdujące się w nim komendy wstawia w miejsce samego siebie. Wykonywanie dołączonego pliku rozpoczyna się od przedostatniej instrukcji.
Jeżeli podany plik nie istnieje, wykonywana jest operacja rope.
shuffle$1,$2
W losowy sposób miesza kod źródłowy pomiędzy linijkami leżącymi $1 oraz
$2 dalej. Przykład: losowanie liczby w zakresie od 1 do 10.
Przykład 2.5. Losowanie liczby
almukantarat~ nope~ null% almukantarat~ come here $2, $2, $4 gifs 3~ hide $4 gifs 21~ hide $2 pos $0~ gifs 74~ gifs 73~ gifs 72~ gifs 71~ gifs 70~ gifs 69~ gifs 68~ gifs 67~ gifs 66~ gifs 65~ shuffle $1, $2 hide $0 gifs 1~ hide $1 gifs 11~ hide $2 %
W przykładzie wskazaliśmy, że wymieszane mają być komendy leżące między 1, a 11 linią wyżej.
Rozdział ten opisuje komendy zarządzania pamięcią operacyjną.
hide $1
Przesuwa wskaźnik interpretera na podaną w argumencie komórkę pamięci. Po tej komendzie nie podajemy tyldy.
gifs wartosc~
Wstawia podaną wartość liczbową do komórki pamięci, na której znajduje się aktualnie wskaźnik interpretera.
Podany poniżej fragment programu wstawia liczbę "20" do komórki $0:
sars 1|2|4
Zmienia długość argumentów przekazywanych do komend. Dozwolone długości do 1, 2 lub 4 bajty. Ponadto
wraz z wywołaniem sars zmienia się także starszeństwo bajtów. Adresy pamięci zawsze wskazują
najstarszy bajt. Jeżeli starszeństwo jest ustawione na big endian, a kolejne bajty odczytywane
są z komórek pamięci o rosnących numerach. Dla little endian - adresy komórek z kolejnymi bajtami
maleją.
Komendy wejścia/wyjścia.
gifts$1[,$2]
Komenda wejścia, wczytuje dane do podanej komórki pamięci. W zależności od wartości w komórce pamięci w argumencie drugim:
Dodatkowe komendy specjalnej troski i/lub uwagi.
rope~
Wykonuje losową komendę z losowymi argumentami. rope jest niezwykle ważna dla języka REVOMER,
ponieważ służy też do domyślania się, co programista miał na myśli, odwołując się np. do nieistniejącego zasobu lub robiąc
błąd składni w danej linijce. Komenda jest zatem wykonywana przy każdej nieprzewidzianej przez interpreter i specyfikację
okazji. Jako jedyna także może, ale nie musi posiadać tyldy na końcu.
Dodatkowe informacje o pamięci oraz o przechowywaniu danych w języku Revomer.
Rozdział ten zawiera podstawowe informacje o systemie logicznym używanym w Revomerze. Jest on ogólnie zbliżony do modelu klasycznego, lecz różni się wieloma istotnymi szczegółami.
Revomerowa Logika operuje na dwóch stanach revomerowych. Fałsz Revomerowy jest równoważny zwykłemu fałszowi i oznaczany jest jako 0. Prawda Revomerowa natomiast, w przeciwieństwie do logiki klasycznej, posiada wartość ujemną: -1.
Logika Revomerowa posiada jeden operator logiczny ????& oraz dwa reduktory pozwalające zredukować każdą inną wartość do Prawdy lub Fałszu Revomerowego. Operator ????& jest dwuargumentowy i daje następujący wynik:
Odpowiada on mniej więcej operatorowi NAND w logice klasycznej.
Reduktor Standardowy jest domyślnie używany do redukcji każdej wartości innej niż -1 i 0 do Prawdy lub Fałszu Revomerowego. Redukcji dokonuje następujący algorytm:
Drugi z reduktorów nazywa się IN (Is Negative). Sprawia on, że każda ujemna wartość zostaje zredukowana do Prawdy Revomerowej (-1), a każda nieujemna do fałszu.
Wskazówki dla interpreterów języka Revomer.
To nie wszystko! W przyszłych wydaniach język Revomer zostanie wzbogacony o wiele nowych możliwości: