Premessa

Ciao! Se è la prima volta che capiti su questo sito, ti consiglio di consultare la pagina principale di questo Giardino Digitale per scoprire meglio cos’è e come navigarlo.

Lo stato di questa nota è al momento: 🔴 Bozza.


All’alba dei tempi della programmazione (ossia intorno agli anni ‘40/’50), i programmi venivano scritti direttamente in linguaggio macchina poiché non esistevano ancora i linguaggi di programmazione: la programmazione era ovviamente molto difficile perché per noi umani non è semplice dover tradurre le istruzioni che vogliamo far eseguire a un computer in una sequenza di zeri e uno, tenendo anche conto del fatto che ogni computer ha una propria architettura e, di conseguenza, un programma scritto per una determinata architettura non funzionerà su ogni computer.

Per questo motivo sono stati inventati i linguaggi di programmazione, ossia linguaggi che ci permettono di scrivere programmi in un formato più leggibile a noi umani (usando parole inglesi al posto di 0 e 1).

Tuttavia c’è un problema: un computer è in grado di comprendere solo il proprio linguaggio macchina e non capisce i linguaggi di programmazione. Ecco che allora serve un “traduttore” che prenda i programmi scritti in un determinato linguaggio di programmazione e li trasformi in un altro linguaggio (per esempio il linguaggio macchina): questi “traduttori” sono detti compilatori.

Definizione: compilatore

Un compilatore è un programma che traduce del codice scritto in un certo linguaggio di programmazione in un altro linguaggio di programmazione.

Osservazione: a cosa serve studiare i compilatori?

Al giorno d’oggi (quasi) nessuno realizza più compilatori (eccetto se si sta inventando un nuovo linguaggio di programmazione), ma allora a cosa serve studiarli?

Innanzitutto, come per qualsiasi altra cosa nel mondo dell’informatica (e non solo), concetti e metodi studiati qua possono essere applicati anche in altri ambiti, come la lettura e l’analisi di dati organizzati in strutture dati, lo studio di linguaggi formali, ecc.

1 - Dal sorgente all’eseguibile

Oltre ai compilatori, molti altri programmi possono essere necessari per ottenere un eseguibile:

  • Un programma sorgente può essere diviso in moduli conservati in file separati e chi riordina questi file è il preprocessore, che per esempio può anche risolvere macro
  • Il codice sorgente modificato dal preprocessore viene dato in pasto al compilatore che produce l’assembly
  • L’assembly viene processato dall’assembler che produce relocatable machine code
  • Il linker risolve gli indirizzi di memoria esterna che nel codice fa riferimento a librerie esterne
  • Il loader monta insieme i pezzi di relocatable machine code e librerie in un unico eseguibile

2 - Fasi della compilazione

Un compilatore non è un unico, ma diviso in due parti principali: analisi e sintesi.

Nella parte di analisi spezzetta il codice sorgente in più pezzi su cui fa controlli della correttezza della sua scrittura (e nel caso segnalare eventuali errori così che l’utente possa risolverli) e crea una symbol table in cui conserva i dati iniziali.

Nella parte di sintesi costruisce il programma destinazione dai risultati della parte di analisi.

Un compilatore è diviso in più fasi:

  1. Fa l’analisi lessicale, generando i token
  2. Fa l’analisi sintattica, generando AST
  3. Fa l’analisi semantica, generando AST
  4. Genera il codice intermedio
  5. Ottimizza il codice intermedio
  6. Genera il codice oggetto

Alcuni compilatori distinguono l’ottimizzazione tra machine-independent (cioè ottimizzazione che riguarda unicamente il codice in sè) e machine-dependent (cioè ottimizzazione specifica per la macchina su cui sta venendo eseguito).

2.1 - Analisi lessicale

Definizione: analisi lessicale

L’analisi lessicale è una delle fasi della compilazione in cui il codice viene convertito in blocchi chiamati token. Il programma che effettua questa operazione è detto analizzatore lessicale (in inglese lexer o scanner).

Definizione: token

Un token è una struttura dati prodotta dall’analisi lessicale composta da una categoria lessicale, che identifica il tipo di elemento riconosciuto, e da un eventuale lessema, ovvero la sequenza specifica di caratteri del codice sorgente che corrisponde al token, sotto forma di riferimento alla relativa entry nella tabella dei simboli.

Osservazione: facoltatività dei lessemi

Nella definizione di token c’è scritto “eventuale lessema” perché, a seconda dell’implementazione, un token può non conservare esplicitamente la sequenza originale di caratteri: per esempio, un token che nel linguaggio C ha come categoria “operatore di assegnazione” non può avere un lessema diverso da =, motivo per cui quest’ultimo può essere omesso.

Definizione: tabella dei simboli

La tabella dei simboli (in inglese symbol table) è una struttura dati utilizzata dal compilatore per memorizzare i lessemi dell’analisi lessicale e associarli ai corrispettivi token.

Per capire esattamente come sono collegati tra loro i concetti di token, lessemi e tabella dei simboli, vediamo un esempio.

3 - Interpreti

Un altro tipo di programmi che manipolano il codice sono gli interpreti.

Definizione: interprete

Un interprete è un programma che, dato un codice, lo esegue direttamente senza doverlo compilare.

Il codice macchina prodotto da un compilatore è spesso molto più veloce da eseguire rispetto a un interprete che lo esegue direttamente, ma quest’ultimo può essere in grado di rilevare errori molto meglio di un compilatore perché esegue le istruzioni del codice sorgente una per volta.

4 - Compilatori just-in-time

Definizione: compilatore just-in-time (JIT)

Un compilatore è detto just-in-time (JIT) se compila durante l’esecuzione del programma anziché precedentemente.


Fonti

  • 🏫 Corso di Laurea in Informatica (L-31 R) presso l’Università di Torino:
  • 📚 Alfred V. Aho, Monica S. Lam, Ravi Sethi, Jeffrey D. Ullman, Compilers - Principles, Techniques, and Tools, Pearson India, 2023 (ISBN: 9789357054119):
    • Chapter 1 - Introduction.
      • Paragraph 1.1 - Language Processors.
      • Paragraph 1.2 - The Structure of a Compiler:
        • Paragraph 1.2.1 - Lexical Analysis.

0 oggetti in questa cartella.