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.
źródło
Odpowiedzi:
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).
źródło
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ę
eval
w 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 :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.
źródło
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:
„HTH,
źródło
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 .
Wtedy częściowa ocena (i prognozy Futamura) i styl kontynuacji mogą być odpowiednie.
źródło