410 likes | 510 Views
Implementazione di Linguaggi 2 PARTE 5. Massimo Ancona DISI Università di Genova Testo: A.V. Aho, R. Sethi, J.D.Ullman Compilers Principles,Techniques and Tools, Addison Wesley. TRADUZIONE GUIDATA (DIRETTA) DALLA SINTASSI. Definizioni guidate dalla sintassi (DGS)
E N D
Implementazione di Linguaggi 2PARTE 5 Massimo Ancona DISI Università di Genova Testo: A.V. Aho, R. Sethi, J.D.Ullman Compilers Principles,Techniques and Tools, Addison Wesley
TRADUZIONE GUIDATA (DIRETTA) DALLA SINTASSI Definizioni guidate dalla sintassi (DGS) Una definizione guidata dalla sintassi è una generalizzazione di una CFG in cui ogni simbolo grammaticale è associato un insieme di attributi, suddiviso in due sottoinsiemi chiamati rispettivamente insieme degli attributi ereditati e insieme degli attributi sintetizzati.
Attributi e loro gestione Se si pensa un nodo del parse tree associato ad un simbolo grammaticale come una struttura di record con campi destinati a mantenere informazioni allora un attributo corrisponde al nome di un campo. ll valore di un attributo in un nodo del parse tree è definito da una regola semantica associata alla produzione applicata in quel nodo. Il valore di un attributo sintetizzato in un nodo è calcolato in funzione del valore degli attributi dei figli del nodo. Il valore di un attributo ereditato in un nodo è calcolato in funzione del valore degli attributi dei fratelli e del genitore del nodo. Le regole semantiche introducono dipendenze tra gli attributi nei nodi. Queste vengono rappresentate da un grafo orientato detto grafo delle dpendenze.
Parsing Tree Decorato e Attribute Grammar Un parsing tree decorato è un parsing tree che riportii valori degli attributi di ogni nodo. Nelle DDS si associa ad ogni produzione A un insieme di regole semantiche della forma: b:=f(c1,c2,...,ck) In cui f è una e b verifica una dei due casi seguenti: • b è un attributo sintetizzato di A e c1,c2,...,ck sono attributi dei simboli nella parte destra della produzione • b è un attributo ereditato di uno dei simboli della parte destra della produzione e c1,c2,...,ck attributi di A e di alcuni simboli della parte destra di A. Una attribute grammar è una definizione guidata dalla sintassi in cui le funzioni f non generano side-effect. Quando si vogliono generare side-effect si usano procedure in luogo di funzioni. Le funzioni sono spesso espresse in forma da espressioni
Attributi Sintrtizzati Esempio di un semplice calcolatore: LEn print(E.val) EE1+T E.val:=E1.val+T.val ET E.val:=T.val TT1*F T.val:=T1.valF.val TF T.val:=F.val F(E) F.val:=E.val Fdigit F.val:=digit.lexval
Attributi Ereditati Dipendono dagli attributi di genitore e fratelli e sono utili per esprimere dipendenze dal contesto del linguaggio. Esempio: DTL L.in:=T.type Tint T.type:=integer Tfloat T.type:=real LL1,id L1.in:=L.in addtype(id.entry,L.in) LL1,id addtype(id.entry,L.in)
Ordine di valutazione-grafo di dipendenza Se l’attributo b nel nodo n dipende da c nel nodo m allora la regola che valuta b in n deve essere valutata dopo quella che valuta c in m. Le interdipendenze di valutazione degli attributi in un parse tree vengono descritte da un grafo diretto etichettato detto grafo di dipendenza (o delle dipendenze). Il grafo ha un nodo per ogni attributo e un arco dal nodo m al nodo n se b dipende da c. Ogni ordinamento topologico del grafo rappresenta un ordine di valutazione possibile.
Ordine di valutazione Qui consideriamo solo metodi che non richiedono la costruzione del grafo di dipendenza (oblivious methods) ma metodi che definiscono l’ordine in base alla tecnica di parsing adottata. Questo restringe la classe degli attributi definibili ma è semplice da implementare ed estrememente efficiente.
Attributi semantici: applicazioni Costruzione di syntax tree. L’uso di alberi sintattici come rappresentazione intermedia consente di disaccoppiare il processo di traduzione da quello di analisi. Un albero sintattico è una forma astratta e compatta di parsing tree dipendente solo dal linguaggio e non dalla grammatica adottata per descriverlo.
Costruzione del Syntax Tree di espressioni Ogni nodo è rappresentato da un record contrnrntr vari campi. Un nodo può rappresentare un operatore o un operando. Nel primo caso deve anche contenere puntatori agli operandi. Si usano tre funzioni. Ciascuna restituisce un puntatore al nodo creato.
Costruzione del Syntax Tree funzioni primitive • mknode(op,left,right), crea nodo op (operatore) op e operandi left right. • mkleaf(id,entry) crea nodo id (operando). entry è uno spix a symbol table. • mkleaf(num,val) , crea un nodo di tipo valore: il campo val contiene il valore
Costruzione del Syntax Tree funzioni primitive EE1+T E.np:=mknode(‘+’,E1.np,T.np) EE1-T E.np:=mknode(‘-’,E1.np,T.np) ET E.np:=T.np T(E) T.np:=E.np Tid T.np:=mkleaf(id,id.entry) Tnum T.np:=mkleaf(num,num.val)
Costruzione del Syntax Tree a DAG Si usa un grafo orientato aciclico per rappresentare sotto-espressioni comuni. Esempio: a+a*(b-c)+(b-c)*d • p1=mkleaf(id,a) • p2:=mkleaf(id,a) • p3:=mkleaf(id,b) • p4:=mkleaf(id,c) • p5:=mknode(‘-’,p3,p4)
Costruzione del Syntax Tree a DAG Esempio: a+a*(b-c)+(b-c)*d • p6:=mknode(‘*’,p2,p5) • p7:=mknode(‘+’,p1,p6) • p8:=mkleaf(id,b) • p9:=mkleaf(id,c)
Costruzione di un Syntax Tree a DAG Algoritmo I nodi del grafo sono memorizzati in un array ciascuno puntato da un cursore (indice). La segnatura di un nodo è formata da una tripla <op,l,r> Input: op l ed r Output: nodo con segnatura <op,l,r> Metodo: scandire l’array fino a trovare nodo con etichetta op
Costruzione di un Syntax Tree a DAG Algoritmo Metodo: scandire l’array fino a trovare un nodo m con etichetta op figliosinistro l e destro r. Se esiste restituire m altrimenti creare un nuovo nodo <op,l,r> alla posizione lst e restituire lst. La ricerca può essere ottimizzato con una tavola hash.
Calcolo bottom-up di definizioni s-attributed In questo caso gli attributi possono essere valutati bottom-up da un parser shift-reduce o di altro tipo bottom-up che conservi i valori associati ai simboli grammaticali sullo stack. Ad ogni azione reduce il parser valuta gli attributi sintetizzati a partire dai valori sullo stack. Il metodo è applicabile anche a certi tipi di attributi ereditati (parser LR)
Calcolo bottom-up di definizioni s-attributed Ipotesi: stack composto da due array paralleli stato-valore. “stato” è uno spix a parsing table (memorizzare sullo stack anche il simbolo grammaticale non serve, ma per leggibilità identifichiamo lo stato con il simbolo grammaticale).
Calcolo bottom-up di definizioni s-attributed Supponendo di valutare gli attributi prima della riduzione e che A.a:=f(X.x,Y.y,Z.z) sia associata a AXYZ. Prima di ridurre XYZ ad A i valori di Z.z, Y.y e X.x si trovano in val[top], val[top-1] e val[top-2] rispettivamente. Dopo la riduzione top viene decrementato di 2 e lo stato corrispondente ad A viene impilato in state[top] mentre il valore di A.a in val[top] .
Definizioni L-attributed Quando il processo di traduzione avviene durante il parsing un ordine di valutazione ottimale dipende dall’ ordine di creazione dei nodi del parsing tree da parte del parser. Un metodo compatibile con molti parser top-down e bottom-up si basa su una visita depth first dell’albero.
Visita depth-first e def. L-attributed PROC dfv(n: node); BEGIN FOR EACH child m OF n FROM left TO right DO eval inherited attributes of m; dfv(m); OD; eval syntetized attributes of n END;
Definizioni L-attributed Una definizione è L-attributed se ciascun attributo di ogni regola semantica di ogni produzione AX1X2…Xnè • un attributo sintetizzato • un attributo ereditato di Xj 1jn che dipende solo da: • Gli attributi di X1X2…Xj-1a sinistra di Xj • Dagli attributi ereditati di A; Ogni definizione S-attributed è L-attributed.
Definizioni L-attributed esempio ALM L.in:=l(A.i) M.i:=m(L.s) A.s:=f(M.s) AQR R.i:=r(A.i) Q.i:=q(R.s) A.s:=f(Q.s)
Schemi di traduzione Uno schema di traduzione è una DGS in cui gli attributi sono associati ai simboli grammaticali e le azioni semantiche sono inserite tra graffe nella parte destra delle produzioni ad indicare l’ordine di valutazione. Esempio: ATR Radop Tprint(adop.lexeme)R1| Tnum print(num.val)
Schemi di traduzione Nel progetto di schemi di traduzione occorre rispettare vincoli per garantire la disponibilità del valore di un attributo al momento dell’ uso. Per questo si usano definizioni L-attributed o meglio s-attributed. In questo caso le azioni vengono inserite in coda alla produzione, esempio: TT1*F T.val:=T1.valF.val TT1*F T.val:=T1.valF.val)
Schemi di traduzione: regole • Un attributo ereditato di un simbolo nella parte destra di una produzione deve essere calcolato un una azione che precede il simbolo, • Un’azione non deve usare un attributo sintetizzati di un token a destra dell’azione stessa, • Un attributo sintetizzato della parte sinistra di una prod. va calcolato solo dopo quelli a cui fa riferimento (OK in coda alla produzione)
Schemi di traduzione L-attributed Una TGDS L-attributed è trasformabile in uno schema conforme alle tre regole precedenti. Esempio (formattazione testo): SB B.ps:=10; S.ht:=B.ht BB1B2B1.ps:=B.ps; B2.ps:=B.ps B.ht:=max(B1.ht,B2.ht) BB1 subB2B1.ps:=B.ps; B2.ps:=shrink(B.ps) B.ht:=disp(B1.ht,B2.ht) Btext B.ht:=text.hB.ps;
Schemi di traduzione L-attributed B sta per box, BB1B2indica giustap-posizione di testo, BB1 subB2 denota l’operazione pedice: B2 viene posto a destra in basso di B1 ma in dimensione ridotta. ps è ereditato e indica l’altezza di una formula
Schemi di traduzione L-attributed SB.ps:=10BS.ht:=B.ht BB1.ps:=B.psB1B2.ps:=B.psB2 B.ht:=max(B1.ht,B2.ht) BB1.ps:=B.psB1 subB2.ps:=shrink(B.ps)B2 B.ht:=disp(B1.ht,B2.ht) Btext B.ht:=text.hB.ps;
Traduzioni topdown Implementazione di DGS L-attributed con parser topdown: EE1+TE.val:=E1.val+T.val EE1-TE.val:=E1.val+T.val ET E.val:=T.val T(E) T.val:=E.val TnumT.val:=num.val
Traduzioni topdown Implementazione di DGS L-attributed con parser topdown: ETR.i:=T.valR E.val:=R.s R+T R1.i:=R.i+T.val R1 R.s:=R1.s R-T R1.i:=R.i-T.val R1 R.s:=R1.s R R.s:=R.i T(E) T.val:=E.val TnumT.val:=num.val
Traduzioni topdown Si ricordi che un attributo ereditato di un token deve essere valutato in una azione che compare prima del token mentre un attributo sintetizzato della parte sinistra deve essere valutato dopo gli attributi Da cui ssso dipende.
Traduzioni topdown AA1YA.a:=g(A1.a,Y.y) AX A.a:=f(X.x) AXR RYR| Con le azioni sementiche diviene: AXR.i:=f(X.x) R A.a:=R.s RY R.i:=g(R.i,Y.y) R1 R.s:=R1.s R R.s:=R.i