Come sono stati realizzati i primi compilatori?


70

Mi chiedo sempre questo, e forse ho bisogno di una buona lezione di storia sui linguaggi di programmazione. Ma dal momento che la maggior parte dei compilatori al giorno d'oggi sono realizzati in C, come sono stati realizzati i primi compilatori (AKA prima di C) o sono state interpretate tutte le lingue?

Detto questo, non capisco ancora come sia stato fatto anche il primo linguaggio assembly, capisco cos'è il linguaggio assembly ma non vedo come abbiano fatto funzionare il MOLTO primo linguaggio assembly (come, come hanno fatto il primo comandi (come mov R21) o impostato sull'equivalente binario?


9
C'era una volta un programmatore comicamente inetto nella mia squadra, dove tutto ciò che faceva era lamentarsi di C #. Scherzavamo su un linguaggio immaginario che ha inventato chiamato Crunk. Un fatto poco noto su Crunk, è la prima lingua in cui il compilatore è stato scritto ANCHE in Crunk. :)
maple_shaft

2
Perché qualcuno dovrebbe lamentarsi di C #? non ha mai usato smalltalk o Lisp? lol

2
possibile duplicato del compilatore C e Dennis Ritchie
vartec,

4
@maple_shaft: ad essere onesti, il compilatore gcc è scritto in C . Questo in realtà non è un problema se hai un buon compilatore incrociato per compilare la prima versione. Il primo compilatore C, ovviamente, doveva essere scritto in un'altra lingua.
Scott Whitlock,

Risposte:


89

Ah, l'ho fatto. Molte CPU hanno semplici istruzioni di dimensioni fisse lunghe solo un paio di byte. Per una CPU semplice come un Motorola 6800, ad esempio, potresti adattare tutte le sue istruzioni su un singolo foglio di carta . Ogni istruzione avrebbe un codice operativo a due byte associato e argomenti. È possibile assemblare manualmente un programma cercando il codice operativo di ciascuna istruzione. Dovresti quindi scrivere il tuo programma su carta , annotando ogni istruzione con il suo codice operativo corrispondente. Dopo aver scritto il programma, è possibile masterizzare ciascun codice operativo in sequenza su una EPROMche quindi memorizzerebbe il tuo programma. Collega la EPROM alla CPU con le giuste istruzioni agli indirizzi giusti e avrai un semplice programma di lavoro. E per rispondere alla tua prossima domanda, sì. È stato doloroso (lo abbiamo fatto al liceo). Ma devo dire che il cablaggio di ogni chip in un computer a 8 bit e la scrittura manuale di un programma mi hanno dato una comprensione approfondita dell'architettura del computer che probabilmente non avrei potuto ottenere in altro modo.

I chip più avanzati (come x86) sono molto più difficili da codificare a mano, perché spesso hanno istruzioni a lunghezza variabile. Processori VLIW / EPIC come Itanium sono quasi impossibili da scrivere a mano in modo efficiente perché gestiscono pacchetti di istruzioni che sono ottimizzati e assemblati da compilatori avanzati. Per le nuove architetture, i programmi vengono quasi sempre scritti e assemblati prima su un altro computer, quindi caricati nella nuova architettura. Infatti, per aziende come Intel che realizzano effettivamente CPU, possono eseguire programmi reali su architetture che non esistono ancora eseguendole su simulatori. Ma sto divagando ...

Per quanto riguarda i compilatori, nella loro forma più semplice, possono essere poco più che programmi "taglia e incolla". Potresti scrivere un "linguaggio di alto livello" molto semplice, non ottimizzante, che raggruppa semplicemente semplici istruzioni per il linguaggio assembly senza un grande sforzo.

Se vuoi una storia di compilatori e linguaggi di programmazione, ti suggerisco GOTO una storia di FORTRAN .


27
. . . e non dovrebbe essere "... ti suggerisco JMP di una storia ..."
Binary Worrier,

2
Mi dispiace davvero tanto. Ma dovevo. Ho solo ... avuto. a ...
Dave Markle il

9
@Dave: ti rendi conto di essere condannato a morte da Velociraptor ?
Binary Worrier,

7
"Sapevano" perché erano letteralmente cablati per eseguire quell'operazione quando videro un segnale 101010100 per una determinata istruzione. In realtà hanno un'unità on-chip responsabile delle istruzioni di decodifica delle istruzioni: en.wikipedia.org/wiki/Decoder
Dave Markle

7
Vale la pena aggiungere: il compilatore per una nuova lingua, quando è scritto nella stessa nuova lingua, è talvolta compilato con un "proto-compilatore" scritto in un'altra lingua che produce un codice dimostrabilmente corretto, ma orribilmente inefficiente. Una volta compilato, viene quindi eseguito su se stesso per produrre un compilatore ragionevolmente veloce. Confronta Von Neumann Machine. : D
BMDan

54

Questo è il bootstrap del compilatore (dal momento che nessuno ha menzionato come si chiama =).

il processo di scrittura di un compilatore (o assemblatore) nel linguaggio di programmazione di destinazione che si intende compilare. L'applicazione di questa tecnica porta a un compilatore self-hosting.

Molti compilatori per molti linguaggi di programmazione vengono avviati, inclusi compilatori per BASIC, ALGOL, C, Pascal, PL / I, Factor, Haskell, Modula-2, Oberon, OCaml, Common Lisp, Scheme, Java, Python, Scala e altro ancora. .

Il problema di pollo e uova

Se uno ha bisogno di un compilatore per la lingua X per ottenere un compilatore per la lingua X (che è scritto nella lingua X), come è stato scritto il primo compilatore? I possibili metodi per risolvere questo problema con l'uovo o la gallina includono:

  • Implementare un interprete o un compilatore per la lingua X in lingua Y. Niklaus Wirth ha riferito di aver scritto il primo compilatore Pascal a Fortran.
  • Un altro interprete o compilatore per X è già stato scritto in un'altra lingua Y; questo è il modo in cui Scheme viene spesso avviato.
  • Versioni precedenti del compilatore erano scritte in un sottoinsieme di X per il quale esisteva qualche altro compilatore; questo è il modo in cui alcuni superset di Java, Haskell e il compilatore iniziale Free Pascal vengono avviati.
  • Il compilatore per X è compilato in modo incrociato da un'altra architettura in cui esiste un compilatore per X; questo è il modo in cui i compilatori per C vengono generalmente trasferiti su altre piattaforme. Anche questo è il metodo usato per Free Pascal dopo il bootstrap iniziale.
  • Scrivere il compilatore in X; quindi compilandolo manualmente dal sorgente (molto probabilmente in modo non ottimizzato) ed eseguendolo sul codice per ottenere un compilatore ottimizzato. Donald Knuth lo usò per il suo sistema di programmazione letterato WEB ...

Buon link che ti porta anche su en.wikipedia.org/wiki/History_of_compiler_writing . In generale, penso che i compilatori originali siano stati scritti in Assembly Language ( en.wikipedia.org/wiki/Assembly_language ). Solo più tardi è nata l'idea di bootstrap o self-hosting.
Michael Levy,

1
+1 FINALMENTE! Strano che questa sia solo la terza risposta più votata. Sì, avvio automatico. Questa è la risposta
Adam Rackis, il

15

Alla fine tutti i computer funzionano con codici binari, che vengono inseriti nella CPU. Questi codici binari sono perfettamente naturali per una CPU, ma anche perfettamente inutili per gli esseri umani. Uno dei primi modi per scrivere un programma è stato quello di fare buchi nelle carte. La posizione dei fori rappresentava una posizione di bit particolare all'interno di una parola e la presenza o l'assenza del foro veniva interpretata come zero o uno. Queste carte sono state messe nella giusta sequenza in una scatola e quindi inserite in un lettore di carte, che le ha effettivamente convertite in codice binario per la CPU (e la tua vita è stata effettivamente persa se hai lasciato cadere la scatola).

Ovviamente i primi programmatori hanno elaborato i codici binari uno per uno e avevano una macchina per perforare le carte. Questa è essenzialmente la programmazione del linguaggio assembly su mani e ginocchia. Una volta che lo hai, puoi creare tutto il resto da esso: un semplice editor di testo, un compilatore di linguaggio assembly (per convertire le istruzioni di assembly di testo in codici binari), un linker e un caricatore. E il resto, come si suol dire, è storia.


4
Prima delle carte avevi un set di interruttori per l'indirizzo, un set per la parola dati e un interruttore per caricare i dati. È stato programmato singolarmente ciascun indirizzo di memoria impostando gli interruttori di indirizzo e dati con la rappresentazione binaria e azionando e disattivando l'interruttore di caricamento. Ci sono voluti anni ma il programma era lungo solo poche parole - allora i byte non erano stati inventati.
uɐɪ

4
... E prima, dovevi ricollegarlo . Funfunfun!
Michael K,

Sì, ma quando dovevi farlo, non era proprio quello che penseremmo come un computer moderno, poiché l'architettura Von Neumann non era ancora stata inventata.
Dave Markle,

7

Un piccolo googling rivela gli ordini iniziali di EDSAC dalla fine degli anni '40. Poiché è stato il primo assemblatore, è stato probabilmente codificato in linguaggio macchina.

Più tardi arrivarono assemblatori per altre macchine, come SOAP I e II per IBM 650. SOAP Anche io ero probabilmente codificato in linguaggio macchina, anche se non ho trovato la dichiarazione definitiva.

Poco dopo è arrivato Fortran (traduttore di formula), per l'IBM 704. Presumibilmente è stato scritto in assemblatore per il 704. Un primo assemblatore per il 701 è accreditato a Nathan Rochester .

Se vuoi avere un'idea di come programmare un computer in linguaggio macchina, dai un'occhiata a uno dei miei siti preferiti, il computer di inoltro di Harry Porter .


Merda, il computer di casa Harry Porter (quasi detto harry potter lol) è FANTASTICO. Vorrei aver capito come è stato costruito qualcosa del genere :(.

1
@Sauron: Harry Porter non vorrebbe niente di meglio che dirtelo. Su quella pagina ha un powerpoint meravigliosamente realizzato che spiega tutto. Presuppone alcune conoscenze di base sui circuiti, ma non è troppo difficile da ottenere.
Mike Dunlavey,

So che sto solo scherzando ^ _ ^, a prescindere dal fatto che sia una macchina davvero impressionante e sono sicuro che ci sono state molte ore da mago :).

6

È possibile (se noioso) scrivere il codice macchina diretto. Forse scrivi il programma nell'assemblatore su un pezzo di carta, e poi lo traduci a mano nelle istruzioni numeriche del codice macchina che inserisci nella memoria della macchina. Puoi anche saltare la fase dell'assemblatore su carta se hai memorizzato i valori numerici di tutte le istruzioni del codice macchina - non insolito in quei giorni, che ci crediate o no!

I primissimi computer sono stati programmati direttamente in binario attivando interruttori fisici. È stato un grande miglioramento della produttività quando l'hardware si è evoluto per consentire al programmatore (o all'assistente per l'immissione dei dati) di inserire il codice in numeri esadecimali tramite una tastiera!

Un assemblatore software è diventato rilevante solo quando è diventata disponibile più memoria (poiché il codice assemblatore occupa più spazio del codice macchina grezzo) e l'hardware si è evoluto per consentire l'input alfanumerico. Quindi i primi assemblatori furono scritti direttamente da persone che parlavano perfettamente il codice macchina.

Quando si dispone di un assemblatore, è possibile scrivere un compilatore per un linguaggio di livello superiore in assemblatore.

La storia di C ha più passaggi. Il primo compilatore C è stato scritto in B (un predecessore di C) che a sua volta è stato scritto in BCPL. BCPL è un linguaggio piuttosto semplice (ad esempio non ha alcun tipo), ma è ancora un passo avanti rispetto al raw assembler. Quindi vedi come gradualmente lingue più complesse vengono costruite in lingue più semplici fino all'assemblatore. E stesso C è un linguaggio piuttosto piccolo e semplice per gli standard odierni.

Oggi, il primo compilatore per una nuova lingua è spesso scritto in C, ma quando la lingua raggiunge una certa maturità viene spesso riscritta "in sé". Il primo compilatore Java è stato scritto in C, ma in seguito riscritto in Java. Il primo compilatore C # è stato scritto in C ++, ma recentemente è stato riscritto in C #. Il compilatore / interprete Python è scritto in C, ma il progetto PyPy è un tentativo di riscriverlo in Python.

Tuttavia, non è sempre possibile scrivere un compilatore / interprete per una lingua nella lingua stessa. Esiste un interprete JavaScript scritto in JavaScript, ma i compilatori / interpreti nei browser attuali sono ancora scritti in C o C ++ per motivi di prestazioni. JavaScript scritto in JavaScript è semplicemente troppo lento.

Ma non devi usare C come "lingua iniziale" per un compilatore. Il primo compilatore F # è stato scritto in OCaml, che è l'altra lingua che è più strettamente correlata a F #. Quando il compilatore è stato completato, è stato riscritto in F #. Il primo compilatore per Perl 6 è stato scritto in Haskell (un linguaggio funzionale puro molto diverso dal Perl) ma ora ha un compilatore scritto in C.

Un caso interessante è Rust, in cui il primo compilatore è stato scritto in OCaml (ora è stato riscritto in Rust). Ciò è notevole perché OCaml è generalmente considerato di livello superiore rispetto a Rust, che è un linguaggio di sistemi più vicino al metallo. Quindi non sono sempre linguaggi di livello superiore implementati in linguaggi di livello inferiore, ma potrebbe anche essere il contrario.


3

Supponendo che tu stia iniziando con un set di istruzioni non elaborato e nient'altro, inizieresti creando un assemblatore o un compilatore minimo e appena funzionale che può caricare un file, analizzare un sottoinsieme minimo della lingua di destinazione e generare un eseguibile file come output, scrivendo il codice macchina grezzo utilizzando un editor esadecimale o simile.

Utilizzeresti quindi quel compilatore o assemblatore appena funzionante per implementare un compilatore o un assemblatore leggermente più capace in grado di riconoscere un sottoinsieme più ampio della lingua di destinazione. Raccogliere, sciacquare, ripetere fino a quando non si ottiene il prodotto finale.


2

Non è così difficile, come sembra. Nell'infanzia;) Ho fatto un po 'di smontaggio x86 in mente.

Non hai nemmeno bisogno di impararlo in particolare. Accade solo quando sei in grado di programmare in ASM e poi cerchi di riparare un binario di terze parti usando i disassemblatori interattivi. O quando si scrive la propria protezione con la crittografia del codice.

Cioè a volte stai migrando anche dalla lingua ai codici senza meraviglia.


1

I primi compilatori sono stati implementati usando il linguaggio assembly. E i primi assemblatori sono stati implementati da programmi di codifica in binario ...


Non è molto tempo fa che la programmazione in binario era ancora un'abilità che la gente usava.

Quando ero un laureando, ricordo di aver fatto un esercizio di programmazione che prevedeva la scrittura di un piccolo programma nel codice macchina PDP-8 (credo), inserendolo tramite gli interruttori del pannello frontale ed eseguendolo. Un paio di anni dopo, mi sono comprato un kit di sviluppo del sistema 6502 che aveva una tastiera esadecimale per accedere ai programmi ... e 4k byte di RAM.


-3

UNA RISPOSTA MOLTO SEMPLICE Supponiamo di scrivere un programma cablato e di memorizzarlo nella ROM. Può essere considerato come compilatore. Quindi voglio semplicemente dire che il primo compilatore era cablato. Man mano che la tecnologia migliorava, questi semplici compilatori venivano quindi utilizzati per scrivere compilatori di alto livello.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.