Rozwijanie dynamicznego języka

11

Stworzyłem kilka ręcznie napisanych kompilatorów dla bardzo prostych języków, ale teraz chcę spróbować swoich sił w tworzeniu dynamicznego języka, podobnego do uproszczonego Pythona lub Ruby. Łatwo mi było jednak owinąć głowę wokół działania kompilatorów. Prymitywne kompilatory po prostu tłumaczą. Ale nie mogę tego zrobić, jeśli język jest dynamiczny. Muszę napisać interpretera lub maszynę wirtualną, która śledzi informacje w czasie wykonywania i nakłada na mnie znacznie więcej pracy.

Krótko mówiąc, czy są jakieś zasoby, które powinienem sprawdzić, skoro wiem, jak działają kompilatory, ale chcę przeprowadzić migrację do tworzenia interpretera? Istnieje kilka maszyn wirtualnych dla języków dynamicznych, ale nie mam problemu z uruchomieniem własnych. To wszystko dla mojego osobistego doświadczenia.

Szukam informacji, jak przejść od kompilatora do tłumacza. Jeśli już stworzyłem kompilator dla języka X, ale teraz co napisać tłumacza, co należy zrobić i czy są jakieś zasoby, które przejdą przez ten proces?

Nie chcę szerokich ani abstrakcyjnych zasobów, które omawiają działanie kompilatorów lub maszyn wirtualnych. Mam mnóstwo podręczników na ten temat. Wszystkie zasoby, które znalazłem online, zakładają, że masz 0 doświadczenia, a więc zaczynasz od analizy leksykalnej lub składniowej lub są one wyjątkowo abstrakcyjne. Mam działający kompilator, ale teraz chcę go przekształcić w tłumacza i dodać dynamiczne funkcje do języka.

Nie mogłem znaleźć zasobów na ten proces, jego zakres może być zbyt ograniczony lub zasoby na „zapleczu” tłumacza, nie będąc zbyt teoretycznym, dlatego opublikowałem tutaj.

Austin Henley
źródło
1
Istnieje mnóstwo takich zasobów. Zauważ, że linia między kompilatorem a tłumaczem jest bardziej rozmyta niż myślisz; kompilator C # 4.0 obsługuje programowanie dynamiczne, podobnie jak wiele innych kompilatorów.
Robert Harvey
@RobertHarvey Tak, proszę o zasoby do stworzenia własnego środowiska wykonawczego / interpretera / maszyny wirtualnej. Interpreter .Net jest dla mnie zbyt skomplikowany, żebym mógł go oprzeć!
Austin Henley
1
I sprawdź to SO pytanie , jest kilka komentarzy z odniesieniami do innych pytań, które są dość interesujące ...
yannis

Odpowiedzi:

4

Najpierw dowiedz się o wdrażaniu tłumaczy. Polecam PLAI (języki programowania: aplikacja i interpretacja) . Dochodzi do interpretacji szybko, bez długiego zastanawiania się nad składnią.

W swoim języku będziesz mógł ponownie wykorzystać front-end kompilatora (głównie analizator składni) i bibliotekę wykonawczą (GC, struktury danych, operacje podstawowe itp.).

Oczywiście można również zaimplementować język dynamiczny za pomocą kompilatora, który tworzy kod, który manipuluje (niektórymi) tymi samymi strukturami danych, które byłyby używane w tłumaczu. Na przykład w interpretatorze możesz zaimplementować zmienne globalne jako tablicę skrótów indeksowaną łańcuchem. W kompilatorze kompilowałbyś odwołania do zmiennych globalnych do kodu, który wykonuje wyszukiwanie przy użyciu tej samej tabeli. W przeciwieństwie do tego, można skompilować zmienne leksykalne w bardziej wydajną reprezentację („rodzime” argumenty i odwołania do struktury zamknięcia).

Ryan Culpepper
źródło
5

Jeśli chcesz nauczyć się podstaw implementacji interpretera dla dynamicznego języka, nie wyobrażam sobie lepszego miejsca do rozpoczęcia niż początki pierwszego dynamicznego, interpretowanego języka programowania: Lisp.

W swoim oryginalnym artykule z 1960 r. John McCarthy zdefiniował 5 prymitywnych funkcji niezbędnych dla Lisp. Oczywiście McCarthy zamierzał jedynie, aby jego artykuł o Lisp był ćwiczeniem akademickim; był to doktorant, który włączył się evalw zgromadzenie i stworzył pierwszego tłumacza Lisp. Paul Graham identyfikuje siedem prymitywów : cytat, atom, eq, minusy, samochód, cdr i cond.

Chodzi o to, że naprawdę możesz zaimplementować Lisp w dowolnym języku; po wdrożeniu evalłatwo jest ustawić REPL i masz interaktywnego tłumacza. Ludzie nudzą się lub są wystarczająco ciekawi, aby wdrożyć Lisps w C, Java, Ruby, Python i wielu innych językach. I nie zawsze celowo; ważne jest, aby pamiętać o dziesiątej regule Greenspun :

Każdy wystarczająco skomplikowany program C lub Fortran zawiera ad hoc, nieformalnie określone, wolne od błędów, powolne wdrożenie połowy Common Lisp.

Nie twierdzę, że twoim celem końcowym powinna być implementacja Lisp; ale homoikoniczność ma swoje zalety w nauce wdrażania dynamicznego języka; po co radzić sobie z problemami ze składnią, kiedy można uczyć się języka, w którym składnia idiomatyczna jest identyczna z AST języka używającego leksera / parsera?

W każdym razie ... tylko sugestia. Ale nie bez powodu większość wspaniałych języków programowania od C ma przynajmniej trochę charakteru Lisp.

Jason Lewis
źródło
1
Chciałbym zaakceptować dwie odpowiedzi. Dzięki, myślę, że naprawdę wdrożę tłumacza Lisp. Jest łatwy do parsowania, ma mnóstwo dokumentacji i istniejącego kodu i powinien dać mi podstawy do pracy. Niestety wziąłem udział w zajęciach licencjackich, które korzystały ze Schematu i sprawiły, że wyciągnąłem włosy;)
Austin Henley
1
Kusi mnie teraz, by skompilować mój język we własnym dialekcie Lisp!
Austin Henley,
1
Zobacz także Lisp in Small Pieces
coredump
0

Umieściłem to (~ 600 wierszy C #) w domenie publicznej, która obsługuje quote / list / Apply / eval / test / itp. I pozwala łatwo dostosować składnię podobną do Lisp i / lub wbudowane semantyczne:

https://repl.it/CdjV/3

Na przykład:

        var factorial = (Lambda)language.
            Evaluate
            (@"
                ( => ( n ) (
                        ? ( != n 0 )
                        ( * n ( this ( - n 1 ) ) )
                        1
                    )
                )
            ");

        var sw = new System.Diagnostics.Stopwatch();
        var n = 12;
        var r = 0;
        int k;
        sw.Start();
        for (k = 0; k < 10000; k++)
        {
            r = (int)factorial.Invoke(null, n);
        }
        sw.Stop();
        Console.WriteLine("{0}! = {1}", n, r);
        Console.WriteLine();
        Console.WriteLine("in {0} ms (for {1} times)", sw.ElapsedMilliseconds, k.ToString("0,0"));

„HTH,

YSharp
źródło
0

Zakładając, że znasz trochę Schemat (np. Przeczytałeś SICP ) lub Lisp, polecam książkę Lisp In Small Pieces z Queinnec. Wyjaśnia kilka wariantów interpreterów i kompilatorów podobnych do Lisp (w tym do kodu bajtowego lub do C).

Przeczytaj także Scott's Programming Language Pragmatics , najnowszą książkę Dragon Book , podręcznik GC , typy i języki programowania Pierce'a .

Szukam informacji, jak przejść od kompilatora do tłumacza.

Wtedy częściowa ocena (i prognozy Futamura) i styl kontynuacji mogą być odpowiednie.

Basile Starynkevitch
źródło