Académique Documents
Professionnel Documents
Culture Documents
Controlli semantici
Congruenza fra le dichiarazioni delle entit e il loro impiego nelle istruzioni Rispetto delle regole che governano i tipi degli operandi nelle espressioni e negli assegnamenti Correttezza delle strutture di controllo del linguaggio Rispetto delle regole di visibilit e unicit degli identificatori Rispetto delle regole di importazione ed esportazione degli oggetti
02/02/2011
Type Checking
Statica le verifiche semantiche vanno eseguite durante la compilazione Dinamica le verifiche sono eseguite a run-time non possiamo fare tutti I type checking a compile-time. Alcuni sistemi usano anche dynamic type checking.
Type Checking
Un type system una collezione di regole per assegnare una espressione di tipo ad una parte di programmi Un type checker implementa un type system. Un sound type system elimina gli errori di tipo. Un linguaggio di programmazione e detto strongly-typed, se ogni programma compilato solo se privo di errori di tipo.
In pratica, alcune operazioni di type checking sono fatti a runtime (la maggioranza dei programmi non strongly-typed). Esempi int x[100]; x[i] la maggioranza dei compilatori non garantiscono che i [0 .. 99]
02/02/2011
Type Expression
Il tipo si un costrutto di un linguaggio denotato dal type expression. Una type expression pu essere:
basic type Un tipo primitivo, int, float, type-error per segnalare un errore di tipo void type name Un nome che denota il tipo di una espressione
Type Expression
arrays: se T un type expression, allora array(I,T) un type expression dove I rappresenta il range degli indici: esempio array(0..99,int) products: se T1 e T2 sono type expressions, allora il prodotto cartesiano T1 x T2 un type expression. esempio: int x int pointers: se T una type expression, allora pointer(T) una type expression. esempio: pointer(int) functions: possiamo trattare funzioni in un linguaggio di programmazione come il mapping da un domain type D ad un range type R. Cosi, il tipo di una funzione puop essere raappresentato dal type expression DR dovee D e R sono type expressions. Esempio: intint reppresenta un tipo di uns funzione che prende come parametro un calore int e tiporrna un valore int.
02/02/2011
Lattributo type
un attributo sintetizzato
associato alle dichiarazioni di tipo, espressioni e descrive il tipo dellentit considerata Azioni semantiche o condizioni
02/02/2011
E E1 + E2
E E1 [E2]
02/02/2011
argument types
Come verificare che due type expression sono uguali? type expressions sono costruiti dai tipi base e (no type names), possiamo utilizzare equivalenza strutturale per due type expressions
02/02/2011
In alcuni linguaggi di programmazione noi diamo un nome ad type expression, e utilizziamo il type expression.
typedef link = *cell; p,q,r,s sono dello stesso tipo? link p,q; *cell r,s;
02/02/2011
Conversioni di tipi
double x; int y; x+y quale il tipo di questa espressione (int o double)? Quale codice produce? inttofloat float+ y,,t1 t1,x,t2
02/02/2011
Azioni di controllo
Lattributo scope rappresenta linsieme di tutte le coppie che definiscono gli identificatori visibili in quel contesto
Sintassi
S while (E) S1 Condizioni if (E.type=int then S.type=S1.type else S.type=type-error Azioni di controllo E.scope = S.scope S1.,scope = S.scope
S id = E
Condizioni if (id.type=E.type then S.type=void else S.type=type-error Azioni di controllo E.scope = S.scope id. scope = S.scope S if (E) S1 Condizioni if (E.type=int then S.type=S1.type else S.type=type-error Azioni di controllo E.scope = S.scope S1.,scope = S.scope
02/02/2011
LD LD1 D LD D T id LI LI Is LI Is id = E
10
02/02/2011
Il codice intermedio sono indipendenti dal linguaggio macchina ma sono legati alle istruzioni macchina Il programma viene tradotto dal linguaggio sorgente in un programma equivalente in un linguaggio intermedio dal generarore di codice intermedio. Come linguaggio intermedio possono essere utilizzati diversi linguaggi:
Lalbero sintattico Una notazione postfissa postfix notation can be used as an intermediate language. three-address code (4-uple) Noi utilizzaremo un linguaggio costituito da 4-uple Il linguaggio delle 4-uple e simile al linguaggio macchina Talvolta I linguaggi di programmazione utilizzano linguaggi intermedi pi evoluti: java java virtual machine C# -clr prolog warren abstract machine
GENERAZIONE DI UN AST
11
02/02/2011
Intro
Vediamo adesso una tecnica che permette di effettuare analisi semantiche e traduzione usando la struttura sintattica data dalla grammatica di un linguaggio Lidea chiave quella di associare, ad ogni costrutto del linguaggio, alcune informazioni utili per il nostro scopo (attributi) Il valore di ogni attributo calcolato tramite regole semantiche associate con le produzioni della grammatica
2.
Definizioni guidate dalla sintassi: sono specifiche di alto livello: nascondono i dettagli implementativi e non richiedono di specificare lordine di valutazione che la traduzione deve seguire Schemi di traduzione, invece, indicano lordine in cui le regole semantiche devono essere valutate e quindi permettono la specifica di alcuni dettagli di implementazione
12
02/02/2011
Il flusso concettuale
Dalla stringa di input viene costruito il parse tree e poi lalbero viene attraversato nella maniera adatta (data dal grafo delle dipendenze) per valutare le regole semantiche che si trovano sui nodi Come al solito, comunque, una reale implementazione non segue questo flusso concettuale, ma esegue tutto durante il parsing senza costruire il parse tree esplicitamente, n il grafo delle dipendenze
Possiamo pensare ad ogni nodo del parse tree come ad un record i cui campi sono i nomi degli attributi Ogni attributo pu rappresentare qualunque cosa vogliamo: stringhe, numeri, tipi, locazioni di memoria, etc. Il valore di ogni attributo ad ogni nodo determinato da una regola semantica associata alla produzione che si usa nel nodo
13
02/02/2011
Regole semantiche
La valutazione, nellordine giusto, delle regole semantiche determina il valore per tutti gli attributi dei nodi del parse tree di una stringa data La valutazione pu avere anche side-effects (effetti collaterali) come la stampa di valori o laggiornamento di una veriabile globale
Decorazioni
Un parse tree che mostri i valori degli attributi ad ogni nodo chiamato parse tree annotato Il processo di calcolo di questi valori si dice annotazione o decorazione del parse tree
14
02/02/2011
Assunzioni e convenzioni
In una definizione guidata dalla sintassi si assume che i simboli terminali abbiano solo attributi sintetizzati I valori per questi attributi sono in genere forniti dallanalizzatore lessicale Il simbolo iniziale, se non diversamente specificato, non ha attributi ereditati
Costruzione di AST
Vediamo come utilizzare le definizioni guidate dalla sintassi per specificare la costruzione degli alberi sintattici Luso degli alberi sintattici come rappresentazione intermedia divide il problema del parsing da quello della traduzione Infatti le routine di traduzione che vengono invocate durante il parsing hanno delle limitazioni
15
02/02/2011
Limitazioni
1.
2.
Una grammatica che sia adatta per il parsing potrebbe non riflettere la naturale struttura gerarchica dei costrutti del linguaggio Il metodo di parsing vincola lordine in cui i nodi del parse tree sono considerati e questo ordine pu non corrispondere con quello in cui linformazione sui costrutti diventa disponibile
Un albero sintattico (astratto) una forma condensata di un parse tree che utile per rappresentare i costrutti dei linguaggi Ad esempio, la produzione S if B then S1 else S2 potrebbe apparire in un albero sintattico come:
if-then-else B S1 S2
16
02/02/2011
Syntax trees
Negli alberi sintattici gli operatori e le parole chiave non appaiono come foglie, ma sono associati ad un nodo interno Inoltre unaltra semplificazione che le catene di applicazione di una singola produzione vengono collassate:
+ * 3 5 4
Syntax trees
La traduzione guidata dalla sintassi pu benissimo essere basata su alberi sintattici piuttosto che su parse tree Lapproccio sempre lo stesso: associamo degli attributi ai nodi dellalbero
17
02/02/2011
Costruzione di un syntree
In un nodo operatore un campo identifica loperatore stesso e i campi rimanenti son i puntatori ai nodi operandi Loperatore spesso chiamato letichetta del nodo Quando vengono usati per la traduzione, i nodi in un syntree possono avere campi addizionali per gli attributi che sono stati definiti
18
02/02/2011
Costruzione di un syntree
1.
2.
3.
In questo esempio usiamo le seguenti funzioni per costruire i nodi degli alberi sintattici per espressioni con operatori binari: mknode(op, left, right) crea un nodo operatore con etichetta op e due campi puntatore alloperando destro e sinistro mkleaf(id, entry) crea un nodo identificatore con etichetta id e puntatore entry alla tabella dei simboli mkleaf(num,val) crea un nodo numero con etichetta num e un campo val contentente il valore
Costruzione di un syntree
1) 2) 3) 4) 5)
Ad esempio il seguente frammento di programma crea (bottom-up) un syntax tree per lespresione a4+c p1 := mkleaf(id, entrya); p2 := mkleaf(num, 4); p3 := mknode(-, p1, p2); p4 := mkleaf(id, entryc); p5 := mknode(+, p3, p4);
19
02/02/2011
Syntree per a 4 + c
id Entrata per c
id Entrata per a
num
Diamo una definizione guidata dalla sintassi Sattributed per la costruzione dellalbero sintattico di una espressione contenente gli operatori + e Definiamo un attributo nptr per ogni simbolo non terminale. Esso deve tenere traccia dei puntatori ritornati dalle funzioni di creazione dei nodi
20
02/02/2011
Syntree
PRODUZIONI REGOLE SEMANTICHE E.nptr := mknode(+, E1.nptr, T.nptr) E.nptr := mknode(-, E1.nptr, T.nptr)
E E1 + T E E1 - T ET T (E) T id T num
E.nptr := T.nptr T.nptr := E.nptr T.nptr := mkleaf(id, id.entry) T.nptr := mkleaf(num, num.val)
Lalbero annotato
E.nptr E.nptr E.nptr T.nptr id id Entrata per a num 4 id Entrata per c + + T.nptr num T.nptr id
21
02/02/2011
Una 4-uple : x := y op z
x, y e z sono nomi, costanti, elementi temporanei generati dal compilatore stesso op un operatore.
Nel seguito utilizzata la seguente notazione (4-uple) op y,z,x con il significato applica loperatore op a y e z, e restitutisci il risultato in x.
22
02/02/2011
una rappresentazione lineare di AST Un indirizzo pu assumere una delle seguenti forme
Nome
cio un nome di un identificatore (in un implementazione reale il puntatore alla tabella dei simboli) Una costante Un nome temporaneo generato dal compilatore
Assegnamento
z
= x op y z = op y
(binario) (unario)
Copia
x
=y
23
02/02/2011
Three-Address: istruzioni
Operatori binari: op y,z,result Dove op un operatore binario o logico. Ex: add a,b,c gt a,b,c addr a,b,c addi a,b,c Unary Operator: op y,,result Dove op un operatore binario o logico. Ex: uminus a,,c not a,,c inttoreal a,,c
Three-Address:istruzioni
Move Operator: mov y,,result
il contenuto di y e copiato in result. Ex: mov a,,c movi a,,c movr a,,c
24
02/02/2011
Ex:
oppure jmpnz jmpz jmpt jmpf y,,L1 y,,L1 y,,L1 y,,L1 // jump to L1 se y == 0 // jump to L1 if y != 0 // jump to L1 if y == true // jump to L1 if y == false
Altre istruzione
Parametri di Procedure : Chiamata di Procedure : param x,, call p,n,
dove x un parametre attuale Ex: param x1,, param x2,, p(x1,...,xn) param xn,, call p,n, f(x+1,y) add param param call x,1,t1 t1,, y,, f,2,
25
02/02/2011
Indexed Assignments: move y[i],,x con il significato x = y[i] move x,,y[i] con il significato y[i] = x Address and Pointer Assignments: moveaddr y,,x con il significato x = &y movecont y,,x con il significato x = *y
Esempio di traduzione
Do i = i + 1 While (a[i]<v)
1. 2. 3.
4. 5.
Add i ,1 , t1 move t1, ,i Mult i, 8, t2 //dimenz move a[t2],,t3 Jump t3<v goto 1
26
02/02/2011
Quadrule
Quattro
Gli
operatori unari e di copia non utilizzano arg Le istruzioni come param non usano ne arg2 ne result Le istruzioni di salto salvano letichetta in result
Per generare il codice nella forma a tre indirizzi dal codice sorgente noi utilizzaremo un approccio basato sulle grammatiche ad attributi. Esempio: le espressioni: Attributi: S ha un attributo "code contiene il frammento di codice E ha due attributi: code - contiene il frammento di codice
27
02/02/2011
Esempi di traduzione
S id := E E E1 + E2
S.code = E.code || gen(mov E.place ,, id.place) E.place = newtemp(); E.code = E1.code || E2.code || gen(add E1.place , E2.place , E.place)
E E1 * E2
E.place = newtemp();
E.code = E1.code || E2.code || gen(mult E1.place , E2.place , E.place)
E - E1 E ( E1 ) E id
E.place = newtemp(); E.code = E1.code || gen(uminus E1.place ,, E.place) E.place = E1.place; E.code = E1.code E.place = id.place; E.code = null
a := b * c + b * -c
S a := E3n E1n * E2n E8n + E7n E4n * E6n
E5n
c
28
02/02/2011
b
c t2 t3 E5n.code || t2 := uminus c E4n.code || E6n.code || t3 := b * t2
Traduzione Syntax-Directed
S while (E) do S1
S.begin = newlabel(); S.after = newlabel(); S.code = gen(S.begin :) || E.code || gen(jmpf E.place ,, S.after) || S1.code || gen(jmp ,, S.begin) || gen(S.after :)
29
02/02/2011
30
02/02/2011
processed string res := a res :=E res :=E res :=E res :=E res :=E res :=E
1 1 1 1 1 1
attributes
output
E .place = <6>
1
* (alpha * (E * (E + -b * (E + -E * (E + E
2 2 2 2 4 5
E .place = <7>
2
E .place = <8>
3
res :=E * (E
1 1
E .place = <9>
4
res :=E * (E )
5
E .place = <10>
5
res :=E * E
1
31
02/02/2011
Arrays
GLi elementi di arrays possono essere recuperati rapidamente se gli elementi sono memorizzati in blocchi consecutivi.
Array monodimenzionali A
baseA lindirizzo della prima locazione dellarray A, width la dimenzione di un elemento dellarray. low lindice del primo elemento dellarray La locazione del generico elemento A[i] baseA+(i-low)*width
Arrays (cont.)
baseA+(i-low)*width Pu essere riscritto come i*width + (baseA-low*width)
Dovrebbe essere calcolato a run-time. e si vuole accedere ad A[i] la formula i*width+c sara calcolata a run time ma c = (baseA-low*width) pu essere calcolato a compile-time. Il generatore di codice intermedio deve comunque produrre il codice per valutare la formula i*width+c.
32
02/02/2011
Array bidimenzionali
Address_of _A[i1,i2] =
baseA+ ((i1-low1)*n2+i2-low2)*width
baseA lindirizzo della prima locazione dellarray A, width la dimenzione di un elemento dellarray low1 lindice della prima riga low2 lindice della prima colonna n2 il numero di elementi in una riga
Grammatica per gli array G1 (richiede attributi ereditati). L id L id [ Elist ] Elist Elist , E Elist E
33
02/02/2011
mov
t3,,x
34
02/02/2011
Codice intermedio per x := A[y,z] mult add mov mult mov mov y,20,t1 t1,z,t1 c,,t2 t1,4,t3 t2[t3],,t4 t4,,x // where c=baseA-(1*20+1)*4
Dichiarazioni
PMD M DD;D D id : T { enter(id.name,T.type,offset); offset=offset+T.width } T int { T.type=int; T.width=4 } T real{ T.type=real; T.width=8 } T array[num] of T1 { T.type=array(num.val,T1.type); T.width=num.val*T1.width } T T1 { T.type=pointer(T1.type); T.width=4 } Dove enter crea una tabella dei simboli per un dato valore { offset=0 }
35
02/02/2011
mktable(previous) crea una nuova tabella dei simboli dove previous la tabella dei simboili che ha generaro la nuova tabella. enter(symtable,name,type,offset) crea un nuovo elemento per una variabile in una data tabella dei simboli. enterproc(symtable,name,newsymbtable) crea un nuovo elemento per un sottoprogramma nella tabella dei simboli dei suoi genitoti. addwidth(symtable,width) pone la dimenzione di tutte gli elementi nella tabella dei simboli nell header della tabella.
tblptr memorizza I puntatori dalla tabella dei simboli offset memorizza loffsets corrente nella tabella dei simbili nella pila tblptr
36
02/02/2011
Chiamata di sottoprogrammi
Valuta gli argomenti e li memorizza in una posizione conosciuta Genera I valori dei puntatori per accedere ai dati Salva lo stato della procedura chiamante Salva lindirizzo di ritorno e salta al codice della procedura chiamata Alla fine (return) richiama e salva qualsiasi valore di ritorno
Schema di traduzione
1) S call id (Elist) {for each item p on queue do emit (param p); emit (call id.place)} 2) Elist Elist .E {append E.place to the end of queue} 3) Elist E {inizilie queue to contein only E.place}
37