280 likes | 440 Views
Sintassi e Semantica Nucleo di C:. Espressioni: numeriche booleane Comandi: assegnamento condizionale iteratore sequenza di istruzioni blocco Dichiarazioni: . Costrutti comuni a tutti i linguaggi imperativi. programma Caml. programma nel nucleo di C. let f x y = if (x=y) then 0
E N D
Sintassi e SemanticaNucleo di C: • Espressioni: • numeriche • booleane • Comandi: • assegnamento • condizionale • iteratore • sequenza di istruzioni • blocco • Dichiarazioni: Costrutti comuni a tutti i linguaggi imperativi
programma Caml programma nel nucleo di C let f x y = if (x=y) then 0 else if (x>y) (f (x-y)y) else f((y-x) x) in f(20 5) int main{ int x=20;int y=5; int z=0; if (x>y) while (x>y){ x=x-y; z=z+1} else if (x<y) while (x<y) {y=y-x; z=z+1;} } Esempio
Un altro esempio int main() { int x=9; (1) int y=3; (2) if (x>=y) {int z=x; (3) x=z-y;} else x=y; (4) y=z; } (5) dichiarazioni blocco assegnamento condizionale Notare il blocco la dichiarazione e l’uso di z. È corretto? Ha senso?
Lo stack (o pila )(proprio quella dei piatti che avete lavato ieri sera) • Lo stack è una sequenza di elementi in cui è definito un particolare ordine di manipolazione degli elementi. • Definiamo • lo stack vuoto: è la particolare pila che non contiene elementi (indicata con nil, EmptyStack, , ecc.) • la testa dello stack (top dello stack): calcola l’ultimo elemento inserito, non modifica lo stack • pop: calcola l’elemento in testa allo stack e modifica lo stack eliminando l’elemento in testa. • push: inserisce un elemento in testa allo stack, nel seguito push è indicata con ‘.’. Modifica lo stack.
s s 6 1 s 49 push(1,s) 49 49 -8 -8 -8 Esempi di stack e operazioni testa pop(s)=6 pop(nil)= (indefinito) è una situazione di errore
Lo stato • Nella semantica che vedremo per il C utilizzeremo i seguenti domini: • Ide: gli identificatori validi del C, • Val: gli interi • Den=Loc FunctDecl {Unbound}. • Loc: gli indirizzi delle locazioni di memoria (sono naturali) • FunctDecl: le dichiarazioni di funzione (le vedremo più avanti
Lo stato Lo stato ha 2 componenti: • L’ambiente (nel seguito indicato con s): che è uno stack di frame. I frame in questo caso rappresentano funzioni da Ide in Den. • La memoria (nel seguito indicato con m): che è una funzione dal Loc -> Val. Anche la memoria è un frame.
Operazioni sulle strutture dello stato(Frame) • Ricerca: • (i) per gli elementi dello stack, ha tipo x Ide Den nell’interprete si chiama look • m(l) per la memoria: ha tipo M x Loc Val nell’interprete si chiama lookM • Inserzione: • free(m) esiste solo per la memoria e corrisponde all’allocazione di memoria, ha tipo M Loc x M, nell’interprete si chiama free. • per gli elementi dello stack j[d/i] ha tipo F x Ide x DenF • Modifica: • per la memoria m[v/l)] ha tipo M x Loc x Val M, nell’interprete si chiama updateM
Operazioni sugli stack • Ricerca: • s(i) per gli elementi dello stack, ha tipo S x Ide Den nell’interprete si chiama lookUp. Si cerca nel frame top dello stack, se non contiene un legame si va cercare nel resto delo stack, secondo l’ordine di accesso degli elementi usuale per gli stack. • Inserzione: • di un legame (ide,d) ha tipo: S x Ide x Den S. Nella semantica si esprime come composizione di inserzione di un bind nel frame e push (.), nell’interprete si chiama addBind
j(Ide) se s = j.s‘ j(Ide) s(Ide)= s‘(Ide) se s = j.s ‘ j(Ide) = se s = Selezione della denotazione associata ad un identificatore nello stack di frame Formalmente abbiamo la seguente definizione ricorsiva:
La Grammatica delC Programma::= Direttive Prototipi TypeR main() {StmtList} FunctDecList Direttive ::= Direttiva Direttive | Direttiva::= #define Ide; | #include <Ide.h>;|... Prototipi::= Prototipo ;Prototipi | Prototipo:= Type Ide(FormalList) ; FunctDecList::= FunctDecl; FunctDecList | FunctDec::= (int | void) Ide (int Ide) {StmtList} StmtList::=Stmt StmtList |
La Grammatica delC - segue Stmt::=Decl | Com Com::=Ide=ExpAssegnamento | if (Exp) Com else Com Condizionale | while (Exp) ComIteratore | {StmtList} Blocco | Ide(Exp) Invocazione di fun | return ExpCalcolo dei valoreExp::= Ide | Const | Exp Op Exp | UopExp | Ide | Ide(Exp) | (Exp)... Decl ::= Type Ide [=Exp] | FunctDec Type::= int | float |double TypeR::=Type |void
PicoC • Restrizioni: • non ci sono le direttive (anche perchè nella semantica non hanno senso) • tipi solo int • parametri: funzioni con un e un solo parametro • non c’è input/output • non ci sono tipi strutturati (array,struct, unioni) ecc). • Estensioni: • le definizioni di funzione sono dichiarazioni e possono comparire in un punto qualunque del programma pres. 13-11-01
PicoC Programma::=int main() {StmtList} StmtList ::= Stmt ; StmtList | Stmt::=Decl | Com Com::=Ide=ExpAssegnamento | if (Exp) Com else Com Condizionale | while (Exp) ComIteratore | {StmtList} Blocco | Ide(Exp) Invocazione di fun | return ExpCalcolo del valoreExp::= Ide | Const | Exp Op Exp | UopExp | Ide | Ide(Exp) | (Exp)... Decl ::= int Ide [=Exp] | FunctDec FunctDec::= (int | void) Ide (int Ide) {StmtList}
3 l2 1 l3 0 s’={<x, l1>, <y, l3>, <z, l2>}.{<x, l4>, <w, l4>}.W j’ j” Rappresentazione delle variabili nello stato s’ m’ s m l1 j’ l1 j 3 l1 x l1 x l2 1 l3 y l2 y l3 0 l2 z l3 z l4 -4 j’’ l4 x s={<x, l1>, <y, l2>, <z, l3>}.W l4 w m(s(y)=? m’(s(y)=?
Sistema di transizioni per le espressioni S exp={< exp , Texp , exp } exp= {<E,<,>>| E Exp, , M} {<v,<,>>|v Val , , M } Texp = {<v,<,>>|v Val , , M } exp = {(+), ..., tutte le regole che vedremo }
Semantica: le espressioni <E,<s,>>exp<v,<s,’>> <E’,<s,’>>exp<v’,<s,”>>v[op]v’= v” <E op E’, <s, > > exp <v”, <s, ”>> <E, <s,>> exp<v, <s, ’>> [uop] v = v’ <uop E, <s,>> exp<v’, <s, ’>> (s(x))= v <x, <s,>> exp <v, <s,>> v= (const) <const,<s,>> exp<v,<s,>> (Eop) (Euop) (B()) (Eidev) (Btrue) (Econst)
Sistema di transizioni per i comandi e dichiarazioni S com={< com , Tcom , com } com= {<C,<,>>| C Stmt, , M} {<,>| , M } Tcom = {<,>| , M } com = {(=), ..., tutte le regole che vedremo }
(=) Assegnamento Sintassi Com ::= Ide = Exp; Semantica <E,<,> > exp <v ,<’,’>> ’(x)=l <x=E;,<,>> com<’,’[v/l]>
Sequenza di istruzioni: StmtList Sintassi StmtList::= Stmt; StmtList | Semantica <Com, <,>> com <”,”>> <StmtList,<”, ”>> com<’,’>> <Com; StmtList,<,>>com <’,’>> <Decl,<,>> com<”,”> <StmtList,<”,”>>com <”,’>> <Decl; StmtList,<,>> com <”,’>> (StmtListcom) (StmtListdecl)
Un condizionale: if Sintassi Com::= ... | if(BE) Com else Com | ... Semantica <E,<,>> exp<tt,<’,’>> <C1,<’,’>>cmd<”,”> <if(E) C1else C2 ,<, >> com<”,”>> <E,< >> exp<ff,<’,’>> <C2,<’,’>> cmd<”,”> <if(E) C1else C2,<, >> com<”,” (if-tt) (if-ff)
(W-ff) (W-tt) Un iteratore: while Sintassi Com::= ... | while (BE) Com |... Semantica <E ,<,> > exp <ff,<’,’>> <while(E) C,<, > > com<’,’> <E,<,>> exp <tt,<’,’>> <C,<’,’>> com <”,”>> <while(E) C,<”, ”>> com <”’,’”> <while(E) C,<,> > com <”’,’”>
La semantica: il Blocco Sintassi Com::= … | {StmtList} |… Semantica <StmtList, <., >> com <j.’, ’> <{StmtList},<,>> com <’,’> ’=? ’≠? (Block)
Semantica delle dichiarazioni Sintassi Decl::= Type Ide ; | Type Ide = Exp; Semantica free (m) = <l,’> s= j.s’ <T x;,<s,>> dcl < j [l /x].s’,’[/l]> <E,<s,>>exp<v,<s,’>> free (m’) = <l,”>s= j.s’ <T x=E;, <s, >> dcl <j [l/x].s’,”[v/l]>> (var1) (var2) Notare l’inserzione del legame nel top dello stack
Semantica del programma Sintassi programma ::= int main () {StmtList} Semantica <StmtList, <.,0>> com<s,> <int main() {StmtList}> <s,> (prog)
Linguaggi a blocchi • C è un linguaggio a blocchi perchè le variabili esistono solo all’interno del blocco in cui sono definite. • In C, come nella maggior parte dei linguaggi a blocchi, è corretto riutilizzare un identificatore per definire una variabile, con la seguente semantica: • Sia y la variabile definita nel blocco più esterno e y la variabile definita nel blocco interno. • y e y sono due variabili diverse. La y esiste solo nel blocco interno e poi scompare. La y esiste sempre (cioè nel blocco esterno e quindi in quello interno) ma nel blocco interno non si riesce a denotare (è coperta dalla y). • In Java il riutilizzo di un identificatore in un blocco annidato è vietato
Equivalenza di programmi • I comandi C e C’ sono equivalenti se <s,m> vale una delle seguenti condizioni: • <C,<s,m>> e <C’, <s,m>> NON portano ad una configurazione terminale • Se <C,<s,m>>* <s’,m’> allora <C’, <s,m>> * <s”,m”> e vale che {x | xIde∧s’(x) ≠}={x | xIde∧s”(x) ≠}∧m’(s’(x)) = m”(s”(x)) cioè le configurazioni terminali definiscono le stesse variabili a cui sono assegnati gli stessi valori. Dimostrazione per casi se necessario
Equivalenza debole (condizionale) di programmi I comandi C e C’ sono equivalenti in uno stato <s,m> che soddisfa una data condizione cioè tale che ...es m(s(x))=v), come prima: Se <C,<s,m>>* <s’,m’> allora <C’, <s,m>> * <s”,m”> e vale che {x | xIde∧s’(x) ≠}={x | xIde∧s”(x) ≠} ∧m’(s’(x)) = m”(s”(x)) cioè le configurazioni terminali definiscono le stesse variabili a cui sono assegnati gli stessi valori. Dimostrazione per casi se necessario anche in questo caso