Le risposte precedenti danno praticamente la spiegazione, sebbene principalmente da un punto di vista pragmatico, per quanto la domanda abbia un senso , come spiegato in modo eccellente dalla risposta di Raffaello .
Aggiungendo a questa risposta, dovremmo notare che, al giorno d'oggi, i compilatori C sono scritti in C. Naturalmente, come notato da Raphael, il loro output e le sue prestazioni possono dipendere, tra le altre cose, dalla CPU su cui è in esecuzione. Ma dipende anche dalla quantità di ottimizzazione eseguita dal compilatore. Se scrivi in C un compilatore con ottimizzazione migliore per C (che poi compili con quello precedente per poterlo eseguire), otterrai un nuovo compilatore che rende C un linguaggio più veloce di prima. Quindi, qual è la velocità di C? Nota che puoi persino compilare il nuovo compilatore con se stesso, come secondo passaggio, in modo che si compili in modo più efficiente, pur continuando a fornire lo stesso codice oggetto. E il teorema della piena occupazione mostra che il loro non ha fine a tali miglioramenti (grazie a Raffaello per l'indicatore).
Ma penso che valga la pena provare a formalizzare il problema, in quanto illustra molto bene alcuni concetti fondamentali, e in particolare la visione denotazionale contro operativa delle cose.
Che cos'è un compilatore?
Un compilatore , abbreviato in se non c'è ambiguità, è una realizzazione di una funzione calcolabile che tradurrà un testo di programma calcola una funzione , scritto in un linguaggio sorgente nel testo del programma scritto in un
lingua di arrivo , che si suppone per calcolare la stessa funzione .CS→TCCS→TP:SP SP:T TP
Da un punto di vista semantico, cioè denotazionalmente , non importa come viene calcolata questa funzione di compilazione , ovvero quale scelta viene scelta. Potrebbe anche essere fatto da un oracolo magico. Matematicamente, la funzione è semplicemente un insieme di coppie .CS→TCS→T{(P:S,P:T)∣PS∈S∧PT∈T}
La funzione di compilazione semantica è corretta se sia e calcolano la stessa funzione . Ma questa formalizzazione si applica anche a un compilatore errato. L'unico punto è che qualunque cosa sia implementata ottiene lo stesso risultato indipendentemente dai mezzi di implementazione. Ciò che conta semanticamente è ciò che viene fatto dal compilatore, non come (e quanto velocemente) viene fatto.CS→TPSPTP
In realtà ottenere da è un problema operativo , che deve essere risolto. Questo è il motivo per cui la funzione di compilazione deve essere una funzione calcolabile. Quindi qualsiasi lingua con potere Turing, indipendentemente dalla lentezza, sarà sicuramente in grado di produrre codice efficiente come qualsiasi altra lingua, anche se potrebbe farlo in modo meno efficiente.P:TP:SCS→T
Affinando l'argomento, probabilmente vogliamo che il compilatore abbia una buona efficienza, in modo che la traduzione possa essere eseguita in tempi ragionevoli. Quindi le prestazioni del programma di compilazione sono importanti per gli utenti, ma non hanno alcun impatto sulla semantica. Sto dicendo performance, perché la complessità teorica di alcuni compilatori può essere molto più elevata di quanto ci si aspetterebbe.
Informazioni sul bootstrap
Ciò illustrerà la distinzione e mostrerà un'applicazione pratica.
Ora è un luogo comune implementare prima una lingua con un interprete , quindi scrivere un compilatore nella lingua stessa. Questo compilatore può essere eseguito con l'interprete per tradurre qualsiasi programma in un programma . Quindi abbiamo un compilatore in esecuzione dal linguaggio al linguaggio (macchina?) , ma è molto lento, se non altro perché gira su un interprete.I S C S → TSIS S C S → TCS→T:SS I S P : S P : T STCS→T:SISP:SP:TST
Ma puoi usare questa funzione di compilazione per compilare il compilatore
, poiché è scritto nella lingua , e quindi ottieni un compilatore scritto in la lingua di destinazione . Se si assume, come spesso accade, che è un linguaggio che viene interpretato in modo più efficiente (macchina nativo, per esempio), allora si ottiene una versione più veloce del compilatore in esecuzione direttamente nel linguaggio . Fa esattamente lo stesso lavoro (ovvero produce gli stessi programmi target), ma lo fa in modo più efficiente. S C S → TCS→T:SS TTTCS→T:TTTT