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ą?
Odpowiedzi:
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.
źródło
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:
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.
źródło
Microsoft.NET\Framework\v2.0.50727\en
na 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.źródło
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 ...
źródło
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.
źródło
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 .
źródło
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.
źródło
Tam są 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!
źródło
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:
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.
źródło
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.
źródło
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.
źródło