Implementacja Języków Programowania

Prowadzący: Tomek Mańko


Kategorie: informatyka

Jak Wytresować Smoka, czyli Warsztat z Podstaw Implementacji Języków Programowania

Rys. 1 Programista obłaskawiający kompilator.

Jako rzecze wielki mędrzec Piotr Fronczewski, aby wyruszyć w drużynę, należy zebrać drogę… czy jakoś tak.  
Nie inaczej jest z programowaniem — każdy aspirujący adept technik komputerowych wie, że aby stworzyć program komputerowy należy pierwej poznać jakiś język programowania. Nie każdy jednak wie, skąd te „magiczne” programistyczne narzędzia się biorą.

W zamierzchłej przeszłości, przez współczesnych zwanych Latami Pięćdziesiątymi, czarodziej McCarthy wykradł z Macierzy Zero — siedziby Cyfrowych Bogów — pierwszy język programowania, który nazwał LISP…

Oczywiście, jak można się domyślić, prowadzący niniejszy warsztat się zgrywa i kompilatory, maszyny wirtualne czy inne interpretery wcale nie są mistycznymi artefaktami bogów programowania ani nie ciągną się one — niczym żółwie ze znanej anegdotki — do samego spodu, a warsztat ten ma na celu przybliżyć ich historię oraz pozwolić zrozumieć przynajmniej podstawowe techniki ich implementacji.

Warsztaty będą prowadzone w formie wykładu mającego za zadanie przekazać słuchaczowi podstawową wiedzę z zakresu implementacji języków programowania, połączonego z segmentami praktycznymi pozwalającymi uczestnikom spróbować własnych sił w pisaniu prostego języka wykorzystując zdobytą właśnie wiedzę.

Zagadnienia

W części wykładowej prowadzący chciałby poruszyć przynajmniej następujące tematy:

  • przedstawienie historii języków programowania od rachunku lambda, maszyny Turinga i kart drukowanych, poprzez Fortrana, LISPa, Cobola oraz Smalltalka aż po SMLa, Haskella i Idris, ze szczególnym uwzględnieniem technik implementacyjnych i nowatorskich rozwiązań które wpłynęły na powstające później języki,
  • jak komputery „rozumieją” kod — gramatyki formalne, podział tekstu na leksemy (lekser), analiza składniowa (parsery), kombinatory parserów, maszyny stanów, drzewa składniowe (AST, Abstract Syntax Trees), składnie prefiksowe, infiksowe i postfiksowe, rozszerzalność składni za pomocą przekształceń AST (makra),
  • interpretowanie (bądź redukcja) AST jako najprostszy sposób implementacji języka programowania, podstawowe zagadnienia semantyki języków, zakres leksykalny vs. zakres dynamiczny, tablica symboli.

W zależności od pozostałego czasu, chęci słuchaczy oraz wiedzy prowadzącego, będzie można pobieżnie omówić któreś z bardziej zaawansowanych technik implementacyjnych, takie jak — statyczna kompilacja, linkowanie i kompatybilność binarna, alokacja rejestrów i optymalizacje, maszyny wirtualne oparte o bajtkod i kompilatory JIT, automatyczne zarządzanie pamięcią (garbage collection), stos zwykły a stos spaghetti, domknięcia oraz kontynuacje, wykorzystanie typów do zapewnienia poprawności programu i emisji lepszego kodu wynikowego, cukier składniowy, desugaring i reprezentacje pośrednie.

W części praktycznej słuchacze będą mogli wykorzystać poznaną wiedzę aby zaimplementować język programowania będący uproszczoną wersją Scheme/LISPa, co — przy dobrych wiatrach — sprawi że każdy słuchacz będzie mógł pochwalić się własnym, działającym interpreterem i obejmie następujące zagadnienia:

  • stworzenie parsera wczytującego formy w notacji prefiksowej i tworzącego drzewo składniowe programu,
  • stworzenie interpretera AST pozwalającego na wykonywanie prostych programów,
  • rozbudowane interpretera — definiowanie funkcji, instrukcje warunkowe, funkcje anonimowe, funkcje wyższego rzędu, domknięcia z wykorzystaniem stosu spaghetti.

Dodatkowo o ile starczy czasu prowadzący postara się zaprezentować przykłady wykorzystania niektórych z bardziej rozbudowanych technik, takich jak statyczna kompilacja za pomocą LLVM, prosty garbage collector czy prosta maszyna wirtualna, oczywiście zgodnie z tym, co słuchacze uznają za interesujące.

Wymagania

  • umiejętność logicznego i algorytmicznego rozumowania (konieczne ze względu na ograniczenia czasowe warsztatu),
  • znajomość jakiegoś języka programowania (mniej koniecznie, gdyż język wykładowy i tak pewnie będzie obcy dla większości słuchaczy),
  • znajomość języka angielskiego (bo kto chce mówić „analizator składniowy” jak można powiedzieć „parser”),
  • laptop lub chęć interakcji z innym uczestnikiem warsztatów, który takowy posiada (Linuks niewymagany, acz mile widziany, bo w razie problemów technicznych typu instalacja bibliotek prowadzący będzie w stanie z tym systemem pomóc).

Są to w zasadzie podstawowe wymagania tych warsztatów, ale są rzeczy które na pewno Ci pomogą wynieść z niego jak najwięcej, drogi uczestniku:

  • jeżeli kiedykolwiek próbowałeś napisać program wczytujący jakiś plik i zamieniający go na struktury danych w pamięci albo — jeszcze lepiej — wiesz z czym się je parsery, to punkt dla Ciebie,
  • podobnie jeżeli wiesz coś o automatach skończonych, drzewach i grafach, gdyż są to struktury danych bardzo często występujące w implementacji języków programowania,
  • znajomość C, działania pamięci w architekturze von Neumanna oraz wskaźników może pomóc zrozumieć pewne bardziej niskopoziomowe koncepcje (na przykład jeżeli zdecydujemy się powiedzieć więcej o automatycznym zarządzaniu pamięcią),
  • styczność z którymś z następujących języków — Haskell, F#, Scheme/Clojure/Racket — to masz szansę być jedną z osób dla których język wykładowy nie będzie obcy.

Materiały

Jeżeli wiesz, dlaczego wybrałem taką, a nie inną nazwę warsztatów, to jesteś już o krok do przodu jeżeli chodzi o materiały. Oprócz tej tajemniczej pozycji, prowadzący warsztaty do ich przygotowania będzie korzystał także z (in no particular order):

  • „Haskell Programming from First Principles” Christopher Allen, Julie Moronuki,
  • „Modern Compiler Implementation” Andrew W. Appel,
  • „Types and Programming Languages” Benjamin C. Pierce,
  • „Advanced Topics in Types and Programming Languages ” Benjamin C. Pierce,
  • „Practical Foundations for Programming Languages” Robert Harper,
  • „Programming Language Pragmatics” Michael L. Scott,
  • „Essentials of Programming Languages” Daniel P. Friedman, Mitchell Wand,
  • „The Implementation of Functional Programming Languages” Simon Peyton Jones,
  • „Lisp in Small Pieces” Christian Queinnec,
  • materiały do wykładu o rachunku lambda z MIM Uniwersytetu Warszawskiego,
  • „Write Yourself a Scheme in 48 Hours”,
  • „Write You a Haskell”,
  • „Baby's First Garbage Collector” (polecam w ogóle całego bloga, koleś ze swadą pisze o ciekawych rzeczach, w tym np. o parserach Pratta),

choć tak naprawdę jeżeli przeczytasz powyższe materiały od deski do deski, to równie dobrze to Ty mógłbyś poprowadzić te warsztaty, więc podrzucam je raczej w charakterze informacyjnym — tak, abyście wiedzieli gdzie szukać informacji do dalszego pogłębiania wiedzy w tym kierunku, gdyby temat okazał się dla Ciebie interesujący.

Ponieważ materiały są równe i równiejsze i w związku z tym, że nie będę z nich korzystał w jednakowym stopniu — z książki o Haskellu interesuje nas głównie pierwszy rozdział, jako przystępne wyjaśnienie rachunku lambda, TAPL posłuży głównie do zarysowania korzyści płynących z typów, a natomiast materiały o implementacji Scheme zostaną dość wyczerpująco wykorzystane — więc mam cichą nadzieję, że okażecie wyrozumiałość jak nie będę w stanie odpowiedzieć na pytania co na stronie 354, w wierszu 23 powiedział SPJ o Maszynie G :V

Zadania Kwalifikacyjne

Będą.

Pierwsze mogę nawet zdradzić już teraz — jak wspomniałem wyżej nazwa warsztatów jest nieprzypadkowa — jeżeli wiesz i/lub umiesz znaleźć jaka jest proweniencja tej nazwy, to zaliczenie pierwszego pytania masz jak w banku.

EDIT: Nadal będą, ale z lekkim poślizgiem. Jak się — wybaczcie moją korpomowę — czelendżuje fakap na asapie w pracy (która na szczęście korpo nie jest) to się obsuwy mogą zdarzyć. Postaram się jak najszybciej to ogarnąć. Mam nadzieję, że wszyscy potencjalnie zainteresowani mi wybaczą ~~'

EDIT2: To straszne, ile mi to zajęło, ale już są!