Elementi di semantica operazionale 1 Sintassi e semantica

  • Slides: 100
Download presentation
Elementi di semantica operazionale 1

Elementi di semantica operazionale 1

Sintassi e semantica § un linguaggio di programmazione, come ogni sistema formale, possiede l

Sintassi e semantica § un linguaggio di programmazione, come ogni sistema formale, possiede l una sintassi • le formule ben formate del linguaggio (o programmi sintatticamente corretti) l una semantica • che assegna un significato alle formule ben formate • dando un’interpretazione ai simboli – in termini di entità (matematiche) note 2

Sintassi e semantica § la teoria dei linguaggi formali fornisce i formalismi di specifica

Sintassi e semantica § la teoria dei linguaggi formali fornisce i formalismi di specifica (e le tecniche di analisi) per trattare gli aspetti sintattici § per la semantica esistono diverse teorie l le più importanti sono la semantica denotazionale e la semantica operazionale § la semantica formale viene di solito definita su una rappresentazione dei programmi in sintassi astratta l invece che sulla reale rappresentazione sintattica concreta 3

Semantica operazionale • lo stile di definizione tradizionale è quello dei sistemi di transizione

Semantica operazionale • lo stile di definizione tradizionale è quello dei sistemi di transizione • insieme di regole che definiscono • attraverso un insieme di relazioni di transizione come lo stato cambia per effetto dell’esecuzione dei vari costrutti • una tipica regola descrive la semantica di un costrutto sintattico c eseguito nello stato s, specificando il nuovo stato s’ e/o il valore calcolato v • i domini semantici con cui rappresentiamo lo stato ed i valori dipendono dal linguaggio di programmazione 4

Linguaggio Didattico § Semplice linguaggio imperativo (frammento di C), blocchi, puntatori, chiamata di funzione

Linguaggio Didattico § Semplice linguaggio imperativo (frammento di C), blocchi, puntatori, chiamata di funzione § Rivediamo l’interprete presentato a Programmazione I 5

Sintassi concreta Programma: : = int main() {Stmt. List} Stmt. List : : =

Sintassi concreta Programma: : = int main() {Stmt. List} Stmt. List : : = Stmt ; Stmt. List | e Stmt: : =Decl | Com

Comandi Com: : =Ide=Exp | Assegnamento if (Exp) Com else Com | Condizionale while

Comandi Com: : =Ide=Exp | Assegnamento if (Exp) Com else Com | Condizionale while (Exp) Com | Iteratore {Stmt. List} | Blocco Ide(Exp) | Invocazione di fun return Exp Calcolo dei risultato di una fun

Espressioni Exp: : = Ide | Identificatore Costante | Costante Exp Op Exp |

Espressioni Exp: : = Ide | Identificatore Costante | Costante Exp Op Exp | Operazioni Binarie Uop Exp | Operazioni Unarie Ide(Exp) | Chiamata di fun (Exp) Parentesi

Espressioni 2 Ide: : = Lettera (Lettera | Cifra | Simbolo)* Costante: : =

Espressioni 2 Ide: : = Lettera (Lettera | Cifra | Simbolo)* Costante: : = Numero | Carattere Un. Op: : = ! | * | Op: : =+ | - | * |. . . & | > | < | ==. . Numero: : =É

Puntatori § ! si applica per semplicita’ ai soli identificatori. La locazione calcolata, in

Puntatori § ! si applica per semplicita’ ai soli identificatori. La locazione calcolata, in questo caso `e la locazione in cui `e memorizzato il valore dell’identificatore § * che si applica ad una qualunque espressione, la calcola ottenendo un valore v che viene per`o trasformato in una locazione l. Il valore finale calcolato `e il valore v’ contenuto nella locazione l.

Dichiarazioni Decl : : = Type Ide [=Exp] | Funct. Dec variabile funzione Funct.

Dichiarazioni Decl : : = Type Ide [=Exp] | Funct. Dec variabile funzione Funct. Dec: : = Type Ide (Formal) {Stmt. List} Type: : = int Formal: : = Type Ide

Nota § Per semplicita’ si considerano funzioni che hanno un solo parametro formale §

Nota § Per semplicita’ si considerano funzioni che hanno un solo parametro formale § L’estensione a piu’ parametri e’ banale § Ricordiamo che il passaggio dei parametri e’ per valore

Semantica Operazionale § Domini dei valori § Componenti dello stato § Regole di Transizione

Semantica Operazionale § Domini dei valori § Componenti dello stato § Regole di Transizione per ogni categoria sintattica (espressioni, dichiarazioni, comandi, programmi)

Domini semantici: lo stato § in un qualunque linguaggio ad alto livello, lo stato

Domini semantici: lo stato § in un qualunque linguaggio ad alto livello, lo stato deve comprendere una componente chiamato ambiente (environment) l per modellare l’associazione tra gli identificatori ed i valori che questi possono denotare (dval) § il nostro frammento è imperativo ed ha la nozione di entità modificabile, cioè le variabili ed i puntatori (create con le dichiarazioni e modificate con l’assegnamento) § è quindi necessario un secondo componente dello stato, chiamato memoria (store) l per modellare l’associazione fra locazioni e valori che possono essere memorizzati (mval) 14

L’ambiente § Per modellare i blocchi l’ambiente e’ una pila di Frames • La

L’ambiente § Per modellare i blocchi l’ambiente e’ una pila di Frames • La politica FIFO permette di catturare la dichiarazione piu’ recente di una variabile

Valori (memorizzabili) § Ide identificatori § Val=Int + {omega}+{Undef} § Loc le locazioni di

Valori (memorizzabili) § Ide identificatori § Val=Int + {omega}+{Undef} § Loc le locazioni di memoria, possono essere rappresentati come numeri naturali. Nel seguito useremo la notazione 0 L , 1 L , 2 L. . . ecc, per indicare rispettivamente le locazioni di indirizzo 0, 1, 2 ecc

Memoria • store: Loc ---> Val (si usa la metavariabile μ) § Nota: Val

Memoria • store: Loc ---> Val (si usa la metavariabile μ) § Nota: Val non contiene le locazioni. Nella semantica data, si usano meccanismi per trasformare locazioni in valori e viceversa. La seconda `e possibile ed anzi molto semplice perch`e le locazioni sono numeri naturali

Frame • frame: Ide ---> Den (si usa la metavariabile φ) § Den =

Frame • frame: Ide ---> Den (si usa la metavariabile φ) § Den = Loc ∪ Fun. Decl ∪ Unbound. L’insieme delle denotazioni `e l’unione dell’insieme Loc degli indirizzi di memoria e dell’insieme Fun. Decl delle definizioni di funzione e della denotazione speciale Undef, che rappresenta una situazione di errore.

Funzioni Fun. Decl `e una tripla Ide × SList × Env 1) il nome

Funzioni Fun. Decl `e una tripla Ide × SList × Env 1) il nome del parametro formale 2) il corpo della funzione 3) l’ambiente di definizione (scoping statico)

Operazioni sui Frames § Empty. Frame crea il frame ovunque indefinito φ(x)=Unbound per ogni

Operazioni sui Frames § Empty. Frame crea il frame ovunque indefinito φ(x)=Unbound per ogni x

Modifica di un frame φ[d/x](y)= φ(y) se x e’ diverso da y d se

Modifica di un frame φ[d/x](y)= φ(y) se x e’ diverso da y d se x=y • La definizione cos`ı data risulta corretta anche nell’eventualit`a che un legame diverso da Unbound per x esista gia’ • non e’ molto corretto solo per programmi sintatticamente corretti

Ambiente • env=Stack(Frames) (si usa la metavariabile σ)

Ambiente • env=Stack(Frames) (si usa la metavariabile σ)

Operazioni sulla pila • Empty. Stack crea la pila vuota • top restituisce l’elemento

Operazioni sulla pila • Empty. Stack crea la pila vuota • top restituisce l’elemento in testa alla pila ovvero l’ultimo elemento inserito. Non modifica la pila. • pop restituisce l’elemento in testa alla pila. Modifica la pila, eliminando l’elemento in testa. • push inserisce un elemento in testa alla pila.

Operazioni sulla memoria • μ : Loc ---> Val=Int + {omega}+{Undef} • Verrebbe da

Operazioni sulla memoria • μ : Loc ---> Val=Int + {omega}+{Undef} • Verrebbe da dare operazioni analoghe a quelle del frame. . si tratta di una funzione parziale

Gestione della memoria • allocazione di memoria: l’inserzione di nuovi legami nella memoria corrisponde

Gestione della memoria • allocazione di memoria: l’inserzione di nuovi legami nella memoria corrisponde alla allocazione di memoria su una machina, e differisce dall’inserzione di un nuovo legame in un generico frame • Deve esserci un meccanismo per assegnare una nuova locazione ancora libera • Deve esserci un modo per distinguere una locazione assegnata con valore indefinito da una libera

Operazioni sulla Memoria • μ(l)=omega • μ(l)=Undef valore speciale indefinita § Empty. Store crea

Operazioni sulla Memoria • μ(l)=omega • μ(l)=Undef valore speciale indefinita § Empty. Store crea una memoria ovunque indefinita μ(x)=Undef per ogni x

Allocazione di Memoria • free: Store---> Loc *Store • restitituisce una nuova locazione libera

Allocazione di Memoria • free: Store---> Loc *Store • restitituisce una nuova locazione libera e la memoria modificata di conseguenza • free(μ) = (μ’, l) dove μ’(l’)= μ(l’) per ogni l’!= l μ’(l)=omega se μ(l)=Undef

Modifica di Memoria μ[v/l](l’)= μ(l’) se l != l’ Undef se μ(l)=Undef v altrimenti

Modifica di Memoria μ[v/l](l’)= μ(l’) se l != l’ Undef se μ(l)=Undef v altrimenti § l’operazione di modifica non effettua l’inserzione del legame per l nel caso non ne esista alcuno ma in questo ultimo caso, lascia la memoria invariata (da un punto di vista matematico va bene. . )

Le funzioni di valutazione semantica § per ogni dominio sintattico esiste una funzione di

Le funzioni di valutazione semantica § per ogni dominio sintattico esiste una funzione di valutazione semantica § E : EXPR * env * store (eval * store) § C : COM * env * store § D : DEC * env * store (env * store) § P : PROG * env * store 29

Implementazione in OCaml § Vediamo i domini § La Sintassi Astratta § Le funzioni

Implementazione in OCaml § Vediamo i domini § La Sintassi Astratta § Le funzioni di valutazione semantica che assegnano un significato ai vari costrutti, con una definizione data sui casi della sintassi astratta § Per semplicita’ nell’interprete si usano funzioni che restituiscono una coppia (ambiente, memoria) per ogni categoria sintattica

Programma Pico. C § http: //www. di. unipi. it/~occhiuto/Pico. C/ § Generatore di programmi

Programma Pico. C § http: //www. di. unipi. it/~occhiuto/Pico. C/ § Generatore di programmi Pico. C in sintassi astratta § Alcuni esempi di programmi Pico. C in sintassi astratta per testare l`interprete

Valori Val=Int + {omega}+{Undef} type value = Val of int | Omega | Undef;

Valori Val=Int + {omega}+{Undef} type value = Val of int | Omega | Undef; ;

Valori Denotabili Den = Loc ∪ Fun. Decl ∪ Unbound type denotation = Loc

Valori Denotabili Den = Loc ∪ Fun. Decl ∪ Unbound type denotation = Loc of int | Funct of string * com * sigma ref | Unbound; ; • In Fun. Decl c’e’ il riferimento all’env (per trattare la ricorsione. . )

Frame • frame: Ide ---> Den (si usa la metavariabile φ) type fi =

Frame • frame: Ide ---> Den (si usa la metavariabile φ) type fi = Frame of (string * denotation) list; ; • Definizione molto a basso livello, una lista di coppie (identificatore, valore)

Ambiente • env=Stack(Frames) type sigma = Stack of fi list; ; • Definizione molto

Ambiente • env=Stack(Frames) type sigma = Stack of fi list; ; • Definizione molto a basso livello, una lista di frames

Memoria • μ : Loc ---> Val § type 'a mu = Mem of

Memoria • μ : Loc ---> Val § type 'a mu = Mem of 'a list ; ; • Definizione molto a basso livello, una lista polimorfa • Si usera’ per memorizzare coppie (identificatore, valore)

Espressioni § type aop = Add | Sub | Mul | Div | And

Espressioni § type aop = Add | Sub | Mul | Div | And | Or | Ls | Gr | Eq ; ; § type unop = Neg | Amp | Star; ; § type a. Exp = Num of int | Exp of a. Exp * aop * a. Exp | Bracket of a. Exp | Un. Exp of unop * a. Exp | Var of string | Apply of string * a. Exp ; ;

Comandi § type com = Assign of string * a. Exp | Assign. De.

Comandi § type com = Assign of string * a. Exp | Assign. De. Ref of a. Exp * a. Exp | If of a. Exp * com | While of a. Exp * com | Block of (stmt list) | Return of a. Exp; ;

Dichiarazioni § type decl = Decl 1 of esp. Type * string | Decl

Dichiarazioni § type decl = Decl 1 of esp. Type * string | Decl 2 of esp. Type * string * a. Exp | Decl. Fun of esp. Type * string * com; ;

Programmi type stmt = St. Dec of decl | St. Com of com; ;

Programmi type stmt = St. Dec of decl | St. Com of com; ; type prog = Prog of (stmt list); ; • Un programma e’ una lista di statements (dichiarazioni, comandi)

Funzione main § let val. Prog (Prog l)= let (sigma, mu)= val. Stmt. L

Funzione main § let val. Prog (Prog l)= let (sigma, mu)= val. Stmt. L l (Stack[Frame[]], (Mem []))in (mu, sigma); ; • Il programma e’ valutato nello stato iniziale, lo stack contiene un frame vuoto e la memoria e’ vuota • restituisce lo stato ottenuto

Per valutare una lista di statements § Funzione ricorsiva (val. Stmt. L) § Per

Per valutare una lista di statements § Funzione ricorsiva (val. Stmt. L) § Per ogni statement (comando o dichiarazione) chiama la funzione di valutazione corrispondente

Lista di Statements let val. Stmt. L l (sigma, mu) = match l with|

Lista di Statements let val. Stmt. L l (sigma, mu) = match l with| [] -> (sigma, mu)| st: : stml -> (match st with | St. Dec d -> let (sigma 1, mu 1) = val. Decl d (sigma, mu) in val. Stmt. L stml (sigma 1, mu 1) | St. Com c -> let (sigma 1, mu 1) = val. Com c (sigma, mu) in val. Stmt. L stml (sigma 1, mu 1)); ;

Dichiarazioni § val. Decl: Decl * (env*mem)---> (env*mem) § Funzione ricorsiva (val. Decl) §

Dichiarazioni § val. Decl: Decl * (env*mem)---> (env*mem) § Funzione ricorsiva (val. Decl) § Usa val. Exp: Exp* (env*mem)---> (Val*env*mem)

Dichiarazioni § Variabile senza inizializzazione § Variabile con inizializzazione § Funzione

Dichiarazioni § Variabile senza inizializzazione § Variabile con inizializzazione § Funzione

Sintassi Astratta § type decl = Decl 1 of esp. Type * string |

Sintassi Astratta § type decl = Decl 1 of esp. Type * string | Decl 2 of esp. Type * string * a. Exp | Decl. Fun of esp. Type * string * com; ;

Funzioni Ausiliarie: memoria • free: Store---> Loc *Store • restitituisce una nuova locazione libera

Funzioni Ausiliarie: memoria • free: Store---> Loc *Store • restitituisce una nuova locazione libera e la memoria modificata di conseguenza (alla nuova locazione viene assegnato il valore omega) type 'a mu = Mem of 'a list ; ;

Implementazione let free (Mem xm) = let loc = (length xm) in ((Loc loc),

Implementazione let free (Mem xm) = let loc = (length xm) in ((Loc loc), (Mem (append xm [((Loc loc), Omega)] ))); ; • la lista e’ del tipo [(0, v 1), (1, v 20). . . ] • la prima locazione libera e’ detreminata con length

Modifica della Memoria § Serve una operazione update. M: Store*Loc*Val---> Store • Modifica la

Modifica della Memoria § Serve una operazione update. M: Store*Loc*Val---> Store • Modifica la memoria rimpiazzando il valore associato alla locazione con il nuovo valore

Implementazione let rec update. M (Mem m) (x, y) = let def m x

Implementazione let rec update. M (Mem m) (x, y) = let def m x = foldr (or) false (map (compose ((=) x) (fst)) m) and modify m (x, y) = let f (x, y) b = if ((fst b)=x) then (x, y) else b in map (f(x, y)) m in if (not(def m x)) then (Mem m) else (Mem (modify m (x, y))); ; Usa due funzioni ausiliarie def e modify per testare se la locazione x e’ definita e per modificarne il valore nella lista

Modifica dell’env let rec add. Bind sigma (x, y) = match sigma with |

Modifica dell’env let rec add. Bind sigma (x, y) = match sigma with | Stack [Frame[]] -> Stack [Frame[(x, y)]] | Stack ((Frame f): : fs) -> Stack ((Frame (append f [(x, y)])) : : fs); ; • inserisce il nuovo legame tra x ed y nell’env sigma (ovvero nel frame al top della pila, tramite append e’ una lista di coppie)

Dichiarazione di variabile semplice let val. Decl d (sigma, mu) = match d with

Dichiarazione di variabile semplice let val. Decl d (sigma, mu) = match d with Decl 1 (t, i) -> let (l, mu 1) = free mu in let sigma 1= (add. Bind sigma (i, l)) in (sigma 1, mu 1) • viene modificata la memoria (l e’ una locazione fresh, coniene valore indefinito) • viene modificato l’env inserendo l’associazione (i, l)

Dichiarazione di variabile con inizializzazione let val. Decl d (sigma, mu) = match d

Dichiarazione di variabile con inizializzazione let val. Decl d (sigma, mu) = match d with Decl 2 (t, i, e) -> let (v, (sigma 1, mu 1)) = (val. Exp e (sigma, mu)) in let (l, mu 2) = free mu 1 in let sigma 2= (add. Bind sigma 1 (i, l)) in let mu 3 = update. M mu 2 (l, v) in (sigma 2, mu 3) • viene modificata la memoria (l e’ una locazione fresh coniene valore indefinito) • viene modificato l ’env inserendo l’associazione (i, l) • il contenuto della locazione l viene poi aggiornato con il valore calcolato per l’espressione e

Dichiarazione di Funzione Decl. Fun (t, i, tp, ip, c) • stiamo dichiarando una

Dichiarazione di Funzione Decl. Fun (t, i, tp, ip, c) • stiamo dichiarando una funzione di nome i, parametro ip, corpo c in (sigma, mu) • dovremmo modificare l’env sigma inserendo l’associazione tra i e la sua descrizione (ip, c, sigma 1) • chi e’ sigma 1? vediamo la regola formale

Problemi di Implementazione • bisogna implementarlo usando un puntatore all’env in Fun. Decl Funct

Problemi di Implementazione • bisogna implementarlo usando un puntatore all’env in Fun. Decl Funct of string * com * sigma ref | Unbound; ;

Dichiarazione di Funzione let val. Decl d (sigma, mu) = match d with Decl.

Dichiarazione di Funzione let val. Decl d (sigma, mu) = match d with Decl. Fun (t, i, tp, ip, c) ->let rec sigma 1=(add. Bind sigma (i, (Funct (ip, c, (ref sigma))))) in ((update i sigma 1), mu) • in sigma 1 la descrizione della funzione i contiene un riferimento a sigma (andrebbe bene se non fossero ricorsive • nota che viene restituito come risultato update i sigma 1

Intuitivamente update i sigma 1 • cerca la descrizione di funzione di i in

Intuitivamente update i sigma 1 • cerca la descrizione di funzione di i in sigma 1 (p, c, sigma ref) • la modifica assegnando sigma 1 al posto di sigma

Funzione Ausiliaria let rec update. F i f sigma = match f with []

Funzione Ausiliaria let rec update. F i f sigma = match f with [] -> f | (j, Funct(x, c, var)): : fs when (i=j) -> var : =sigma; f | (_, _): : fs -> update. F i fs sigma; ; let rec update i s sigma = match s with Stack [Frame[]]-> s | Stack ((Frame fs): : ss) -> (update. F i fs sigma); s; ;

Comandi § val. Com: Com * (env*mem)---> (env*mem) § Funzione ricorsiva (val. Com) §

Comandi § val. Com: Com * (env*mem)---> (env*mem) § Funzione ricorsiva (val. Com) § Usa val. Exp: Exp* (env*mem)---> (Val*env*mem)

Comandi § § § Condizionale While Assegnamento Blocco Return

Comandi § § § Condizionale While Assegnamento Blocco Return

Comandi § type com = Assign of string * a. Exp | Assign. De.

Comandi § type com = Assign of string * a. Exp | Assign. De. Ref of a. Exp * a. Exp | If of a. Exp * com | While of a. Exp * com | Block of (stmt list) | Return of a. Exp; ;

Funzioni Ausiliarie: env • lookup: Env * Ide---> Den = Loc ∪ Fun. Decl

Funzioni Ausiliarie: env • lookup: Env * Ide---> Den = Loc ∪ Fun. Decl ∪ Unbound • restitituisce il valore denotabile associato all’identificatore • Env e’ uno Stack di Frames, in realta’ e’ una lista di frames • la ricerca ricorsiva inizia dal frame al top, e. g. dal primo elemento della lista

Funzioni Ausiliarie: frame • look: Frame * Ide---> Den = Loc ∪ Fun. Decl

Funzioni Ausiliarie: frame • look: Frame * Ide---> Den = Loc ∪ Fun. Decl ∪ Unbound • restitituisce il valore denotabile associato all’identificatore • Frame e’ una lista di coppie (identificatore, valore)

Implementazione let rec look. Up sigma y = match sigma with | Stack []

Implementazione let rec look. Up sigma y = match sigma with | Stack [] -> Unbound | Stack (x : : xs) -> let b= (look x y) in if (not (b=Unbound)) then b else (look. Up (Stack xs) y); ; let rec look fi y = match fi with | Frame [] -> Unbound | Frame ((i, d) : : xs) -> if (i=y) then d else (look (Frame xs) y); ;

Condizionale let val. Com c (sigma, mu) = match c with | If (e,

Condizionale let val. Com c (sigma, mu) = match c with | If (e, c 1, c 2) -> let ((Val i), (sigma 1, mu 1)) = (val. Exp e (sigma, mu)) in if not (i=0) then val. Com c 1 (sigma, mu 1) else val. Com c 2 (sigma, mu 1) • viene calcolato il valore di e • se true esegue c 1, altrimenti c 2

While let val. Com c (sigma, mu) = match c with | While (e,

While let val. Com c (sigma, mu) = match c with | While (e, c) -> let ((Val i), (sigma 1, mu 1)) = (val. Exp e (sigma, mu)) in if not (i=0) then let (sigma 2, mu 2) = (val. Com c (sigma 1, mu 1))in val. Com (While (e, c)) (sigma 2, mu 2) else (sigma 1, mu 1) • viene calcolato il valore di e, se false restituisce (sigma 1, mu 1) • se true esegue While (e, c) nello stato modificato da c

Assegnamento let val. Com c (sigma, mu) = match c with | Assign (s,

Assegnamento let val. Com c (sigma, mu) = match c with | Assign (s, e) -> let (v, (sigma 1, mu 1)) = (val. Exp e (sigma, mu)) and (Loc l) = (look. Up sigma s) in (sigma 1, update. M mu 1 ((Loc l), v) • viene calcolato il valore v di e e la locazione l legata alla variabile s in sigma • viene modificato lo store assegnando alla locazione l il valore v

Blocco let val. Com c (sigma, mu) = match c with | Block l

Blocco let val. Com c (sigma, mu) = match c with | Block l -> let (Stack (f: : rl), mu 1) = val. Stmt. L l ((match sigma with Stack fl -> Stack (Frame[]: : fl)) , mu) in (Stack rl, mu 1) • valuta l nello stato in cui un frame vuoto Frame[] e’ stato messo al top della pila • restituisce l’env da cui e’ stato fatto pop (le variabili del blocco sono locali)

Blocco: regola astratta • l’implementazione delle operazioni di pop() e push(frame) e’ parecchio complicata

Blocco: regola astratta • l’implementazione delle operazioni di pop() e push(frame) e’ parecchio complicata • regola astratta

Return let val. Com c (sigma, mu) = match c with | Return e

Return let val. Com c (sigma, mu) = match c with | Return e -> val. Com (Assign ("ret. Val", e)) (sigma, mu)) • assegna il valore di e ad una variabile speciale retval, valore di ritorno della funzione che e’ in esecuzione

Assegnamento Deferenziato let val. Com c (sigma, mu) = match c with | Assign.

Assegnamento Deferenziato let val. Com c (sigma, mu) = match c with | Assign. De. Ref (e, ev) -> let (v, (sigma 1, mu 1)) = (val. Exp ev (sigma, mu)) in let (v 1, (sigma 2, mu 2)) = (val. Exp e (sigma 1, mu 1)) in let (Loc l) = (eta. Loc v 1) in (sigma 2, update. M mu 2 ((Loc l), v)) • viene calcolato il valore v di e e il valore v 1 di e • viene modificato lo store assegnando alla locazione corrispondente a v 1 il valore v

Funzione Ausiliaria: let ni. Loc x = match x with (Loc l) -> (Val

Funzione Ausiliaria: let ni. Loc x = match x with (Loc l) -> (Val l) |_ -> Undef; ; let eta. Loc x = match x with (Val n) when (n>=0) -> (Loc n) | _ -> Unbound; ; • trasformano locazioni in valori interi e viceversa

Espressioni § val. Expr: Expr * (env*mem)---> Val *(env*mem) § Funzione ricorsiva (val. Expr)

Espressioni § val. Expr: Expr * (env*mem)---> Val *(env*mem) § Funzione ricorsiva (val. Expr)

Espressioni § § costanti valore di una variabile risultato di una chiamata di funzione

Espressioni § § costanti valore di una variabile risultato di una chiamata di funzione operazioni di confonto, somma tra espressioni (binarie) § operazione unaria

Espressioni § type aop = Add | Sub | Mul | Div | And

Espressioni § type aop = Add | Sub | Mul | Div | And | Or | Ls | Gr | Eq ; ; § type unop = Neg | Amp | Star; ; § type a. Exp = Num of int | Exp of a. Exp * aop * a. Exp | Bracket of a. Exp | Un. Exp of unop * a. Exp | Var of string | Apply of string * a. Exp ; ;

Funzioni Ausiliarie: stato • get. Val: (Env*Mem) * Ide---> Val • deve restituire il

Funzioni Ausiliarie: stato • get. Val: (Env*Mem) * Ide---> Val • deve restituire il valore associato all’identificatore x • cercare nella pila di Frames Env la locazione l associata ad x • restituire il valore associato ad l nella memoria

Implementazione let rec get. Val (sigma, mu) x = let b=(look. Up sigma x)

Implementazione let rec get. Val (sigma, mu) x = let b=(look. Up sigma x) in match b with | Loc n -> (look. M mu (Loc n)) | _ -> Undef; ; • look. Up cerca nell’env (pila) la locazione n associata ad x • look. M cerca nella memoria il valore associato ad n

Implementazione: look. M let rec look. M mu y = match mu with Mem

Implementazione: look. M let rec look. M mu y = match mu with Mem [] -> Undef | Mem (( i, v) : : xs) -> if (i=y) then v else (look. M (Mem xs) y); ; | la memoria e’ una lista di coppie (i, v), cerca ricorsivamente un identificatore uguale ad y

Costante, Parentesi let rec val. Exp e (sigma, mu) = match e with |

Costante, Parentesi let rec val. Exp e (sigma, mu) = match e with | Num n -> ((Val n), (sigma, mu)) | Bracket x -> val. Exp x (sigma, mu)

Variabile let rec val. Exp e (sigma, mu) = match e with | Var

Variabile let rec val. Exp e (sigma, mu) = match e with | Var s -> ((get. Val (sigma, mu) s), (sigma, mu)) • restituisce il valore associato alla variabile s, calcolato tramite get. Val

Operazioni Binarie let rec val. Exp e (sigma, mu) = match e with |

Operazioni Binarie let rec val. Exp e (sigma, mu) = match e with | Exp (x, op, y) -> let (v 1, (sigma 1, mu 1))= (val. Exp x (sigma, mu)) in let (v 2, (sigma 2, mu 2))= (val. Exp y (sigma, mu 1)) in. . . • calcola ricorsivamente i valore v 1 e v 2 di x ed y, rispettivamente • in un ordine

Procede per casi sull’operazione if (is. Num. Op op) then (ni. Num ( (fun.

Procede per casi sull’operazione if (is. Num. Op op) then (ni. Num ( (fun. Num. Op op) (eta. Num v 1) (eta. Num v 2)), (sigma 2, mu 2)) else • is. Num. Op restituisce true se e’ una operazione numerica (somma etc. . ) • Fun. Num. Op applica l’operazione corrispondente a op ai valori v 1 e v 2 • ni. Num, eta. Num servono solo per convertire i valori Val i in i e viceversa

Funzioni ausiliarie let | | | is. Num. Op op = match op with

Funzioni ausiliarie let | | | is. Num. Op op = match op with Add -> true Sub -> true Div -> true Mul -> true _ -> false; ;

Funzioni ausiliarie let fun. Num. Op op = match op with| Add -> (+)|

Funzioni ausiliarie let fun. Num. Op op = match op with| Add -> (+)| Sub -> (-)| Mul -> (fun x y -> x*y) | Div -> (/) ; ;

Funzioni ausiliarie di conversione per interi let ni. Num x = (Val x); ;

Funzioni ausiliarie di conversione per interi let ni. Num x = (Val x); ; let eta. Num (Val x) = x; ;

Procede per casi if (is. Bool. Op op) then (ni. Bool( (fun. Bool. Op

Procede per casi if (is. Bool. Op op) then (ni. Bool( (fun. Bool. Op op) (eta. Bool v 1) (eta. Bool v 2)) , (sigma 2, mu 2)) else (ni. Bool( (fun. Rel. Op op) (eta. Num v 1) (eta. Num v 2)) , (sigma 2, mu 2)) • se e’ un’operazione booleana applica la relativa operazione ai valori booleani v 1 e v 2 • se e’ un’operazione relazionale applica la relativa operazione ai valori booleani v 1 e v 2

Funzioni ausiliarie let | | | is. Bool. Op op = match op with

Funzioni ausiliarie let | | | is. Bool. Op op = match op with And -> true Or -> true _ -> false; ;

Funzioni Ausiliarie let fun. Bool. Op op = match op with | And ->

Funzioni Ausiliarie let fun. Bool. Op op = match op with | And -> (&) | Or -> (or) ; ; let fun. Rel. Op op = match op with| Ls -> (<) | Gr -> (>) | Eq -> (=); ;

Funzioni Ausiliarie di conversione let ni. Bool x = if x then (Val 1)

Funzioni Ausiliarie di conversione let ni. Bool x = if x then (Val 1) else (Val 0); ; let eta. Bool (Val x) = if (x=0) then false else true; ;

Operazioni Unarie: per casi let rec val. Exp e (sigma, mu) = match e

Operazioni Unarie: per casi let rec val. Exp e (sigma, mu) = match e with | Un. Exp (op, x) -> (match op with Neg -> let (v 1, (sigma 1, mu 1))= (val. Exp x (sigma, mu)) in (ni. Bool( (funop 1 op) (eta. Bool(v 1)) ), (sigma 1, mu 1)) § caso della negazione e’ analogo a quello visto prima § calcola il valore v di x e chiama funzioni

Operazioni Unarie: puntatore | Un. Exp (op, x) -> (match op with |Amp ->

Operazioni Unarie: puntatore | Un. Exp (op, x) -> (match op with |Amp -> ((val. Den x sigma), (sigma, mu)) § deve restituire la locazione di x § usa una funzione ausiliaria val. Den

Funzione ausiliaria: val. Den let rec val. Den e sigma = (match e with

Funzione ausiliaria: val. Den let rec val. Den e sigma = (match e with |Var s -> ni. Loc(look. Up sigma s) |Exp (x, y, z) -> Undef|Un. Exp(x, y) -> Undef| Bracket x -> Undef); ; § e’ definita nel caso di espressione e generica, ma e’ definita solo per le variabili § tramite lookup restituisce la locazione associata ad s nell’ambiente sigma

Operazioni Unarie: deferenziato | Un. Exp (op, x) -> (match op with |Star ->

Operazioni Unarie: deferenziato | Un. Exp (op, x) -> (match op with |Star -> let (v, (sigma, mu 1)) =(val. Exp x (sigma, mu)) in (look. M mu 1 (eta. Loc v), (sigma, mu 1))) § calcola il valore v di x (tramite val. Exp) § restuisce il valore memorizzato nella memoria nella locazione v

Chiamata di Funzione § Apply(s, a) dobbiamo applicare la funzione s al parametro attuale

Chiamata di Funzione § Apply(s, a) dobbiamo applicare la funzione s al parametro attuale a nello stato (sigma, mu) § Parte I: dobbiamo cercare il nome s nell’ambiente sigma, restituisce un Fun. Decl Funct(f, c, sigmaf) • f e’ il parametro formale • c e’ il corpo della funzione • sigmaf e’ l’ambiente al momento della dichiarazione della funzione s (scoping statico) § Parte II: dobbiamo valutare il parametro a nello stato corrente, calcolarne il valore v (per valore)

Chiamata di Funzione: Part II § Dobbiamo valutare il corpo della funzione c, in

Chiamata di Funzione: Part II § Dobbiamo valutare il corpo della funzione c, in quale stato? § Lo stato di valutazione si costruisce a partire da (sigmaf, mu) • Bisogna mettere sulla pila sigmaf un Empty. Frame (push) che serve per contenere le dichiarazioni locali alla funzione • Le dichirazioni locali conterranno il legame tra il parametro formale f ed il valore del parametro attuale v e la variabile speciale retval • Nota che per inserire un legame devono essere modifica sia l’ambiente che la memoria

Chiamata di Funzione: Part III § Cosa restituisce? § il valore associato alla variabile

Chiamata di Funzione: Part III § Cosa restituisce? § il valore associato alla variabile retval § l’ambiente sigma al momento della chiamata (non modificato) § la memoria modificata dall’esecuzione dei comandi

Chiamata di Funzione: val. Exp • Vediamo il codice di val. Exp per la

Chiamata di Funzione: val. Exp • Vediamo il codice di val. Exp per la funzione • Molto complicato, perche’ di basso livello • La nozione di stato (env, mem) non fornisce operazioni chiare per fare push, pop • Inoltre l’introduzione di un nuovo legame in un frame viene fatto a mano, operando direttamente sulla lista che implementa il frame • Analogamente l’introduzione di un nuovo legame nella memoria viene fatto a mano, operando direttamente sulla lista che lo implementa

Chiamata di funzione let rec val. Exp e (sigma, mu) = match e with

Chiamata di funzione let rec val. Exp e (sigma, mu) = match e with | Apply (s, a) -> let (v, (sigma 1, mu 1))= val. Exp a (sigma, mu) in (match (look. Up sigma s) with Funct (f, c, sigmaf) ->. . • calcola tramite val. Exp il valore v del parametro attuale a • cerca tramite look. Up la Fun. Decl relativa ad s

Chiamata di funzione (let (l, mu 2)=(free mu 1) in let (l 1, mu

Chiamata di funzione (let (l, mu 2)=(free mu 1) in let (l 1, mu 3) =(free mu 2) in let sigmav=(match (! sigmaf) with Stack sl -> add. Bind (Stack (Frame []: : sl)) (f, l)) ("ret. Val", l 1)) • sceglie due locazioni libere in memoria l ed l 1 • modifica l’ambiente sigmaf , facendo push di un frame che contiene (f, l) e (retval l 1)

Chiamata di funzione in let (sigma 2, mu 4)= val. Com c (sigmav, update.

Chiamata di funzione in let (sigma 2, mu 4)= val. Com c (sigmav, update. M mu 3 (l, v)) in ((look. M mu 4 l 1), (sigma, mu 4))) • valuta il corpo della funzione c nell’ambiente sigmav costruito in precedenza, e nella memoria ottenuta aggiungendo il legame tra (l, v) • restituisce il valore della locazione l 1 nella memoria (il valore di retval), l’ambiente sigma iniziale, e la memoria finale mu 4