Jak powstały pierwsze kompilatory?

70

Zawsze się nad tym zastanawiam i być może potrzebuję dobrej lekcji historii na temat języków programowania. Ale skoro większość współczesnych kompilatorów jest napisanych w C, jak powstały pierwsze kompilatory (AKA przed C) lub czy wszystkie języki były właśnie interpretowane?

Biorąc to pod uwagę, nadal nie rozumiem, w jaki sposób powstał nawet pierwszy język asemblera, rozumiem, co to jest asembler, ale nie widzę, jak sprawili, że działał BARDZO język pierwszego asemblera (na przykład, w jaki sposób stworzyli pierwszy polecenia (jak mov R21) lub w / e ustawione na binarny odpowiednik?

komar
źródło
9
Kiedyś w moim zespole był komicznie nieudolny programista, w którym narzekał na C #. Żartowaliśmy z fikcyjnego języka, który wynalazł, zwanego Crunk. Mało znany fakt o Crunk, jest to pierwszy język, w którym kompilator napisano TAKŻE w Crunk. :)
wałek klonowy
2
Dlaczego ktoś miałby narzekać na C #? czy nigdy nie używał smalltalk lub Lisp? lol
2
możliwy duplikat kompilatora C i Dennisa Ritchie
vartec 30.06.11
4
@maple_shaft: być uczciwym, kompilator gcc jest napisany w C . W rzeczywistości nie stanowi to problemu, jeśli masz dobry kompilator krzyżowy do skompilowania pierwszej wersji. Pierwszy kompilator C musiał oczywiście zostać napisany w innym języku.
Scott Whitlock
5
możliwy duplikat Jak napisano pierwszy kompilator?
Greg Hewgill

Odpowiedzi:

89

Ha, zrobiłem to. Wiele procesorów ma proste instrukcje o stałym rozmiarze, które mają zaledwie kilka bajtów. W przypadku prostego procesora, takiego jak na przykład Motorola 6800, możesz zmieścić wszystkie jego instrukcje na jednym arkuszu papieru . Każda instrukcja ma powiązany z nią dwubajtowy kod operacji i argumenty. Możesz ręcznie złożyć program, sprawdzając kod operacji każdej instrukcji. Następnie napisałeś swój program na papierze , adnotując każdą instrukcję odpowiednim kodem operacji. Po napisaniu programu możesz nagrać każdy kod operacji kolejno w pamięci EPROMktóre następnie zapisałyby twój program. Podłącz EPROM do procesora za pomocą odpowiednich instrukcji pod właściwymi adresami, a otrzymasz prosty działający program. Aby odpowiedzieć na twoje następne pytanie, tak. To było bolesne (robiliśmy to w szkole średniej). Ale muszę powiedzieć, że podłączenie każdego układu w 8-bitowym komputerze i ręczne napisanie programu dało mi głębokie zrozumienie architektury komputera, czego prawdopodobnie nie osiągnąłem w żaden inny sposób.

Bardziej zaawansowane układy (takie jak x86) są znacznie trudniejsze do ręcznego kodowania, ponieważ często mają instrukcje o zmiennej długości. Procesory VLIW / EPIC, takie jak Itanium, są prawie niemożliwe do skutecznego ręcznego kodowania, ponieważ zajmują się pakietami instrukcji zoptymalizowanymi i złożonymi przez zaawansowane kompilatory. W przypadku nowych architektur programy prawie zawsze są pisane i montowane najpierw na innym komputerze, a następnie ładowane do nowej architektury. W rzeczywistości dla firm takich jak Intel, które faktycznie budują procesory, mogą uruchamiać rzeczywiste programy na architekturach, które jeszcze nie istnieją, uruchamiając je na symulatorach. Ale dygresję ...

Jeśli chodzi o kompilatory, w najprostszym przypadku mogą one być czymś więcej niż programami „wycinaj i wklej”. Możesz napisać bardzo prosty, nieoptymalizujący „język wysokiego poziomu”, który po prostu grupuje proste instrukcje języka asemblera bez większego wysiłku.

Jeśli chcesz historię kompilatorów i języków programowania, sugeruję GOTO historię FORTRAN .

Dave Markle
źródło
27
. . . i shoudn't że będzie "... Proponuję ci JMP do historii ..."
Binary Worrier
2
Bardzo mi przykro. Ale musiałem. Po prostu ... miałem. do ...
Dave Markle
9
@Dave: Zdajesz sobie sprawę, że Velociraptor skazałeś się na śmierć ?
Binary Worrier
7
„Wiedzieli”, ponieważ byli dosłownie przygotowani do wykonania tej operacji, gdy zobaczyli sygnał 101010100 dla danej instrukcji. W rzeczywistości mają jednostkę na chipie odpowiedzialną za instrukcje dekodowania instrukcji: en.wikipedia.org/wiki/Decoder
Dave Markle
7
Warto dodać: kompilator dla nowego języka, gdy jest napisany w tym samym nowym języku, jest czasami kompilowany z „proto-kompilatorem” napisanym w innym języku, który wytwarza wyraźnie poprawny, ale przerażająco nieefektywny kod. Po skompilowaniu jest on następnie uruchamiany w celu uzyskania stosunkowo szybkiego kompilatora. Porównaj maszynę von Neumanna. : D
BMDan
54

O to właśnie chodzi w ładowaniu kompilatora (ponieważ nikt nie wspomniał, jak to się nazywa =).

proces pisania kompilatora (lub asemblera) w docelowym języku programowania, który ma zostać skompilowany. Zastosowanie tej techniki prowadzi do kompilatora samoobsługowego.

Wiele kompilatorów dla wielu języków programowania jest ładowanych, w tym kompilatory dla BASIC, ALGOL, C, Pascal, PL / I, Factor, Haskell, Modula-2, Oberon, OCaml, Common Lisp, Scheme, Java, Python, Scala i więcej .. .

Problem z kurczakiem i jajkami

Jeśli potrzebny jest kompilator dla języka X, aby uzyskać kompilator dla języka X (który jest napisany w języku X), jak powstał pierwszy kompilator? Możliwe metody rozwiązania tego problemu z kurczakiem lub jajami obejmują:

  • Implementacja interpretera lub kompilatora dla języka X w języku Y. Niklaus Wirth poinformował, że napisał pierwszy kompilator Pascal w Fortranie.
  • Inny tłumacz lub kompilator dla X został już napisany w innym języku Y; w ten sposób Schemat jest często uruchamiany.
  • Wcześniejsze wersje kompilatora zostały napisane w podzbiorze X, dla którego istniał jakiś inny kompilator; w ten sposób ładowane są niektóre nadzbiory Java, Haskell i początkowy kompilator Free Pascal.
  • Kompilator dla X jest kompilowany krzyżowo z innej architektury, w której istnieje kompilator dla X; w ten sposób kompilatory dla C są zwykle przenoszone na inne platformy. Jest to również metoda używana dla Free Pascal po początkowym ładowaniu.
  • Pisanie kompilatora w X; następnie ręcznie skompiluj go ze źródła (najprawdopodobniej w sposób niezoptymalizowany) i uruchom go w kodzie, aby uzyskać zoptymalizowany kompilator. Donald Knuth wykorzystał to w swoim systemie programowania do obsługi Internetu ...
winorośl
źródło
Dobry link, który prowadzi również do en.wikipedia.org/wiki/History_of_compiler_writing . Ogólnie myślę, że oryginalne kompilatory zostały napisane w asemblerze ( en.wikipedia.org/wiki/Assembly_language ). Dopiero później pojawił się pomysł bootstrapowania lub samodzielnego hostingu.
Michael Levy
1
+1 WRESZCIE! Dziwne, że to dopiero trzecia najlepiej oceniana odpowiedź. Tak, ładowanie początkowe. Oto odpowiedź
Adam Rackis,
15

Ostatecznie wszystkie komputery działają na kodach binarnych, które są podawane do procesora. Te kody binarne są całkowicie naturalne dla procesora, ale także idealnie bezużyteczne dla ludzi. Jednym z pierwszych sposobów pisania programu było dziurkowanie kart. Położenie otworów reprezentowało określoną pozycję bitu w słowie, a obecność lub brak otworu interpretowano jako zero lub jeden. Karty te zostały umieszczone w odpowiedniej kolejności w pudełku, a następnie wprowadzone do czytnika kart, który skutecznie przekształcił je w kod binarny dla procesora (a twoje życie zostało skutecznie utracone, jeśli upuściłeś pudełko).

Oczywiście pierwsi programiści opracowywali kody binarne jeden po drugim i mieli maszynę do dziurkowania kart. Jest to zasadniczo programowanie w języku asemblera na dłoniach i kolanach. Kiedy już to zrobisz, możesz stworzyć z niego wszystkie inne rzeczy: prosty edytor tekstu, kompilator języka asemblera (do konwersji instrukcji asemblacyjnych na kody binarne), linker i moduł ładujący. A reszta, jak mówią, to historia.

wolfgangsz
źródło
4
Przed kartami miałeś zestaw przełączników adresu, zestaw słowa danych i przełącznik do ładowania danych. Każdy adres pamięci zaprogramowałeś osobno, ustawiając adres i przełączniki danych z reprezentacją binarną, a następnie włączyłeś, a następnie wyłączyłeś przełącznik obciążenia. Zajęło to wieki, ale program miał tylko kilka słów - wówczas nie wynaleziono bajtów.
u
4
... A wcześniej musiałeś to przełączyć . Zabawa zabawa zabawa!
Michael K
Tak, ale kiedy trzeba było to zrobić, tak naprawdę nie myśleliśmy o nowoczesnym komputerze, ponieważ architektura Von Neumanna nie została jeszcze wynaleziona.
Dave Markle
7

Trochę googlingu pokazuje Pierwsze Zamówienia EDSAC z późnych lat 40. Ponieważ był to pierwszy asembler, prawdopodobnie został napisany w języku maszynowym.

Później pojawiły się asemblery dla innych maszyn, takich jak SOAP I i II dla IBM 650. SOAP I również prawdopodobnie został napisany w języku maszynowym, chociaż nie znalazłem ostatecznego stwierdzenia.

Nieco później pojawił się Fortran (tłumacz formuły) dla IBM 704. Prawdopodobnie został napisany w asemblerze dla 704. Wczesny asembler dla 701 przypisuje się Nathanowi Rochesterowi .

Jeśli chcesz dowiedzieć się, jak zaprogramować komputer w języku maszynowym, sprawdź jedną z moich ulubionych stron, przekaźnik komputera Harry'ego Portera .

Mike Dunlavey
źródło
Cholera jasna, domowy komputer Harry'ego Portera (prawie powiedział Harry Potter Lol) jest niesamowity. Chciałbym zrozumieć, jak zbudowano coś takiego :(.
1
@Sauron: Harry Porter nie chciałby nic lepszego niż powiedzieć. Na tej stronie ma pięknie wykonany powerpoint wyjaśniający to wszystko. Zakłada podstawową wiedzę na temat obwodów, ale nie jest to zbyt trudne do zdobycia.
Mike Dunlavey
Wiem, że po prostu zadzieram ^ _ ^, niezależnie od tego, że jest to imponująca maszyna i jestem pewien, że włożono w nią wiele godzin czarodzieja :).
6

Możliwe jest (jeśli jest to uciążliwe) pisanie bezpośredniego kodu maszynowego. Może zapisujesz program w asemblerze na kawałku papieru, a następnie tłumaczysz go ręcznie na instrukcje numerycznego kodu maszynowego, które wprowadzasz do pamięci maszyny. Możesz nawet pominąć krok asemblera na papierze, jeśli zapamiętałeś wartości liczbowe wszystkich instrukcji kodu maszynowego - nierzadko w tych dniach, wierz lub nie!

Pierwsze komputery były programowane bezpośrednio w systemie binarnym poprzez przełączanie fizycznych przełączników. To była wielka poprawa wydajności, gdy sprzęt ewoluował, aby pozwolić programistowi (lub asystentowi wprowadzania danych) wprowadzać kod w liczbach szesnastkowych za pomocą klawiatury!

Asembler oprogramowania stał się istotny tylko wtedy, gdy stała się dostępna większa pamięć (ponieważ kod asemblera zajmuje więcej miejsca niż surowy kod maszynowy) i sprzęt ewoluował, aby umożliwić wprowadzanie alfanumeryczne. Tak więc pierwsze asemblery zostały napisane bezpośrednio przez osoby biegle posługujące się kodem maszynowym.

Gdy masz asembler, możesz napisać kompilator dla języka wyższego poziomu w asemblerze.

Historia dla C ma wiele kroków. Pierwszy kompilator C został napisany w B (poprzednik C), który z kolei został napisany w BCPL. BCPL jest dość prostym językiem (na przykład w ogóle nie ma typów), ale wciąż jest o krok od surowego asemblera. Widzisz więc, jak stopniowo coraz bardziej skomplikowane języki są budowane w prostszych językach aż do asemblera. A samo C jest dość małym i prostym językiem według dzisiejszych standardów.

Dzisiaj pierwszy kompilator nowego języka jest często pisany w C, ale kiedy język osiąga pewną dojrzałość, często jest przepisywany „sam w sobie”. Pierwszy kompilator Java został napisany w C, ale później przepisany w Javie. Pierwszy kompilator C # został napisany w C ++, ale ostatnio został przepisany w C #. Kompilator / interpreter języka Python jest napisany w języku C, ale projekt PyPy jest próbą przepisania go w języku Python.

Jednak nie zawsze jest możliwe napisanie kompilatora / tłumacza dla języka w samym języku. Istnieje interpreter JavaScript napisany w JavaScript, ale kompilatory / interpretatory w obecnych przeglądarkach są nadal napisane w C lub C ++ ze względu na wydajność. JavaScript napisany w JavaScript jest po prostu zbyt wolny.

Ale nie musisz używać C jako „języka początkowego” kompilatora. Pierwszy kompilator F # został napisany w OCaml, który jest drugim językiem najbardziej zbliżonym do F #. Gdy kompilator został ukończony, został przepisany w języku F #. Pierwszy kompilator dla Perla 6 został napisany w Haskell (czysty język funkcjonalny bardzo różny od Perla), ale teraz ma kompilator napisany w C.

Ciekawym przypadkiem jest Rust, gdzie pierwszy kompilator został napisany w OCaml (teraz jest napisany w Rust). Jest to godne uwagi, ponieważ OCaml jest ogólnie uważany za wyższy poziom niż Rust, który jest językiem systemów zbliżonych do metalu. Dlatego nie zawsze języki wyższego poziomu są implementowane w językach niższego poziomu, może być też na odwrót.

JacquesB
źródło
3

Zakładając, że zaczynasz z kompletnym zestawem instrukcji i niczym innym, zaczniesz od utworzenia minimalnego , ledwie funkcjonalnego asemblera lub kompilatora, który może załadować plik, przeanalizować minimalny podzbiór języka docelowego i wygenerować plik wykonywalny plik jako wynik, pisząc surowy kod maszynowy za pomocą edytora szesnastkowego lub podobnego.

Następnie użyłbyś tego ledwo funkcjonalnego kompilatora lub asemblera do zaimplementowania nieco bardziej wydajnego kompilatora lub asemblera, który może rozpoznać większy podzbiór języka docelowego. Spłukuj, spłucz, powtórz, aż uzyskasz końcowy produkt.

John Bode
źródło
2

Jak się wydaje, nie jest to takie trudne. W dzieciństwie;) Miałem na myśli demontaż x86.

Nawet nie musisz się tego specjalnie uczyć. Tak się dzieje, gdy jesteś w stanie programować w ASM, a następnie próbować naprawić plik binarny innej firmy za pomocą interaktywnych deasemblerów. Lub podczas pisania własnej ochrony z szyfrowaniem kodu.

To znaczy, że czasami migrujesz nawet z języka na kody, nic dziwnego.

Pavel Koryagin
źródło
1

Pierwsze kompilatory zostały zaimplementowane przy użyciu języka asemblera. A pierwsze asemblery zostały zaimplementowane przez programowanie programów w binarnym ...


Nie tak dawno temu programowanie binarne było nadal umiejętnością, z której ludzie korzystali.

Gdy byłem studentem, pamiętam ćwiczenie programistyczne, które polegało na napisaniu małego programu w PDP-8 (tak mi się wydaje), wprowadzeniu go za pomocą przełączników na panelu przednim i uruchomieniu go. Kilka lat później kupiłem sobie zestaw do programowania systemu 6502, który miał sześciokątną klawiaturę do wprowadzania programów ... i 4k bajtów pamięci RAM.

Stephen C.
źródło
-3

BARDZO PROSTA ODPOWIEDŹ Załóżmy, że piszemy program przewodowy i przechowujemy go w pamięci ROM. Można to uznać za kompilator. Chcę po prostu powiedzieć, że pierwszy kompilator był podłączony na stałe. W miarę udoskonalania technologii te proste kompilatory były następnie używane do pisania kompilatorów wysokiego poziomu.

DINOTOPO
źródło