Perché i compilatori self-hosting sono considerati un rito di passaggio per le nuove lingue?


30

Ho sentito in diversi posti ora che le persone si aspettano che le lingue utilizzino, o almeno abbiano, un compilatore self-hosting per meritare rispetto.

Sono curioso di sapere perché. Un compilatore sembra un software molto significativo da scrivere e immagino che non tutte le lingue siano adatte alla loro creazione. Non avrebbe più senso dedicare lo sforzo a lavorare su qualcosa che dia risultati migliori?


17
"Un compilatore sembra un software molto significativo da scrivere e immagino che non tutte le lingue siano adatte alla loro creazione.": Considero questo un ottimo motivo per provare a scrivere un compilatore in una nuova lingua, vale a dire per dimostrare che la lingua è all'altezza del compito.
Giorgio,

13
A meno che non sia un linguaggio per scopi speciali, un linguaggio in cui non è adatto scrivere un compilatore probabilmente non è adatto a quello che voglio fare.
CodesInChaos,

3
AFAIK, questo non è sempre vero per Fortran. Diversi compilatori Fortran (ad es. gfortranDa GCC ...) non sono codificati in Fortran.
Basile Starynkevitch,

Risposte:


29

Non avrebbe più senso dedicare lo sforzo a lavorare su qualcosa che dia risultati migliori?

Tipo cosa?

La cosa bella dei compilatori è che non hanno molte dipendenze. Questo li rende buoni candidati per una nuova lingua che probabilmente non ha ancora una libreria standard molto ampia o diversificata.

Meglio ancora, richiedono una varietà di cose, pur essendo ben studiate. La varietà aiuta a verificare che il tuo esempio verifichi varie parti della lingua. Essere ben studiati significa che hai altri compilatori con cui confrontare - oltre a dare più credibilità ai tipi accademici che sai cosa stai facendo.

E mentre i compilatori sembrano un sacco di lavoro, sono piuttosto piccoli nel grande schema delle cose. Se gli implementatori di lingue non possono nemmeno fare qualcosa che hanno già fatto nella nuova lingua, come faranno cose nuove? Come gestiranno le cose veramente grandi come le librerie standard o un IDE?


Proprio come nota a margine, vorrei ricordare che, nonostante sia bello, ci sono ancora una serie di ragioni per cui un compilatore potrebbe essere scritto in un'altra lingua. Ad esempio, la maggior parte dei motori javascript non sono scritti in javascript. Ci sono molte ragioni per questo: integrazione con altri software, collegamento a librerie / dipendenze esistenti, strumenti superiori, prestazioni, codice legacy ... A volte, l'auto-compilazione del linguaggio è buona, ma ha ancora senso mantenere il compilatore principale in un altro. Tuttavia, il linguaggio da solo ha senso. È solo che di solito non puoi permetterti di riqualificare un intero ecosistema.
Dagnelies,

2
@arnaud E il fatto che un compilatore Javascript richiederebbe un ambiente Javascript, che non può essere scritto in Javascript perché Javascript richiede un ambiente Javascript, <ripeti paradossalmente> , perché un ambiente Javascript non è fornito dal sistema operativo (e se era, non sarebbe stato scritto in Javascript).
Qix

3
@Qix en.wikipedia.org/wiki/Bootstrapping_%28compilers%29 Ma principalmente non c'è motivo di usarlo. È ampiamente noto come un linguaggio scadente, i browser evitano di usarlo per la compilazione perché hanno il controllo della situazione :), mentre il resto di noi non ha scelta sul web.
Den,

3
Non sono così sicuro dell'affermazione "non avere molte dipendenze". Questo potrebbe essere vero per il front-end del compilatore . Ma non appena hai un AST, girare il tuo ottimizzatore e generatore di codice non sembra un percorso promettente. A parte il fatto che le moderne tecniche di ottimizzazione richiedono sofisticati motori logici formali per i quali si potrebbe desiderare di utilizzare una libreria di terze parti, non c'è motivo di reinventare la ruota per ogni nuovo linguaggio invece di basarsi su una base di forza del settore come GCC o LLVM.
5gon12eder,

30

L'obiettivo di avere un compilatore nella lingua che viene compilata fa spesso parte della pratica di " mangiare il proprio cibo per cani ". Dimostra al mondo che consideri il linguaggio, il compilatore e l'ecosistema di moduli e strumenti di supporto come "abbastanza buono per un lavoro serio" o "pronto per la produzione".

Ha anche l'effetto virtuoso di forzare le persone più vicine al linguaggio, al compilatore e al design di runtime per affrontare direttamente gli effetti di tutte le decisioni che hanno preso e le priorità di sviluppo che hanno scelto: le verruche e tutto il resto. Ciò porta spesso a un gruppo centrale che non solo comprende l'ambiente linguistico in teoria, ma che ha una vasta esperienza pratica nell'uso del linguaggio / degli strumenti nel crogiolo di condizioni difficili, di parole reali.


1
per completezza: mangiare il proprio cibo per cani ; vedere dog fed (agg.) o dogfooding (verbo)
Qix

17

Le persone creano nuove lingue di uso generale per un motivo principale: odiano almeno una cosa su ogni altra lingua là fuori. Ecco perché così tante lingue non escono da terra. Hai una grande idea per un linguaggio che migliorerebbe la tua vita di programmazione, ma devi fare la prima implementazione in un linguaggio che ti infastidisce in almeno un modo. Self-hosting significa che non devi più lavorare in quel vecchio linguaggio fastidioso. Ecco perché i creatori di una lingua lavorano per quel passo e lo vedono come una pietra miliare importante.

Molte funzionalità linguistiche sembrano buone sulla carta, ma quando si arriva a usarle in un progetto reale, si iniziano a vedere i loro limiti. Per un esempio, molte lingue non hanno inizialmente un supporto unicode decente. Il completamento di un grande progetto aiuta a garantire che molte di queste situazioni siano state affrontate e affrontate e che un compilatore self-hosting sia un progetto valido come un altro. Ecco perché le persone diverse dai creatori della lingua lo vedono come una pietra miliare importante.

Ciò non significa che sia l' unica pietra miliare degna di nota. Esistono funzionalità che non sono esercitate da un compilatore, come l'integrazione del database, interfacce grafiche, reti, ecc.


Sento che una lingua (nativa) è una lingua in cui può compilare se stessa e un kernel Linux può essere portato su di essa (dal momento che comprende la maggior parte / tutti i compiti necessari per far funzionare la maggior parte dei sistemi operativi moderni).
Qix

Tuttavia, non è necessario un supporto Unicode decente per scrivere un compilatore.
Paŭlo Ebermann,

11

Steve Yegge ha scritto un ottimo post sul blog che, indirettamente, affronta questo problema.

Punto 1 n. 1: i compilatori comprendono praticamente ogni aspetto dell'informatica. Sono un corso di livello superiore perché per iniziare devi conoscere tutte le altre cose che impari nel curriculum di informatica. Strutture dati, ricerca e ordinamento, prestazioni asintotiche, colorazione grafica? È tutto lì dentro.

C'è una ragione per cui Knuth ha lavorato sul suo monumentale (e senza fine) "Art of Computer Programming" per diversi decenni, anche se è iniziato come (solo) un libro di testo per compilatori. Allo stesso modo in cui Carl Sagan disse "Se vuoi fare una torta di mele da zero, devi prima inventare l'universo", se vuoi scrivere un compilatore, devi prima occuparti di quasi ogni aspetto dell'informatica.

Ciò significa che se il compilatore è auto-ospitato, allora è abbastanza sicuro di essere in grado di fare ciò di cui ho bisogno, indipendentemente da ciò che sto facendo. Al contrario, se non hai scritto un compilatore nella tua lingua, c'è una buona probabilità che manchi qualcosa di veramente importante per qualcuno, perché gli implementatori del linguaggio non hanno mai dovuto scrivere un programma che richiedesse loro di pensare a tutti quei problemi.

Grande punto n. 2: da 30.000 piedi, un numero sorprendente di problemi sembra proprio un compilatore.

I compilatori prendono un flusso di simboli, determinano la loro struttura secondo alcune regole predefinite specifiche del dominio e li trasformano in un altro flusso di simboli. Sembra abbastanza generale, vero? Bene sì.

Che tu faccia parte o meno del team di Visual C ++, molto spesso ti ritroverai a dover fare qualcosa che assomiglia a un compilatore. Lo faccio letteralmente ogni giorno.

A differenza della maggior parte delle altre professioni, i programmatori non solo usano strumenti, ma costruiscono i propri strumenti. Un programmatore che non è in grado (a causa della mancanza di abilità o della mancanza di strumenti utilizzabili con cui costruire altri strumenti) di scrivere per sempre sarà handicappato, limitato agli strumenti forniti da qualcun altro.

Se una lingua "non è adatta alla creazione" di programmi che possono prendere un flusso di simboli, applicarli a regole e trasformarlo in un altro flusso di simboli, sembra un linguaggio piuttosto limitato e non uno che sarebbe utile per me.

(Fortunatamente, non penso che ci siano molti linguaggi di programmazione inadatti alla trasformazione dei simboli. C è probabilmente tra i peggiori linguaggi in uso oggi, ma i compilatori C sono di solito auto-ospitati, quindi non hanno mai fermato nessuno.)

Un terzo motivo con cui finirò, per esperienza personale, non menzionato da Yegge (perché non stava scrivendo del "perché auto-host"): scuote i bug. Quando si scrive un compilatore, ciò significa ogni volta che lo si crea (non solo ogni volta che lo si esegue ), si dipende da esso per funzionare e funzionare correttamente su una base di codice di dimensioni decenti (il compilatore stesso).

Questo mese ho usato un compilatore non self-hosted relativamente nuovo e famoso (probabilmente puoi indovinare quale), e non posso andare 2 giorni senza segfaultare la cosa. Mi chiedo quanto i designer dovevano effettivamente usarlo.


8

Se vuoi avere un compilatore per il linguaggio X come self-hosting, devi prima implementarlo in un'altra lingua, diciamo Y, in modo tale che richieda input per il linguaggio X e sputi codice assembly, o codice intermedio, o anche codice oggetto per la macchina su cui è in esecuzione il compilatore. Volete scegliere la lingua Y per essere il più simile possibile alla lingua X, poiché ad un certo punto tradurrete il codice scritto da Y a X.

Ma non vuoi scrivere più del compilatore nel linguaggio Y del necessario, quindi, per cominciare, implementi solo un sottoinsieme del linguaggio, eliminando i costrutti ridondanti. Nel caso di un linguaggio di tipo 'C', while ma no for o do while . se ma nessun caso o terziario op. Nessuna struttura o sindacato o enumerazione. Ecc. Quello che ti rimane è la lingua sufficiente per scrivere un parser e un generatore di codice rudimentale per la lingua X. Quindi controlla l'output. Ancora.

Una volta che hai funzionato, puoi riscrivere la fonte del compilatore che è stata scritta nella lingua Y nella lingua X e compilare la fonte della lingua X usando il compilatore scritto nella lingua Y. L'output sarà un nuovo compilatore scritto nella nuova lingua X che compila il linguaggio X, ovvero ora è self-hosting. Tuttavia non è completo poiché hai implementato solo un sottoinsieme della lingua nella lingua Y.

Quindi ora aggiungi le funzionalità mancanti, testando ognuna (o gruppo di funzionalità) che generano il codice corretto. cioè una volta implementata la funzionalità nel compilatore, è possibile scrivere programmi di test utilizzando le nuove funzionalità, compilarle e testarle, ma non è necessario usarle ancora nella fonte del compilatore. Una volta verificate le nuove funzionalità, è possibile utilizzare queste nuove funzionalità nell'origine del compilatore stesso, magari sostituendo parte del codice originale scritto nel sottoinsieme di lingue, ricompilare l'origine del compilatore utilizzando la versione con le nuove funzionalità.

Ora disponi di un meccanismo per aggiungere nuove funzionalità al linguaggio e, una volta verificata la generazione del codice per le funzionalità, queste possono essere utilizzate nella generazione successiva del compilatore stesso.

Circa 60 anni fa, quando i computer arrivarono per la prima volta sulla scena (e più tardi quando arrivarono i microprocessori), non c'erano altre lingue adatte per implementare il compilatore iniziale. Quindi i primi compilatori dovevano essere scritti nel codice assembly, e quindi quando era in esecuzione una parte sufficiente del compilatore, il codice assembly sarebbe stato sostituito dalla versione scritta in una nuova lingua. Neanche un assemblatore? L'intero processore è sceso di un altro livello, con l'assemblatore inizialmente scritto nel codice macchina .


2

È possibile produrre un linguaggio di programmazione che non è ben progettato per scrivere un compilatore ma è ben progettato per qualche altro scopo?

Guardando un linguaggio come SQL suppongo che la risposta sia sì. Ma linguaggi di quella natura non sono scopi generali.


1
Sfidato accettato: scrivere un compilatore C in SQL.
Qix

2

Chi lo dice? ... comunque, è solo un'opinione. Alcuni potrebbero essere d'accordo, altri no, qui non c'è giusto o sbagliato. Alcune lingue hanno compilatori scritti in sé, altri no. Qualunque cosa.

Tuttavia, penso che sia un buon esercizio / prova di concetto se un linguaggio è in grado di "autocompilarsi" ... è solo ... bello ... e dimostra che il linguaggio è adatto a fare cose complesse.

Vorrei anche menzionare che, nonostante sia carino, ci sono ancora molte ragioni per cui un compilatore potrebbe essere scritto in un'altra lingua. Ad esempio, la maggior parte dei motori javascript non sono scritti in javascript. Ci sono molte ragioni per questo: integrazione con altri software, collegamento a librerie / dipendenze esistenti, strumenti superiori, prestazioni, codice legacy ... A volte, l'auto-compilazione del linguaggio è buona, ma ha ancora senso mantenere il compilatore principale in un altro. Tuttavia, il linguaggio da solo ha senso. È solo che di solito non puoi permetterti di riqualificare un intero ecosistema.


2

Clang è scritto in C ++. Non sarebbe troppo difficile riscrivere il compilatore Clang Objective-C in Objective-C, ma sarebbe abbastanza inutile. Qualsiasi modifica nel compilatore C ++ dovrebbe essere rifatta in Objective-C e viceversa. Allora perchè?

Ora c'è un compilatore di Clang Swift. Sicuramente quel compilatore potrebbe essere riscritto in Swift. Ma quale sarebbe lo scopo? Per dimostrare che il linguaggio è abbastanza potente da scrivere un compilatore in esso? A nessuno importa se puoi scrivere compilatori in Swift. La gente non importa se si può scrivere interfacce utente a Swift, e si può dimostrabile.

Se hai un compilatore ben collaudato che può essere facilmente adattato per compilare lingue diverse, è abbastanza inutile riscriverlo in lingue diverse, a meno che la riscrittura in una lingua diversa non semplifichi il lavoro con il compilatore. E se avesse senso scrivere Clang in Swift, ad esempio, i compilatori Clang C, C ++ e Objective-C sarebbero tutti scritti in Swift.

Ci sono cose più importanti da fare che provare che è possibile scrivere un compilatore in un linguaggio di programmazione.


1

Mostra che la lingua è in grado di elaborare elaborazioni di stringhe complesse e tradurle in un'altra lingua / interpretare se stessa.

Nel processo di creazione di un compilatore (il primo grande progetto) ci saranno problemi che verranno alla ribalta.

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.