Laboratorio di programmazione

Compilatore

Il compilatore è un programma che traduce le istruzioni scritte in un linguaggio di programmazione, per esempio il C, in linguaggio comprensibile al microprocessore, ovvero in Assembler. Il computer infatti non lavorerà con le istruzioni scritte da noi, ma con le istruzioni molto più a basso livello tipiche di tale linguaggio. Il sorgente (cioè il file contenente il testo scritto dal programmatore in un dato linguaggio di programmazione) viene letto dal compilatore, che effettua il controllo sintattico sulle istruzioni e le traduce in linguaggio macchina. Il risultato della traduzione è scritto in un secondo file, detto object file. Questo non è ancora eseguibile dal microprocessore, in quanto non incorpora il codice binario delle funzioni esterne al linguaggio: è dunque necessaria una fase ulteriore di elaborazione, alla quale provvede il linker, che incorpora nell'object file gli object file contenenti le funzioni esterne, già compilate in precedenza, solitamente raccolti in "contenitori" detti librerie. Il linker produce in output un terzo file, il programma vero e proprio, direttamente eseguibile dal microprocessore con la sola intermediazione del sistema operativo. I vantaggi rispetto all'interprete, in termini di velocità e semplicità di esecuzione, sono evidenti, a fronte di una maggiore complessità del ciclo di sviluppo. Infatti il compilatore, nel caso in cui rilevi errori nel sorgente, li segnala e non produce alcun object file. Il programmatore deve analizzare il sorgente, correggere gli errori e ritentare la compilazione: detta sequenza va ripetuta sino a quando, in assenza di segnalazioni d'errore da parte del compilatore, viene prodotto un object file pronto per l'operazione di linking. Anche in questa fase potranno verificarsi errori: il caso classico è quello della funzione esterna non trovata nella libreria. Anche questa volta occorre analizzare il sorgente, correggere l'errore e ripetere non solo il linking, ma anche la compilazione. Solo in assenza di errori tanto nella fase di compilazione quanto in quella di linking si può ottenere un file eseguibile; in altre parole: il programma. Il linguaggio C consente la scrittura di programmi veloci e compatti. Quando si scrive un programma in Pascal, un linguaggio che come il C utilizza le funzioni come mattoni sui quali basare il programma, tutte le funzioni debbono trovarsi disposte nel listato sorgente in scala gerarchica: per prime quelle di livello più basso, che debbono usare solo i comandi del linguaggio, poi altre che possono usare solo le prime funzioni e così via. Nel C questa richiesta piuttosto innaturale non esiste: siamo liberi di disporre le funzioni nel programma secondo l'ordine che più ci è comodo. Questa libertà in più concessaci dal C dipende dal fatto che, mentre il compilatore Pascal legge il programma una sola volta durante la compilazione, e quindi non può ammettere di ritrovarsi a compilare per prime funzioni che dipendono da altre non ancora esaminate, il compilatore C legge più di una volta (due o tre) il programma. I signori Kernighan e Ritchie, i "papà" del C, hanno pensato bene di prendere due piccioni con una fava. La facilità nella scrittura dei programmi conseguente alla doppia o tripla lettura del programma sorgente da parte del compilatore ha un prezzo da pagare in termini di velocità di compilazione (ed in effetti normalmente un compilatore C è più lento di un compilatore Pascal). Così, hanno approfittato delle multiple letture per metterci a disposizione un pre processore. Si tratta, per dirla in termini semplici, di un programma che legge il nostro listato prima del compilatore C, ed esegue certe trasformazioni al nostro servizio. Per esempio possiamo mandare dei comandi al pre processore iniziando una riga con il segno diesis (o cancelletto, se preferite: il simbolo #). Quando il pre processore vede quel simbolo intercetta la riga ed esegue il comando: il compilatore non vedrà mai quel comando, che per lui non significherebbe nulla. Questa fase, è opportunamente chiamata precompilazione in quanto avviene prima della compilazione. Nel caso che il programma sia suddiviso su più sorgenti, per ogni sorgente vengono eseguite le fasi di precompilazione e di compilazione, producendo un file oggetto avente lo stesso nome del file sorgente, ma con estensione .o oppure .obj (dipende dal sistema operativo). Durante questo processo non vengono risolti i nomi esterni, ovvero vengono lasciati irrisolti gli agganci con il codice delle funzioni e con gli indirizzi di aree di memoria delle variabili definite su altri files. In questa fase vengono solamente eseguiti dei controlli formali con tali funzioni e variabili. Con il collegamento o linking vengono uniti insieme i files oggetto, risolvendo gli indirizzi del codice di esecuzione delle funzioni o di memoria delle variabili. Sia le funzioni che le variabili, possono essere presenti in altri files oggetto o nelle librerie (standard o dell'utente). Il risultato di questa fase e' la creazione di un unico file oggetto: il programma eseguibile. Di seguito un esempio delle varie fasi di compilazione di un programma scritto in C:























































Tutto quanto riportato in questa pagina è a puro scopo informativo personale. Se non ti trovi in accordo con quanto riportato nella pagina, vuoi fare delle precisazioni, vuoi fare delle aggiunte o hai delle proposte e dei consigli da dare, puoi farlo mandando un email. Ogni indicazione è fondamentale per la continua crescita del sito.