Dlaczego nie ma automatycznych tłumaczy z jednego języka programowania na inny? [Zamknięte]


37

Większość języków programowania jest kompletna, co oznacza, że ​​każde zadanie, które można rozwiązać w jednym języku, można rozwiązać w innym, a nawet na maszynie Turinga. Dlaczego więc nie ma automatycznych tłumaczy, którzy mogliby konwertować programy z dowolnego języka na inny? Widziałem kilka prób dla dwóch języków, ale zawsze działają one tylko na ograniczonym podzbiorze języka i z trudem można je wykorzystać do konwersji prawdziwych projektów.

Czy jest możliwe, przynajmniej teoretycznie, napisanie 100% poprawnego tłumacza między wszystkimi językami? Jakie są wyzwania w praktyce? Czy są jacyś tłumacze, którzy działają?


5
Pamiętaj, że „wszystkie języki” obejmują nawet głupie, takie jak Oook! (Kompletowanie Turinga nie jest całą historią; w praktyce potrzebne są również syscalls.)
Donal Fellows

Tam jest trochę. Tłumacze C na Pascala i Pascala na C były dość powszechne w pewnym momencie. Jak sugerują poniższe odpowiedzi, wynik zwykle nie był tak czytelny bez przynajmniej ręcznego uporządkowania. I są to stosunkowo proste języki ze stosunkowo prostymi bibliotekami - wykonanie zadania dobrze np. Dla C ++ na Haskell lub odwrotnie byłoby prawdopodobnie niemożliwe.
Steve314,

Sprawdź kompilator .net Roslyn jako usługę, która ma możliwość tłumaczenia C # na VB i odwrotnie.
Daniel Little,

2
Wszystkie kompilatory tłumaczą jeden PL na inny, nie gwarantują jednak, że kod w docelowej PL jest łatwy do odczytania
jk.

Po sprawdzeniu dokładności tłumaczenia Google jestem przekonany, że w moim życiu zobaczę uniwersalnego tłumacza. Tak, będzie to trudny wysiłek i może wymagać ogromnego wysiłku, jak w przypadku analizy dużej bazy kodu, takiej jak github lub stackoverflow, ale tak się stanie i popyt na takie narzędzie również wzrośnie w nadchodzących wiekach, zwłaszcza teraz że istnieje duża liczba programistów do nauki AI i ML. Może nie istnieć jedna osoba, która opracuje takie narzędzie samodzielnie. Jednak można opracować bota do tworzenia botów, aby rozwiązać ten problem.
Ganesh Kamath - „Code Frenzy”

Odpowiedzi:


32

Największym problemem nie jest faktyczne tłumaczenie kodu programu, ale przeniesienie interfejsu API platformy.

Rozważ tłumacz z PHP na Java. Jedynym wykonalnym sposobem na to, bez osadzania części pliku binarnego PHP, jest reimplementacja wszystkich modułów PHP i API w Javie. Obejmuje to wdrożenie ponad 10.000 funkcji. W porównaniu do tego zadanie przetłumaczenia składni jest łatwe. I nawet po tych wszystkich pracach, w których nie miałbyś kodu Java, miałbyś jakąś potworność, która zdarza się działać na platformie Java, ale miała strukturę wewnętrzną podobną do PHP.

Dlatego jedyne takie narzędzia, które przychodzą na myśl, polegają na tłumaczeniu kodu w celu jego wdrożenia, a nie jego późniejszej konserwacji. Google GWT „kompiluje” Javę do JavaScript. Hiphop Facebooka kompiluje PHP do C.



Wygląda na to, że ktoś utworzył translator php na java i faktycznie osadził plik binarny PHP. Zgadzam się, ale to nie zmienia twojego punktu. runtimeconverter.com/single-post/2017/09/15/…
user1122069

20

Jeśli masz format pośredni, możesz zaimplementować coś, co tłumaczy program z języka X na ten format, a także z tego formatu na język Y. Zaimplementuj te konwersje dla wszystkich języków, które Cię interesują, i gotowe?

Wiesz co? Taki format już istnieje: montaż. Kompilator wykonuje już konwersję „Montaż języka X do zestawu” i dezasembluje konwersję „Montaż języka Y”.

Asembler nie jest tak dobrym językiem do przeprowadzania konwersji odwrotnej, ale MSIL nie jest wcale taki zły. Pobierz Reflector, a zobaczysz, że ma opcje dezasemblacji zestawu .NET na kilka różnych języków (a wtyczki zapewniają jeszcze więcej). Jest więc całkiem możliwe, aby wziąć program w języku C #, skompilować go do biblioteki DLL (czyli MSIL), a następnie użyć reflektora, aby rozłożyć go na VB, C ++ / CLI, F # i całą masę innych. Oczywiście, wszystkie inne konwersje też działają. Weź plik F #, skompiluj do DLL, użyj Reflectora, aby przekonwertować go do C #.

Oczywiście dwa duże problemy, które znajdziesz:

  1. Kod jest w zasadzie nieczytelny. MSIL (nawet z informacjami o debugowaniu) usuwa wiele informacji z oryginalnego źródła, więc przetłumaczona wersja nie ma 100% wierności (teoretycznie konwersja C # -> MSIL-> C # powinna dać ci oryginalny kod, ale przyzwyczajenie).
  2. Wiele języków .NET ma własne biblioteki niestandardowe (np. Biblioteka uruchomieniowa VB, biblioteka F # i tak dalej). Należy je uwzględnić (lub przekonwertować) również podczas konwersji.

Naprawdę nie ma nic do obejścia # 2, ale prawdopodobnie możesz dostać się do # 1 z dodatkowymi adnotacjami w MSIL (być może za pomocą atrybutów). Oczywiście byłaby to dodatkowa praca.


Wiele metadanych z oryginalnego źródła znajduje się w MSIL (w tym komentarze XML i oryginalna metoda, nazwy właściwości i członków), więc nie sądzę, aby konwersja do C # była tak nieczytelna, jak mówisz. Spróbuj zdemontować części środowiska .NET; jest bardzo czytelny. Oczywiście sytuacja może wyglądać inaczej w przypadku konwersji F # na C #.
Robert Harvey,

@Robert: Komentarze XML nie są zawarte w MSIL. Jeśli spojrzysz Microsoft.NET\Framework\v2.0.50727\enna przykład, możesz zobaczyć całą dokumentację XML bibliotek systemowych. Tego właśnie używa Reflector (i in.) Do wyświetlania komentarzy. Konwersja nie jest nieczytelna, wszystko co powiedziałem to, że nie jest to 100% wierność, której można oczekiwać od tłumaczenia na poziomie źródłowym.
Dean Harding,

2
Dezasembler konwertuje binarny plik wykonywalny maszyny z powrotem na asembler dla tego konkretnego typu procesora (nie cały świat to x86). Naprawdę masz na myśli dekompilator, który zabiera skompilowany kod z powrotem do źródła. Jest to przerażająco trudne zadanie, ponieważ każdy kompilator, od każdego producenta, na każdym poziomie optymalizacji przekształci wiersze źródłowe w inną wyjściową postać binarną.
uɐɪ

20

Czy jest możliwe, przynajmniej teoretycznie, napisanie 100% poprawnego tłumacza między wszystkimi językami? Jakie są wyzwania w praktyce?

  • Tłumaczenie z bardziej ustrukturyzowanego języka na mniej ustrukturyzowany język, który wciąż jest kompletny w Turinga, jest zawsze możliwe.
    • Twierdzenie to należy rozpatrywać w ściśle technicznym sensie: oznacza to, że przetłumaczony program przyniesie dokładnie taki sam wynik, gdy zostanie wykonany.
    • Nic nie wskazuje na czytelność przetłumaczonego kodu lub zachowanie oryginalnych struktur programu.
  • Tłumaczenie z mniej uporządkowanego języka na bardziej uporządkowany jest możliwe, ale przetłumaczony kod pozostanie w mniej uporządkowanej formie.

1
Trafiłeś w gwóźdź. Spróbuj odczytać kod, który pochodzi z backendu C LLVM. Jest to technicznie legalny kod C, ale nie jest ładny (TM).
dsimcha

1
@dsimcha: Pomijając czytelność, zaplecze C znacznie ułatwia odczytanie danych wyjściowych niż debugowanie lub deasemblacja. Cieszę się, że ponownie przywrócili ten backend, gdy na jakiś czas przestał działać.
JM Becker

10

Dlaczego chcesz przekonwertować program?

Oba języki, język źródłowy i docelowy są w każdym razie kompilowane do (wirtualnego) kodu maszynowego *, więc ze względów technicznych nie ma potrzeby posiadania kompilatora w innym języku wysokiego poziomu.

Języki są dla ludzi. Tak więc domniemany wymóg twojego pytania brzmi: „dlaczego nie ma tłumacza, który generuje czytelny kod” , a odpowiedź brzmiałaby (imho): ponieważ jeśli istnieją dwa języki, które są wystarczająco różne, sposób pisania „czytelnego kodu” jest pisany różni się w sposób, który wymagałby nie tylko tłumaczenia algorytmów, ale także różnych algorytmów.

Na przykład porównaj typową iterację w C i jedną w lisp. Lub pytony „jeden najlepszy sposób” z idiomatycznym rubinem.

Tutaj zaczynają się pojawiać te same problemy, które masz w prawdziwych językach, np. Kiedy tłumaczysz „Pada deszcz kotom i psom” na coś w znaczeniu „Leje jak z wiader” podczas tłumaczenia z angielskiego na niemiecki, nie możesz tłumaczyć już słowo po słowie, ale trzeba szukać znaczenia.

A „znaczenie” nie jest łatwą koncepcją.

*) no cóż, jest coffeescript ...


1
Dobra odpowiedź. Można dodać, że gdyby dwa języki miały dokładnie ten sam zestaw cech i idiomów, możliwe byłoby dość skuteczne tłumaczenie jednego języka na inny, ale większość języków została zaprojektowana w celu wspierania funkcji i idiomów, które zdaniem ich twórców nie są odpowiednio obsługiwane w innych językach . Mechaniczne tłumaczenie konserwowalnego kodu jest czasem wykonalne, gdy funkcje i idiomy w języku docelowym są nadzbiorem tych i języka źródłowego, ale takie sytuacje nie są strasznie częste.
supercat,

6

Jest to teoretycznie możliwe, ale w większości bezużyteczne. Możliwa jest prawie każda kombinacja języków źródłowych i docelowych, ale w większości przypadków nikt nigdy nie chciałby przyjrzeć się wynikowi ani go użyć.

Spora liczba kompilatorów celuje w C, po prostu dlatego, że kompilatory C są dostępne dla prawie każdej istniejącej platformy (i istnieją automatyczne generatory kompilatorów, które pozwolą ci zaprojektować procesor i automatycznie wygenerują kompilator C, który celuje w twój nowy procesor). Istnieje również oczywiście spora liczba implementacji ukierunkowanych na języki używane przez różne maszyny wirtualne, takie jak .NET, JVM, C-- i LLVM.

Kluczową kwestią jest jednak to, że naprawdę jest użyteczne tylko wtedy, gdy traktujesz cel jako język asemblera, który jest używany tylko jako krok w procesie kompilacji. W szczególności na ogół nie chcesz, aby normalny programista czytał lub pracował z tym wynikiem; zwykle nie będzie bardzo czytelny.


5

FWIW, jest tłumacz z Javy na D. Nazywa się TioPort i został użyty w dość poważnej próbie przeniesienia SWT do D. Główny problem, na jaki natrafił, polegał na tym, że konieczne byłoby przeniesienie ogromnej części standardowej biblioteki Java .


4

Choć samo w sobie nie jest to tłumaczenie kodu, koncepcja warsztatów językowych pokazuje, w jaki sposób można zaimplementować coś podobnego do 100% poprawnego tłumacza między wszystkimi językami.

W naszym obecnym podejściu kod źródłowy jest przechowywany w formacie tekstowym. Podczas kompilacji te czytelne dla człowieka pliki tekstowe są przetwarzane w abstrakcyjną reprezentację drzewa składni, która z kolei służy do generowania kodu bajtowego lub kodu maszynowego. Ta abstrakcyjna reprezentacja jest jednak tymczasowa i wewnętrzna dla kompilatora.

W podejściu do warsztatu językowego podobną abstrakcyjną reprezentacją drzewa składni jest stały, przechowywany artefakt. Zarówno kod maszynowy, jak i tekstowy kod „źródłowy” są generowane na podstawie tej abstrakcyjnej reprezentacji. Jedną z konsekwencji takiej metody jest to, że abstrakcyjna reprezentacja programu jest w rzeczywistości niezależna od języka i może być używana do generowania kodu tekstowego w dowolnym zaimplementowanym języku. Oznacza to, że jedna osoba może swobodnie pracować nad różnymi aspektami systemu, używając dowolnego języka, który uważa za najbardziej odpowiedni, lub każdy członek zespołu może pracować nad wspólnym projektem w języku, który jest mu najbardziej znany.

O ile mi wiadomo, technologia wciąż jest daleka od użyteczności w rozwoju głównego nurtu, jednak istnieje kilka grup pracujących nad nią niezależnie. Trudno powiedzieć, czy któryś z nich spełni swoje obietnice, ale byłoby ciekawe, gdyby tak się stało.


Czy mógłbyś wymienić niektóre z tych grup?
Qwertie,

4

Tam niektóre automatycznych tłumaczy. Jeśli Twoim celem jest stworzenie kodu, który można skompilować, a nie kodu do odczytu, jest to całkiem możliwe i czasami przydatne, po prostu niezbyt często. Znany pierwszy kompilator C ++ nie był tak naprawdę kompilatorem, ale przetłumaczył C ++ na (naprawdę skomplikowane) źródło C, które zostało następnie skompilowane przez kompilator C. Wiele kompilatorów może generować kod asemblera na żądanie - ale zamiast wyrzucać tekst asemblera, a następnie tłumaczyć go na kod maszynowy, zwykle mogą generować kod maszynowy bezpośrednio.

Biorąc pod uwagę pełną specyfikację języka A, zasadniczo nie jest tak trudno napisać program, który wyraża swoje dyrektywy w jakimś języku B. Ale zazwyczaj każdy, kto zadaje sobie trud, wybiera coś naprawdę „niskiego” dla „języka B”: kod maszynowy , lub w dzisiejszych czasach bajtecode: Jython jest implementacją Pythona, która generuje kod bajtu java, który jest interpretowany przez maszynę wirtualną Java. Nie musisz zawracać sobie głowy pisaniem i kompilowaniem hierarchii klas Java!


3

Odbywa się to cały czas.

Każdy kompilator tłumaczy „język podstawowy”, taki jak C ++, na natywny język asemblera maszyny lub niezależny od architektury kod bajtowy w przypadku języków interpretowanych.

Wyobrażam sobie jednak, że nie o tym mówisz. Prawdopodobnie potrzebujesz tłumacza, który konwertuje C ++ na coś takiego jak Java lub Python. Ale po co to ma sens? W najlepszym wypadku wynik końcowy będzie miał dokładnie taką samą wydajność jak oryginalne źródło. (Praktycznie będzie znacznie gorzej.)

Jeśli chcesz po prostu przetłumaczyć kod, abyś mógł go przeczytać jako język, który rozumiesz, taki tłumacz miałby przeciwieństwo pożądanego efektu. Pozostanie ci mnóstwo tajemniczego, nieintuicyjnego i nieczytelnego kodu.

Jest tak, ponieważ tylko najbardziej trywialne rzeczy tłumaczą bezpośrednio z jednego języka na inny. Często to, co jest proste w jednym języku, wymaga ogromnych bibliotek dla innego - lub może być całkowicie niemożliwe. W związku z tym:

  1. Jeśli program jest trywialny, możesz uzyskać przyzwoity wynik. Ale jeśli to takie proste, jaki jest sens przeprowadzania go przez tłumacza?
  2. Jeśli program nie jest łatwy w obsłudze, kod będzie niskiej jakości.

Ostatecznie jedynym sposobem na napisanie dobrego kodu jest napisanie go. Komputery po prostu nie mogą - a przynajmniej jeszcze nie są - porównywać ludzi pod względem czytelności, najlepszych praktyk i eleganckich rozwiązań.

Krótko mówiąc, po prostu nie jest tego warte.


Twoja analogia dotyczyłaby również normalnej kompilacji i wiemy empirycznie, że nie! Komputery „generują” (nie zapisują) kod dobrej jakości. Często źle robią to czytelność / łatwość konserwacji. Gdyby ktoś potrzebował takiego procesu, co, jak wierzą, ludzie czasem tego potrzebują, żaden z problemów nie jest przeszkodą. Jeśli tak, to oczywiście tłumaczenie nigdy nie było ważne.
JM Becker

1

Brak języków dla języków programowania, ponieważ języki programowania są niezwykle złożone. Chociaż jest to hipotetycznie możliwe, istnieje wiele wyzwań.

Pierwszym wyzwaniem są jedynie akceptowalne praktyki języka. Konwersja między dwoma obiektowymi językami, takimi jak Java i C ++, jest niezwykle złożona i oba są oparte na języku C. Program tłumaczący musiałby mieć doskonałą znajomość standardowych bibliotek dla obu języków i być w stanie poznać różnice w zachowaniu. Musiałbyś stworzyć ogromny słownik, a nawet wtedy różnice w stylach programowania między programistami oznaczałyby, że musiałby zgadywać, jak wprowadzić pewne zmiany.

Po zakończeniu tłumaczenia składni musisz dowiedzieć się, jak przekonwertować konstrukt w pierwszym języku na konstrukt w drugim języku. Jest to w porządku, jeśli przenosisz obiekt w C ++ do obiektu w Javie (to stosunkowo łatwe), ale co robisz ze swoimi strukturami C ++? Czy funkcje poza klasami C ++? Decyzja o tym, jak sobie z tym poradzić, może być trudna, ponieważ może spowodować inny problem, a mianowicie utworzenie obiektu blob. Kropelka jest anty-wzorem, który jest dość powszechny.

To nie jest pełna lista problemów, ale są to tylko dwa i są duże. Jeden z moich profesorów wspomniał, że ktoś przekonał swojego pracodawcę, że w latach 80. można go stworzyć z kodu maszynowego na C, ale wtedy to nie działało. Wątpię, czy kiedykolwiek będzie taki, który działa w pełni.


Myślę, że nie trzeba znać istniejących bibliotek, może po prostu tłumaczyć biblioteki na bieżąco (zakładając, że mają dostępne źródła).
serg

1
To faktycznie zwiększa złożoność drugiego problemu. Zakładając, że masz dostęp do kodu źródłowego, aby go przetłumaczyć. Tak czy inaczej, jest to wciąż niewykonalne.
indyK1ng

+1 punkt za libs jest całkowicie poprawny i ZAWSZE są lib.
Dan Rosenstark

1

Celem kompilacji jest uzyskanie czegoś przydatnego dla komputera. tzn. coś, co można uruchomić. Po co kompilować się do czegoś, co może być nawet na wyższym poziomie niż to, w którym napisałeś?

Bardziej podoba mi się strategia .NET. Kompiluj wszystko do wspólnego języka. Daje to korzyść z tego, że języki mogą się komunikować bez konieczności tworzenia kompilatorów międzyjęzykowych (N ^ 2) -N.

Na przykład, jeśli masz 10 języków programowania, wystarczy napisać 10 kompilatorów w modelu .NET i wszystkie one mogą się ze sobą komunikować. Jeśli stworzyłeś wszystkie możliwe kompilatory wielojęzyczne, musisz napisać 90 kompilatorów. To dużo dodatkowej pracy przynoszącej niewielkie korzyści.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.