Semantyka i weryfikacja programów/Ćwiczenia 5: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Sl (dyskusja | edycje)
Nie podano opisu zmian
Sl (dyskusja | edycje)
Nie podano opisu zmian
Linia 1: Linia 1:




== Zawarto¶æ ==
== Zawartość ==


Kontynuujemy æwiczenie semantyki naturalnej,
Kontynuujemy ćwiczenie semantyki naturalnej,
dodaj±c pewne konstrukcje do jêzyka Tiny.
dodając pewne konstrukcje do języka Tiny.
W szczególno¶ci rozszerzymy go o deklaracje zmiennych (bloki).
W szczególności rozszerzymy go o deklaracje zmiennych (bloki).
Po raz pierwszy roszdzielimy informacjê przechowywan± w konfiguracji
Po raz pierwszy roszdzielimy informację przechowywaną w konfiguracji
na ''¶rodowisko'' okre¶laj±ce wi±zanie identyfikatorów i ''stan''
na ''środowisko'' określające wiązanie identyfikatorów i ''stan''
przechowuj±cy warto¶ci zmiennych.
przechowujący wartości zmiennych.
Bêdzie to przygotowanie do kolejnych zajêæ.
Będzie to przygotowanie do kolejnych zajęć.




Linia 18: Linia 18:




Rozszerzamy jêzyk Tiny nastêpuj±co:
Rozszerzamy język Tiny następująco:


<math>
<math>
Linia 28: Linia 28:


Znaczenie instrukcji <math>\mathbf{for}\, x = e_1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2</math>
Znaczenie instrukcji <math>\mathbf{for}\, x = e_1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2</math>
jest nastêpuj±ce.
jest następujące.
Obliczamy warto¶ci wyra¿eñ <math>e_1</math> i <math>e_2</math>. Je¶li pierwsza
Obliczamy wartości wyrażeń <math>e_1</math> i <math>e_2</math>. Jeśli pierwsza
z nich jest mniejsza lub równa od drugiej, to podstawiamy pierwsz±
z nich jest mniejsza lub równa od drugiej, to podstawiamy pierwszą
warto¶æ (warto¶æ wyra¿enia <math>e_1</math>) na zmienn± <math>x</math> i uruchamiamy <math>I_1</math>.
wartość (wartość wyrażenia <math>e_1</math>) na zmienną <math>x</math> i uruchamiamy <math>I_1</math>.
Je¶li w <math>I_1</math> nie zostanie napotkana instrukcja <math>\mathbf{fail}</math>,  
Jeśli w <math>I_1</math> nie zostanie napotkana instrukcja <math>\mathbf{fail}</math>,  
koñczymy instrukcjê <math>\mathbf{for}\,</math> i przyracamy warto¶æ zmiennej <math>x</math>
kończymy instrukcję <math>\mathbf{for}\,</math> i przyracamy wartość zmiennej <math>x</math>
sprzed tej instrukcji.
sprzed tej instrukcji.
Natomiast je¶li w <math>I_1</math> zostanie napotkana instrukcja <math>\mathbf{fail}</math>,
Natomiast jeśli w <math>I_1</math> zostanie napotkana instrukcja <math>\mathbf{fail}</math>,
podstawiamy na <math>x</math> kolejn±, o jeden wiêksz± warto¶æ,  
podstawiamy na <math>x</math> kolejną, o jeden większą wartość,  
przywracamy warto¶ci wszystkich
przywracamy wartości wszystkich
pozosta³ych zmiennych sprzed instrukcji <math>\mathbf{for}\,</math>, i ponownie
pozostałych zmiennych sprzed instrukcji <math>\mathbf{for}\,</math>, i ponownie
wykonujemy <math>I_1</math>.  
wykonujemy <math>I_1</math>.  
Powtarzamy w ten sposób a¿ <math>I_1</math> zakoñczy siê nie napotkawszy <math>\mathbf{fail}</math>,
Powtarzamy w ten sposób <math>I_1</math> zakończy się nie napotkawszy <math>\mathbf{fail}</math>,
albo warto¶æ zmiennej <math>x</math> przekroczy warto¶æ wyra¿enia <math>e_2</math>
albo wartość zmiennej <math>x</math> przekroczy wartość wyrażenia <math>e_2</math>
obliczon± na pocz±tku.
obliczoną na początku.
W pierwszym przypadku  
W pierwszym przypadku  
koñczymy instrukcjê <math>\mathbf{for}\,</math> i przyracamy warto¶æ zmiennej <math>x</math>
kończymy instrukcję <math>\mathbf{for}\,</math> i przyracamy wartość zmiennej <math>x</math>
sprzed tej instrukcji.
sprzed tej instrukcji.
W drugim przywracamy warto¶ci wszystkich zmiennych sprzed instrukcji
W drugim przywracamy wartości wszystkich zmiennych sprzed instrukcji
<math>\mathbf{for}\,</math> i uruchamiamy <math>I_2</math>.
<math>\mathbf{for}\,</math> i uruchamiamy <math>I_2</math>.
}}
}}
Linia 52: Linia 52:


{{przyklad|||
{{przyklad|||
Oto przyk³adowy program:
Oto przykładowy program:
}}
}}


Linia 62: Linia 62:




Warto¶ci zmiennych po zakoñczeniu programu to: <math>x = 0, y = 2, z = 5</math>.
Wartości zmiennych po zakończeniu programu to: <math>x = 0, y = 2, z = 5</math>.




Linia 70: Linia 70:
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">


Bêdziemy pos³ugiwaæ siê jak zwykle tranzycjami postaci:
Będziemy posługiwać się jak zwykle tranzycjami postaci:


<math>
<math>
Linia 77: Linia 77:


Zacznijmy od najprostszego przypadku, gdy nie ma wogóle potrzeby
Zacznijmy od najprostszego przypadku, gdy nie ma wogóle potrzeby
uruchamiania instrukcji wewnêtrznej <math>I_1</math>, poniewa¿
uruchamiania instrukcji wewnętrznej <math>I_1</math>, ponieważ
warto¶æ wyra¿enia <math>e_1</math> jest wiêksza od <math>e_2</math>:
wartość wyrażenia <math>e_1</math> jest większa od <math>e_2</math>:


<math>
<math>
Linia 90: Linia 90:
</math>
</math>


Po prostu uruchamiamy instrukcjê <math>I_2</math> w stanie <math>s</math>, ignoruj±c
Po prostu uruchamiamy instrukcję <math>I_2</math> w stanie <math>s</math>, ignorując
<math>I_1</math>.
<math>I_1</math>.


Kolejny nietrudny przypadek to sytuacja, w której  
Kolejny nietrudny przypadek to sytuacja, w której  
<math>n_1 \leq n_2</math> a wykonanie instrukcji wewnêtrznej <math>I_1</math>
<math>n_1 \leq n_2</math> a wykonanie instrukcji wewnętrznej <math>I_1</math>
koñczy siê sukcesem, tzn. nie nastêpuje wywo³anie instrukcji  
kończy się sukcesem, tzn. nie następuje wywołanie instrukcji  
<math>\mathbf{fail}</math>. Oto regu³a dla tego przypadku:
<math>\mathbf{fail}</math>. Oto reguła dla tego przypadku:


<math>
<math>
Linia 108: Linia 108:
</math>
</math>


Tym razem uruchamiamy instrukcjê <math>I_1</math>, podstawiaj±c
Tym razem uruchamiamy instrukcję <math>I_1</math>, podstawiając
pod zmienn± <math>x</math> warto¶æ <math>n_1</math>.
pod zmienną <math>x</math> wartość <math>n_1</math>.
Zwróæmy uwagê, ¿e po zakoñczeniu <math>I_1</math> przywracamy
Zwróćmy uwagę, że po zakończeniu <math>I_1</math> przywracamy
warto¶æ zmiennej <math>x</math> sprzed jej wykonania.
wartość zmiennej <math>x</math> sprzed jej wykonania.


Pozosta³ nam trzeci przypadek, gdy <math>n_1 \leq n_2</math>
Pozostał nam trzeci przypadek, gdy <math>n_1 \leq n_2</math>
a wykonanie instrukcji <math>I_1</math> zakoñczy³o siê
a wykonanie instrukcji <math>I_1</math> zakończyło się
wykonaniem instrukcji <math>\mathbf{fail}</math> gdzie¶ wewn±trz <math>I_1</math>.
wykonaniem instrukcji <math>\mathbf{fail}</math> gdzieś wewnątrz <math>I_1</math>.
Aby poprawnie opisaæ takie zdarzenie, potrzebujemy dodatkowych
Aby poprawnie opisać takie zdarzenie, potrzebujemy dodatkowych
tranzycji postaci:
tranzycji postaci:


<math>
<math>
I, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}.
I, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}.
</math>
</math>


Mówi±c formalnie, poszerzamy zbiór konfiguracji o jeden element
Mówiąc formalnie, poszerzamy zbiór konfiguracji o jeden element
<math>\mbox{by³o-}\mathbf{fail}</math>.
<math>\mbox{było-}\mathbf{fail}</math>.
Zauwa¿my, ¿e po prawej stronie tranzycji nie ma wogóle stanu.
Zauważmy, że po prawej stronie tranzycji nie ma wogóle stanu.
Nie potrzebujemy go dla opisania semantyki instrukcji <math>\mathbf{for}\,</math>:
Nie potrzebujemy go dla opisania semantyki instrukcji <math>\mathbf{for}\,</math>:
je¶li wyst±pi <math>\mathbf{fail}</math>, powtarzamy <math>I_1</math> dla wiêkszej o <math>1</math> warto¶ci
jeśli wystąpi <math>\mathbf{fail}</math>, powtarzamy <math>I_1</math> dla większej o <math>1</math> wartości
zmiennej <math>x</math>, ale pozosta³ym zmiennym przywracamy warto¶æ ''sprzed''
zmiennej <math>x</math>, ale pozostałym zmiennym przywracamy wartość ''sprzed''
<math>I_1</math>.
<math>I_1</math>.
A wiêc za³ó¿my, ¿e
A więc załóżmy, że


<math>I_1, s[x \mapsto n_1] \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}.</math>
<math>I_1, s[x \mapsto n_1] \,\longrightarrow\, \mbox{było-}\mathbf{fail}.</math>


W takiej sytuacji powinni¶my przypisaæ <math>n_1 + 1</math>
W takiej sytuacji powinniśmy przypisać <math>n_1 + 1</math>
na zmienn± <math>x</math> i spróbowaæ ponownie wykonaæ
na zmienną <math>x</math> i spróbować ponownie wykonać
<math>I_1</math> przy warto¶ciach wszystkich pozosta³ych
<math>I_1</math> przy wartościach wszystkich pozostałych
zmiennych takich, jak na pocz±tku instrukcji <math>\mathbf{for}\,</math>.
zmiennych takich, jak na początku instrukcji <math>\mathbf{for}\,</math>.
I powtarzaæ ten schemat a¿ do skutku, tzn. a¿ do mementu,
I powtarzać ten schemat do skutku, tzn. do mementu,
gdy zaistnieje która¶ z poprzednich dwóch (prostych) sytuacji.
gdy zaistnieje któraś z poprzednich dwóch (prostych) sytuacji.
Oto odpowiednia regu³a:
Oto odpowiednia reguła:


<math>
<math>
Linia 147: Linia 147:
       e_2, s \,\longrightarrow\, n_2
       e_2, s \,\longrightarrow\, n_2
       \quad
       \quad
       I_1, s[x \mapsto n_1]  \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}
       I_1, s[x \mapsto n_1]  \,\longrightarrow\, \mbox{było-}\mathbf{fail}
       \quad
       \quad
       \mathbf{for}\, x = e_1 + 1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, s'}
       \mathbf{for}\, x = e_1 + 1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, s'}
Linia 154: Linia 154:
</math>
</math>


Zwróæmy uwagê na pewnien niezwykle istotny szczegó³: po zakoñczeniu
Zwróćmy uwagę na pewnien niezwykle istotny szczegół: po zakończeniu
wykonania instrukcji <math>\mathbf{for}\, x = e_1 + 1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2</math>
wykonania instrukcji <math>\mathbf{for}\, x = e_1 + 1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2</math>
otrzymujemy stan <math>s'</math>, w którym '''nie przywracamy''' warto¶ci
otrzymujemy stan <math>s'</math>, w którym '''nie przywracamy''' wartości
zmiennej <math>x</math>. Gdyby¶my tak zrobili, tzn. gdyby¶my zast±pili <math>s'
zmiennej <math>x</math>. Gdybyśmy tak zrobili, tzn. gdybyśmy zastąpili <math>s'
</math> przez <math>s'[x \mapsto s(x)]</math>, nasze semantyka by³aby
</math> przez <math>s'[x \mapsto s(x)]</math>, nasze semantyka byłaby
niepoprawna. Dlaczego? Dlatego, ¿e nie wiemy tak naprawdê,
niepoprawna. Dlaczego? Dlatego, że nie wiemy tak naprawdę,
czy powinni¶my przywracaæ warto¶æ zmiennej <math>x</math> czy nie.
czy powinniśmy przywracać wartość zmiennej <math>x</math> czy nie.
Je¶li ostatecznie nasza instrukcja <math>\mathbf{for}\,</math> zakoñczyla
Jeśli ostatecznie nasza instrukcja <math>\mathbf{for}\,</math> zakończyla
siê przez bezb³êdne zakoñczenie instrukcji <math>I_1</math>
się przez bezbłędne zakończenie instrukcji <math>I_1</math>
(przypadek drugi), to powinni¶my to zrobiæ;
(przypadek drugi), to powinniśmy to zrobić;
ale je¶li zakoñczy³a siê wykonaniem instrukcji <math>I_2</math>
ale jeśli zakończyła się wykonaniem instrukcji <math>I_2</math>
(przypadek pierwszy),
(przypadek pierwszy),
to powinni¶my pozostawiæ warto¶æ zmiennej <math>x</math> tak±,
to powinniśmy pozostawić wartość zmiennej <math>x</math> taką,
jaka jest ona po zakoñczeniu <math>I_2</math>.
jaka jest ona po zakończeniu <math>I_2</math>.
A zatem w powy¿szej regule dla przypadku trzeciego  
A zatem w powyższej regule dla przypadku trzeciego  
nie przywracamy warto¶ci zmiennej <math>x</math>; je¶li by³o
nie przywracamy wartości zmiennej <math>x</math>; jeśli było
to konieczne, to zosta³o ju¿ wykonane ,,g³êbiej",
to konieczne, to zostało już wykonane ,,głębiej",
dziêki regule dla przypadku drugiego oraz dziêki temu,
dzięki regule dla przypadku drugiego oraz dzięki temu,
¿e instrukcja <math>\mathbf{for}\, x = e_1 + 1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2</math>
że instrukcja <math>\mathbf{for}\, x = e_1 + 1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2</math>
wykonywana jest w orginalnym stanie <math>s</math>,
wykonywana jest w orginalnym stanie <math>s</math>,
a nie w stanie, w którym koñczy siê <math>I_1</math>
a nie w stanie, w którym kończy się <math>I_1</math>
(tego ostatniego stanu nawet nie znamy).
(tego ostatniego stanu nawet nie znamy).


Jeszcze jeden drobiazg: zamiast <math>e_1 {+} 1</math> w
Jeszcze jeden drobiazg: zamiast <math>e_1 {+} 1</math> w
<math>\mathbf{for}\, x = e_1 + 1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, s'</math>
<math>\mathbf{for}\, x = e_1 + 1 \,\mathbf{to}\, e_2 \,\mathbf{try}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, s'</math>
w regule powy¿ej, mogliby¶my podstawiæ policzon± ju¿
w regule powyżej, moglibyśmy podstawić policzoną już
warto¶æ, czyli <math>n_1 {+} 1</math>.
wartość, czyli <math>n_1 {+} 1</math>.


Na zakoñczenie prezentujemy regu³y niebêdne do tego,
Na zakończenie prezentujemy reguły niebędne do tego,
aby wygenerowaæ <math>\mbox{by³o-}\mathbf{fail}</math>:
aby wygenerować <math>\mbox{było-}\mathbf{fail}</math>:


<math>
<math>
\mathbf{fail}, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}
\mathbf{fail}, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}
</math>
</math>


oraz aby wyst±pienie <math>\mathbf{fail}</math> umiejscowione gdzie¶ ,,g³êboko"
oraz aby wystąpienie <math>\mathbf{fail}</math> umiejscowione gdzieś ,,głęboko"
zosta³o rozpropagowane do najbli¿szej otaczaj±cej
zostało rozpropagowane do najbliższej otaczającej
instrukcji <math>\mathbf{for}\,</math>.
instrukcji <math>\mathbf{for}\,</math>.
Je¶li pojawi³ siê <math>\mathbf{fail}</math>, powinni¶my zaniechaæ dalszego
Jeśli pojawił się <math>\mathbf{fail}</math>, powinniśmy zaniechać dalszego
wykonania instrukcji a w przypadku pêtli, powinni¶my
wykonania instrukcji a w przypadku pętli, powinniśmy
zaniechaæ dalszego iterowania tej pêtli.
zaniechać dalszego iterowania tej pętli.
Oto odpowiednie regu³y:
Oto odpowiednie reguły:


<math>
<math>
\frac{I_1, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
\frac{I_1, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
     {I_1;\, I_2, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
     {I_1;\, I_2, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
\quad \quad
\quad \quad
\frac{I_1, s \,\longrightarrow\, s' \quad \quad I_2, s' \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
\frac{I_1, s \,\longrightarrow\, s' \quad \quad I_2, s' \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
     {I_1;\, I_2, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
     {I_1;\, I_2, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
</math>
</math>


<math>
<math>
\frac{b, s \,\longrightarrow\, \mathbf{true} \quad \quad I_1, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
\frac{b, s \,\longrightarrow\, \mathbf{true} \quad \quad I_1, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
\quad \quad
\quad \quad
\mbox{ i analogicznie gdy } b, s \,\longrightarrow\, \mathbf{false}
\mbox{ i analogicznie gdy } b, s \,\longrightarrow\, \mathbf{false}
Linia 213: Linia 213:


<math>
<math>
\frac{b, s \,\longrightarrow\, \mathbf{true} \quad \quad I, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
\frac{b, s \,\longrightarrow\, \mathbf{true} \quad \quad I, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
     {\mathbf{while}\, b \,\mathbf{do}\, I, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
     {\mathbf{while}\, b \,\mathbf{do}\, I, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
\quad \quad
\quad \quad
\frac{b, s \,\longrightarrow\, \mathbf{true} \quad \quad I, s \,\longrightarrow\, s' \quad \quad
\frac{b, s \,\longrightarrow\, \mathbf{true} \quad \quad I, s \,\longrightarrow\, s' \quad \quad
       \mathbf{while}\, b \,\mathbf{do}\, I, s' \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
       \mathbf{while}\, b \,\mathbf{do}\, I, s' \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
     {\mathbf{while}\, b \,\mathbf{do}\, I, s \,\longrightarrow\, \mbox{by³o-}\mathbf{fail}}
     {\mathbf{while}\, b \,\mathbf{do}\, I, s \,\longrightarrow\, \mbox{było-}\mathbf{fail}}
</math>
</math>


Widaæ podobieñstwo do analogicznych regu³ dla
Widać podobieństwo do analogicznych reguł dla
pêtli <math>\mathbf{loop}\, I</math>, któr± zajmowali¶my siê na wcze¶niejszych
pętli <math>\mathbf{loop}\, I</math>, którą zajmowaliśmy się na wcześniejszych
zajêciach.
zajęciach.


Zauwa¿my, ¿e jesli <math>\mathbf{fail}</math> zosta³o wykonane poza jak±kolwiek
Zauważmy, że jesli <math>\mathbf{fail}</math> zostało wykonane poza jakąkolwiek
pêtl± <math>\mathbf{for}\,</math>, to program ,,zakoñczy siê" w konfiguracji
pętlą <math>\mathbf{for}\,</math>, to program ,,zakończy się" w konfiguracji
<math>\mbox{by³o-}\mathbf{fail}</math>. Mo¿emy zatem tê w³a¶nie konfiguracjê
<math>\mbox{było-}\mathbf{fail}</math>. Możemy zatem tę właśnie konfigurację
uznaæ za konfiguracjê koñcow±, informuj±c± o pora¿ce
uznać za konfigurację końcową, informującą o porażce
wykonania programu.
wykonania programu.


Linia 240: Linia 240:
{{cwiczenie|2 (bloki i deklaracje zmiennych)|cw2|
{{cwiczenie|2 (bloki i deklaracje zmiennych)|cw2|


Rozszerz semantykê jêzyka Tiny o deklaracjê zmiennej:
Rozszerz semantykę języka Tiny o deklarację zmiennej:


<math>
<math>
Linia 248: Linia 248:
</math>
</math>


Zasiêgiem zmiennej <math>x</math>  jest instrukcja <math>I</math>
Zasięgiem zmiennej <math>x</math>  jest instrukcja <math>I</math>
czyli wnêtrze bloku, w którym jest zadeklarowana.
czyli wnętrze bloku, w którym jest zadeklarowana.
Zak³adamy zwyk³e (statyczne) regu³y widoczno¶ci, przes³aniania, itp.
Zakładamy zwykłe (statyczne) reguły widoczności, przesłaniania, itp.
}}
}}


Linia 258: Linia 258:
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">


'''Rozwi±zanie 1 (tylko stan)'''
'''Rozwiązanie 1 (tylko stan)'''
<br>
<br>


Oczywi¶cie powinni¶my odró¿niaæ zmienne zadeklarowane (i zarazem
Oczywiście powinniśmy odróżniać zmienne zadeklarowane (i zarazem
zainicjowane) od tych niezadeklarowanych.
zainicjowane) od tych niezadeklarowanych.
Zatem przyjmijmy, ¿e
Zatem przyjmijmy, że


<math>\mathbf{State} = \mathbf{Var} \to_{\mathrm{fin}} \mathbf{Num}</math>.
<math>\mathbf{State} = \mathbf{Var} \to_{\mathrm{fin}} \mathbf{Num}</math>.


Zachowujemy wszystkie regu³y semantyczne dla jêzyka Tiny
Zachowujemy wszystkie reguły semantyczne dla języka Tiny
i dodajemy jedn± now±:
i dodajemy jedną nową:


<math>
<math>
Linia 275: Linia 275:
</math>
</math>


mówi±c±, ¿e instrukcja wewnêtrzna <math>I</math> ewaluowana jest
mówiącą, że instrukcja wewnętrzna <math>I</math> ewaluowana jest
w stanie, w którym dodatkowo zaznaczono warto¶æ zmiennej <math>x</math>
w stanie, w którym dodatkowo zaznaczono wartość zmiennej <math>x</math>
równ± warto¶ci, do której oblicza siê <math>e</math>.
równą wartości, do której oblicza się <math>e</math>.
Oczywi¶cie takie rozwi±zanie jest niepoprawne, gdy¿ warto¶æ
Oczywiście takie rozwiązanie jest niepoprawne, gdyż wartość
zmiennej <math>x</math>  pozostaje w stanie nawet po wyj¶ciu z bloku
zmiennej <math>x</math>  pozostaje w stanie nawet po wyjściu z bloku
(,,wycieka" z bloku).
(,,wycieka" z bloku).
Musimy dodaæ ,,dealokacjê" zmiennej <math>x</math>:
Musimy dodać ,,dealokację" zmiennej <math>x</math>:


<math>
<math>
Linia 289: Linia 289:
</math>
</math>


I znów napotykamy podobnie trudno¶ci jak na wcze¶niejszych zajêciach:
I znów napotykamy podobnie trudności jak na wcześniejszych zajęciach:
powy¿sza regu³a nie obejmuje przypadku, gdy <math>s(x)</math> jest
powyższa reguła nie obejmuje przypadku, gdy <math>s(x)</math> jest
nieokre¶lone.
nieokreślone.
I choæ mogliby¶my naprawiæ ten mankament podobnie jak kiedy¶
I choć moglibyśmy naprawić ten mankament podobnie jak kiedyś
(co pozostawiamy Czytelnikowi), istnieje inne, bardzo eleganckie
(co pozostawiamy Czytelnikowi), istnieje inne, bardzo eleganckie
i elastyczne rozwi±zanie tego problemu, które teraz omówimy.
i elastyczne rozwiązanie tego problemu, które teraz omówimy.




<br>
<br>
'''Rozwi±zanie 2 (stan i ¶rodowisko)'''
'''Rozwiązanie 2 (stan i środowisko)'''
<br>
<br>


Podstawowy pomys³ polega na rozdzielenie informacji przechowywanej
Podstawowy pomysł polega na rozdzielenie informacji przechowywanej
dotychczas w stanie na dwa ,,etapy".
dotychczas w stanie na dwa ,,etapy".
Pierwszy z nich, odwzorowuje identyfikatory zmiennych na ''lokacje'', a drugi
Pierwszy z nich, odwzorowuje identyfikatory zmiennych na ''lokacje'', a drugi
lokacje na warto¶ci.
lokacje na wartości.
Mamy wiêc ''¶rodowiska'' <math>E \in \mathbf{Env}</math>, bêd±ce funkcjami czê¶ciowymi z <math>\mathbf{Var}</math>
Mamy więc ''środowiska'' <math>E \in \mathbf{Env}</math>, będące funkcjami częściowymi z <math>\mathbf{Var}</math>
do <math>\mathbf{Loc}</math>, zbioru lokacji:
do <math>\mathbf{Loc}</math>, zbioru lokacji:


Linia 312: Linia 312:
</math>
</math>


oraz stany, bêd±ce teraz funkcjami czê¶ciowymi z <math>\mathbf{Loc}</math> do <math>\mathbf{Num}</math>:
oraz stany, będące teraz funkcjami częściowymi z <math>\mathbf{Loc}</math> do <math>\mathbf{Num}</math>:


<math>
<math>
Linia 318: Linia 318:
</math>
</math>


Dla jednoznaczno¶ci u¿ywamy innej nazwy (<math>\mathbf{Store}</math>) ale bêdziemy
Dla jednoznaczności używamy innej nazwy (<math>\mathbf{Store}</math>) ale będziemy
zwykle u¿ywaæ symbolu <math>s, s', s_1, \ldots \in \mathbf{Store}</math> itp. do nazywania stanów.
zwykle używać symbolu <math>s, s', s_1, \ldots \in \mathbf{Store}</math> itp. do nazywania stanów.
Intuicyjnie mo¿na my¶leæ o lokacjach w pamiêci
Intuicyjnie można myśleć o lokacjach w pamięci
operacyjnej maszyny. ¦rodowisko zawiera informacjê o lokacji, w której
operacyjnej maszyny. Środowisko zawiera informację o lokacji, w której
przechowywana jest warto¶æ danej zmiennej
przechowywana jest wartość danej zmiennej
a stan opisuje w³a¶nie zawarto¶æ u¿ywanych lokacji.
a stan opisuje właśnie zawartość używanych lokacji.


Zak³adamy przy tym, ¿e mamy do dyspozycji nieskoñczony zbiór
Zakładamy przy tym, że mamy do dyspozycji nieskończony zbiór
lokacji <math>\mathbf{Loc} = \{ l_0, l_1, \ldots \}</math> i ¿e
lokacji <math>\mathbf{Loc} = \{ l_0, l_1, \ldots \}</math> i że
w ka¿dym momencie tylko skoñczenie wiele spo¶ród nich jest
w każdym momencie tylko skończenie wiele spośród nich jest
wykorzystywane.
wykorzystywane.
Formalnie mowi±c, dziedzina funkcji czê¶ciowej <math>s</math> jest zawsze skoñczona.  
Formalnie mowiąc, dziedzina funkcji częściowej <math>s</math> jest zawsze skończona.  
Daje nam to pewno¶æ, ¿e zawsze jest jaka¶ nieu¿ywana lokacja.  
Daje nam to pewność, że zawsze jest jakaś nieużywana lokacja.  


¦rodowisko pocz±tkowe, w którym uruchamiany
Środowisko początkowe, w którym uruchamiany
bêdzie program, bêdzie z regu³y puste.
będzie program, będzie z reguły puste.
Ponadto obraz funkcji czê¶ciowej <math>E</math>  
Ponadto obraz funkcji częściowej <math>E</math>  
bêdzie zawsze zawarty w zbiorze aktualnie u¿ywanych lokacji,
będzie zawsze zawarty w zbiorze aktualnie używanych lokacji,
czyli zawarty w dziedzinie funkcji czê¶ciowej <math>s</math>, oznaczanej
czyli zawarty w dziedzinie funkcji częściowej <math>s</math>, oznaczanej
<math>\mathrm{dom}(s)</math>.
<math>\mathrm{dom}(s)</math>.


Po¿ytek z tego podzia³u na dwa etapy bêdzie taki, ¿e
Pożytek z tego podziału na dwa etapy będzie taki, że
bêdziemy umieli ³atwo i elastycznie opisywaæ deklaracje zmiennych,
będziemy umieli łatwo i elastycznie opisywać deklaracje zmiennych,
przes³anianie identyfikatorów, itp.
przesłanianie identyfikatorów, itp.
Tranzycje bêd± teraz postaci:
Tranzycje będą teraz postaci:


<math>
<math>
Linia 348: Linia 348:
</math>
</math>


czyli instrukcja <math>I</math> bêdzie modyfikowaæ stan ale nie bêdzie
czyli instrukcja <math>I</math> będzie modyfikować stan ale nie będzie
zmieniaæ ¶rodowiska <math>E</math>. Dla czytelno¶ci bêdziemy zapisywaæ
zmieniać środowiska <math>E</math>. Dla czytelności będziemy zapisywać
nasze regu³y w nastêpuj±cy sposób:
nasze reguły w następujący sposób:


<math>
<math>
Linia 356: Linia 356:
</math>
</math>


podkre¶laj±c w ten sposób, ¿e ¶rodowisko nie ulega zmianie.
podkreślając w ten sposób, że środowisko nie ulega zmianie.
Ale nale¿y pamiêtaæ, ¿e konfiguracja, w której ,,uruchamiamy"
Ale należy pamiętać, że konfiguracja, w której ,,uruchamiamy"
instrukcjê <math>I</math> sk³ada siê naprawdê z pary <math>(E, s)</math>.
instrukcję <math>I</math> składa się naprawdę z pary <math>(E, s)</math>.


Deklaruj±c now± zmienn± <math>x</math> dodamy po prostu do <math>E</math> parê
Deklarując nową zmienną <math>x</math> dodamy po prostu do <math>E</math> parę
<math>(x, l)</math>, gdzie <math>l</math> jest now±, nieu¿ywan± dotychczas lokacj±.
<math>(x, l)</math>, gdzie <math>l</math> jest nową, nieużywaną dotychczas lokacją.
Dla wygody zapisu za³ó¿my, ¿e mamy do dyspozycji funkcjê
Dla wygody zapisu załóżmy, że mamy do dyspozycji funkcję
funkcjê
funkcję


<math>
<math>
Linia 369: Linia 369:
</math>
</math>


która zwraca jak±¶ now±, nieu¿ywan± lokacjê. Formalnie wymagamy, by  
która zwraca jakąś nową, nieużywaną lokację. Formalnie wymagamy, by  


<math>
<math>
Linia 375: Linia 375:
</math>
</math>


Dla ilustracji popatrzmy na przyk³adow± regu³ê dla deklaracji.
Dla ilustracji popatrzmy na przykładową regułę dla deklaracji.


<math>
<math>
Linia 384: Linia 384:
</math>
</math>


Zauwa¿my, ¿e stan <math>s'</math> po zakoñczeniu instrukcji
Zauważmy, że stan <math>s'</math> po zakończeniu instrukcji
<math>\mathbf{begin}\, \mathbf{var}\, x=e;\, I \,\mathbf{end}</math> zawiera informacjê o zmiennej
<math>\mathbf{begin}\, \mathbf{var}\, x=e;\, I \,\mathbf{end}</math> zawiera informację o zmiennej
lokalnej <math>x</math>, tzn. <math>s(l)</math> jest okre¶lone.
lokalnej <math>x</math>, tzn. <math>s(l)</math> jest określone.
Ale lokacja <math>l</math> jest ,,nieosi±galna" w ¶rodowisku
Ale lokacja <math>l</math> jest ,,nieosiągalna" w środowisku
<math>E</math>, gdy¿ para <math>x \mapsto l</math> zosta³a dodana tylko do
<math>E</math>, gdyż para <math>x \mapsto l</math> została dodana tylko do
¶rodowiska, w którym ewaluuje siê wnêtrze bloku, a ¶rodowisko
środowiska, w którym ewaluuje się wnętrze bloku, a środowisko
<math>E</math> ca³ego bloku nie jest modyfikowane.
<math>E</math> całego bloku nie jest modyfikowane.


Poni¿ej przedstawiamy regu³y dla pozosta³ych instrukcji.
Poniżej przedstawiamy reguły dla pozostałych instrukcji.
Przede wszystkim z³o¿enie sekwencyjne:
Przede wszystkim złożenie sekwencyjne:


<math>
<math>
Linia 402: Linia 402:
</math>  
</math>  


Regu³a ta  uzmys³awia nam ró¿nicê pomiêdzy ¶rodowiskiem a stanem:
Reguła ta  uzmysławia nam różnicę pomiędzy środowiskiem a stanem:
¶rodowisko pozostaje to samo, gdy przechodzimy od jednej instrukcji do
środowisko pozostaje to samo, gdy przechodzimy od jednej instrukcji do
nastêpnej, a stan oczywi¶cie ewoluuje wraz ze zmieniaj±cymi siê
następnej, a stan oczywiście ewoluuje wraz ze zmieniającymi się
warto¶ciami zmiennych.
wartościami zmiennych.


Regu³y dla przypisania, instrukcji warunkowej i pêtli
Reguły dla przypisania, instrukcji warunkowej i pętli
nie przedstawiaj± ¿adnych nowych trudno¶ci.  
nie przedstawiają żadnych nowych trudności.  
Musimy tylko najpierw ustaliæ postaæ regu³ dla wyra¿eñ:
Musimy tylko najpierw ustalić postać reguł dla wyrażeń:


<math>
<math>
Linia 415: Linia 415:
</math>
</math>
   
   
która jest zupe³nie naturalna w naszym podej¶ciu opartym o ¶rodowiska
która jest zupełnie naturalna w naszym podejściu opartym o środowiska
i stany.  
i stany.  
Regu³y mog± wygl±daæ np. tak:
Reguły mogą wyglądać np. tak:


<math>
<math>
Linia 443: Linia 443:
</math>
</math>


Regu³y dla wyra¿eñ s± oczywiste:
Reguły dla wyrażeń są oczywiste:


<math>
<math>
Linia 452: Linia 452:
</math>
</math>


i tak dalej -- pomijamy pozosta³e regu³y.
i tak dalej -- pomijamy pozostałe reguły.




Linia 459: Linia 459:
<br>
<br>


Przypomnijmy sobie semantykê bloku
Przypomnijmy sobie semantykę bloku


<math>
<math>
Linia 468: Linia 468:
</math>
</math>


i zastanówmy siê, jak ,,posprz±taæ" po zakoñczeniu wykonania bloku,
i zastanówmy się, jak ,,posprzątać" po zakończeniu wykonania bloku,
tzn. zwolniæ lokacjê <math>l</math>, która by³a u¿ywana tylko w tym bloku
tzn. zwolnić lokację <math>l</math>, która była używana tylko w tym bloku
i w zwi±zku z tym nie bêdzie ju¿ potrzebne.
i w związku z tym nie będzie już potrzebne.
Oznacza³oby to przywrócenie lokacji <math>l</math> do puli wolnych
Oznaczałoby to przywrócenie lokacji <math>l</math> do puli wolnych
(nieu¿ywanych) lokacji.
(nieużywanych) lokacji.


Zmodyfikowana regu³a dla instrukcji bloku powinna wygl±daæ mniej wiêcej tak:
Zmodyfikowana reguła dla instrukcji bloku powinna wyglądać mniej więcej tak:


<math>
<math>
Linia 484: Linia 484:


gdzie <math>\bar{s}</math> to stan <math>s''</math> ,,okrojony" do dziedziny stanu <math>s</math>.
gdzie <math>\bar{s}</math> to stan <math>s''</math> ,,okrojony" do dziedziny stanu <math>s</math>.
Powinni¶my po prostu przywróciæ nieokre¶lono¶æ stanu dla lokacji
Powinniśmy po prostu przywrócić nieokreśloność stanu dla lokacji
<math>l</math>.
<math>l</math>.
Natomiast oczywi¶cie nie ma potrzeby dealokownia ¶rodowiska!
Natomiast oczywiście nie ma potrzeby dealokownia środowiska!
Oto rozwi±zanie:
Oto rozwiązanie:


<math>
<math>
Linia 504: Linia 504:
{{cwiczenie|1|cw1.dom|
{{cwiczenie|1|cw1.dom|


Napisz semantykê naturaln± dla nastêpuj±cego
Napisz semantykę naturalną dla następującego
rozszerzenia jêzyka Tiny:
rozszerzenia języka Tiny:


<math>
<math>
Linia 520: Linia 520:
</math>
</math>


Instrukcja <math>\mathbf{throw}\, x</math> oznacza podniesienie wyj±tku o nazwie <math>x</math>.
Instrukcja <math>\mathbf{throw}\, x</math> oznacza podniesienie wyjątku o nazwie <math>x</math>.
Instrukcja <math>I = \,\mathbf{try}\, I_1 \,\mathbf{catch}\, exc\, I_2</math> wykonuje <math>I_1</math>.
Instrukcja <math>I = \,\mathbf{try}\, I_1 \,\mathbf{catch}\, exc\, I_2</math> wykonuje <math>I_1</math>.
Je¶li podczas wykonania <math>I_1</math> zostanie podniesiony wyj±tej <math>x
Jeśli podczas wykonania <math>I_1</math> zostanie podniesiony wyjątej <math>x
</math>, i <math>exc = x</math> albo <math>exc = \mathbf{any}</math>, to nastêpuje przerwanie <math>
</math>, i <math>exc = x</math> albo <math>exc = \mathbf{any}</math>, to następuje przerwanie <math>
I_1</math> i sterowanie zostaje przeniesione do <math>I_2</math>
I_1</math> i sterowanie zostaje przeniesione do <math>I_2</math>
(nastêpuje ''obs³uga wyj±tku'').  
(następuje ''obsługa wyjątku'').  
Je¶li za¶ podczas wykonania <math>I_1</math> zostanie podniesiony wyj±tej <math>x
Jeśli zaś podczas wykonania <math>I_1</math> zostanie podniesiony wyjątej <math>x
</math> oraz <math>exc \neq x</math> i <math>exc \neq \mathbf{any}</math>, to obs³uga wyj±tku
</math> oraz <math>exc \neq x</math> i <math>exc \neq \mathbf{any}</math>, to obsługa wyjątku
przekazana jest do najbli¿szej instrukcji <math>\,\mathbf{try}\,</math> otaczaj±cej <math>I
przekazana jest do najbliższej instrukcji <math>\,\mathbf{try}\,</math> otaczającej <math>I
</math>.
</math>.
Umawiamy siê, ¿e <math>\,\mathbf{try}\, I_1 \,\mathbf{catch}\, exc\, I_2</math> ''otacza'' <math>I_1</math>
Umawiamy się, że <math>\,\mathbf{try}\, I_1 \,\mathbf{catch}\, exc\, I_2</math> ''otacza'' <math>I_1</math>
i wszystkie instrukcje wewn±trz <math>I_1</math>,
i wszystkie instrukcje wewnątrz <math>I_1</math>,
ale ''nie'' otacza <math>I_2</math>.
ale ''nie'' otacza <math>I_2</math>.
}}
}}
Linia 538: Linia 538:
{{cwiczenie|2|cw2.dom|
{{cwiczenie|2|cw2.dom|


Zaproponuj modyfikacjê semantyki, w której deklaracja
Zaproponuj modyfikację semantyki, w której deklaracja
jest wykonywana ,,równolegle", analogicznie do przypisania
jest wykonywana ,,równolegle", analogicznie do przypisania
równoleg³ego. Przy takiej semantyce kolejno¶æ poszczególnych
równoległego. Przy takiej semantyce kolejność poszczególnych
deklaracji powinna byæ nieistotna.
deklaracji powinna być nieistotna.
}}
}}

Wersja z 08:10, 10 sie 2006


Zawartość

Kontynuujemy ćwiczenie semantyki naturalnej, dodając pewne konstrukcje do języka Tiny. W szczególności rozszerzymy go o deklaracje zmiennych (bloki). Po raz pierwszy roszdzielimy informację przechowywaną w konfiguracji na środowisko określające wiązanie identyfikatorów i stan przechowujący wartości zmiennych. Będzie to przygotowanie do kolejnych zajęć.


Semantyka naturalna pewnej instrukcji 𝐟𝐨𝐫

Ćwiczenie 1


Rozszerzamy język Tiny następująco:

I::=|𝐟𝐨𝐫x=e1𝐭𝐨e2𝐭𝐫𝐲I1𝐞𝐥𝐬𝐞I2|𝐟𝐚𝐢𝐥

Znaczenie instrukcji 𝐟𝐨𝐫x=e1𝐭𝐨e2𝐭𝐫𝐲I1𝐞𝐥𝐬𝐞I2 jest następujące. Obliczamy wartości wyrażeń e1 i e2. Jeśli pierwsza z nich jest mniejsza lub równa od drugiej, to podstawiamy pierwszą wartość (wartość wyrażenia e1) na zmienną x i uruchamiamy I1. Jeśli w I1 nie zostanie napotkana instrukcja 𝐟𝐚𝐢𝐥, kończymy instrukcję 𝐟𝐨𝐫 i przyracamy wartość zmiennej x sprzed tej instrukcji. Natomiast jeśli w I1 zostanie napotkana instrukcja 𝐟𝐚𝐢𝐥, podstawiamy na x kolejną, o jeden większą wartość, przywracamy wartości wszystkich pozostałych zmiennych sprzed instrukcji 𝐟𝐨𝐫, i ponownie wykonujemy I1. Powtarzamy w ten sposób aż I1 zakończy się nie napotkawszy 𝐟𝐚𝐢𝐥, albo wartość zmiennej x przekroczy wartość wyrażenia e2 obliczoną na początku. W pierwszym przypadku kończymy instrukcję 𝐟𝐨𝐫 i przyracamy wartość zmiennej x sprzed tej instrukcji. W drugim przywracamy wartości wszystkich zmiennych sprzed instrukcji 𝐟𝐨𝐫 i uruchamiamy I2.


Przykład

Oto przykładowy program:

x := 0; y := 1;
𝐟𝐨𝐫 x := 1 \,\mathbf{to}\, 5 𝐭𝐫𝐲
  y := y+1;
  𝐢𝐟 x <= 4 𝐭𝐡𝐞𝐧𝐟𝐚𝐢𝐥𝐞𝐥𝐬𝐞 z:= x
𝐞𝐥𝐬𝐞𝐬𝐤𝐢𝐩


Wartości zmiennych po zakończeniu programu to: x=0,y=2,z=5.


Rozwiązanie

{{{3}}}


Semantyka naturalna bloków

Ćwiczenie 2 (bloki i deklaracje zmiennych)

Rozszerz semantykę języka Tiny o deklarację zmiennej:

I::=|𝐛𝐞𝐠𝐢𝐧𝐯𝐚𝐫x=e;I𝐞𝐧𝐝

Zasięgiem zmiennej x jest instrukcja I czyli wnętrze bloku, w którym jest zadeklarowana. Zakładamy zwykłe (statyczne) reguły widoczności, przesłaniania, itp.


Rozwiązanie

{{{3}}}

Zadania domowe

Ćwiczenie 1

Napisz semantykę naturalną dla następującego rozszerzenia języka Tiny:

Parser nie mógł rozpoznać (nieznana funkcja „\ldotes”): {\displaystyle I \, ::= \,\, \ldotes \,\,|\,\, \mathbf{throw}\, x \,\,|\,\, \,\mathbf{try}\, I_1 \,\mathbf{catch}\, exc\, I_2 }

exc::=x|𝐚𝐧𝐲

Instrukcja 𝐭𝐡𝐫𝐨𝐰x oznacza podniesienie wyjątku o nazwie x. Instrukcja I=𝐭𝐫𝐲I1𝐜𝐚𝐭𝐜𝐡excI2 wykonuje I1. Jeśli podczas wykonania I1 zostanie podniesiony wyjątej x, i exc=x albo exc=𝐚𝐧𝐲, to następuje przerwanie I1 i sterowanie zostaje przeniesione do I2 (następuje obsługa wyjątku). Jeśli zaś podczas wykonania I1 zostanie podniesiony wyjątej x oraz excx i exc𝐚𝐧𝐲, to obsługa wyjątku przekazana jest do najbliższej instrukcji 𝐭𝐫𝐲 otaczającej I. Umawiamy się, że 𝐭𝐫𝐲I1𝐜𝐚𝐭𝐜𝐡excI2 otacza I1 i wszystkie instrukcje wewnątrz I1, ale nie otacza I2.


Ćwiczenie 2

Zaproponuj modyfikację semantyki, w której deklaracja jest wykonywana ,,równolegle", analogicznie do przypisania równoległego. Przy takiej semantyce kolejność poszczególnych deklaracji powinna być nieistotna.