Elementi di semantica
operazionale
1
Sintassi e semantica
un linguaggio di programmazione, come ogni sistema formale, possiede
una sintassi
• le formule ben formate del linguaggio (o programmi sintatticamente
corretti)
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
(e le tecniche di analisi) per trattare gli aspetti sintattici
per la semantica esistono diverse teorie
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
invece che sulla reale rappresentazione sintattica concreta
3
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
Rivediamo l’interprete presentato a
Programmazione I
5
Sintassi concreta
Programma::= int main() {StmtList}
StmtList ::= Stmt ; StmtList | e
Stmt::=Decl | Com
Comandi
Com::=Ide=Exp |
Assegnamento
if (Exp) Com else Com |
Condizionale
while (Exp) Com |
Iteratore
{StmtList} |
Blocco
Ide(Exp) |
Invocazione di fun
return Exp
Calcolo dei risultato di una fun
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::= Numero | Carattere
UnOp::= ! | * |
Op::=+ | - | * |...& | > | < | ==....
Numero::=É
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] |
FunctDec
variabile
funzione
FunctDec::= Type Ide (Formal) {StmtList}
Type::= int
Formal::= Type Ide
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 per ogni categoria
sintattica (espressioni, dichiarazioni,
comandi,programmi)
Domini semantici: lo stato
in un qualunque linguaggio ad alto livello, lo stato
deve comprendere una componente chiamato
ambiente (environment)
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)
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 politica FIFO permette di catturare la
dichiarazione piu’ recente di una variabile
Valori (memorizzabili)
Ide identificatori
Val=Int + {omega}+{Undef}
Loc le locazioni di memoria, possono essere
rappresentati come numeri naturali. Nel seguito
useremo la notazione 0L , 1L , 2L ...ecc, per indicare
rispettivamente le locazioni di indirizzo 0, 1, 2 ecc
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 = Loc ∪ FunDecl ∪ Unbound.
L’insieme delle denotazioni `e l’unione
dell’insieme Loc degli indirizzi di memoria e
dell’insieme FunDecl delle definizioni di
funzione e della denotazione speciale Undef,
che rappresenta una situazione di errore.
Funzioni
FunDecl `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
EmptyFrame 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 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 σ)
Operazioni sulla pila
• EmptyStack 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
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 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
EmptyStore crea una memoria ovunque
indefinita
μ(x)=Undef per ogni x
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
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
valutazione semantica
E : EXPR * env * store (eval * store)
C : COM * env * store store
D : DEC * env * store (env * store)
P : PROG * env * store store
29
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 PicoC
http://www.di.unipi.it/~occhiuto/PicoC/
Generatore di programmi PicoC in
sintassi astratta
Alcuni esempi di programmi PicoC in
sintassi astratta per testare l`interprete
Valori
Val=Int + {omega}+{Undef}
type value =
Val of int |
Omega |
Undef;;
Valori Denotabili
Den = Loc ∪ FunDecl ∪ Unbound
type denotation =
Loc of int |
Funct of string * com * sigma ref |
Unbound;;
•
In FunDecl c’e’ il riferimento all’env (per
trattare la ricorsione ..)
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 a basso livello, una lista di
frames
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
| Or | Ls | Gr | Eq ;;
type unop = Neg | Amp | Star;;
type aExp = Num of int |
Exp of aExp * aop * aExp |
Bracket of aExp |
UnExp of unop * aExp |
Var of string |
Apply of string * aExp ;;
Comandi
type com = Assign of string * aExp |
AssignDeRef of aExp * aExp |
If of aExp * com * com |
While of aExp * com |
Block of (stmt list) |
Return of aExp;;
Dichiarazioni
type decl =
Decl1 of espType * string |
Decl2 of espType * string * aExp |
DeclFun of espType * string * espType *
string * com;;
Programmi
type stmt = StDec of decl |
StCom of com;;
type prog = Prog of (stmt list);;
• Un programma e’ una lista di statements
(dichiarazioni, comandi)
Funzione main
let valProg (Prog l)=
let (sigma,mu)=
valStmtL 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 (valStmtL)
Per ogni statement (comando o
dichiarazione) chiama la funzione di
valutazione corrispondente
Lista di Statements
let valStmtL l (sigma, mu) =
match l with|
[] -> (sigma, mu)|
st::stml ->
(match st with
| StDec d -> let (sigma1, mu1) = valDecl d
(sigma,mu)
in valStmtL stml (sigma1,mu1)
|
StCom c -> let (sigma1,mu1) = valCom c
(sigma,mu)
in valStmtL stml (sigma1,mu1));;
Dichiarazioni
valDecl:
Decl * (env*mem)---> (env*mem)
Funzione ricorsiva (valDecl)
Usa valExp:
Exp* (env*mem)---> (Val*env*mem)
Dichiarazioni
Variabile senza inizializzazione
Variabile con inizializzazione
Funzione
Sintassi Astratta
type decl =
Decl1 of espType * string |
Decl2 of espType * string * aExp |
DeclFun of espType * string * espType *
string * com;;
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),
(Mem (append xm [((Loc loc),Omega)]
)));;
• la lista e’ del tipo [(0,v1),(1,v20)...]
• la prima locazione libera e’ detreminata con
length
Modifica della Memoria
Serve una operazione
updateM:Store*Loc*Val---> Store
• Modifica la memoria rimpiazzando il
valore associato alla locazione con il
nuovo valore
Implementazione
let rec updateM (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 addBind 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 valDecl d (sigma,mu) = match d with
Decl1 (t,i) ->
let (l,mu1) = free mu
in let sigma1= (addBind sigma (i, l))
in (sigma1, mu1)
• 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 valDecl d (sigma,mu) = match d with
Decl2 (t,i,e) ->
let (v,(sigma1,mu1)) = (valExp e (sigma,mu))
in let (l,mu2) = free mu1 in
let sigma2= (addBind sigma1 (i,l))
in let mu3 =
updateM mu2 (l, v) in (sigma2, mu3)
• 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
DeclFun (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,sigma1)
• chi e’ sigma1? vediamo la regola formale
Problemi di Implementazione
• bisogna implementarlo usando un
puntatore all’env in FunDecl
Funct of string * com * sigma ref |
Unbound;;
Dichiarazione di Funzione
let valDecl d (sigma,mu) = match d with
DeclFun (t,i,tp,ip, c) ->let rec
sigma1=(addBind sigma (i,
(Funct (ip,c, (ref sigma)))))
in ((update i sigma1 sigma1),mu)
• in sigma1 la descrizione della funzione i contiene
un riferimento a sigma (andrebbe bene se non
fossero ricorsive
• nota che viene restituito come risultato
update i sigma1 sigma1
Intuitivamente
update i sigma1 sigma1
• cerca la descrizione di funzione di i in sigma1
(p,c, sigma ref)
• la modifica assegnando sigma1 al posto di sigma
Funzione Ausiliaria
let rec updateF i f sigma = match f with
[] -> f |
(j, Funct(x,c,var))::fs when (i=j) ->
var :=sigma; f
| (_,_)::fs -> updateF i fs sigma;;
let rec update i s sigma = match s with
Stack [Frame[]]-> s |
Stack ((Frame fs)::ss) ->
(updateF i fs sigma); s;;
Comandi
valCom:
Com * (env*mem)---> (env*mem)
Funzione ricorsiva (valCom)
Usa valExp:
Exp* (env*mem)---> (Val*env*mem)
Comandi
Condizionale
While
Assegnamento
Blocco
Return
Comandi
type com = Assign of string * aExp |
AssignDeRef of aExp * aExp |
If of aExp * com * com |
While of aExp * com |
Block of (stmt list) |
Return of aExp;;
Funzioni Ausiliarie: env
• lookup: Env * Ide---> Den
Den = Loc ∪ FunDecl ∪ 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
Den = Loc ∪ FunDecl ∪ Unbound
• restitituisce il valore denotabile
associato all’identificatore
• Frame e’ una lista di coppie (identificatore,
valore)
Implementazione
let rec lookUp sigma y =
match sigma with
|
Stack [] -> Unbound
|
Stack (x :: xs) -> let b= (look x y)
in if (not (b=Unbound))
then b else (lookUp (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 valCom c (sigma,mu) = match c with
| If (e,c1,c2) -> let
((Val i),(sigma1,mu1)) = (valExp e (sigma,mu))
in if not (i=0) then valCom c1 (sigma,mu1)
else valCom c2 (sigma,mu1)
• viene calcolato il valore di e
• se true esegue c1, altrimenti c2
While
let valCom c (sigma,mu) = match c with
| While (e,c) -> let
((Val i),(sigma1,mu1)) = (valExp e (sigma,mu))
in
if not (i=0) then
let (sigma2,mu2) = (valCom c (sigma1,mu1))in
valCom (While (e,c)) (sigma2,mu2)
else
(sigma1, mu1)
• viene calcolato il valore di e, se false restituisce
(sigma1,mu1)
• se true esegue While (e,c) nello stato
modificato da c
Assegnamento
let valCom c (sigma,mu) = match c with
| Assign (s,e) -> let
(v,(sigma1,mu1)) = (valExp e (sigma,mu))
and (Loc l) = (lookUp sigma s) in
(sigma1, updateM mu1 ((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 valCom c (sigma,mu) = match c with
| Block l ->
let (Stack (f::rl),mu1) =
valStmtL l
((match sigma with Stack fl ->
Stack (Frame[]::fl)) ,mu)
in (Stack rl, mu1)
• 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
• regola astratta
Return
let valCom c (sigma,mu) =
match c with
| Return e ->
valCom (Assign ("retVal",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 valCom c (sigma,mu) = match c with
| AssignDeRef (e,ev) -> let
(v,(sigma1,mu1)) =
(valExp ev (sigma,mu))
in let
(v1,(sigma2,mu2)) =
(valExp e (sigma1,mu1))
in let (Loc l) = (etaLoc v1) in
(sigma2, updateM mu2 ((Loc l),v))
• viene calcolato il valore v di e e il valore v1 di e
• viene modificato lo store assegnando alla
locazione corrispondente a v1 il valore v
Funzione Ausiliaria:
let niLoc x = match x with
(Loc l) -> (Val l)
|_ -> Undef;;
let etaLoc x = match x with
(Val n) when (n>=0) -> (Loc n)
| _ -> Unbound;;
• trasformano locazioni in valori interi e viceversa
Espressioni
valExpr:
Expr * (env*mem)---> Val *(env*mem)
Funzione ricorsiva (valExpr)
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
| Or | Ls | Gr | Eq ;;
type unop = Neg | Amp | Star;;
type aExp = Num of int |
Exp of aExp * aop * aExp |
Bracket of aExp |
UnExp of unop * aExp |
Var of string |
Apply of string * aExp ;;
Funzioni Ausiliarie: stato
• getVal: (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 getVal (sigma,mu) x =
let b=(lookUp sigma x) in
match b with
|
Loc n -> (lookM mu (Loc n))
| _ -> Undef;;
• lookUp cerca nell’env (pila) la locazione n
associata ad x
• lookM cerca nella memoria il valore associato ad
n
Implementazione:lookM
let rec lookM mu y = match mu with
Mem [] -> Undef
| Mem (( i, v) :: xs) ->
if (i=y) then v else
(lookM (Mem xs) y);;
|
la memoria e’ una lista di coppie (i,v),
cerca ricorsivamente un identificatore
uguale ad y
Costante, Parentesi
let rec valExp e (sigma,mu) = match e
with
| Num n -> ((Val n),(sigma,mu))
| Bracket x
-> valExp x (sigma,mu)
Variabile
let rec valExp e (sigma,mu) = match e
with
| Var s ->
((getVal (sigma,mu) s),(sigma,mu))
• restituisce il valore associato alla
variabile s, calcolato tramite getVal
Operazioni Binarie
let rec valExp e (sigma,mu) = match e
with
| Exp (x, op, y) -> let
(v1, (sigma1,mu1))= (valExp x (sigma,mu))
in let
(v2,(sigma2,mu2))= (valExp y (sigma,mu1))
in...
• calcola ricorsivamente i valore v1 e v2 di
x ed y, rispettivamente
• in un ordine
Procede per casi sull’operazione
if (isNumOp op) then
(niNum ( (funNumOp op) (etaNum v1)
(etaNum v2)),(sigma2,mu2))
else
• isNumOp restituisce true se e’ una operazione
numerica (somma etc..)
• FunNumOp applica l’operazione corrispondente a op
ai valori v1 e v2
• niNum,etaNum servono solo per convertire i valori
Val i in i e viceversa
Funzioni ausiliarie
let
|
|
|
|
|
isNumOp op = match op with
Add -> true
Sub -> true
Div -> true
Mul -> true
_ ->
false;;
Funzioni ausiliarie
let funNumOp op = match op with|
Add -> (+)|
Sub -> (-)|
Mul -> (fun x y -> x*y) |
Div -> (/) ;;
Funzioni ausiliarie di
conversione per interi
let niNum x =
(Val x);;
let etaNum (Val x) = x;;
Procede per casi
if (isBoolOp op) then
(niBool( (funBoolOp op) (etaBool v1)
(etaBool v2)) ,(sigma2,mu2))
else
(niBool( (funRelOp op) (etaNum v1)
(etaNum v2)) ,(sigma2,mu2))
• se e’ un’operazione booleana applica la relativa
operazione ai valori booleani v1 e v2
• se e’ un’operazione relazionale applica la relativa
operazione ai valori booleani v1 e v2
Funzioni ausiliarie
let
|
|
|
isBoolOp op = match op with
And -> true
Or -> true
_ -> false;;
Funzioni Ausiliarie
let funBoolOp op = match op with
| And -> (&)
| Or -> (or) ;;
let funRelOp op = match op with|
Ls -> (<) |
Gr -> (>) |
Eq -> (=);;
Funzioni Ausiliarie di
conversione
let niBool x = if x then
(Val 1) else (Val 0);;
let etaBool (Val x) = if (x=0)
then false else true;;
Operazioni Unarie: per casi
let rec valExp e (sigma,mu) = match e with
| UnExp (op, x) -> (match op with
Neg ->
let
(v1, (sigma1,mu1))= (valExp x (sigma,mu))
in
(niBool( (funop1 op) (etaBool(v1))
),(sigma1,mu1))
caso della negazione e’ analogo a quello
visto prima
calcola il valore v di x e chiama funzioni
Operazioni Unarie: puntatore
| UnExp (op, x) -> (match op with
|Amp -> ((valDen x sigma),(sigma,mu))
deve restituire la locazione di x
usa una funzione ausiliaria valDen
Funzione ausiliaria:valDen
let rec valDen e sigma = (match e with |Var s ->
niLoc(lookUp sigma s)
|Exp (x,y,z) ->
Undef|UnExp(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
| UnExp (op, x) -> (match op with
|Star ->
let (v,(sigma,mu1)) =(valExp x (sigma,mu))
in (lookM mu1 (etaLoc v),(sigma,mu1)))
calcola il valore v di x (tramite valExp)
restuisce il valore memorizzato nella
memoria nella locazione v
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 FunDecl
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 quale
stato?
Lo stato di valutazione si costruisce a partire da
(sigmaf,mu)
• Bisogna mettere sulla pila sigmaf un EmptyFrame
(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 retval
l’ambiente sigma al momento della chiamata (non
modificato)
la memoria modificata dall’esecuzione dei comandi
Chiamata di Funzione: valExp
• Vediamo il codice di valExp 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 valExp e (sigma,mu) = match e
with
| Apply (s,a) ->
let
(v,(sigma1,mu1))=
valExp a (sigma,mu) in
(match (lookUp sigma s) with
Funct (f,c, sigmaf) ->
....
• calcola tramite valExp il valore v del parametro
attuale a
• cerca tramite lookUp la FunDecl relativa ad s
Chiamata di funzione
(let (l,mu2)=(free mu1) in let (l1,mu3)
=(free mu2)
in let
sigmav=(match (! sigmaf) with
Stack sl ->
addBind (addBind (Stack
(Frame []::sl)) (f,l)) ("retVal",l1))
• sceglie due locazioni libere in memoria l ed l1
• modifica l’ambiente sigmaf , facendo push di
un frame che contiene (f,l) e (retval l1)
Chiamata di funzione
in let (sigma2,mu4)=
valCom c (sigmav,updateM mu3 (l, v))
in ((lookM mu4 l1),(sigma,mu4)))
• 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 l1 nella memoria (il
valore di retval), l’ambiente sigma iniziale, e la
memoria finale mu4