coldwa.st
Tutte le guideProgrammazioneWebDatiStrumentiDatabaseHaskellConcettiCabal e buildToolchainCompilatorePrestazioniEditor e HLS

Programmazione · Concetti · Compilatore

Cos’è un compilatore?

Di ColdwastAggiornato il 23 giu 20268 min di lettura#compiler#concepts#haskell
Codice sorgente C++ evidenziato con numeri di riga in un editor scuro
Un codice sorgente come questo — variabili, cicli e condizioni scritti da una persona — è l’input che il compilatore legge per trasformarlo in un programma eseguibile dalla macchina.

Scrivi un programma in un linguaggio che sai leggere: parole, indentazione, nomi con un significato. Il processore della tua macchina non ne capisce nulla — esegue istruzioni binarie grezze. Lo strumento che colma il divario è il compilatore. Questa guida spiega cos’è un compilatore, le fasi che attraversa, in cosa differisce da un interprete, e dove si colloca un compilatore come GHC quando scrivi Haskell.

La definizione breve

Un compilatore è un programma che traduce codice sorgente scritto in un linguaggio verso un’altra forma — di solito il codice macchina che un computer può eseguire direttamente. Gli consegni i file di testo che hai scritto e produce un eseguibile (o un formato intermedio) che la macchina, o un runtime, può eseguire. La traduzione avviene una volta, in anticipo, e il risultato gira da solo, senza che il compilatore sia presente.

Come funziona un compilatore, fase dopo fase

Un compilatore non traduce in un solo salto. Attraversa una catena di fasi, ognuna delle quali passa il proprio risultato alla successiva:

  • Analisi lessicale (tokenizzazione): il testo sorgente viene suddiviso in piccole unità — parole chiave, nomi, numeri, simboli — chiamate token.
  • Analisi sintattica (parsing): i token vengono organizzati in un albero che riflette la struttura del programma, secondo la grammatica del linguaggio.
  • Analisi semantica: il compilatore controlla che il programma abbia senso — nomi definiti, tipi coerenti, regole del linguaggio rispettate. È qui che vengono rilevati molti dei tuoi errori.
  • Ottimizzazione: il compilatore riscrive il programma in un equivalente più veloce o più piccolo senza cambiare ciò che fa.
  • Generazione del codice: infine emette l’output di destinazione — codice macchina, o una rappresentazione intermedia che un altro strumento completerà.

Se una fase trova un problema, ottieni un errore di compilazione e non viene prodotto alcun programma. È il patto del compilatore: si rifiuta di costruire codice rotto, così un’intera classe di errori viene intercettata prima ancora che il programma venga eseguito.

Uno sviluppatore con le cuffie che lavora a una scrivania con un monitor e un portatile che mostrano del codice in una stanza blu scuro
Uno sviluppatore al lavoro: scrivi e modifichi il codice sorgente, poi avvii il compilatore, che legge i tuoi file e produce il programma eseguibile.

Compilatore vs interprete

L’altro approccio comune è l’interprete, che legge il tuo codice sorgente e lo esegue direttamente, riga per riga, ogni volta che il programma gira — non viene costruito alcun eseguibile separato in anticipo. Un compilatore traduce l’intero programma una volta, all’inizio, in una forma che la macchina esegue da sola.

La differenza pratica: i programmi compilati di solito si avviano e girano più velocemente, perché la traduzione e l’ottimizzazione sono già avvenute, e gli errori emergono al momento della compilazione. I programmi interpretati sono più rapidi da provare e più flessibili, ma rifanno il lavoro di traduzione a ogni esecuzione. Molte toolchain reali mescolano entrambi — compilano in una forma intermedia e poi la eseguono su una macchina virtuale.

Dove si collocano GHC e Haskell

Quando scrivi Haskell, il compilatore che usi è GHC (il Glasgow Haskell Compiler). Legge i tuoi file sorgente .hs, ne verifica a fondo i tipi, ottimizza il risultato e produce un eseguibile nativo che puoi avviare da solo. Il forte sistema di tipi di Haskell fa sì che la fase di analisi semantica di GHC lavori molto per te: molti bug vengono segnalati come errori di compilazione invece di andare in crash a runtime. Per la guida completa al suo uso, vedi la nostra guida al compilatore GHC e come installare Haskell con GHCup.

I comandi che incontri davvero

  • Compilare un singolo file: uno strumento come ghc Main.hs legge il tuo sorgente e produce un eseguibile.
  • Costruire un progetto: strumenti di build come Cabal o Stack guidano il compilatore attraverso molti file e dipendenze al posto tuo.
  • Verificare i tipi senza un build completo: molti compilatori offrono una modalità più veloce che cerca gli errori senza emettere un binario.

La maggior parte delle volte non chiami il compilatore a mano — lo fa il tuo strumento di build o il tuo editor, mostrandoti gli errori. Ma sapere cosa fa sotto rende quegli errori molto più facili da leggere.

I compromessi onesti

I compilatori aggiungono un passaggio: cambi il codice, aspetti il build, poi esegui. Su un progetto grande quell’attesa può farsi sentire, ed è per questo che contano i compilatori veloci e i build incrementali. La ricompensa è reale: errori intercettati presto, output ottimizzato e un unico eseguibile che puoi distribuire senza distribuire la tua toolchain. Per un linguaggio fortemente tipizzato come Haskell, questa verifica anticipata è gran parte del fascino — il compilatore è una rete di sicurezza, non solo un traduttore.

Domande frequenti

Cos’è un compilatore in parole semplici?

Un compilatore è un programma che traduce il codice sorgente che scrivi in una forma che il computer può eseguire — di solito codice macchina. Gli dai i tuoi file di testo e produce un eseguibile che gira da solo, senza che il compilatore sia presente. La traduzione avviene una volta, in anticipo.

Qual è la differenza tra un compilatore e un interprete?

Un compilatore traduce l’intero programma una volta, in anticipo, in una forma eseguibile, così il risultato si avvia e gira velocemente. Un interprete legge ed esegue il codice sorgente direttamente a ogni esecuzione, senza un passo di build separato. I programmi compilati sono di solito più veloci; quelli interpretati sono più rapidi da provare e più flessibili.

Quali sono le fasi di un compilatore?

Un compilatore attraversa tipicamente l’analisi lessicale (suddividere il testo in token), l’analisi sintattica (costruire un albero di struttura), l’analisi semantica (controllare nomi e tipi), l’ottimizzazione (rendere il programma più veloce o più piccolo) e la generazione del codice (emettere il codice macchina finale o una forma intermedia). Un errore in qualsiasi fase ferma il build.

GHC è un compilatore?

Sì. GHC, il Glasgow Haskell Compiler, è il compilatore standard di Haskell. Legge i tuoi file sorgente .hs, ne verifica i tipi e li ottimizza, e produce un eseguibile nativo che puoi avviare da solo. Il forte sistema di tipi di Haskell fa sì che GHC intercetti molti bug come errori di compilazione prima ancora che il programma giri.

Guida indipendente, mantenuta dalla comunità. coldwa.st è un sito di risorse di programmazione; questo articolo è un testo esplicativo originale e inedito su come funzionano i compilatori. Le fasi descritte sono standard nei compilatori più diffusi; consulta la documentazione del tuo compilatore per il comportamento esatto.
Consigliato

Una macchina Linux per compilare ed eseguire il tuo codice

Compilare un progetto vero — costruire GHC, verificare i tipi di una grande base di codice Haskell e poi avviare l’eseguibile — è molto più facile su una vera macchina Linux che su un portatile. Un server cloud ti dà accesso root per installare una toolchain di compilazione e costruire la tua app in un ambiente pulito. Infomaniak — un provider svizzero rispettoso della privacy — offre server cloud che configuri e raggiungi via SSH.

Scopri Infomaniak Cloud →

Link di affiliazione — sostiene queste guide gratuite.

Sfoglia altre spiegazioni chiare nel nostro indice delle guide.