Krótka odpowiedź brzmi: masz rację, zawsze potrzebujesz innego tłumacza napisanego w X lub kompilatora z Y na inny język, dla którego już masz tłumacza. Tłumacze wykonują, kompilatory tłumaczą tylko z jednego języka na inny, w pewnym momencie w twoim systemie musi być tłumacz… nawet to jest tylko procesor.
Bez względu na to, ilu nowych tłumaczy piszesz w języku Y , zawsze będziesz musiał użyć pierwszego tłumacza napisanego w X do tłumaczenia kolejnych tłumaczy. Wydaje się, że jest to problem tylko ze względu na naturę tłumaczy.
Poprawny. Co można zrobić, to napisać kompilator od Y do X (lub inny język, dla którego trzeba tłumacza), a można nawet zrobić w Y . Następnie możesz uruchomić kompilator Y napisany w Y na interprecie Y napisanym w X (lub na Y interpreter napisany w Y, uruchomiony na interpreter Y napisany w X lub na interpreter Y napisany w Y, uruchomiony na interpreter Y napisany w Y działa na Yinterpreter napisany w X lub… ad infinitum) w celu skompilowania interpretera Y napisanego w Y do X , abyś mógł go następnie wykonać na interpreterze X. W ten sposób pozbyłeś się swojego interpretera Y napisanego w X , ale teraz potrzebujesz interpretera X (wiemy, że już go mamy, ponieważ inaczej nie moglibyśmy uruchomić interpretera X napisanego w Y ), a ty najpierw musiał napisać kompilator Y - to - X .
Jednak z drugiej strony, artykuł Wikipedii na temat tłumaczy faktycznie mówi o tłumaczach z własnym hostingiem. Oto mały fragment, który jest istotny:
Tłumacz ustny to tłumacz języka programowania napisany w języku programowania, który może się interpretować; przykładem jest interpreter języka BASIC napisany w języku BASIC. Interpretatory są powiązane z kompilatorami hostującymi.
Jeśli nie ma kompilatora dla języka, który ma być interpretowany, utworzenie własnego interpretera wymaga implementacji języka w języku hosta (który może być innym językiem programowania lub asemblerem). Dzięki posiadaniu pierwszego takiego tłumacza system jest ładowany i nowe wersje interpretera mogą być opracowywane w samym języku
Jednak nadal nie jest dla mnie jasne, jak dokładnie to zostanie zrobione. Wydaje się, że bez względu na wszystko, zawsze będziesz zmuszony użyć pierwszej wersji tłumacza napisanej w języku hosta.
Poprawny. Pamiętaj, że artykuł w Wikipedii wyraźnie mówi, że potrzebujesz drugiej implementacji swojego języka i nie mówi, że możesz się go pozbyć.
Teraz wspomniany wyżej artykuł prowadzi do innego artykułu, w którym Wikipedia podaje przykłady domniemanych tłumaczy hostingowych. Po bliższym przyjrzeniu się wydaje się, że główna część „tłumaczeń ustnych” wielu tłumaczy z własnego hostingu (zwłaszcza niektórych z bardziej powszechnych, takich jak PyPy lub Rubinius), są w rzeczywistości napisane w innych językach, takich jak C ++ lub C.
Znowu poprawne. To są naprawdę złe przykłady. Weźmy na przykład Rubiniusa. Tak, to prawda, że rubinowa część Rubiniusa jest hostowana przez siebie, ale jest to kompilator, a nie interpreter: kompiluje się do kodu źródłowego Ruby do kodu bajtowego Rubiniusa. Część OTOH tłumacza nie jest hostowana: interpretuje kod bajtowy Rubiniusa, ale jest napisany w C ++. Tak więc nazywanie Rubiniusa „tłumaczem na własnym serwerze” jest błędne: część hostowana nie jest tłumaczem , a część tłumacza nie jest hostowana na własną rękę .
PyPy jest podobny, ale jeszcze bardziej niepoprawny: nie jest nawet napisany w Pythonie, jest napisany w RPython, który jest innym językiem. Jest składniowo podobny do Pythona, semantycznie „rozszerzonym podzbiorem”, ale w rzeczywistości jest to język o typie statycznym z grubsza na tym samym poziomie abstrakcji co Java, a jego implementacją jest kompilator z wieloma zapleczami, który kompiluje kod źródłowy RPython do C, ECMAScript kod źródłowy, kod bajtu CIL, kod bajtowy JVM lub kod źródłowy Pythona.
Czy to, co opisałem powyżej, jest możliwe? Czy tłumacz-tłumacz może być niezależny od swojego oryginalnego hosta? Jeśli tak, to jak dokładnie to zrobić?
Nie, nie na własną rękę. Musisz zachować oryginalnego tłumacza lub napisać kompilator i skompilować własnego interpretera.
Tam są niektóre meta-okrągły maszyn wirtualnych, takich jak Klein (napisany w Jaźni ) i Maxine (napisany w Javie). Zauważ jednak, że tutaj definicja „meta-okólnika” jest jeszcze inna: te maszyny wirtualne nie są napisane w języku, który wykonują: Klein wykonuje własny kod bajtowy, ale jest napisany w Self, Maxine wykonuje kod bajtowy JVM, ale jest napisany w Javie. Jednak kod źródłowy Własna / Java VM faktycznie pobiera skompilowany do self / JVM kodu bajtowego, a następnie wykonywany przez maszynę wirtualną, więc do czasu VM zostanie wykonany, to jest w języku to wykonuje. Uff
Zauważ też, że różni się to od maszyn wirtualnych, takich jak SqueakVM i Jikes RVM . Jikes jest napisany w Javie, a SqueakVM jest napisany w Slangu (statycznie typowany składniowy i semantyczny podzbiór Smalltalk z grubsza na tym samym poziomie abstrakcji, co asembler wysokiego poziomu), i oba są statycznie kompilowane do kodu natywnego przed ich uruchomieniem. Nie biegają w sobie. Państwo może jednak uruchomić je na górze siebie (lub na górze innego Smalltalk VM / JVM). W tym sensie nie jest to jednak „meta-okrągły”.
Maxine i Klein, OTOH zróbwbiegać w siebie; wykonują swój własny kod bajtowy przy użyciu własnej implementacji. To naprawdę zaskakujące! Daje to kilka fajnych możliwości optymalizacji, na przykład ponieważ maszyna wirtualna wykonuje się sama z programem użytkownika, może wstawiać połączenia z programu użytkownika do maszyny wirtualnej i odwrotnie, np. Wywoływanie śmietnika lub alokatora pamięci można wprowadzić w użytkownika kod i odblaskowe wywołania zwrotne w kodzie użytkownika można wstawić do maszyny wirtualnej. Ponadto, wszystkie sprytne sztuczki optymalizacyjne, jakie wykonują współczesne maszyny wirtualne, polegające na obserwowaniu wykonującego programu i optymalizowaniu go w zależności od rzeczywistego obciążenia i danych, maszyna wirtualna może zastosować te same sztuczki do siebie podczas wykonywania programu użytkownika podczas działania programu użytkownika wykonuje określone obciążenie. Innymi słowy, VM bardzo się w tym specjalizujeokreślony program uruchamiający to obciążenie.
Zauważ jednak, że omijałem użycie słowa „tłumacz” powyżej i zawsze używałem słowa „wykonać”? Cóż, te maszyny wirtualne nie są zbudowane wokół interpreterów, są oparte na kompilatorach (JIT). Do Maxine został dodany interpreter później, ale zawsze potrzebujesz kompilatora: musisz uruchomić maszynę wirtualną raz na innej maszynie wirtualnej (np. Oracle HotSpot w przypadku Maxine), aby maszyna wirtualna mogła (JIT) się skompilować. W przypadku Maxine JIT skompiluje własną fazę rozruchu, a następnie serializuje ten skompilowany kod natywny do obrazu VM bootstrap i przyklei bardzo prosty bootloader z przodu (jedyny składnik VM napisany w C, chociaż to tylko dla wygody , może być również w Javie). Teraz możesz użyć Maxine do samodzielnego wykonania.