...

Traduttore diretto dalla sintassi (prima parte)

by user

on
Category: Documents
20

views

Report

Comments

Transcript

Traduttore diretto dalla sintassi (prima parte)
Sintassi
(prima parte)
Giuseppe Morelli
Introduzione
• Abbiamo già visto come la fase di analisi di un
compilatore
consente
di
suddividere
un
programma sorgente in “pezzi” e produce una
rappresentazione interna (codice intermedio)
• L’analisi è organizzata attorno alla sintassi del
linguaggio in cui il programma sorgente è
scritto.
– Sintassi: descrive la forma di un programma
– Semantica: descrive cosa il programma fa quando è in esecuzione
• La specifica della sintassi viene fatta secondo la
notazione delle Grammatiche Context Free
Grammatiche [Context Free] - definizioni
• Una grammatica descrive naturalmente la
struttura gerarchica della maggior parte
costrutti
dei
diversi
linguaggi
di
programmazione; es:
– If (expression) statement else statement
• Si tratta della concatenzione di più elementi
• Utilizzando un’altra
espressa come
notazione
può
essere
stmt -> if (expr) stmt else stmt
• Una regola così fatta è chiamata produzione
stmt -> if (expr) stmt else stmt
• If , (, ), else sono detti simboli Terminali
• stmt, expr sono sequenze di simboli terminali e
sono detti simboli non terminali
• La -> si legge “può avere la forma”
• I simboli non terminali in corsivo
• Lettere in Neretto, non corsivo, digits ed
operatori, aritmetici e ralazionali sono terminali
Definizione di grammatica
1. Un insieme di simboli terminali (token)
2. Un insieme di non terminali (variabili sintattiche)
3. Un insieme di produzioni,dove ognuna consiste
di:
1. Un simbolo non terminale (head or left side)
2. Una freccia
3. Una sequenza di simboli terminali e/o non
terminali (body or right side); permette di
specificare un costrutto
4. Un simbolo non terminale è designato quale
Iniziale (Start symbol)
.. continua
• Una grammatica è specificata attraverso la lista
delle sue produzioni.
• La produzione per il simbolo iniziale è
posizionata in testa alla lista
• Le produzioni con lo stesso simbolo non
terminale come Head (left side) hanno il corpo
(body) accorpato ovvero i diversi bodies sono
separati dal simbolo | (or)
• NOTA: equivalenza tra token e simboli terminali
Esempio (ricorrente)
• Costruiamo una grammatica in grado di
rappresentare l’espressione 9 -5 +2, e simili
list -> list + digit
list -> list – digit
list -> digit
digit -> 0|1|2|3|4|5|6|7|8|9
• In pratica stiamo affermando che chiamiamo list
due o più digit separati da + o –
• In sintesi
list -> list + digit | list – digit | digit
digit -> 0|1|2|3|4|5|6|7|8|9
Derivazione
• Una grammatica deriva una stringa, iniziando
con il simbolo iniziale e rimpiazzando
ripetutamente un simbolo non terminale con la
produzione per lo stesso simbolo.
• L’insieme delle stringhe derivabili a partire del
simbolo iniziale si dice il linguaggio definito dalla
grammatica.
Esempio
• Si consideri la grammatica:
1. list -> list + digit
2. list -> list – digit
3. list -> digit
4. digit -> 0|1|2|3|4|5|6|7|8|9
• La stringa 9-5+2 può essere derivata(dedotta):
1. Il 9 è una list (3) poichè 9 è un digit (4)
2. 9-5 è una list poiché 9 è list e 5 è digit (2)
3. 9-5+2 è una list poiché 9-5 è list e 2 è digit
(1)
Esempio
• Supponiamo di voler scrivere la grammatica e
voler riconoscere una chiamata a funzione con
relativa lista parametri ( nomefunz(x,y) ).
1.
2.
3.
4.
Call -> id ( optparams )
Optparams -> params | E
Params -> params, params | param
Param ????? (dipende dal linguaggio …..)
• Note:
– Lista dei parametri può essere vuota
– Params coincide con la definizione di list esempio
precedente (, al posto di + e – e param per digit)
Parsing
• È il nome del problema di prendere una stringa
di simboli terminali e mostrare come è possibile
derivarla a partire dal simbolo iniziale della
grammatica.
• Nel caso la derivazione non possa avvenire
permette di segnalare errori di sintassi nella
stringa
• Il parsing è propedeutico alla esecuzione del
lexer (lessemi --- Token)
• Negli esempi successivi si partirà sempre da
stringhe di terminali
Alberi di parsing
• Un albero sintattico permette di illustrare il
procedimento di parsing ovvero come si può
derivare una stringa del linguaggio a partire dal
simbolo iniziale della grammatica
• Sia A un generico simbolo non terminale che ha
a produzione A->XYZ, il suo “parse tree” avrà
un nodo interno etichettato con A con tre figli
etichettati da sinistra a destra con X,Y, e Z
ovvero:
A
X
Y
Z
..continua
• Data una grammatica context free, il suo
albero sintattico è un albero con le seguenti
caratteristiche:
1. La root è etichettata con il simbolo iniziale
2. Ogni foglia è etichettata con un simbolo terminale
3. Ogni nodo interno è etichettato con un simbolo nonterminale
4. Se A è un non terminale che etichetta un nodo
interno e X1, X2, …. , Xn sono etichette per i figli di
detto nodo allora la grammatica deve possedere la
produzione A -> X1 X2…. Xn
Esempio
Start symbol (1)
• Esperssione 9-5+2
list
1.
2.
3.
4.
list -> list + digit
list -> list – digit
list -> digit
digit -> 0|1|2|3|4|5|6|7|8|9
9-5 (2)
2 (4)
list
digit
9 (3)
5 (4)
list
9 (4)
digit
Yield ()
9
digit
-
5
+
Stringa derivata o generata
2
Ambiguità
• Una grammatica si dice ambigua quando un
stringa di terminali può essere generata da due
o più parse tree.
• Ciò dipende da come vengono scritte le
produzioni
• Per la realizzazione dei applicazioni di
compilazione è necessario scrivere grammatiche
non ambigue, o utilizzare grammatiche ambigue
ma con regole addizionali che permetto di
risolvere tali ambiguità.
Esempio
1. list -> list + list
2. list -> list – list
3. list -> 0|1|2|3|4|5|6|7|8|9
9-5+2
list
list
list
9
-
+
list
list
list
2
9
list
-
list
list
5
5
list
+
2
Associatività degli operatori
• La proprietà associativa, in presenza di una
espressione in cui un operando compare fra due
operatori, ci permette di scegliere quale
operatore applicare all’operando.
• Quando si dice che l’operatore + è associativo a
sinistra significa che in presenza di un
operando con due segni + (dx e sx) appartiene
all’operatore di sinistra ( 9+5+2 - (9+5)+2 )
• Gli operatori + - * / sono associativi a sinistra
• ^p è associativo a destra
• Operatore di assegnazione = è associativo a
destra
Esempio
right -> letter = right
right -> letter
letter -> a | b | …. |z
• Permette di riconoscere stringe del tipo a=b=c e
generarle attraverso l’albero:
right
• Nota sbilanciamento
letter
a
right
=
letter
b
right
= letter
c
Precedenza degli operatori
•
•
•
•
Si consideri 9+5*2
2 interpretazioni possibili (9+5)*2 o 9+(5*2)
L’associatività a sinistra di entrambi non aiuta
Quando sono presenti differenti tipi di operatore
è necessario definire delle regole di precedenza
• Un operatore ha precedenza maggio re rispetto
ad un altro quando prende l’operando prima
dell’altro
• * ha precedenza maggiore rispetto a + così
l’espressione precedente è valutata come
9+(5*2)
Esempio: espressioni aritmetiche
• l’associatività è evidenziata esplicitamente
left-associative +,- ……(expr)
left-associative *,/ ……(term)
expr -> expr + term | expr – term | term
term -> term * factor | term / factor | factor
factor –> digit | (expr)
• Attraverso i due non terminali vengono
evidenziati i livelli di precedenza (+,- e *,/)
Parse tree di espressioni aritmetiche
expr -> expr + term | expr – term | term
term -> term * factor | term / factor | factor
factor –> digit | (expr)
expr
Deriviamo: 9+5*2
term
expr
term
term
factor
factor
factor
9
+
5
*
2
Esercizio
• Consideriamo la grammatica
S -> S S + | S S * | a
- Mostrare che aa+a* può essere generata dalla
grammatica
- Costruire l’albero di parsing
Esercizi
• Quali linguaggi sono generati dalle
grammatiche:
A.
B.
C.
D.
E.
S
S
S
S
S
->
->
->
->
->
0 S 1 | 01
+SS|-SS|a
S(S)S|ε
aSbS|bSaS|ε
a | S + S | S S | S* | ( S )
Fly UP