1 Implementazione di Linguaggi 2 Massimo Ancona DISI Università di Genova Testo: A.V. Aho, R. Sethi, J.D.Ullman Compilers Principles,Techniques and Tools, Addison Wesley
2 Diagramma del processo di compilazione
3 Strumenti associati al compilatore: il Linker
4 Contesto/ambiente di un cmp Programming Environment Un ambiente grafico interattivo per lo sviluppo, il testing e la manutenzione dei programmi: integra e gestisce gli strumenti e i meccanismi seguenti Un ambiente grafico interattivo per lo sviluppo, il testing e la manutenzione dei programmi: integra e gestisce gli strumenti e i meccanismi seguenti Strumenti e meccanismi correlati ai compilatori Sistemi per le compilazioni separate Sistemi per le compilazioni separate Sistemi per il controllo delle versioni Sistemi per il controllo delle versioni Meccanismi per le ricompilazioni efficienti Meccanismi per le ricompilazioni efficienti Macroprocessori e Preprocessori Macroprocessori e Preprocessori Linker loader Linker loader
5 PROCESSO DI COMPILAZIONE PROCESSO DI COMPILAZIONE Nella sua forma piu' astratta il processo di compilazione e' descritto nella figura seguente: il compiler e' una funzione che mappa un programma in linguaggio sorgente in un programma equivalente in linguaggio oggetto.
6 FASI E PASSI (PASSATE) Sono due concetti ortogonali: Le fasi denotano trasformazioni sul programma eseguite da tutti i compilatori, i passi si riferiscono al numero di processi successivi, in cui e' suddiviso un compilatore (il loro numero dipende in parte dal linguaggio) Il compilatore in una passata, legge il codice sorgente o una sua forma intermedia equivalente, raffinando il processo di treduzione e producendo una nuova rappresentazione intermedia, fino ad arrivare al codice target, nellultima passata.
7 FASI DI COMPILAZIONE FASI DI COMPILAZIONE Una fase denota il tipo di operazione effettuata. Fasi e le passate sono concetti ortogonali anche se una struttura canonica del compilatore tende ad incapsulare una (o piu') fasi, in una specifica passata. La divisione piu' grossolana prevede due fasi: analisi e sintesi. Con la prima il programma sorgente viene suddiviso nelle parti costituenti ottenendone una rappresentazione intermedia. Nella seconda si costruisce il programma target nel linguaggio oggetto.
8 Analisi e Sintesi Strumenti che eseguono lanalisi dellinput Editori di testo, Formattatori e Sistemi Ipertestuali (HTML, XML, PDF, TEX) Editori di testo, Formattatori e Sistemi Ipertestuali (HTML, XML, PDF, TEX) Silicon Compilers Silicon Compilers Query Interpreters Query Interpreters Motori di Ricerca e strumenti correlati Motori di Ricerca e strumenti correlati
9 Analisi e Sintesi Analisi Analisi divide il pgm sorgente nelle parti costituenti creando una rappresentazione intermedia. Sintesi Sintesi costruisce il programma oggetto dalla rappresentazione intermedia.
10 DETTAGLIO DELLE FASI DETTAGLIO DELLE FASI ELenco completo delle possibili fasi di compilazione:
11 RAPPRESENTAZIONI INTERMEDIE sorgente primo := base + 53 * delta; out lessicale id[1] <-- id[2] op= id[3] op+ ci=53 op* id[3] out sintattico op= / \ id[1] op+ / \ id[2] op* / \ id[3] 53
12 RAPPRESENTAZIONI INTERMEDIE (E FINALI) semantica op= / \ id[1] op+ / \ id[2] op* / \ id[3] float | 53
13 RAPPRESENTAZIONI INTERMEDIE codice intermedio tmp1 = float(53) tmp2 = id[3] op* tmp1 tmp3 = id[2] op+ tmp2 id[1] = tmp3 Ottimizzazione di codice (intermedio) tmp1 = id[3] op* id[1] = id[2] op+ tmp1
14 RAPPRESENTAZIONE FINALE codice macchina movf id3.off[FP],rf2 mulf 53.00,rf2 movf id[2][FP].offs,rf1 addf rf2,rf1 movf rf1,id[1].offs[FP]
15 Tipi di Compilatori Vi sono diversi tipi di compilatori Ad un sol passo Ad un sol passo Multi-passo Multi-passo Load_and_go Load_and_go Debugging Debugging Optimizing Optimizing
16 Introduzione alla Compilazione Un compilatore in due passate
17 Le fasi di analisi del sorgente Sono tre: analisi lessicale, sintattica e semantica Analisi lessicale o lineare: in inglese skanning/ skanner. Ad esempio listruzione: alpha:=beta+gamma*100; viene codificata in: Gli spazi ridondanti, i fine linea ecc. che separano i token vengono eliminati.
18 Le fasi di analisi del sorgente Analisi sintattica o gerarchica: in inglese parsing/ parser. Agisce dopo lanalisi lessicale. Esempio: Si puo codificare in un albero sintattico del tipo: ( ) ( )
19 La fase di analisi del sorgente Analisi Lineare o lessicale: In inglese scanning/ scanner. Ad esempio listruzione: alpha:=beta+gamma*100; viene codificata in: Gli spazi ridondanti, i fine linea ecc. che separano i token vengono eliminati.
20 La fase di analisi sintattica Analisi Gerarchica o sintattica: In inglese parsing/ parser. Agisce dopo lanalisi lessicale. Esempio: Si codifica in un albero: ( ) ( )
21 Relazione tra le Fasi La suddivisione tra analisi lessicale e sintattica e piuttosto arbitraria (come per le altre fasi della compilazione); Uno dei metodi usati per discriminarle si basa sulla ricorsione: i costrutti descrivibili senza ricorsione si assegnano allanalisi lessicale; i costrutti descrivibili senza ricorsione si assegnano allanalisi lessicale; quelli sostanzialmente ricorsivi a quella sintattica. quelli sostanzialmente ricorsivi a quella sintattica.
22 Sintassi formale dei linguaggi di programmazione La si specifica tramite: diagrammi sintattici; diagrammi sintattici; equazioni BNF EBNF; equazioni BNF EBNF; grammatiche non contestuali (context free) grammatiche non contestuali (context free) Sono tutte forme sostanzialmente equivalenti.
23 Grammatiche CFG definizione formale Alfabeto: formalmente un alfabeto T ( ) e un insieme finito non vuoto. Gli elementi di T ( ) vengono chiamati simboli o caratteri. Useremo le lettere V, T, N, per indicare alfabeti Parola: una parola, di lunghezza k 0, su un alfabeto T, e una sequenza finita w=x 1 x 2 …x k di elementi di T. k, denotata anche k=|w| e detta lunghezza di w. La parola di lunghezza zero, detta parola vuota, e indicata.
24 Grammatiche CFG definizione formale L insieme delle parole su T viene indicato T* Monoide libero: T* e strutturato in monoide dalloperazione di concatenazione di parole. Date w 1,w 2 T, con w 1 = x 1 x 2 …x k,w 2 = y 1 y 2 …y l, la parola w= w 1.w 2 = x 1 x 2 …x k y 1 y 2 …y l, di lunghezza k+l, e detta concatenazione di w 1 e w 2. Il monoide (T*,.) e detto monoide libero su T.
25 Grammatiche CFG definizione formale In particolare: loperazione di concatenazione di parole struttura linsieme T* in monoide detto monoide libero su T (w. =.w=w). Grammatica CFG: formalmente e una quadrupla G=(N,T,P,S) con N T= e dove: T e un alfabeto detto dei simboli terminali di G T e un alfabeto detto dei simboli terminali di G N e un alfabeto detto dei non terminali di G N e un alfabeto detto dei non terminali di G P e un insieme finito di produzioni di G P e un insieme finito di produzioni di G S N e detto simbolo iniziale di G S N e detto simbolo iniziale di G
26 Grammatiche CFG definizione formale Ogni produzione N V* Ogni produzione N V* Notazione: a,b,c,d,.. Indicano elementi di T a,b,c,d,.. Indicano elementi di T A,B,C,… indicano elementi di N A,B,C,… indicano elementi di N U,V,X,Y,Z indicano elementi di V=T N U,V,X,Y,Z indicano elementi di V=T N u,v,x,y,z indicano elementi di T* u,v,x,y,z indicano elementi di T*,,,…, indicano elementi di V*,,,…, indicano elementi di V* =(A, ) N V* e indicata da A =(A, ) N V* e indicata da A
27 Forme Sentenziali Forma sentenziale: data G=(N,T,P,S) una forma sentenziale di G e definita ricorsivamente: Forma sentenziale: data G=(N,T,P,S) una forma sentenziale di G e definita ricorsivamente: S e una forma sentenziale di G S e una forma sentenziale di G se A e una forma sentenziale di G e A e una produzione di G allora e una forma sentenziale di G. se A e una forma sentenziale di G e A e una produzione di G allora e una forma sentenziale di G. La relazione tra A e al precedente punto 2 viene indicata: A A
28 Derivazioni dirette e non Derivazione diretta: A esprime che deriva direttamente da A o che A genera direttamente. Derivazione diretta: A esprime che deriva direttamente da A o che A genera direttamente. Le notazioni * + indicano rispettivamente la chiusura transitiva-riflessiva e transitiva di Le notazioni * + indicano rispettivamente la chiusura transitiva-riflessiva e transitiva di * denota che = o i i=1,n * denota che = o i i=1,n = 1 2 … n = e n>0, mentre = 1 2 … n = e n>0, mentre denota che e n>0. + denota che = 1 2 … n = e n>0.
29 Linguaggio generato da una grammatica: linguaggi CFG Linguaggio generato da G: L(G)= w T*| S * w L(G)= w T*| S * w Un linguaggio L T* e libero da contesto se esiste G=(N,T,P,S) CFG tale che L=L(G)
30 Derivazioni canoniche, parsing tree, ambiguita Una derivazione e detta canonica destra, indicata se per ogni i si ha i = i A i x i, i+1 = i i x i,, Una derivazione * e detta canonica destra, indicata rm * se per ogni i si ha i = i A i x i, i+1 = i i x i, A i i, = 1 2 … n = i=1,…,n Una derivazione e detta canonica sinistra, indicata se per ogni i si ha i =x i A i i, Una derivazione * e detta canonica sinistra, indicata lm * se per ogni i si ha i =x i A i i, i+1 =x i i i, A i i, = 1 2 … n = i=1,…,n
31 Esempio Sia G=({E,T,P},{(,),a,b,c,*,+,-},P,E) dove P={E E+T|E-T|T, T T*P|P, P (E)|a|b} Notazione: E E+T|E-T|T, T T*P|P e P (E)|a|b abbreviano le produzioni E E+T, E E-T, E T, T T*P, T P, P (E), P a, P b, P c} La derivazione E E E-T T-T P-T (E)-T (E-T)-T (T-T)-T (P-T)-T (a-T)-T (a-P)-T (a-b)-T (a-b)-P (a-b)-c e canonica sinistra,
32 Esempio Sia G=({E,T,P},{(,),a,b,c,*,+,-},P,E) dove P={E E+T|E-T|T, T T*P|P, P (E)|a|b} Mentre la derivazione: E E E-T E-P E-c T-c P-c (E)-c (E-T)-c (E-P)-c (E-b)-c (T-b)-T (P-b)-c (a-b)-c e canonica destra, Confrontandola con la sinistra: E E E-T T-T P-T (E)-T (E-T)-T (T-T)-T (P-T)-T (a-T)-T (a-P)-T (a-b)-T (a-b)-P (a-b)-c Si vede che differiscono solo per lordine di applicazione delle produzioni. Entrambe applicano le stesse produzioni alle stesse istanze di non terminali
33 Parsing Tree Tutte le derivazioni che differiscono solo per lordine di applicazione delle produzioni sono sostanzialmente equivalenti e possono essere rappresentate da ununica derivzione canonica destra, un unica derivazione canonica sinistra o da un unico albero etichettato detto Parsing Tree definito come segue:
34 Parsing Tree La radice e etichettata da S Ogni nodo terminale dellalbero e etichettato da o da un simbolo di T (terminale) Ogni nodo interno e etichettato da un simbolo di N (non terminale) Se A etichetta un nodo interno e X 1,X 2,…, X n sono le etichette dei figli, allora A X 1 X 2 …X n
35 Esempio di Parsing Tree e deriv. canonica associata Esempio di Parsing Tree e deriv. canonica associata E E E-T E-P E-c T-c P-c (E)-c (E-T)-c (E-P)-c (E-b)-c (T-b)-T (P-b)-c (a-b)-c
36 Esempio di Parsing Tree Esempio di Parsing Tree E E E-T E-P E-c T-c P-c (E)-c (E-T)-c (E-P)-c (E-b)-c (T-b)-T (P-b)-c (a-b)-c
37 Esempio di Parsing Tree Esempio di Parsing TreeAmbiguita Una grammatica G e ambigua se esiste w L(G) con due parsing tree diversi (con due derivazioni canoniche destre o sinistre distinte). Una grammatica G e ambigua se esiste w L(G) con due parsing tree diversi (con due derivazioni canoniche destre o sinistre distinte). Un linguaggio e inerentemente ambiguo se per ogni G tale che L=L(G) si ha che G e ambigua.
38 Esempio di GRM G ambigua Esempio di GRM G ambigua S if b then S | if b then S else S| s G=({S},{if,then,else,s}, P={S if b then S | if b then S else S|s}, S) S rm if b then S rm if b then if b then S else S rm if b then if b then S else s rm if b then if b then s else s S rm if b then S else S rm if b then S else s rm if b then if b then S else s rm if b then if b then s else s Grammatica equivalente non ambigua (due non terminali) S S 1 S 1 if b then S 1 | if b then S 2 else S 1 | s S 2 if b then S 2 else S 1 | s
39 Esempio di G ambigue e non con proprieta opportune Esempio di G ambigue e non con proprieta opportune Di seguito si mostrano solo le produzioni Grammatica di espressioni non ambigua con priorita di operatori e associativita cablate E E+T | E-T | T T T*F | T/F | F F P^F | P P (E) | I | N I a|b|c|d N 0 | 1 | 2 G per espressioni, semplice ma ambigua E EOE|(E)|a|b|c|d O +|-|*|^
40 Altri esempi di grammatiche Altri esempi di grammatiche Di seguito si presentano solo le produzioni Grammatica G 0 di espressioni non ambigua con priorita di operatori e associativita cablate E E+T | E-T | T|-T|+T T T*F | T/F | F F (E) | I | N I a|b|c|d N 0 | 1 | 2 G 1 per espressioni, semplice, non ambigua ma flat E EOT|T|-T|+T T (E)|a|b|c|d|0|1|2 O +|-|*|/
41 Due derivazioni canoniche di G0 e G1 Due derivazioni canoniche di G0 e G1 Data a-b*c abbiamo G 0 : E rm E-T rm E-T*F rm E-T*I rm E-T*c rm E-F*c rm E-I*c rm E-b*c rm T-b*c rm F-b*c rm I-b*c rm a-b*c G 1 : E rm EOT rm EOc rm E*c rm EOT*c rm E-b*c rm T-b*c rm a-b*c Esercizio: studiare G 2 E FOT|T ; F FOT|T| ; T (E)|a|b|c|d|0|1|2 ; O +|-|*|^
42 I relativi parse tree (G 0 ) I relativi parse tree (G 0 ) E E-T T T*F F F I I I c a b a b G 0 : E rm E-T rm E-T*F rm E-T*I rm E-T*c rm E-F*c rm E-I*c rm E-b*c rm T-b*c rm F-b*c rm I-b*c rm a-b*c
43 I relativi parse tree (G 1 ) I relativi parse tree (G 1 ) E EOT E O T*c E O T*c T - b T - b a G 1 : E rm EOT rm EOc rm E*c rm EOT*c rm E-b*c rm T-b*c rm a-b*c
44 Operazioni sui Linguaggi Operazioni sui Linguaggi Dati due linguaggi L,MT* definiamo prodotto di L ed M indicato LM o L M linsieme Dati due linguaggi L,M T* definiamo prodotto di L ed M indicato LM o L M linsieme L M ={uv|u L&v M} Definiamo chiusura di Kleene di L, indicata L* loperazione: L 0 ={ } L 1 =L L i =L L i-1 i>0 L*= i 0 L i L + = i>0 L i L + = i>0 L i
45 Esempio di G ambigue e non con proprieta opportune Esempio di G ambigue e non con proprieta opportune Proprieta: supponiamo T terminale e vediamo le produzioni di E G 0 =({E},{t,+,-},P0,E) P 0 ={E E+t | E-t | t|-t|+t} L(G 0 )={-t,+t,t}({+,-}t)* e G 1 =({E,O},{t,+,-},P1,E) P 1 ={E EOt|t|-t|+t,O +|-} O +|- L(G 1 )=L(G 0 )
46 Un esempio di LNG inerentemente ambiguo e uno di LNG non CFL Un esempio di LNG inerentemente ambiguo e uno di LNG non CFL L={a i b j c k | i=j OR j=k; i,j,k 0} S S 1 S 2 | S 3 S 4 S 1 aS 1 b | S 2 S 2 c| S 1 aS 1 b | S 2 S 2 c| S 4 bS 4 c | S 3 S 3 a| S 4 bS 4 c | S 3 S 3 a| L={a n b n c n | n>( ) 0} non e un CFL
47 Syntax Tree (albero sintattico) e Parsing Tree Syntax Tree (albero sintattico) e Parsing Tree Albero Sintattico Una delle rappresentazioni intermedie piu usate. Piu astratto del parsing tree, Una delle rappresentazioni intermedie piu usate. Piu astratto del parsing tree, dipende solo dal linguaggio (non dalla grammatica)
48 EBNF EBNF Usa i simboli metalinguistici = | [ ] {. }. Usa i simboli metalinguistici = | [ ] {. }. […] significa opzionalita {…} significa ripetizione: 0 o piu volte (…) significa raggruppamento | indica alternativa. termina una produzione I simboli terminali vengono racchiusi tra I simboli terminali vengono racchiusi tra Esempio Expression = SimpleExpression [ Relation SimpleExpression ]. Relation = "=" | "<>" | " " | ">=" | IN. SimpleExpression = [ "+" | "-" ] Term { AddOperator Term }. AddOperator = "+" | "-" | OR. Term = Factor { MulOperator Factor }. MulOperator = "*" | "/" | DIV | MOD | AND
49 EBNF Esempio (Espressioni) EBNF Esempio (Espressioni) Expression = SimpleExpression [ Relation SimpleExpression ]. Relation = "=" | "<>" | " " | ">=" | IN. SimpleExpression = [ "+" | "-" ] Term { AddOperator Term }. AddOperator = "+" | "-" | OR. Term = Factor { MulOperator Factor }. MulOperator = "*" | "/" | DIV | MOD | AND
50 EBNF Espressioni (cont.) EBNF Espressioni (cont.) Designator [ ActualParameters ] | "(" Expression ")" | NOT Factor. Set = "[" [ Element { "," Element } ] "]". Element = OrdinalConstant [ ".." OrdinalConstant]. OrdinalConstant= Char | Integer. ActualParameters = ["(" [ ExpressionList ] ")"]. Ident = IdChar { IdChar | Digit }. IdChar = Letter | "_". Number = Integer | Real.
51 EBNF Espressioni (cont. 2) EBNF Espressioni (cont. 2) Integer = Digit { Digit } | Digit { HexDigit } "H". Real = Digit { Digit } "." { Digit } [ ScaleFactor ]. ScaleFactor = "E" [ "+" | "-" ] Digit { Digit }. HexDigit = Digit | "A" | "B" | "C" | "D" | "E" | "F". Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9". CharConstant = "'" Char "'" | Digit { HexDigit } "X". String = ' { CharN | "''" } '. Char = CharN | "'".