Il bootstrap richiede ancora un supporto esterno


96

Ho sentito parlare dell'idea di eseguire il bootstrap di una lingua, ovvero scrivere un compilatore / interprete per la lingua stessa. Mi chiedevo come si potesse ottenere questo risultato e mi sono guardato intorno un po ', e ho visto qualcuno dire che poteva essere fatto solo da entrambi

  • scrivere un compilatore iniziale in una lingua diversa.
  • codificare manualmente un compilatore iniziale in Assembly, che sembra un caso speciale del primo

Per me, nessuno di questi sembra effettivamente avviare un linguaggio nel senso che entrambi richiedono un supporto esterno. C'è un modo per scrivere effettivamente un compilatore nella sua lingua?


Non ho molta esperienza con queste cose, ma presumo che il compilatore iniziale debba essere scritto in un'altra lingua. Sono abbastanza certo che "bootstrap", in riferimento ai compilatori, si riferisca semplicemente alla scrittura di un compilatore per una lingua nella lingua che si intende compilare, non a scrivere il primo compilatore per la lingua nella lingua che si intende compilare.
jdd

1
Grazie per le informazioni a tutti. Quando viene spiegato con l'idea di scrivere inizialmente un compilatore limitato, poi costruirlo sopra, allora l'idea del bootstrap ha più senso. Sto frequentando un corso di compilatori questo semestre, una decisione in gran parte influenzata dal post di Steve Yegge sull'importanza di una lezione in compilatori , e ho appena acquistato una copia del libro di Dragon dal collegamento di Amazon che è stata così sottovalutata in precedenza.
pbh101

Risposte:


107

C'è un modo per scrivere effettivamente un compilatore nella sua lingua?

Devi avere un linguaggio esistente per scrivere il tuo nuovo compilatore. Se stavi scrivendo un nuovo, diciamo, compilatore C ++, dovresti semplicemente scriverlo in C ++ e compilarlo prima con un compilatore esistente. D'altra parte, se stavi creando un compilatore per una nuova lingua, chiamiamolo Yazzleof, dovresti prima scrivere il nuovo compilatore in un'altra lingua. In generale, questo sarebbe un altro linguaggio di programmazione, ma non deve esserlo. Può essere assemblaggio o, se necessario, codice macchina.

Se stavate andando a creare un semplice compilatore per Yazzleof, in genere non sarebbe scrivere un compilatore per il linguaggio pieno inizialmente. Invece dovresti scrivere un compilatore per Yazzle-lite, il più piccolo sottoinsieme possibile di Yazzleof (beh, almeno un sottoinsieme piuttosto piccolo ). Quindi in Yazzle-lite, scriveresti un compilatore per la lingua completa. (Ovviamente questo può avvenire in modo iterativo invece che in un salto.) Poiché Yazzle-lite è un sottoinsieme appropriato di Yazzleof, ora hai un compilatore che può compilarsi da solo.

C'è una davvero buona interessante resoconto su bootstrap un compilatore dal livello più basso possibile (che su una macchina moderna è fondamentalmente un editor esadecimale), dal titolo Inizializzare un semplice compilatore dal nulla . Può essere trovato su https://web.archive.org/web/20061108010907/http://www.rano.org/bcompiler.html .


19

La spiegazione che hai letto è corretta. C'è una discussione su questo in Compilatori: principi, tecniche e strumenti (il Libro del drago):

  • Scrivi un compilatore C1 per la lingua X nella lingua Y
  • Utilizzare il compilatore C1 per scrivere il compilatore C2 per la lingua X nella lingua X
  • Ora C2 è un ambiente di hosting completamente autonomo.

7

Una discussione molto interessante di questo è nella conferenza del Turing Award del co-creatore di Unix Ken Thompson .

Comincia con:

Quello che sto per descrivere è uno dei tanti problemi "gallina e uovo" che sorgono quando i compilatori sono scritti nella loro lingua. In questa semplicità, userò un esempio specifico dal compilatore C.

e procede a mostrare come ha scritto una versione del compilatore C Unix che gli avrebbe sempre permesso di accedere senza password, perché il compilatore C riconoscerebbe il programma di login e aggiungerebbe un codice speciale.

Il secondo modello è rivolto al compilatore C. Il codice sostitutivo è un programma di fase I che si riproduce automaticamente che inserisce entrambi i cavalli di Troia nel compilatore. Ciò richiede una fase di apprendimento come nell'esempio della Fase II. Per prima cosa compiliamo il sorgente modificato con il normale compilatore C per produrre un binario con bug. Installiamo questo binario come il C ufficiale. Ora possiamo rimuovere i bug dai sorgenti del compilatore e il nuovo binario reinserirà i bug ogni volta che viene compilato. Ovviamente, il comando di accesso rimarrà bloccato senza alcuna traccia nella fonte da nessuna parte.


9
Questo è fuori tema .. Interessante, ma confuso e non una risposta alla domanda.
Blueshift

5

Il modo in cui ho sentito è scrivere un compilatore estremamente limitato in un'altra lingua, quindi usarlo per compilare una versione più complicata, scritta nella nuova lingua. Questa seconda versione può quindi essere utilizzata per compilare se stessa e la versione successiva. Ogni volta che viene compilato viene utilizzata l'ultima versione.

Questa è la definizione di bootstrap:

il processo di un sistema semplice che attiva un sistema più complicato che ha lo stesso scopo.

EDIT: l' articolo di Wikipedia sul bootstrap del compilatore copre il concetto meglio di me.




3

A quanto ho capito, il primo interprete Lisp è stato avviato compilando a mano le funzioni del costruttore e il lettore di token. Il resto dell'interprete è stato quindi letto dalla fonte.

È possibile verificare la presenza di se stessi leggendo il giornale originale McCarthy, funzioni ricorsive di espressioni simboliche e loro calcolo a macchina, parte I .


Che fine hanno fatto le parti 2 e 3? ... Come ho fatto a non accorgermi che @Wing aveva postato la stessa cosa 3 anni prima di me? Sono un asino. Almeno ho collegato il giornale (con l'aiuto).
luser droog

2

Un'altra alternativa è creare una macchina bytecode per la tua lingua (o usarne una esistente se le sue caratteristiche non sono molto insolite) e scrivere un compilatore in bytecode, nel bytecode o nella lingua desiderata usando un altro intermedio, come un parser toolkit che restituisce l'AST come XML, quindi compila l'XML in bytecode utilizzando XSLT (o un altro linguaggio di corrispondenza dei modelli e una rappresentazione basata su albero). Non rimuove la dipendenza da un'altra lingua, ma potrebbe significare che la maggior parte del lavoro di bootstrap finisce nel sistema finale.


2

È la versione informatica del paradosso della gallina e dell'uovo. Non riesco a pensare a un modo per non scrivere il compilatore iniziale in assembler o in qualche altro linguaggio. Se fosse stato possibile, avrei potuto farlo Lisp.

In realtà, penso che Lisp si qualifichi quasi. Controlla la sua voce su Wikipedia . Secondo l'articolo, la funzione eval Lisp potrebbe essere implementata su un IBM 704 in codice macchina, con un compilatore completo (scritto in Lisp stesso) che sarebbe nato nel 1962 al MIT .


2

Ogni esempio di bootstrap di un linguaggio a cui riesco a pensare ( C , PyPy ) è stato fatto dopo che c'era un compilatore funzionante. Devi iniziare da qualche parte e reimplementare una lingua in sé richiede prima di scrivere un compilatore in un'altra lingua.

In quale altro modo funzionerebbe? Non credo sia nemmeno concettualmente possibile fare diversamente.


4
Il primo compilatore Lisp, almeno, è stato avviato utilizzando un interprete Lisp esistente . Quindi non un'altra lingua semanticamente, ma un'altra implementazione del linguaggio.
Ken

0

Alcuni compilatori o sistemi con bootstrap mantengono sia il modulo sorgente che il modulo oggetto nel loro repository:

  • ocaml è un linguaggio che ha sia un interprete bytecode (cioè un compilatore per bytecode Ocaml) che un compilatore nativo (per x86-64 o ARM, ecc ... assembler). Il suo repository svn contiene sia il codice sorgente (file */*.{ml,mli}) che il formato bytecode (file boot/ocamlc) del compilatore. Quindi, quando si compila, utilizza per la prima volta il suo bytecode (di una versione precedente del compilatore) per compilarsi. Successivamente il bytecode appena compilato è in grado di compilare il compilatore nativo. Quindi il repository svn di Ocaml contiene sia i *.ml[i]file sorgente che il boot/ocamlcfile bytecode.

  • Il compilatore rust scarica (usando wget, quindi è necessaria una connessione Internet funzionante) una versione precedente del suo binario per compilarsi.

  • MELT è un linguaggio simile a Lisp per personalizzare ed estendere GCC . Viene tradotto in codice C ++ da un traduttore bootstrap. Il codice C ++ generato del traduttore viene distribuito, quindi il repository svn contiene sia i *.meltfile sorgente che i file melt/generated/*.cc"oggetto" del traduttore.

  • Il sistema di intelligenza artificiale CAIA di J.Pitrat è completamente autogenerante. È disponibile come raccolta di migliaia di [A-Z]*.cfile generati (anche con un dx.hfile di intestazione generato ) con una raccolta di migliaia di _[0-9]*file di dati.

  • Anche diversi compilatori di schemi vengono avviati. Scheme48, Chicken Scheme, ...

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.