Traduzione dal linguaggio di alto livello al linguaggio macchina

Un programma scritto in un qualsiasi linguaggio di programmazione di alto livello non può essere compreso e, quindi, eseguito da una macchina.
Affinchè esso possa essere eseguito è necessaria una traduzione nel linguaggio macchina specifico dell'esecutore.
A seconda del momento in cui viene affettuata la traduzione, del linguaggio risultante e della quantità di codice tradotto, possiamo distinguere i seguenti approcci:

  • compilato
  • interpretato
  • misto

Approccio compilato

L'approccio compilato prevede che la traduzione sia effettuata da un programma chiamato compilatore, che riceve in input il programma scritto nel linguaggio di programmazione di alto livello e produce in output un programma scritto in linguaggio macchina, attraverso un lavoro in due fasi.

La prima fase consiste nella traduzione vera e propria.
Il suo risultato è un codice oggetto (non ancora completamente eseguibile), scritto in linguaggio macchina.

La seconda fase effettua un collegamento tra il codice oggetto appena generato ed il codice oggetto di eventuali librerie utilizzate, contenenti funzioni non native del linguaggio utilizzato, ma sviluppate da altri programmatori, magari anche in altri linguaggi di programmazione, e messe a disposizione in termini di codice oggetto, dopo opportuna operazione di traduzione.
La parte del compilatore che si occupa della fase di collegamento tra il codice oggetto principale e quello delle librerie utilizzate si chiama linker.

Le sequenza delle azioni di traduzione del programma iniziale (codice sorgente), scritto in un linguaggio di alto livello, e collegamento con le librerie utilizzate prende il nome di compilazione.
Il risultato del lavoro svolto dal linker prende il nome di codice eseguibile (file .exe di windows).

Questo processo può essere sintetizzato graficamente dalla figura seguente.

Approccio compilato

Vediamo ora nel dettaglio alcune caratteristiche della compilazione:
  • è effettuata una sola volta, al termine della scrittura del programma e deve essere eseguita nuovamente solo se il codice sorgente necessita di modifiche per integrazioni di funzionalità o correzione di anomalie
  • il codice eseguibile è generato traducendo l'intero programma, e quindi, esso potrà essere ottimizzato e particolarmente efficiente per la macchina su cui dovrà essere eseguito
  • per eseguire il programma è necessario solo il codice eseguibile, quindi, dopo la compilazione, il codice sorgente può non essere più utilizzato, fino ad eventuale necessità di modifiche
  • tutti gli errori sintattici vengono rilevati durante la compilazione, perchè essa traduce tutto il codice sorgente, quindi deve processarlo nella sua interezza
  • il codice eseguibile generato è specifico per una determinata tipologia di macchina e, quindi, non è portabile su macchine con processore differente; per poter eseguire il programma su macchine differenti, occorre compilare nuovamente lo stesso, con un compilatore che produce codice macchina specifico per la famiglia di processori di tale macchina
  • la fase di sviluppo del programma è più lenta, perchè ogni volta che si effettua una modifica e si vuole testarne il funzionamento, occorre ricompilare tutto il programma nella sua interezza e tale operazione può essere dispendiosa, quando i programmi raggiungono dimensioni e complessità elevate

Approccio interpretato

L'approccio interpretato prevede che la traduzione sia effettuata da un programma, chiamato interprete, che deve essere in esecuzione sulla macchina su cui deve essere esguito il codice sorgente.
Tale traduzione, dal linguaggio di alto livello nel relativo linguaggio macchina, è effettuata, una istruzione alla volta, man mano che l'esecuzione del programma avanza.
L'istruzione corrente viene, quindi, tradotta in tempo reale ed eseguita sulla macchina sulla quale è in esecuzione il programma interprete.
Questo vuol dire che la traduzione sarà effettuata ogni volta che il programma dovrà essere eseguito e per le sole istruzioni coinvolte dalla particolare esecuzione.

Una sintesi grafica di quanto detto è rappresentata dalla figura seguente.

Approccio interpretato

Esaminiamo ora nel dettaglio anche le caratteristiche dell'approccio interpretato:
  • la traduzione è effettuata ogni volta che il programma deve essere eseguito
  • essendo la traduzione limitata alla sola istruzione corrente, tale approccio non considera il codice sorgente nella sua interezza e non è in grado di effettuare ottimizzazioni sul codice macchina generato, risultando, per tale ragione, meno efficiente dell'approccio compilato
  • il codice sorgente deve essere utilizzato ogni volta che il programma deve essere eseguito, in quanto l'interprete non salva nulla delle traduzioni effettuate, anche perchè ogni esecuzione potrebbe essere diversa dalle precedenti, in termini di flusso delle istruzioni eseguite e tradotte
  • il codice sorgente non è tradotto nella sua interezza e quindi potrebbe accadere che una esecuzione vada in errore, a causa di errori sintattici in percorsi dell'algoritmo mai eseguiti, anche dopo numerose esecuzioni terminate con successo ed anche molto tempo dopo il completamento dello sviluppo del programma
  • essendo il programma in linguaggio di alto livello indipendente dalla macchina per definizione, questo risulta portabile su macchine con architettura differente, purchè sia disponibile, installato ed in esecuzione un interprete del linguaggio utilizzato
  • la fase di sviluppo dei programmi, anche quando questi raggiungono dimensioni e complessità elevate, risulta più efficiente, in quanto non è necessario attendere il completamento della traduzione di tutto il codice sorgente ogni volta che viene implementata una modifica e deve esserne effettuato il test

Approccio misto (compilato e interpretato)

L'approccio misto vuole combinare i benefici di entrambe le tecniche viste finora.
Esso si basa, infatti, su una prima fase di compilazione per giungere ad un codice intermedio portabile, eseguibile su macchine di tipo differenze, attraverso un interprete specifico per ciascuna macchina.
Diversi linguaggi di programmazione più usati al giorno d'oggi si basano su tale approccio (Java, C#, VB.NET, ...)

Vediamo graficamente, nella figura che segue, come esso può essere rappresentato.

Approccio misto


Concludiamo esaminando nel dettaglio le caratteristiche salienti di tale approccio:
  • la prima fase di compilazione esegue una analisi di tutto il codice sorgente, per cui, al termine della stessa, possiamo essere sicuri che il codice non presenta errori sintattici, inoltre il codice intermedio generato è un codice ottimizzato e pertanto efficiente
  • ogni esecuzione del programma necessita solo del codice in linguaggio intermedio, generato dalla fase di compilazione, quindi, anche in questo approccio, dopo la compilazione, il codice sorgente può non essere più utilizzato, fino ad eventuale necessità di modifiche
  • il codice intermedio, generato dalla fase di compilazione, risulta essere portabile ed eseguibile su tutte le macchine che abbiano il suo interprete installato ed in esecuzione
  • la fase di sviluppo, quando i programmi raggiungono dimensioni e complessità elevate, è rallentata dalla necessità di ricompilare il tutto per poter effettuare il test, ma, rispetto all'approccio puramente compilato, risulta più efficiente, in quanto la compilazione, avente come risultato il codice intermedio, risulta più efficiente rispetto al stesso lavoro volto al risultato in codice macchina direttamente eseguibile