– sintassi – semantica – pragmatica – implementazione
Transcript
– sintassi – semantica – pragmatica – implementazione
Sintassi e semantica • La sintassi dei linguaggi e la compilazione (cenni, materia ripresa nel corso di Linguaggi di Programmazione) • Introduzione alla semantica • La semantica operazionale di un semplice linguaggio 1 abbiamo visto: Linguaggi (artificiali) La descrizione di un linguaggio avviene su tre dimensioni (Morris, 1939): – sintassi regole di formazione: quando una frase è corretta relazioni tra segni – semantica attribuzione di significato: cosa significa una frase corretta relazioni tra segni e significato – pragmatica in qual modo frasi corrette e sensate sono usate relazioni tra segni, significato e utente Per un linguaggio eseguibile: eseguire una frase corretta, rispettandone la semantica – implementazione 2 1 già visto: Come è descritto un LP in queste tre dimensioni? – Sintassi • formale: grammatiche formali, BNF (Backus Naur Form) • quasi-formale: tipizzazione, vincoli contestuali – Semantica • informale: linguaggio naturale, manuale • formale: denotazione, operazionale – Pragmatica • informale: esempi • semi-formale: metodologie di programmazione – Implementazione • derivazione dalla semantica • macchina astratta 3 Sintassi e semantica Sintassi • Definisce quali frasi fanno parte del linguaggio, ovvero quali sequenze di caratteri costituiscono un programma “legale” • Ci dice come “appare” un programma • Strumenti per descrivere la sintassi: – grammatiche generative (Chomsky) – automi – BNF Semantica • Specifica il “significato” di ogni programma legale • Specifica il comportamento del programma al momento dell’esecuzione • Semantica Statica : Semantica che può essere determinata al momento della compilazione • Semantica Dinamica: Semantica determinata durante l’esecuzione • Metodologie usate per definire la semantica: – Algebrica - Operazionale – Assiomatica - Denotazionale 4 2 Sintassi • • Ci dice come costruire le frasi corrette del linguaggio: var A: integer; if a> 0 then C else C’ Var A: intgr; if a> 0 else C’ then C; Errore lessicale Errore grammaticale Stessi costrutti espressi in modo diverso in linguaggi diversi. Es: un vettore di 10 elementi interi In C: int V[10] In Pascal: V: array[0..9] of integer Presumibilmente questi due oggetti hanno lo stesso significato (ovvero la stessa semantica). 5 Sintassi • Come definire e riconoscere i costrutti corretti del linguaggio ? • Problema essenziale nella fase di compilazione di un programma • Enumerazione di tutti i programmi ben formati ? … un po’ lungo • Vari strumenti: - grammatiche generative: regole per costruire le frasi del linguaggio - grammatiche regolari - grammatiche libere da contesto - automi: formalismi per riconoscere i costrutti di un linguaggio - BNF: Backus Naur Form usata la prima volta per Algol in 1958 da Naur (chair di Algol committee) e Backus (segretario) - stessa cosa della grammatiche libere da contesto 6 3 Fasi nella traduzione di un programma 7 Fasi principali della compilazione Analisi lessicale (Scanner): Spezza un programma nei componenti sintattici primitvi, chiamati tokens (identificatori, numeri, parole riservate …) - grammatiche regolari - automi a stati finiti Analisi sintattica (Parsing): Crea una rappresentazione ad albero della sintassi del programma. Riconosce le frasi ben formate del linguaggio - grammatiche libere da contetso - pushdown automata - BNF Tabella dei simboli: Memorizza le informazioni sugli oggetti dichiarati (identificatori, procedure … ) Analisi semantica: Esegue dei controlli di semantica staticaper rilevare eventuali errori (vedi pu’ avanti). Ottimizzazione: Riscrive l’albero sintattico che rappresenta un programma in modo da migliorarne l’efficienza Generazione del codice: converte il programma analizzato sintatticamente in una versione eseguibile Tutto questo (e altro) è argomento di un corso del III Anno: Linguaggi di Programmazione 8 4 Traduzione ed esecuzione 9 Definire un linguaggio: un esempio Le stringhe delle espressioni aritmetiche formate a partire dalle variabili A, B con gli operatori *, + e le parentesi (, ) Esempî: A A+B+A A+(A*B) A+B (A+B+A) … Un’espressione può essere: la variabile A oppure la variabile B oppure un’espressione * un’espressione oppure un’espressione + un’espressione oppure ( un’espressione ) La definizione è ricorsiva… 10 5 Derivare una stringa Un’espressione può essere: la variabile A oppure la variabile B oppure un’espressione * un’espressione oppure un’espressione + un’espressione oppure ( un’espressione ) Distinguiamo: terminali non-terminali ausiliari Riscriviamo un nonterminale usando una regola della forma: A+(A*B) è un’espressione, perché: un’espressione può essere un’espressione + un’espressione ovvero può essere A + un’espressione ovvero può essere A + ( un’espressione ) ovvero può essere A + ( un’espressione * un’espressione ) ovvero può essere A + ( A * un’espressione) ovvero può essere A + ( A * B ) non-terminale può essere stringa-di-terminali-e-nonterminali 11 Linguaggi formali Def.: Un alfabeto A è un qualsiasi insieme (finito, non vuoto) i cui elementi sono detti caratteri (o simboli) Def.: Una parola sull’alfabeto A è una sequenza finita o nulla di caratteri appartenenti ad A. Def.: Un linguaggio (formale) L su A è un qualsiasi insieme di parole su A. Ovvero L è un qualsiasi sottoinsieme di A* dove A* = Un>=0 A n e A 0 = {λ} e A n = A A n-1 Indichiamo con la giustapposizione la concatenazione di sequenze, estesa in modo ovvio agli insiemi L’operatore * (stella di Kleene) applicato ad un simbolo indica 0 o più ripetizioni del simbolo. Sopra usiamo la sua estensione a un insieme. 12 6 Esempi L’insieme di tutti i programmi C è un linguaggio (il linguaggio C, in effetti) L’insieme di tutti gli assegnamenti che si possono scrivere in C è un linguaggio L’insieme {an b cn | n >1 } è un linguaggio (sull’alfabeto {a,b,c }) Un linguaggio, essendo un insieme, puo’ essere definito: - In modo estensionale: elencando tutti gli elementi dell’insieme … - In modo intensionale: definendo delle regole che ci dicono come sono fatti gli elementi dell’insieme. 13 Le formule aritmetiche con + e * Alfabeto dei terminali Alf = {A0, A1, A2,…,+,*, (, ) } Regole per produrre le formule <fbf> ::= A0 | A1 | A2 | … | (<fbf>+<fbf>) | (<fbf>∗<fbf>) può essere oppure ((A0 ∗ A2) + A0) è una formula: <fbf> ⇒ (<fbf> + <fbf> ) ⇒ ( <fbf> + A0) ⇒ (( <fbf> ∗ <fbf> ) + A0) ⇒ ((A0 ∗ <fbf> ) ) + A0 )⇒ ((A0 ∗ A2) ) + A0 ) 14 7 Le fbf del calcolo proposizionale Alfabeto Alf = {A0, A1, A2,…, →, ∧, ∨, ⊥, ¬, (, ) } Formule <fbf> ::= A0 | A1 | A2 | … | ⊥| (<fbf>∧ <fbf>) | (<fbf> ∨ <fbf>) | (<fbf>→<fbf>) | (¬ <fbf> ) ((¬(A0 ∧ A2)) ∨ ⊥) è una fbf: <fbf> ⇒ (<fbf> ∨ <fbf> ) ⇒ ( <fbf> ∨ ⊥) ⇒ ((¬ <fbf> ) ∨ ⊥) ⇒ ((¬ ( <fbf> ∧ <fbf> ) ) ∨ ⊥) ⇒ ((¬ (A0 ∧ <fbf> ) ) ∨ ⊥) ⇒ ((¬ (A0 ∧ A2) ) ∨ ⊥) 15 Grammatiche Libere • Grammatiche generative (introdotte da N. Chomsky, circa 1959) Def Una grammatica libera da contesto è una quadrupla (NT,T,S, R) dove - NT è un insieme finito di simboli non terminali T è un insieme (finito o numerabile) T di simboli terminali S ∈ NT è detto simbolo iniziale R è un insieme di regole (o produzioni) della forma: A ---> b dove A ∈ NT e b ∈ (NT ∪ T) * Il linguaggio L generato da una tale grammatica è definito come L = { w ∈ T * | S --->* w} dove, dati v, w ∈ (NT ∪ T) * , v ---> w sse v = xAy, W = xby e A ---> b è una regola della grammatica 16 8 BNF La Forma di Backus e Naur (BNF) è una notazione per presentare grammatiche libere, utilizzata per la prima volta nella definizione della sintassi Algol 60. - Si usa la notazione < w > per indicare un simbolo non terminale (w è una sequenza qualsiasi di caratteri - Si usa la notazione <A> ::= b invece che A ---> b - Si usa (nella versione estesa) la notazione per indicare due regole <A> ::= b | c <A> ::= b e <A> ::= c - Si usa (nelle versione estesa) il simbolo * (stella di Kleene) con il significato già visto - Operatore di riscrittura ⇒: sostituisce un non-terminale A in una parola con b se esiste la regola <A> ::= b 17 BNF Esempio Non terminali : {<frase>, <soggetto>, <articolo>, <nome>,<verbo>,<comp.oggetto> } Terminali: {un, cane, gatto, topo, mangia,insegue} Simbolo Iniziale: <frase> Regole: <frase> ::= <soggetto> <verbo><comp.oggetto> <soggetto> ::= <articolo> <nome> <verbo> ::= mangia | insegue <comp.oggetto> ::= <articolo> <nome> <articolo> ::= un <nome> ::= cane | gatto | topo 18 9 Esempio di riscrittura <frase> . I regola ⇒ <soggetto > <verbo><comp.oggetto> II regola ⇒ <articolo> <nome> <verbo><comp.oggetto> V regola ⇒ un <nome> <verbo><comp.oggetto> ⇒ un gatto <predicato> <verbo><comp.oggetto> … un gatto insegue un topo Ma potremmo derivare anche un topo mangia un gatto La sintassi corretta non implica che la semantica sia corretta ! 19 Esempio Letterali numerici in un linguaggio di programmazione <cifra> :: = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 <int_senza_segno> :: = <cifra><cifra>* <numero> :: = <int_senza_segno> <dec> <exp> <dec> ::= . <int_senza_segno> | ε <exp> ::= e <segno> <int_senza_segno> | ε <segno> :: = + | - | ε (In realtà una grammatica regolare, basta fare lo scanning da sinistra a destra) Espressioni <exp> :: = <identificatore> | <numero> | - <exp> ( <exp> ) | <exp> + exp> | <exp> *exp> (il linguaggio generato necessita della piena potenza delle grammatiche libere) 20 10 Esempi di derivazioni <exp> :: = <identificatore> | <numero> | - <exp> ( <exp> ) | <exp> + <exp> | <exp> *<exp> <exp> ⇒ <exp>*<exp> ⇒(<exp>)*<exp> ⇒(<exp>+<exp>)*<exp> ⇒(A+<exp>)*<exp> ⇒(A+B)*<exp> ⇒(A+B)*C <exp> ⇒ <exp>*<exp> ⇒<exp>*C ⇒(<exp>)*C ⇒(<exp>+<exp>)*C ⇒(A+<exp>)*C ⇒(A+B)*C <exp> <exp> * ( <exp> ) <exp> + <exp> A <exp> C B le due derivazioni distinte corrispondono allo stesso albero di derivazione 21 Alberi di derivazione Def. Data una grammatica G = (NT, T, S, R) un albero di derivazione (o di parsing) è un albero in cui: • ogni nodo è etichettato con un simbolo in NT ∪ T ∪ {ε}; • la radice è etichettata con S; • ogni nodo interno è etichettato con un simbolo in NT; • se il nodo n: ha etichetta A i suoi figli sono m1, … ,mk etichettati con X1,…,Xk (dunque A è in NT; X1,…,Xk sono in NT ∪ T ∪ {ε}) allora A ::= X1…Xk è una regola in R; • se il nodo n ha etichetta ε, allora n è una foglia ed è figlio unico. Teor. Una stringa (di terminali) w appartiene al linguaggio di G sse ammette un albero di derivazione (cioè un albero di derivazioni le cui foglie, lette da sin a destra, diano la stringa w). 22 11 Alberi di derivazione e precedenze La struttura dell’albero di derivazione di una buona grammatica dovrebbe rispecchiare la struttura “intesa” della stringa: <exp> <exp> <exp> + <exp> * <exp> C A B L’albero “dice”: fai prima A*B e poi somma il risultato per C. L’albero è la rappresentazione interna della stringa (del programma) usata dall’interprete o dal compilatore: la struttura dell’albero rappresenta la semantica della stringa. 23 Ambiguità <exp> :: = <identificatore> | <numero> | - <exp> ( <exp> ) | <exp> + <exp> | <exp> * <exp> <exp> <exp> <exp> A <exp> + <exp> * <exp> C B <exp> A * <exp> <exp> + <exp> B in questa grammatica la stessa stringa ha più di un albero di derivazione: la grammatica è ambigua. Inutilizzabile come rappresentazione della semantica! C 24 12 Grammatiche ambigue Def. Una grammatica è ambigua se: esiste almeno una stringa di simboli terminali che ammette più alberi di derivazione La grammatica delle espressioni è ambigua, perché A*B+C ha due alberi di derivazione anche se (A+B)*C ha un solo albero (e più derivazioni). Alcune grammatiche possono essere modificate in modo da: - rimuovere l’ambiguità, e - definire lo stesso linguaggio. Esistono grammatiche (patologiche) dalle quali non è possibile rimuovere l’ambiguità (i linguaggi generati sono inerentemente ambigui) 25 Rimuovere l’ambiguità <exp> :: = <identificatore> | <numero> | - <exp> ( <exp> ) | <exp> + exp> | <exp> *<exp> <exp> Introduciamo la precedenza di * su + complicando la grammatica <exp> <exp> :: = <term> ::= <atom> ::= <literal> ::= <term> | <exp> + <exp> <atom> | <term>*<term> <literal> | - <atom> | (<exp>) <identificatore> | <numero> + <exp> <term> <term> <atom> * <term> <term> <atom> <literal> L’altro albero non è più possibile La grammatica modificata e’ ancora ambigua ? <atom> <literal> <literal> A B C 26 13 Rimuovere l’ambiguità <exp> :: = <identificatore> | <numero> | - <exp> ( <exp> ) | <exp> + exp> | <exp> *<exp> <exp> Si, la seguente grammatica e’ ambigua <exp> :: = <term> ::= <atom> ::= <literal> ::= <exp> <term> | <exp> + <exp> <atom> | <term>*<term> <literal> | - <atom> | (<exp>) <identificatore> | <numero> Per disambiguarla dobbiamo introdurre anche la precedenza fra gli operandi: <term> | <term> + <exp> <atom> | <atom>*<term> <literal> | - <atom> | (<exp>) <identificatore> | <numero> <exp> <term> <term> <atom> <exp> :: = <term> ::= <atom> ::= <literal> ::= + * <term> <term> <atom> <atom> <literal> <literal> <literal> A B C 27 Il dangling else La dis-ambiguazione spiega alcuni contorcimenti delle grammatiche dei LP. Esempio in Java: if (porta-aperta) if (nessuno-in-vista) return “C’e’ nessuno?”; else suona-campanello(); Con quale “if” si accoppia “else”? Guardiamo alla definizione ufficiale di Java… 28 14 Da Java Language Specification http://java.sun.com/docs/books/jls/index.html ! " # " $ % $ & " Z [ \ [ ] ^ ] _ [ ' ( " ) * + " b a c , - # ( . ( & / ! 3 ` a Z [ d e + 4 5 Z g e l b \ [ ] ^ ] f " 7 8 6 1 # " $ 9 % $ 4 & : " ; B = C I J 2 < = > ? = @ = A ; A D E F G H p [ F K F E L E I ] _ Z [ _ [ v z r w v { | } | v ~ v z | v z r w v { | } | v ~ v z | [ \ [ ] ^ p ] ] _ [ i j [ b a k [ l \ j a c Z b z | m j _ n Z k o \ [ ] ^ ] _ F M N O P Q R S T { | } | v ~ v z | { | } | v ~ v z | U V R W X P Y R U [ h e if ( l h b r ] s _ t q u w w { y u Z x r y m v if ( f d d 0 [ \ [ ] ) y z ^ { ] | } _ | v [ ~ v t u v w w x y z s t u v w w x y z a c [ d e ) s ` { | } | v ~ v z | y { { | } | v ~ v z | y { y u | y u | else | if ( r Semplice variante di BNF: ) else y { y u | per non-terminali (nostro: <Statement>) : invece di ::= 29 Dunque … La lettura corretta e’: if (porta-aperta) if (nessuno-in-vista) return “C’e’ nessuno?”; else suona-camp(); “The Java programming language, like C and C++ and many programming languages before them, arbitrarily decree that an else clause belongs to the innermost if to which it might possibly belong” Ecco la derivazione: ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ if if if if if if if ( ( ( ( ( ( ( ) ) ) if ) if ) if ) if ) if ( ( ( ( ( ¡ ¢ ) else ) ) else ) return “C’e’ nessuno?”; else ) return “C’e’ nessuno?”; else ¥ ¢ £ ¢ ¤ ) if ( ) if ( ¡ ¢ £ ¢ ¤ § ¨ © ) return “C’e’ nessuno?”; else ) return “C’e’ nessuno?”; else suona-camp(); ¦ else ⇒ if ( ⇒ if ( 30 15 Vincoli sintattici contestuali Il numero di parametri attuali di una chiamata di procedura deve essere eguale al numero dei parametri formali della dichiarazione. Vincolo sintattico! Ma: lo strumento formale che usiamo (BNF) non è capace di esprimere vincoli che dipendono dal contesto (delle dichiarazioni). Soluzioni: usare strumenti più potenti per esempio: grammatiche contestuali riscrittura di un non-terminale solo in un determinato contesto no: non esistono tecniche automatiche di generazione di riconoscitori usare controlli ad hoc 31 Sintassi o semantica ? I vincoli contestuali per esempio: numero parametri attuali = parametri formali un identificatore deve essere dichiarato prima dell’uso compatibilità dei tipi in un assegnamento ecc. appartengono alla sintassi. Ma tradizionalmente, nel gergo dei LP, si intende: Sintassi: Quello che si descrive in BNF Semantica: Il resto… I vincoli contestuali sono dunque vincoli “semantici”… 32 16 Controlli “semantici” • Semantica Statica Vincoli (sintattici contestuali) determinabili al momento della compilazione – var A: integer; tipo e allocazione di memoria per A – int B[10]; tipo e allocazione di memoria per il vettore B – float MyProcC(float x,float y){...}; parametri – X = 3.2; in Java errore compilazione se X è int • Semantica Dinamica Vincoli determinabili durante l’esecuzione del programma: Z= X/Y Z= V[Y] errore se Y = 0 errore se Y = 11 e V: array[0..9] of integer (Pascal) Questi errori possono essere rilevati solo a run-time Non può esistere un compilatore che rileva tutti i possibili errori che si verificheranno a run-time. (E’ indecidibile sapere staticamente se si verificherà un errore in un programma) 33 Possibile? L’azienda Macrosoft ha rilasciato un’applicazione di debugging H. Dato un qualsiasi programma P: H chiamata su P stampa 1 se P termina quando è applicato a se stesso; H chiamata su P stampa 0 se P cicla quando è applicato a se stesso. L’azienda Moon sostiene che Macrosoft racconta balle. Chi ha ragione? 34 17 No! Macrosoft ha preso una cantonata. H non può esistere. Supponiamo che esista. Sfruttando H, costruiamo una nuova applicazione G che si comporta così: G(P) = 1 se H(P) = 0 G(P) cicla se H(P) = 1 Scrivere G, sfruttando H come sottoprogramma è un gioco da ragazzi… Ma cosa succede se chiamiamo G su se stessa? G(G) = 1 sse H(G) = 0 sse G(G) cicla G(G) cicla sse H(G) = 1 sse G(G) non cicla assurdo! dunque G non può esistere, ovvero non può esistere H 35 Ma allora altre applicazioni non esistono… Esiste un’applicazione T tale che: T(P,x)=1 se P(x) termina T(P,x)=0 se P(x) cicla ? NO: T permetterebbe di costruire H: H(P) = T(P,P) Esiste un’applicazione Z tale che: Z(P)=1 se P(x) è sempre lo stesso output per ogni x Z(P)=0 in caso contrario ? NO: Z permetterebbe di costruire H: costruisci prima un’applicazione F che manipola programmi e si comporta così: F(P) è un programma che, dato in input un generico x (che non viene usato), prova ad eseguire P sull’input P. Se e quando tale esecuzione termina, F(P)(x) stampa 0. Altrimenti (ovviamente) F(P)(x) cicla. Scrivere F non è problematico se si ha a disposizione un interprete (per eseguire P su P). Ora, se esistesse Z, si potrebbe definire H: H(P) = Z ( F (P)). 36 18 H(P) = Z ( F (P)) Infatti Z(F(P)) = 1 se F(P)(x) e’ lo stesso per ogni input x se P(P) termina Z(F(P) = 0 se F(P)(x) non e’ lo stesso per ogni input x se P(P) non termina 37 Ma allora altre applicazioni non esistono… Esiste un’applicazione Equiv tale che: Equiv(P,Q)=1 se P e Q hanno la stessa semantica Equiv(P,Q)=0 se P e Q sono distinti da almeno un input. ? NO: Equiv permetterebbe di costruire Z: Scriviamo prima un programmino ZERO che stampa sempre 0. Z(P) = Equiv (P, ZERO) (suppodniamo per semplicita’ che il valore prodotto da P sia 0). Il sogno dell’ingegneria del software è destinato a rimanere tale… 38 19 Semantica • Serve per poter definire con esattezza ``cosa fa‘’ un programma (e quindi sviluppare tecniche di ottimizzazione, debugging, verifica di correttezza, traduzione fra formalismi diversi ecc. ecc.) • La definizione (semi) formale della semantica fa parte dello standard di definizione di un linguaggio a partire dagli anni ‘80 • Vari metodi per definire la semantica di un linguaggio di programmazione - Algebrica - Assiomatica - Operazionale - Denotazionale • Non esiste una metodologia standard universalmente accettata 39 Semantica Operazionale • Ottenuta definendo un interprete del linguaggio L su di una macchina ospite i cui componenti sono descritti in modo matematico. • Utile soprattutto perche’ fornisce direttamente un modello di implementazione • E’ possibile definirla in modo formale e guidato dalla sintassi (SOS) 40 20 Structured Operational Semantics (SOS) • Definizione della semantica in modo guidato dalla sintassi: • Si definiscono delle regole di transizione che specificano i passi di computazione per un costrutto composto A op B in termini di quelli dei componenti A e B • Regole date nello stile della deduzione naturale: Premessa Conseguenza 41 SOS • Dato che i costrutti che ci interessano in generale modificano una qualche nozione di stato, di solito le regole di transizione sono definite su configurazioni del tipo <Comando, Stato> Le regole specificano dunque transizioni del tipo <C, σ > → <C`, σ`> • Formalmente le regole definiscono (induttivamente) la relazione che dice come una configurazione evolve in un’altra → • L’insieme delle configurazioni e la relazione di transizione costituiscono un Sistema di Transizione (TS) 42 21 Sistema di Transizione (TS) • Un TS e’ definito da una quadrupla (S,I,F, →) dove – S e’ l’insieme delle configurazioni – I ⊆ S e’ l’insieme delle configurazioni iniziali – F ⊆ S e’ l’insieme delle configurazioni finali – → ⊆ S x S e’ una relazione di transizione ( scriviamo s → s’ per indicare (s,s’) ∈ →) • Una sequenza di esecuzione e’ una sequenza di configurazioni C1 C2 ….. Cn tale che: – C1 ∈I, – Cn ∈ F, – Ci → Ci+1 per ogni 0 <= i < n 43 Sistema di Transizione (TS) • Un TS e’ detto deterministico se per ogni c ∈C esiste al piu’ un c’ tale che c → c’ . • La relazione → e’ definita (induttivamente) da un insieme di regole del tipo c1→ c1’ ……. cn → cn’ op (c1……. cn ) → op’ (c1’ ……. cn’ ) ovvero e’ il minimo insieme che soddisfa l’insieme delle regole date 44 22 Un mini-linguaggio imperativo 45 Semantica delle espressioni aritmetiche 46 23 Nota sulle regole • • Le regole usano metavariabili (n, X, a0 etc.) sui vari domini sintattici. Una istanza di una regola si ottiene istanziando queste variabili a particolari numeri, variabili, espressioni etc. Esempio di istanza 47 Nota sulle regole • Le istanze delle regole si compongono in strutture ad albero dette alberi di derivazione (o derivazioni) dove: – tutte le premesse di istanze di regole sono conclusioni di istanze di regole immediatamente sopra nell’albero; – alla sommita’ dell’albero ci sono assiomi del tipo <a,σ > Esempio di derivazione: 48 24 Semantica delle espressioni booleane 49 Semantica delle espressioni booleane 50 25 Semantica dei comandi 51 Semantica del while 52 26