Revomer to ezoteryczny język programowania, który opracowałem wspólnie z kumplem z Katowic, Krzyśkiem Piecuchem. Interpreter powstał w spartańskich warunkach pod koniec wakacji 2006 (sala gimnastyczna lubelskiego Staszica). Słowo "ezoteryczny" oznacza, że jest nastawiony na maksymalne utrudnienie lub udziwnienie programowania w nim. Inne przykłady tego typu języków to INTERCAL, Brainfuck, Whitespace czy Malbolge. Można się z nim zapoznać, wybierając odpowiednią zakładkę w pasku nawigacyjnym u góry tej strony.
Podstawowe założenia Revomera nie ulegają zmianie. Nadal jest on nastawiony na destrukcję, negację i usuwanie wszystkiego, co się da. Nadal jedynymi dostępnymi działaniami matematycznymi jest odejmowanie i dzielenie. Nadal jedynym sposobem zakończenia funkcji jest skasowanie jej kodu (lub sprawienie, by interpreter myślał, że tego kodu już nie ma :)). Nadal kod wykonywany jest od dołu do góry, a całość wygląda, jak wymyślony po trzeciej pochodnej z taniego wina assembler. Zmienia się kilka szczegółów oraz dochodzi sporo nowości.
Zmiany
Zmieniłem nieco organizację funkcji. Teraz stanowią one zamkniętą całość, co oznacza, że każda funkcja ma własną tablicę poleceń niezależną od pozostałych i nie można sobie bezkarnie przenieść kluczowego fragmentu poza funkcję - zostanie on wprawdzie przemieszczony, ale tylko w obrębie tej funkcji. Pozbawia to wprawdzie jednego ze sposobów na jej zakończenie, ale za to stwarza inne możliwości i ułatwia interpretowi kontrolowanie ilości komend, co nabierze teraz zresztą trochę większego znaczenia. Na pocieszenie pojawiły się dwie nowe komendy: steal oraz gift, których zadaniem jest: kradzież instrukcji z innej funkcji lub wysłanie własnej instrukcji w prezencie gdzie indziej (a żeby było ciekawiej, przy tej okazji "przypadkowo" przesyła się też wskaźnik programu, oczywiście bez odnotowania tego faktu na stosie). Lekko zmieniłem zestaw instrukcji sterujących. Nie ma już come here, na jego miejsce pojawiły się:
- tmfher - (TAKE ME FROM HERE) - odmiana goto. Różnica polega na tym, że zabiera ze sobą także samą instrukcję.
- gefrm - (GET FROM) - działa bardzo podobnie do come here, lecz uniemożliwia przenoszenie wraz z kodem wskaźnika programu.
Wielowyjątkowość i zarządzanie pamięcią
Zupełną nowością jest mechanizm wielowyjątkowości, czyli połączenia mechanizmu wątków z wyjątkami. Dotychczas Revomer w przypadku każdego błędu wykonywał komendę ROPE (Random Operation). Zmodyfikowałem nieco jej znaczenie - teraz powoduje ona wygenerowanie wyjątku. Jeżeli nie jest on obsłużony, wykonuje się natychmiast losowa operacja. Gdy jednak zajdzie on w obrębie bloku hope... fuck, uruchomiony zostaje nowy wątek, którego zadaniem jest właśnie obsługa napotkanego wyjątku. Jedynym sposobem zakończenia wątku jest wykonanie przechwyconej losowej operacji komendą dude.
Znacznej rozbudowie uległ też system pamięci. Dotąd program w Revomerze miał do dyspozycji 65 tysięcy jednobajtowych komórek, do których mógł odwoływać się za pośrednictwem ich numeru. Istniały także wskaźniki. Oczywiście do wielu zadań 65 KB to trochę za mało, dlatego wzorem wielu innych języków pojawiła się dynamiczna alokacja. Pamięć teraz podzielona jest na taśmy pełniące funkcję stron pamięci. Wbrew nazwie, w obrębie jednej taśmy dostęp do komórek jest swobodny - wzięła się ona z trochę innej przyczyny. Oto pełen zestaw operacji na pamięci (pierwsze trzy istnieją także w Revomerze 0.9):
- hide - ustawia kursor na podanej komórce pamięci.
- gifs - zapisuje podaną wartość do aktualnej komórki pamięci.
- sars - zmienia długość argumentów, przy okazji odwracając starszeństwo bajtów.
- <<<< - przewija pamięć do przodu. Przewinięcie np. o 5 komórek oznacza, że jeśli mieliśmy wskaźnik $5 wskazujący na 14 komórkę, to teraz będzie on reprezentować komórkę 19.
- >>>> - przewija pamięć do tyłu.
- !!tape - tworzy nową taśmę o podanym rozmiarze i zwraca jej numeryczny identyfikator (wzięty z kosmosu :)).
- @tape@ - usuwa podaną taśmę pamięci. Jeśli taśma ta była użyta, powoduje stworzenie jednej pustej instrukcji NOPE :).
- ^tape> - zmienia aktualnemu wątkowi taśmę. Należy z tym uważać, gdyż nie zapisuje ona nigdzie adresu starej taśmy, tak więc jeżeli zamierzamy do niej wrócić, musimy wymyślić sposób przekazania go bez użycia pamięci :)
Programowanie obiektowe
Tak, to prawda. W projekcie znalazł się wyraźny zapis, że Revomer jest językiem prawdziwie obiektowym. Z klasami, metodami, polami, dziedziczeniem i przeciążaniem operatorów. Przyjąłem założenia:
- Każda instrukcja jest klasą, a komendy w kodzie są jej obiektami. Posiada pole "ziz" z numerem tokenu, który je obsługuje oraz dwie metody: "upset" i "downset" wykonywane bezpośrednio przed i po komendzie.
- Każda funkcja jest klasą, a zarazem swoim własnym obiektem. Jej pola to odwołania do poszczególnych komend zawartych w funkcji.
- Każda komórka pamięci jest obiektem klasy CELL.
- W przypadku klas użytkownika metody są jednocześnie polami, których wartością jest ilość posiadanych komend.
Przeciążenie operatora powoduje, że we wszystkich metodach danej klasy zacznie on pełnić zaprogramowaną przez nas funkcję. Tworzenie obiektu danej klasy powoduje utworzenie dla jego metod własnych buforów kodu, tak więc jeżeli mamy obiekty A i B od tej samej klasy i obiektowi A w jego metodzie x skasujemy 5 linijek, to w B te 5 linijek dalej będzie istnieć. Niestety, zgodnie z polityką Revomera, jest coś za coś. Obiekt tak sam z siebie się nie utworzy - musimy złożyć mu ofiarę z innej funkcji, z której nowy obiekt zabierze dokładnie tyle instrukcji, ile liczą sobie sumarycznie jego wszystkie metody.
Warto też wspomnieć, że podobnie, jak w przypadku funkcji, także i tutaj można dokonywać operacji zamiany klas nazwami, a zmiana ta jest uwzględniana w już istniejących obiektach. Można więc sobie podmienić klasę instrukcji np. gefrm na własną.
Biblioteka Funkcji Nieużytecznych
Jedną ze specyficznych cech Revomera będzie biblioteka funkcji nieużytecznych, czyli takich, których raczej sam z siebie programista nie będzie wywoływać. Ich aktualny zestaw to:
- dts - (DELETE THIS SHIT) kasuje plik z kodem źródłowym programu. Jeśli jest zabezpieczony przed zapisem, kasuje interpreter. Jak i to się nie uda, wykonuje ROPE.
- mine - wysadza fragment kodu źródłowego wokół siebie w przypadku wykonania.
- catbat - taśma zmienia się na losową i zostaje przewinięta w nieznane miejsce.
- forsh - zawiesza interpreter.
- wft - instrukcja ta służy do komunikacji programu z urządzeniem wyroczni w komputerach wyposażonych w obsługę wyroczni. W tym celu interpreter musi mieć dostęp do urządzenia /dev/oracle w systemach uniksowych. Jeżeli komputer nie obsługuje wyroczni, uruchamiany jest tryb emulacji.
Zakończenie
Nowości jest jeszcze kilka. Rozszerzyłem system wejścia/wyjścia o obsługę plików oraz operacje sieciowe (po wydaniu interpretera czekam na pierwszy serwer napisany w Revomerze :)). Jednak wszystko wykrystalizuje się, jak ten interpreter powstanie. Język jest bardziej rozbudowany, ale z drugiej strony mam teraz znacznie większe doświadczenie, no i przede wszystkim nie piszę tego na sali gimnastycznej lubelskiego liceum o 4 rano po 3 dniach niemalże bez snu na laptopie współdzielonym przez ok. 12 osób, posiłkując się specyfikacją napisaną na papierze toaletowym :D.















Napisał Unit03 w niedzielę, 3 lutego 2008 o 00:32
Lubelski Staszic i jego spartańskie warunki pozdrawiają :D