Linguaggi e Ambienti di
Programmazione
Principi e tecniche diffuse che si incontrano spesso nelle
applicazioni dell’informatica.
Compilatori
Editor di struttura:
struttura riceve in input una sequenza di comandi per
costruire un programma sorgente. Non solo esegue i
compiti di un text editor normale, ma analizza il testo
imponendo una struttura gerarchica, aggiunge
automaticamente parole chiave,...
Pretty printer:
printer analizza un programma e lo stampa in modo
che la sua struttura diventi visibile usando font speciali
e indentazioni.
Verificatori statici:
statici cercano di scoprire errori nei programmi
senza mandarli in esecuzione. Puo’ scoprire che parti
del codice non vengono mai eseguite o che alcune
variabili non sono definite o che una variabile di tipo
reale e’ usata come puntatore.
Interpreti di interrogazioni:
interrogazioni traducono un predicato che
contiene operatori booleani e relazionali in comandi per
cercare in un database i record che soddisfano il
predicato
Formattatori di testo,
testo ...
Programma
scritto in
linguaggio
sorgente
compilatore
messaggi
d’errore
Programma
scritto in
linguaggio
oggetto (target)
Modello di compilazione analisi - sintesi
analisi: spezza il programma in parti costituenti e crea una
rappresentazione intermedia
sintesi: partendo dalla rappresentazione intermedia costruisce
il programma nel linguaggio target
La fase di analisi può essere suddivisa a sua volta in tre fasi:
• analisi lineare:
lineare
raggruppa i caratteri della stringa di input in token, ossia
identifica sequenze che hanno un significato.
• analisi gerarchica:
gerarchica
raggruppa i token in una struttura gerarchica.
• analisi semantica:
semantica
verifica che le componenti di un programma stiano insieme
in modo significativo.
Esempio:
1
analisi lineare
usata anche nei linguaggi di interrogazione e nei sistemi di
information retrieval, in un compilatore viene chiamata analisi
lessicale o scanning.
position := initial + rate * 60
identificatore
numero
simbolo
segno di
d’assegnazione moltiplicazione
2
analisi gerarchica
chiamata analisi sintattica o parsing: raggruppa i token in frasi
di una grammatica. Di solito le frasi vengono rappresentate da un
albero di parsificazione.
:=
position
+
initial
*
rate
60
La struttura gerarchica è di solito espressa da regole ricorsive
Un identificatore è un’espressione
Un numero è un’espressione
Se espressione1 e espressione2 sono espressioni,
sono espressioni anche
espressione1 + espressione2
espressione1 * espressione2
(espressione1)
se id è un identificatore e expr è un’espressione, allora
id := expr
è un’istruzione
se expr è un’espressione e st è un’istruzione, allora
while (expr) do st
if (expr) then st
sono istruzioni
Le grammatiche sono una formalizzazione delle regole
ricorsive che possono essere usate per guidare l’analisi
sintattica
Un identificatore è un’espressione
Un numero è un’espressione
Se espressione1 e espressione2 sono espressioni,
sono espressioni anche
espressione1 + espressione2
espressione1 * espressione2
se id è un identificatore
e expr è un’espressione,
allora
id := expr
è un’istruzione
istruzione
identificatore
position
espressione
:=
espressione
+
espressione
identificatore
espressione
initial
identificatore
numero
rate
60
*
espressione
3
analisi semantica
Verifica l’esistenza di errori semantici e raccoglie informazioni
per la fase di generazione del codice.
Usa la struttura gerarchica della fase 2 (analisi sintattica) per
identificare operatori e operandi di espressione e istruzioni.
Una parte importante è la verifica dei tipi.
Type checking: ogni operatore deve avere operandi del tipo
corretto.
La rappresentazione interna di un numero intero è diversa da
quella di un numero reale.
Se position, rate e initial sono stati dichiarati reali e 60 è
assunto intero, il type checker rileva che il prodotto è tra un
intero e un reale.
Di solito l’intero viene convertito in un reale.
programma
sorgente
analisi lessicale
front end
analisi sintattica
analisi semantica
symbol table
manager
generazione codice
intermedio
trattamento
degli errori
ottimizzazione
generazione codice
programma
finale
back end
Symbol table management
Funzione essenziale di un compilatore è quella di ricordare gli
identificatori e raccogliere informazioni sui loro vari attributi:
• memoria allocata
• tipo
• scope
• nome e tipo degli argomenti per le procedure
• ...
È una struttura dati con un record per ogni identificatore. Quando
l’analisi lessicale riconosce nel programma sorgente un
identificatore, esso viene inserito nella symbol table. Gli attributi
vengono di solito determinati nelle fasi successive.
var position, initial, rate : real
quando l’analizzatore incontra position il tipo real non è ancora
noto
Error Detection and Reporting
Quando si incontra un errore, bisogna trattarlo in modo che la
compilazione possa procedere. Un compilatore che si ferma
quando trova il primo errore non è utile.
Errori si possono trovare in tutte le fasi, ad esempio:
nell’analisi lessicale: caratteri che non formano token del
linguaggio
nell’analisi sintattica: una sequenza di token che viola le
regole strutturali
nell’analisi semantica: la somma tra due identificatori di
cui uno è il nome di un array oppure
il nome di una procedura
position := initial + rate * 60
analizzatore lessicale
id1 := id2 + id3 * 60
analizzatore sintattico
:=
id1
+
id2
*
id3
60
analizzatore semantico
analizzatore semantico
:=
id1
+
id2
*
id3
intoreal
60
generatore codice
intermedio
temp1 := intoreal (60)
temp2 := id3 * temp1
temp3 := id2 + temp2
id1 := temp3
temp1 := intoreal (60)
temp2 := id3 * temp1
temp3 := id2 + temp2
id1 := temp3
Symbol Table
1 position
2 initial
3 rate
4
…….
…….
…….
ottimizzatore
temp1 := id3 * 60.0
id1 := id2 + temp1
generatore codice
MOVF
MULF
MOVF
ADDF
MOVF
id3, R2
#60.0, R2
id2, R1
R2, R1
R1, id1
Linguaggi artificiali e formali
Nei linguaggi formali la forma delle frasi, cioè la sintassi,
e il loro significato, la semantica, sono definiti in modo
algoritmico, cioè è possibile scrivere una procedura per
verificare la correttezza grammaticale delle frasi e per
calcolarne il significato.
Struttura matematica costruita a partire da un alfabeto per
mezzo di regole assiomatiche o definita per mezzo di
macchine chiamate automi.
Teoria dei linguaggi formali:
formali sintassi delle frasi.
Impalcatura su cui si può costruire la semantica.
Come specificare un numero infinito di frasi mediante una
descrizione finita?
Algoritmi di enumerazione: insieme finito di regole
grammatica generativa
Per progettare un compilatore, cioè un algoritmo che verifica
la correttezza delle frasi e ne calcola il significato, è necessario
un approccio più analitico, riconoscitivo.
I due approcci, generativo e riconoscitivo sono duali ed
equivalenti: si può passare da un algoritmo di enumerazione
ad uno di riconoscimento in modo meccanico.