mercoledì 26 novembre 2008

Compilazione vs Interpretazione

Ad un livello molto alto di astrazione possiamo considerare la compilazione ed l'esecuzione di un programma scritto in un linguaggio di alto livello, come segue:

Programma(Codice) Sorgente → Compilatore → Programma Target
Input → Programma Target → Output

Il compilatore traduce il programma di alto livello in uno equivalente Target( tipicamente in linguaggio macchina ).
Il compilatore utilizzato nei sistemi operativi produce object files che oltre al linguaggio macchina contiene informazioni per il runtime, riallocazione, stack unwinding, commenti, tabella dei simboli (nomi di variabili e funzioni) per il linking e/o debugging.

Uno stile alternativo d' implementazione per i linguaggi di altro livello è l' interpretazione

(Programma(Codice) Sorgente, Input ) → Interpretazione → Output

Nei programmi interpretati le decisioni vengono prese a run-time(tempo di esecuzione), a regola una decisione presa a compile-time(a tempo di compilazione) non deve essere ri-presa a run-time; ne' segue che, generalmente, la compilazione e' più' performante dell'interpretazione.
Es.
Il compilatore può' garantire che una variabile x ha una indirizzo di memoria '0xF' e genera il linguaggio macchina in modo tale che quando il programma sorgente si riferisce a x lo trova sempre nella locazione di memoria '0xF'.
Di contro un interprete ha bisogno di accedere ad una tabella, ogni volta che vuole utilizzare x, per trovare la sua locazione.


Un interprete si occupa anche della dell'esecuzione del programma sorgente per mezzo di una macchina intermedia(virtuale) che a run-time legge uno o più statements alla volta e li compila o interpreta in linguaggio macchina.
In questo caso siamo di fronte ad una implementazione mista.

Programma(Codice) Sorgente → Compilazione → Programma Intermedio
(Programma Intermedio, Input ) → Macchina Virtuale → Output


Alcuni linguaggio che usano la virtual machine sono : Java, C#, VB.net, Python, Perl.
Nel caso in cui la macchina intermedia coincide con la macchina concreta abbiamo l traduzione pura, es. l'assembler.


Nella maggior parte dei linguaggi interpretati viene eseguita una fase iniziali(preprocessor) nella quale vengono eliminati i commenti,gli spazi vuoti, insiemi di caratteri vengono trasformati in tokens (keyword, identificatori, numeri, simboli) e vengono espanse le macro.
Nelle prime versioni di Basic il manuale suggeriva di eliminare i commenti per migliorare le performance.

I linguaggi di alto livello che utilizzano la compilazione pura, in genere contano sull'esistenza di librerie di sotto-routines che non sono parte del programma originario. Es. includono funzioni matematiche o di I/O.
Il compilatore si appoggia su un programma separato chiamato linker, che compone le librerie appropriate al programma finale
Es. Linker

programma → Compilatore → Linguaggio macchina incompleto
(Linguaggio macchina incompleto,Librerie di routunes ) → Linker → Linguaggio macchina completo.

Molti compilatori generano il codice assembly anziche' codice macchina per facilitarne il debugger dato che piu' facile da leggere.
Es. Compilatore C++

Programma Sorgente → Preprocessor → Programma Sorgente Modificato (Espande macro, toglie spazi)
Programma sorgente Modificato → Compilatore c++ → Codice C
Codice C → Compilatore C → Linguaggio Assembly
Linguaggio Assembly → Assembler → linguaggio macchina

In molte macchine l'insieme di istruzioni assembly non sono implementato ad hardware ma vengono interpretate, dall'interprete firmware, in istruzioni di basso livello chiamate “micro istruzioni” implementate ad hardware.
Di conseguenza abbiamo il seguente schema:

Linguaggio Assembly → Assembler → Microlinguaggio
Microlinguaggio → Firmware → Linguaggio macchina


Ref.
Programming Launguage Pragmatics, Michael L. Scott, University of Rochester

slide, http://www.di.unipi.it/~levi/corsoMP/corso2/sld010.htm

Daniele Licari

Nessun commento: