Perché il primo compilatore è stato scritto prima del primo interprete?

72

Il primo compilatore è stato scritto da Grace Hopper nel 1952 mentre l'interprete Lisp è stato scritto nel 1958 dallo studente di John McCarthy Steve Russell. Scrivere un compilatore sembra un problema molto più difficile di un interprete. Se è così, perché il primo compilatore è stato scritto sei anni prima del primo interprete?

    
posta anguyen 28.07.2014 - 15:19
fonte

10 risposte

97

Writing a compiler seems like a much harder problem than an interpreter.

Potrebbe essere vero oggi, ma direi che non era il caso di circa 60 anni fa. Alcuni motivi per cui:

  • Con un interprete, devi conservare sia esso che il programma in memoria. In un'epoca in cui 1kb di memoria era un lusso enorme, mantenere l'impronta di memoria in esaurimento era la chiave. E l'interpretazione richiede un po 'più di memoria rispetto all'esecuzione di un programma compilato.
  • Le moderne CPU sono estremamente complesse con enormi cataloghi di istruzioni. Quindi scrivere un buon compilatore è davvero una sfida. Le vecchie CPU erano molto più semplici, quindi anche la compilazione era più semplice.
  • I linguaggi moderni sono molto più complessi dei vecchi linguaggi, quindi anche i compilatori sono molto più complessi. I vecchi linguaggi avrebbero quindi compilatori più semplici.
risposta data 28.07.2014 - 15:27
fonte
42

Il punto fondamentale è che l'ambiente di calcolo degli anni '50 lo rendeva tale che solo un compilatore era fattibile data l'elaborazione batch-oriented dei computer.

All'epoca le migliori interfacce utente erano principalmente limitate alle schede perforate e alle stampanti telescriventi . Nel 1961 il sistema SAGE divenne il primo Display Cathode-Ray Tube (CRT) su un computer. Quindi la natura interattiva di un interprete non era preferibile o naturale fino a molto più tardi.

Numerosi computer negli anni '50 usavano gli interruttori del pannello frontale per caricare le istruzioni, e l'uscita era semplicemente righe di lampade / LED, e gli hobbisti persino usavano gli interruttori e gli amplificatori del pannello anteriore. LED negli anni '70. Forse hai familiarità con il famigerato Altair 8800 .

Altre limitazioni hardware hanno reso gli interpreti non fattibili. C'era l'estrema disponibilità limitata di memoria primaria (ad es. RAM) nei computer negli anni '50. Prima del circuito integrato dei semiconduttori (che non arrivò fino al 1958) la memoria era limitata alla memoria di memoria magnetica oppure memoria della linea di ritardo misurata in bit o parole , nessun prefisso Combinato con la lentezza della memoria di archiviazione secondaria (ad esempio disco o nastro), sarebbe considerato uno spreco, se non impossibile da avere molta della memoria utilizzata per l'interprete, anche prima che il programma da interpretare fosse caricato.

I limiti di memoria erano ancora un fattore importante quando il team guidato da John Backus in IBM ha creato il compilatore FORTRAN nel 1954-57. Questo innovativo compilatore ha avuto successo solo perché era un ottimizzatore del compilatore .

La maggior parte dei computer negli anni '50 aveva a malapena il sistema operativo , per non parlare delle funzionalità moderne come il collegamento dinamico e la gestione della memoria virtuale, quindi l'idea di un interprete era troppo radicale e poco pratica in quel momento .

Addendum

Le lingue degli anni '50 erano primitive. Includevano solo una piccola manciata di operazioni, spesso influenzate dalle istruzioni dell'hardware sottostante o dalla definizione del problema del loro uso mirato.

A quei tempi, i computer erano raramente computer generici nel senso che oggi pensiamo ai computer. Il fatto che fossero riprogrammabili senza dover essere ricostruiti era considerato un concetto rivoluzionario - in precedenza le persone utilizzavano macchine elettromeccaniche (tipicamente calcolatrici) per calcolare o calcolare le risposte (la maggior parte delle applicazioni negli anni '50 erano numeriche in la natura).

Dal punto di vista dell'Informatica, i compilatori e gli interpreti sono entrambi traduttori e sono approssimativamente uguali nella complessità da implementare.

    
risposta data 28.07.2014 - 17:32
fonte
12

I primi linguaggi di programmazione erano abbastanza semplici (nessuna ricorsione per esempio) e vicino all'architettura della macchina che era di per sé semplice. La traduzione era quindi un processo semplice .

Un compilatore era più semplice di un programma che un interprete dovrebbe tenere insieme entrambi i dati per l'esecuzione del programma e le tabelle per interpretare il codice sorgente. E l'interprete lo farebbe prendi più spazio , per se stesso, per il codice sorgente del programma e per il simbolico tabelle.

La memoria potrebbe essere così scarsa (sia per ragioni di costo che di architettura) i compilatori potrebbero essere programmi standalone che hanno sovrascritto il file sistema operativo (ho usato uno di questi). Il sistema operativo doveva essere ricaricato dopo la compilazione per eseguire il programma compilato. ... che fa chiarisci che l'esecuzione di un interprete per il lavoro reale non era semplicemente un'opzione .

Per essere vero, la semplicità richiesta ai compilatori era tale i compilatori non erano molto bravi (l'ottimizzazione del codice era ancora in tenera età, se considerata affatto). Il codice macchina scritto a mano aveva, almeno fino alla fine degli anni '60 in alcuni luoghi, la reputazione di essere significativamente più efficiente del codice generato dal compilatore. C'era persino un concetto di rapporto di espansione del codice , che confrontava le dimensioni di codice compilato per il lavoro di un ottimo programmatore. Di solito era maggiore di 1 per la maggior parte dei compilatori (tutti?), il che significava programmi più lenti e, molto più importante, programmi più grandi richiedono più memoria. Questo era ancora un problema negli anni sessanta.

L'interesse del compilatore era nella facilità di programmazione, specialmente per gli utenti che non erano esperti di informatica, come gli scienziati in vari campi. Questo interesse non era il rendimento del codice. Ma ancora, programmatore il tempo è stato quindi considerato una risorsa economica. Il costo era nel computer tempo, fino al 1975-1980, quando il costo passò dall'hardware a Software. Ciò significa che anche i compilatori non sono stati presi seriamente in considerazione alcuni professionisti .

L'altissimo costo del tempo del computer era ancora un altro motivo interpreti squalificatori , al punto che l'idea stessa avrebbe avuto stato ridicolo per la maggior parte delle persone.

Il caso di Lisp è molto speciale, perché era estremamente semplice linguaggio che lo ha reso fattibile (e il computer era diventato un po ' più grande in 58). Ancora più importante, l'interprete Lisp era una prova di concetto riguardo all'autodeterminabilità di Lisp ( meta-circolarità ), indipendentemente da qualsiasi problema dell'usabilità.

Il Lisp successo è dovuto in gran parte al fatto che questa auto-definizione lo ha reso un ottimo banco di prova per studiare strutture di programmazione e progettare nuovi lingue (e anche per la sua convenienza per il calcolo simbolico).

    
risposta data 28.07.2014 - 18:29
fonte
4

Non sono d'accordo con la premessa della domanda.

Adm. Il primo compilatore di Hopper (l'A-0) era più simile a un linker o a un linguaggio macro. Ha memorizzato le subroutine su un nastro (a ciascuna assegnato un numero) e i suoi programmi sarebbero stati scritti come un elenco di subroutine e argomenti. Il compilatore copiava le subroutine richieste dal nastro e le riordinava in un programma completo.

Ha utilizzato la parola "compile" nello stesso senso in cui compila un'antologia di poesie: raccoglie vari elementi in un unico volume.

Il primo compilatore non aveva un lexer o un parser, per quanto ne so io, il che lo rende un lontano antenato di un compilatore moderno. In seguito creò un altro compilatore (il B-0, alias FLOW-MATIC) con l'obiettivo di una sintassi più simile all'inglese, ma non fu completato fino al 1958 o 1959 - all'incirca nello stesso periodo dell'interprete Lisp.

Pertanto, penso che la domanda in sé sia un po 'sbagliata. Sembra che compilatori e interpreti si siano evoluti quasi esattamente allo stesso tempo, senza dubbio a causa della condivisione di idee che avrebbero avuto molti scienziati a riflettere sulla stessa linea in quei giorni.

Una risposta migliore con le citazioni qui: link .

    
risposta data 10.11.2014 - 15:49
fonte
3

L'altra parte dell'equazione è che i compilatori erano un'astrazione passo sopra un assemblatore. Prima avevamo il codice macchina hard-coded. "Noi" eravamo l'assemblatore. Ogni salto e offset, ecc. È stato calcolato a mano in esadecimale (o ottale) e poi perforato in un nastro di carta o carte. Quindi, quando gli assemblatori sono entrati in scena, è stato un enorme risparmio di tempo. Il passo successivo furono i macro assemblatori. Ciò ha dato la possibilità di scrivere una macro che si espanderebbe in una serie di istruzioni della macchina. Quindi Fortran e Cobol sono stati un enorme passo avanti. La mancanza di risorse (cicli di archiviazione, memoria e cpu) significava che gli interpreti di scopo generale dovevano aspettare che la tecnologia crescesse. La maggior parte dei primi interpreti erano motori di codici byte (come Java o CLR di oggi, ma con capacità molto inferiori). UCSD Pascal era un linguaggio molto popolare (e veloce). MS Basic era un motore byte-code sotto il cofano. Quindi la "compilazione" era in realtà per generare un flusso di codice byte che è stato effettivamente eseguito dal runtime.

In termini di overhead delle istruzioni, dipendeva totalmente da quale processore veniva eseguito. L'industria ha attraversato un grande tumulto RISC e CISC per un po '. Ho personalmente scritto un assemblatore per IBM, Data General, Motorola, Intel (quando si presentarono), TI e molti altri. C'era una differenza abbastanza significativa in insiemi di istruzioni, registri, ecc. Che avrebbe influenzato ciò che era necessario per "interpretare" un p-code.

Come riferimento temporale, ho iniziato a programmare nella compagnia telefonica intorno al 1972.

    
risposta data 29.07.2014 - 05:53
fonte
2

Se non stai tenendo tutto in memoria, il codice compilato è molto più veloce. Non dimenticare che in questi orari le funzioni sono state unite al codice compilato. Se non stai compilando, non sai quali funzioni ti serviranno. Quindi, stai chiamando funzioni da ... Oh, non da disco ancora, siamo nei primi 50 anni, ma dalle carte! In runtime!

Naturalmente, è possibile trovare soluzioni alternative, ma non sono state ancora trovate, poiché le lingue erano molto semplici e non così lontane dal codice macchina. E la compilazione è stata facile e sufficiente.

    
risposta data 28.07.2014 - 15:49
fonte
1

Prima che fosse scritto il primo compilatore, la gente scriveva il codice assemblatore che era un enorme progresso rispetto al semplice codice binario. A quel tempo, c'era una strong argomentazione sul fatto che il codice compilato da un compilatore sarebbe meno efficiente del codice assembler - in quel momento la relazione tra (costo del computer) e (costo del programmatore) era molto, molto diversa da oggi. Quindi c'era una strong resistenza contro i compilatori da quel punto di vista.

Ma i compilatori sono molto più efficienti degli interpreti. Se avessi suggerito di scrivere un interprete in quel momento, la gente avrebbe pensato che fossi pazzo. Riuscite ad immaginare di comprare un computer da un milione di dollari e poi sprecare il 90% del suo potere per interpretare il codice?

    
risposta data 28.07.2014 - 16:35
fonte
1

Prima che un programma di loop possa essere interpretato, deve essere memorizzato su un supporto che può essere letto ripetutamente. Nella maggior parte dei casi, l'unico supporto adatto sarebbe la RAM. Poiché il codice verrà in genere inserito su schede perforate che, per i linguaggi leggibili dall'uomo, sono probabilmente in gran parte vuote, è necessario eseguire una sorta di elaborazione sul codice prima che venga archiviato nella RAM. In molti casi, l'elaborazione del testo della scheda perforata in un formato adatto all'esecuzione diretta da parte del processore non è in realtà più difficile dell'elaborazione in un formato che potrebbe essere gestito in modo efficiente tramite un interprete.

Si noti che l'obiettivo dei primi compilatori non era quello di produrre un file assembly-language o un codice oggetto su disco, ma piuttosto di finire il codice nella RAM che era pronto per l'esecuzione. Questo è in realtà sorprendentemente facile quando non c'è nessun sistema operativo a mettersi in mezzo. Un compilatore può generare codice a partire da una parte della memoria e allocare variabili e diramazioni che iniziano dall'altra. Se un'istruzione è contrassegnata con l'etichetta "1234", il compilatore memorizzerà nella variabile denominata "1234" un'istruzione per passare all'indirizzo di generazione del codice corrente, creando tale variabile se non esiste. Una dichiarazione "goto 1234" creerà una variabile "1234" se non esiste, e poi salterà a quella variabile [che si spera avrà un salto nella posizione corretta memorizzata in essa prima dell'esecuzione di tale istruzione]. Nota che il compilatore non deve fare nulla di speciale per consentire al codice di goto un'etichetta che non è stata ancora definita, poiché sa quando la goto compila dove sta per saltare - a una variabile. Questo potrebbe non essere il modo più efficiente per generare codice, ma è adeguato per le dimensioni dei programmi che i computer dovevano gestire.

    
risposta data 28.07.2014 - 20:21
fonte
0

Perché gli interpreti hanno bisogno di compilatori per funzionare.

L'affermazione di cui sopra non è proprio vera. A rigor di termini, puoi fare un interprete senza mai usare o altrimenti interagire con un compilatore. Ma il risultato di questo non sarebbe molto simile a quello che penso tu intenda con quei termini.

In senso stretto, i compilatori e gli interpreti fanno cose completamente diverse. Un compilatore legge il testo da una fonte e lo trasforma in un altro formato: linguaggio assembly, codice macchina, un altro linguaggio di alto livello, una struttura dati o qualsiasi altra cosa. Un interprete, nel frattempo, acquisisce una struttura di dati di qualche tipo ed esegue istruzioni basate su di esso.

Ciò che tendiamo a considerare come un "compilatore" al giorno d'oggi è in realtà un compilatore che è stato accoppiato con un generatore di codice : un programma che raccoglie dati da alcuni fonte e output codice in qualche formato in base a ciò che vede. È un uso abbastanza intuitivo per i compilatori ed è stata una delle prime cose in cui sono stati creati i compilatori. Ma se lo guardi in un altro modo, questo sembra molto simile a quello che fa un interprete. Emette sempre codice invece di eseguire operazioni più generali, ma il principio è lo stesso.

Se guardiamo dall'altra parte, un interprete deve ottenere i suoi dati da qualche parte . Questi sono solo dati, quindi puoi crearlo nello stesso modo in cui creerai qualsiasi altro tipo di dati. Dato che stiamo parlando di interpretazione, sembra naturale che tu possa costruire i tuoi dati basandoti sulle istruzioni in un file di testo. Ma per farlo, è necessario qualcosa da leggere nel testo e creare la struttura dei dati, e che è un compilatore . È collegato all'interprete anziché a un generatore di codice, ma è sempre un compilatore.

Ecco perché i compilatori sono stati scritti per primi. L'idea di interpretare le strutture dati non era nuova anche quando i compilatori erano concepiti, ma i compilatori erano il "collegamento mancante" che permetteva ai programmatori di costruire quelle strutture senza testo.

    
risposta data 29.07.2014 - 19:16
fonte
-1

Un altro fattore: quando sono stati scritti i primi compilatori, il costo del tempo della macchina era molto più alto di adesso. Gli interpreti usano molto più tempo della macchina.

    
risposta data 29.07.2014 - 06:47
fonte

Leggi altre domande sui tag