Czy istnieją programy, które potrafią „tłumaczyć” kod źródłowy między dowolnymi dwoma językami?

28

Czy istnieją programy, które potrafią „tłumaczyć” kod źródłowy między dowolnymi dwoma językami (zakładając, że tłumacz ma dostęp do wymaganych bibliotek)?

Jeśli tak, to w jaki sposób działają (zastosowane techniki, wymagana wiedza itp.)? Jak można by je wykonalnie skonstruować?

Jeśli nie są, jakie są ograniczenia uniemożliwiające ich rozwój? Czy jest to kompletny problem sztucznej inteligencji (tłumaczenie na język naturalny jest wymienione jako jeden)?

EDIT Konwersja jest oczekiwana tylko wtedy, gdy język ma tę samą moc wyrażania, może rozwiązać ten sam rodzaj problemów, a kod do konwersji może być wyrażony w języku docelowym. (Np. Konwersja ze skryptu powłoki do MATLAB nie jest oczekiwana).

Tobi Alafin
źródło
14
Co rozumiesz przez „dowolne dwa języki”? Z pewnością istnieją programy, które mogą tłumaczyć z jednego języka na inny. Nazywa się je „kompilatorami”. To dosłownie definicja kompilatora: program, który tłumaczy programy z jednego języka na inny. Ale „jakieś dwa języki”? Nie sądzę, żeby to było możliwe. Tłumacz musi znać zarówno język źródłowy, jak i docelowy, i zwykle jest specyficzny dla konkretnej pary języków.
Jörg W Mittag,
Program jest dostarczany w języku źródłowym i docelowym. Zastanawiam się nad napisaniem programu w C ++, przetłumaczeniem go na Javę, Pythona, Perla, Ruby, Go itd. Mogą istnieć pewne ograniczenia (nie oczekuję, że na przykład przekonwertuje skrypt powłoki na MATLAB).
Tobi Alafin,
4
Tak, nazywane są kompilatorami, działają jak kompilatory i można je konstruować jak kompilatory.
user253751,
1
Jeśli przez „dowolnych dwóch językach” dosłownie znaczy, że program (skończone) powinien być w stanie przeczytać i zrozumieć nieskończoną liczbę języków wejściowych, odpowiedź brzmi trywialnie nie . Jednak weź skończony zestaw języków wejściowych, a znajdziesz kompilator dla wszystkich tych języków.
Bakuriu,

Odpowiedzi:

57

TLDR; jest to możliwe, ale niepraktyczne.

(zakładając, że tłumacz ma dostęp do wymaganych bibliotek)?

To jest trudna sprawa i jest częścią tego, dlaczego takie rzeczy nie są używane w praktyce.

  1. Wszystkie kompilatory są tłumaczami. Tłumaczenie z jednego języka na drugi jest zdecydowanie możliwe, i to dosłownie wszystko, co robi kompilator. Językiem, który kompilator wyrzuca jako dane wyjściowe, jest na ogół kod maszynowy lub asembler, ale jest to po prostu inny język i istnieją kompilatory (czasami nazywane transpilatorami lub transkompilatorami), które tłumaczą między dwoma językami . Na przykład istnieje cała gama języków kompilacji do Javascript, takich jak PureScript, Elm, ClojureScript itp.

  2. Tłumaczenie między dwoma dowolnymi językami Turing Complete jest zawsze możliwe. Ignorowanie takich rzeczy jak wywołania biblioteczne, FFI i inne nieprzyjemne praktyczne bity, które przeszkadzają. Jeśli język jest ukończony przez Turinga, masz:

    • Tłumaczenie, które konwertuje maszynę Turinga na kod w tym języku
    • Tłumaczenie z tego języka na maszynę Turinga

    Aby przetłumaczyć z języka A ​​na język B, konwertujesz kod A na maszynę Turinga, a następnie konwertujesz tę maszynę na kod B.

    Oczywiście w praktyce przeszkadzają w tym praktyczne elementy, a to wymaga również posiadania dostępnych tłumaczeń. Istnieją w zasadzie dla każdego języka, ale to nie znaczy, że ktoś poświęcił czas na ich napisanie.

  3. Skuteczne wykonanie tego tłumaczenia jest trudne . Inny język nadaje priorytet różnym rzeczom. Na przykład, jeśli tłumaczysz z C na Python, prawdopodobnie będziesz musiał skończyć z symulacją pamięci C jako słownika Pythona, abyś mógł wykonywać arytmetykę wskaźników. Będzie się to wiązało z narzutem, ponieważ nie masz teraz dostępu do instrukcji pamięci od zera.

    Różne języki mają różne priorytety wydajności, więc coś, co optymalizuje jeden język (a raczej implementacja jednego języka optymalizuje), może być niemożliwe do zrobienia szybko w innym języku. Tłumaczenie funkcjonalnego języka z odpowiednimi wywołaniami ogona ulegnie spowolnieniu, jeśli przetłumaczysz go na język bez odpowiednich wywołań ogona.

  4. Wykonanie tego tłumaczenia nie powoduje, że kod jest czytelny . Łatwo jest uzyskać fragment kodu w języku B, który zachowuje się tak samo jak kod z języka A. Trudno jest sprawić, aby wyglądał tak, jakby kod napisany przez człowieka był napisany w języku B z wielu powodów. A i B mogą mieć różne narzędzia abstrakcyjne, a komputer nie ma pojęcia, co czyni kod możliwym do odczytania. Będzie to szczególnie prawdziwe, jeśli skończysz na tłumaczeniu Turinga, które opisałem wcześniej.

    Rodzi to pytanie: jaki jest sens takiego tłumaczenia? Jeśli na końcu otrzymujesz blok wolnego, nieczytelnego kodu, to dlaczego nie po prostu skompilować go do kodu maszynowego i użyć jakiegoś FFI lub komunikacji między procesami, aby połączyć elementy ze sobą?

    Istnieją pewne wyjątki od tego. Czasami potrzebujesz rzeczy w określonym języku (np. JavaScript). Czasami język jest podobny, a rozsądne tłumaczenie jest łatwe. Czasami język nie jest przeznaczony do uruchamiania, ale do wyodrębnienia kodu w innym języku (np. Coq).

    Ale ogólnie rzecz biorąc, nie jest to bardzo praktyczna rzecz.

jmite
źródło
5
Jednym z przykładów pkt 4 asm.js . Dzisiaj można uczynić go w pewnym stopniu czytelnym, używając Map źródłowych Javascript i Inspektora Elementów, ale nikt nie będzie chciał tego robić ...
Ismael Miguel,
1
Modelica to kolejny przykład języka zaprojektowanego do kompilacji na inny język (w tym przypadku C).
Przywróć Monikę
Tłumaczenie stron internetowych z C ++ na javascript.
Surt,
Istnieje wiele przykładów transpilatorów od X do Y, ale różni się to od uniwersalnego kompilatora „wszystko do wszystkiego”. Oczywiście istnieją przypadki, w których transpozycja ma sens.
jmite
Brakuje jednego ważnego wyjątku IMO: kompilacja do C. Powodem jest to, że wiele nietypowych systemów ma istniejący kompilator C, który generalnie może emitować całkiem rozsądny kod maszynowy. Dlatego, kompilując język do C, nie potrzebujesz backendów dla tych rzadkich architektur.
MSalters
2

Istnieją takie programy. Na przykład tłumacze Lisp-for-Fortran, którzy byli wówczas powszechnie używani. Kompilatory Sole Lisp nie kompilują bezpośrednio Lisp, ale zamiast tego generują kod C, który następnie jest kompilowany przez zwykły kompilator C. Innym przykładem może być Vala, która nie jest skompilowana bezpośrednio, ale najpierw przetłumaczona na C ++ przed skompilowaniem kodu C ++. Qt jest napisany w MOC, języku, który jest tłumaczony na C ++ w celu jego skompilowania (ale ponieważ MOC to po prostu C ++ z kilkoma dodatkowymi poleceniami, można się spierać, czy naprawdę należy go nazwać „nowym językiem”) - i wcześniej były kompilatory C ++, były C ++ - na C-translatory. Niektóre projekty zostały napisane w języku Pascal, a następnie przetłumaczone na C. Także clang i Java są czymś w rodzaju, ponieważ tłumaczą kod C ++ i Java na jakiś język pośredni, który następnie może być dalej przetwarzany.

To, czego nie można oczekiwać po wynikach tłumacza języka, to fakt, że wynik ma sens dla ludzkiego czytelnika: zadaniem programu jest napisanie kodu, w wyniku którego program będzie działał tak samo jak kod oryginalny (co z mojego doświadczenia może lub może nie działa, w zależności od funkcji języka i używanych bibliotek zewnętrznych). Ponieważ jednak nie wie on, jaki jest cel tego zadania, reszta znaczenia programu może zostać w dużym stopniu utracona.

Gunter Königsmann
źródło
0

Nie jest to bezpośrednia odpowiedź, ale istnieje wywołanie narzędzia ILSpy , które zostało napisane dla .NET Framework i pozwala na dekompilację zestawu .Net do C # lub VB.Net.

Jeśli nie znasz natury .Net, możesz pisać .Net kod w wielu językach, ale przede wszystkim w C # lub VB.Net. Gdy kompilator kompiluje aplikację, tłumaczy kod na „język pośredni” (lub w skrócie IL). Ten kod jest następnie kompilowany do plików binarnych .Net.

Ponieważ aplikacje .Net to pliki binarne skompilowane z kodu IL, ILSpy może przenieść aplikację .Net, odwrócić ją z powrotem do kodu IL, a następnie pójść o krok dalej i odwrócić z powrotem do C # lub VB.Net.

Za pomocą tego narzędzia wystarczy skompilować aplikację, a następnie przeglądać skompilowane pliki jako kod IL, C # lub VB.Net. Żeby było jasne, nie ma znaczenia, w jakim języku kod został początkowo napisany. Tak długo, jak plik binarny jest zestawem .Net, może dokonywać inżynierii wstecznej skompilowanych plików i wyświetlać zawartość w dowolnym z tych trzech języków.

Wiem, że to nie jest dokładnie kompilator, ale jest to narzędzie, które oferuje efekt końcowy podobny do tego, czego szukasz, i w rzeczywistości użyłem go do „przetłumaczenia” projektów VB.Net na coś trochę bardziej mi znany - C #.

RLH
źródło
0

W twoim przypadku użycia (na podstawie komentarzy) wygląda na to, że SWIG może być przydatny.

SWIG to narzędzie do tworzenia oprogramowania, które łączy programy napisane w C i C ++ z różnymi językami programowania wysokiego poziomu. SWIG jest używany z różnymi typami języków docelowych, w tym popularnymi językami skryptowymi, takimi jak Javascript, Perl, PHP, Python, Tcl i Ruby. Lista obsługiwanych języków obejmuje również języki inne niż skryptowe, takie jak C #, Common Lisp (CLISP, Allegro CL, CFFI, UFFI), język D, Go, Java, w tym Android, Lua, Modula-3, OCAML, Octave, Scilab i R Obsługiwanych jest także kilka interpretowanych i skompilowanych implementacji schematów (Guile, MzScheme / Racket, Chicken).

Nathan Ringo
źródło
0

Przypominam sobie czcigodnego f2c , który dokonuje tłumaczenia między źródłami z Fortran 77 do C.

Był (czasem jest ...) używany głównie do tłumaczenia kodu numerycznego sprzed kilkudziesięciu lat bez konieczności integracji kompilatora fortran z łańcuchem narzędzi.

Alexandre C.
źródło
0

Teoria, która mówi, że takie programy istnieją, nazywa się w zasadzie dopuszczalnymi numeracjami . Możemy udowodnić, że istnieją kompilatory obliczalne między dowolnymi dwoma takimi numeracjami, a każdy formalizm Turinga (lub język programowania) jest w istocie jednym.

Raphael
źródło