Semantyka i weryfikacja programów/Ćwiczenia 3: 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 7: Linia 7:
wyrażeń boolowskich i arytmetycznych i semantykę dla
wyrażeń boolowskich i arytmetycznych i semantykę dla
błędów wykonania.
błędów wykonania.
Wreszcie dodamy instrukcję pętli <math> \mathbf{loop}\, </math> i instrukcje
Wreszcie dodamy nową instrukcję pętli <math>\mathbf{loop}\,</math> pozwalającą na 
niestrukturalnego zakończenia pętli (instrukcje <math> \mathbf{exit}</math> i <math> \mathbf{continue} </math>).
niestrukturalne przerwanie lub wznowienie iteracji (instrukcje <math>\mathbf{exit}</math> i <math>\mathbf{continue}</math>).




Linia 14: Linia 14:




==== Zadanie 1 ====
{{cwiczenie|1|cw1|


Zdefiniuj znaczenie wyrażeń boolowskich i arytmetycznych
Zdefiniuj znaczenie wyrażeń boolowskich i arytmetycznych
w języku Tiny, w stylu dużych kroków (semantyka naturalna).
w języku Tiny, w stylu dużych kroków (semantyka naturalna).
}}


==== Rozwiązanie ====


{{rozwiazanie||roz1|


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


Przypomnijmy składnię wyrażeń boolowskich i arytmetycznych
Przypomnijmy składnię wyrażeń boolowskich i arytmetycznych
Linia 37: Linia 39:
l \, ::= \,\,
l \, ::= \,\,
         \mathbf{true}    \,\,|\,\,
         \mathbf{true}    \,\,|\,\,
         \mathbf{true}         
         \mathbf{false}         
</math>
</math>


Linia 55: Linia 57:
</math>
</math>


Chcemy, aby tranzycje wyrażen wyglądały następująco:
Chcemy, aby tranzycje wyrażeń wyglądały następująco:


<math>
<math>
Linia 63: Linia 65:
</math>
</math>


gdzie <math> s \in \mathbf{State} </math>, <math> n \in </math> jest liczbą całkowitą,  
gdzie <math>s \in \mathbf{State}</math>, <math>n \in</math> jest liczbą całkowitą,  
<math> n \in \mathbf{Num} </math>, a <math> l \in \mathbf{Bool} = \{ \mathbf{true}, \mathbf{true} \} </math>.
<math>n \in \mathbf{Num}</math>, a <math>l \in \mathbf{Bool} = \{ \mathbf{true}, \mathbf{false} \}</math>.
Tranzycja taka oznacza, że wyrażenie <math> e </math> w stanie <math> s </math> wylicza się do
Tranzycja taka oznacza, że wyrażenie <math>e</math> w stanie <math>s</math> wylicza się do
wartości <math> n </math> oraz analogicznie, wyrażenie logiczne <math> b </math> w
wartości <math>n</math> oraz analogicznie, wyrażenie logiczne <math>b</math> w
stanie <math> s </math> wylicza się do <math> l </math>.
stanie <math>s</math> wylicza się do <math>l</math>.
Zatem zbiór konfiguracji dla semantyki całego języka Tiny to znów
Zatem zbiór konfiguracji dla semantyki całego języka Tiny to znów


Linia 74: Linia 76:
\mathbf{Num} \, \cup \, \mathbf{Bool} \, \cup \, \mathbf{State}
\mathbf{Num} \, \cup \, \mathbf{Bool} \, \cup \, \mathbf{State}
</math>
</math>
a konfiguracje końcowe to <math> \mathbf{State} </math> tak jak poprzednio.
a konfiguracje końcowe to <math>\mathbf{State}</math> tak jak poprzednio.
Tranzycje dla instrukcji pozostają zasadniczo bez zmian, z tym,
Tranzycje dla instrukcji pozostają zasadniczo bez zmian, z tym,
że odwołania do funkcji semantycznych dla wyrażen zastępujemy
że odwołania do funkcji semantycznych dla wyrażen zastępujemy
Linia 86: Linia 88:


<math>
<math>
\frac{b, s \,\longrightarrow\, \mathbf{true}}
\frac{b, s \,\longrightarrow\, \mathbf{false}}
     {\mathbf{while}\, b \,\mathbf{do}\, I, s \,\longrightarrow\, s}
     {\mathbf{while}\, b \,\mathbf{do}\, I, s \,\longrightarrow\, s}
</math>
</math>
Linia 109: Linia 111:
</math>
</math>


Czyli aby obliczyć sumę <math> e_1 + e_2 </math> w stanie  
Czyli aby obliczyć sumę <math>e_1 + e_2</math> w stanie  
<math> s </math>, trzeba najpierw obliczyć <math> e_1 </math> i  
<math>s</math>, trzeba najpierw obliczyć <math>e_1</math> i  
<math> e_2 </math> w tym stanie, a następnie dodać obliczone wartości.
<math>e_2</math> w tym stanie, a następnie dodać obliczone wartości.
Zauważmy, że nie specyfikujemy kolejności, w jakiej mają się
Zauważmy, że nie specyfikujemy kolejności, w jakiej mają się
obliczać obydwa podwyrażenia.
obliczać obydwa podwyrażenia.
Linia 131: Linia 133:


<math>
<math>
\frac{b_1, s \,\longrightarrow\, \mathbf{true}}
\frac{b_1, s \,\longrightarrow\, \mathbf{false}}
     {b_1 \land b_2, s \,\longrightarrow\, \mathbf{true}}
     {b_1 \land b_2, s \,\longrightarrow\, \mathbf{false}}
 
\quad \quad
\frac{b_1, s \,\longrightarrow\, \mathbf{true}  \quad \quad   
\frac{b_1, s \,\longrightarrow\, \mathbf{true}  \quad \quad   
       b_2, s \,\longrightarrow\, l}
       b_2, s \,\longrightarrow\, l}
Linia 140: Linia 142:


Inny wariant to wariant prawo-stronny (
Inny wariant to wariant prawo-stronny (
najpierw <math> b_2 </math>, potem <math> b_1 </math>).
najpierw <math>b_2</math>, potem <math>b_1</math>).
Wreszcie rozważmy kombinację obydwu semantyk (reguły ''równoległe''):
Wreszcie rozważmy kombinację obydwu semantyk (reguły ''równoległe''):


<math>
<math>
\frac{b_1, s \,\longrightarrow\, \mathbf{true}}
\frac{b_1, s \,\longrightarrow\, \mathbf{false}}
     {b_1 \land b_2, s \,\longrightarrow\, \mathbf{true}}
     {b_1 \land b_2, s \,\longrightarrow\, \mathbf{false}}
\quad \quad \quad
\quad \quad \quad
\frac{b_2, s \,\longrightarrow\, \mathbf{true}}
\frac{b_2, s \,\longrightarrow\, \mathbf{false}}
       {b_1 \land b_2, s \,\longrightarrow\, \mathbf{true}}
       {b_1 \land b_2, s \,\longrightarrow\, \mathbf{false}}
</math>
</math>


Czyli jeśli którekolwiek z podwyrażeń daje wynik <math> \mathbf{true} </math>,
Czyli jeśli którekolwiek z podwyrażeń daje wynik <math>\mathbf{false}</math>,
to taki wynik zyskuje całe wyrażenie.
to taki wynik zyskuje całe wyrażenie.
Dodatkowo potrzebujemy jeszcze reguły:
Dodatkowo potrzebujemy jeszcze reguły:
Linia 167: Linia 169:
ćwiczenie.
ćwiczenie.


</div></div>
}}




 
{{cwiczenie|2|cw2|
==== Zadanie 2 ====


Rozważ dodatkowo operację dzielenia:
Rozważ dodatkowo operację dzielenia:
Linia 184: Linia 187:
Oprócz stanu wynikiem programu powinna byc informacja o błędzie,
Oprócz stanu wynikiem programu powinna byc informacja o błędzie,
jeśli błąd wystąpił.
jeśli błąd wystąpił.
}}


==== Rozwiązanie (szkic) ====


{{rozwiazanie||roz2|


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


Dopóki nie wystąpi błąd dzielenia przez zero, semantyka programu
Dopóki nie wystąpi błąd dzielenia przez zero, semantyka programu
Linia 199: Linia 204:
Zaczynamy od pierwszego punktu.
Zaczynamy od pierwszego punktu.
W tym celu dodajemy do konfiguracji jedną konfigurację końcową
W tym celu dodajemy do konfiguracji jedną konfigurację końcową
<math> \mathtt{Blad} </math>.
<math>\mathtt{Blad}</math>.
Reguła opisująca powstanie błędu może wyglądać np. tak:
Reguła opisująca powstanie błędu może wyglądać np. tak
(duże i małe kroki):


<math>
<math>
\frac{e_2, s \longrightarrow 0}
\frac{e_2, s \,\longrightarrow\, 0}
{e_1 / e_2, s \longrightarrow Blad}
{e_1 / e_2, s \,\longrightarrow\, \mathtt{Blad}}
\quad \quad
e_1 / 0, s \,\Longrightarrow\, \mathtt{Blad}.
</math>
</math>


Linia 217: Linia 225:


<math>
<math>
e_1 / 0, s \Longrightarrow Blad, s
\frac{e_2, s \,\longrightarrow\, 0}
{e_1 / e_2, s \,\longrightarrow\, \mathtt{Blad}, s}
\quad \quad
e_1 / 0, s \,\Longrightarrow\, \mathtt{Blad}, s
</math>
</math>


i zamiast pojedyńczej konfiguracji końcowej <math> \mathtt{Blad} </math> potrzebowalibyśmy
i zamiast pojedyńczej konfiguracji końcowej <math>\mathtt{Blad}</math> potrzebowalibyśmy
oczywiście całego zbioru <math> \{ \mathtt{Blad} \} \times \mathbf{State} </math>.
oczywiście całego zbioru <math>\{ \mathtt{Blad} \} \times \mathbf{State}</math>.


Przejdźmy teraz do drugiego punktu. Potrzebujemy dodatkowych reguł,
Przejdźmy teraz do drugiego punktu. Potrzebujemy dodatkowych reguł,
Linia 264: Linia 275:
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, \mathtt{Blad}}
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, \mathtt{Blad}}
\quad \quad \quad
\quad \quad \quad
\frac{b, s \,\longrightarrow\, \mathbf{true} \quad \quad I_2, s \,\longrightarrow\, \mathtt{Blad}}
\frac{b, s \,\longrightarrow\, \mathbf{false} \quad \quad I_2, s \,\longrightarrow\, \mathtt{Blad}}
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, \mathtt{Blad}}
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, \mathtt{Blad}}
</math>
</math>
Linia 277: Linia 288:
</math>
</math>


Zwróćmy szczególnie uwagę na ostatnią regułę dla pętli <math>\mathbf{while}\,</math>:
wyraża ona przypadek, gdy błąd został wygenerowany
nie w pierwszym obiegu pętli, ale w którymś z kolejnych.
Musieliśmy rozważyc również ten przypadek, ponieważ wybraliśmy
podejście dużych kroków; w podejściu małych kroków nie byłoby
to zapewne konieczne.


</div></div>
}}




==== Zadanie 3 ====
{{cwiczenie|3|cw3|


Rozszerz język Tiny o następującą instrukcję pętli:
Rozszerz język Tiny o następującą instrukcję pętli:
Linia 291: Linia 310:
</math>
</math>


<math> \mathbf{loop}\, I </math> to instrukcja pętli, <math> I </math> stanowi instrukcję wewnętrzną.
<math>\mathbf{loop}\, I</math> to instrukcja pętli, <math>I</math> stanowi instrukcję wewnętrzną.
Instrukcja <math> \mathbf{exit} </math> wychodzi z nabliższej pętli <math> \mathbf{loop}\, </math>
Instrukcja <math>\mathbf{exit}</math> wychodzi z nabliższej pętli <math>\mathbf{loop}\,</math>
i kontynuuje wykonanie programu od pierwszej instrukcji za tą pętlą.
i kontynuuje wykonanie programu od pierwszej instrukcji za tą pętlą.
Instrukcje <math> \mathbf{continue} </math> powraca na początek instrukcji wewnętrznej
Instrukcje <math>\mathbf{continue}</math> powraca na początek instrukcji wewnętrznej
najbliższej pętli.
najbliższej pętli.


Pozważ zarówno semantykę naturalną jak i semantykę małych kroków.
Pozważ zarówno semantykę naturalną jak i semantykę małych kroków.
}}




==== Rozwiązanie 1 (semantyka naturalna) ====
{{rozwiazanie||roz3.1|(semantyka naturalna)
 


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


Dodamy do reguł semantyki naturalnej dla języka Tiny
Dodamy do reguł semantyki naturalnej dla języka Tiny
kilka nowych reguł opisujących nową konstrukcję języka
kilka nowych reguł opisujących nową konstrukcję języka
i jej ''interakcję'' z pozostałymi konstrukcjami.
i jej ,,interakcję\'' z pozostałymi konstrukcjami.


Pomysł polega na dodaniu specjalnych konfiguracji zawierających
Pomysł polega na dodaniu specjalnych konfiguracji zawierających
informację o tym, że została wykonana instrukcja <math> \mathbf{exit} </math>
informację o tym, że została wykonana instrukcja <math>\mathbf{exit}</math>
lub <math> \mathbf{continue} </math>. Oto odpowiednie reguły:
lub <math>\mathbf{continue}</math>. Oto odpowiednie reguły:


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


Czyli instrukcje <math> \mathbf{exit} </math> i <math> \mathbf{continue} </math> nie modyfikują
Czyli instrukcje <math>\mathbf{exit}</math> i <math>\mathbf{continue}</math> nie modyfikują
stanu <math> s </math>, ale zostawiają po sobie \''ślad".  
stanu <math>s</math>, ale zostawiają po sobie ,,ślad".  
Zauważmy, że taki ślad zostaje pozostawiony tylko wtedy, jesli
Zauważmy, że taki ślad zostaje pozostawiony tylko wtedy, jesli
nie było dotychczas innego śladu, to znaczy jeśli <math> \mathbf{exit} </math>
nie było dotychczas innego śladu, to znaczy jeśli <math>\mathbf{exit}</math>
(lub <math> \mathbf{continue} </math>) zostało wykonane w zwykłym stanie <math> s </math>.
(lub <math>\mathbf{continue}</math>) zostało wykonane w zwykłym stanie <math>s</math>.
Oczywiście poszerzamy odpowiednio zbiór konfiguracji o:
Oczywiście poszerzamy odpowiednio zbiór konfiguracji o:


</math>[
<math>
\mathbf{State} \times \{ \mbox{było-}\mathbf{exit}, \mbox{było-}\mathbf{continue} \}
\mathbf{State} \times \{ \mbox{było-}\mathbf{exit}, \mbox{było-}\mathbf{continue} \}
</math>
</math>
,
 
'''Pytanie''': jakie powinno być zachowanie <math> \mathbf{exit} </math> i
'''Pytanie''': jakie powinno być zachowanie <math>\mathbf{exit}</math> i
<math> \mathbf{continue} </math> w konfiguracji <math> s, \mbox{było-}\mathbf{exit} </math>
<math>\mathbf{continue}</math> w konfiguracji <math>s, \mbox{było-}\mathbf{exit}</math>
lub <math> s, \mbox{było-}\mathbf{continue} </math>?
lub <math>s, \mbox{było-}\mathbf{continue}</math>?
Czy instrukcje <math> \mathbf{exit} </math> i <math> \mathbf{continue} </math>
Czy instrukcje <math>\mathbf{exit}</math> i <math>\mathbf{continue}</math>
będą faktycznie wykonywane w takich konfiguracjach?
będą faktycznie wykonywane w takich konfiguracjach?


Zapiszmy teraz jak inne instrukcje korzystają z dodatkowej informacji
Zapiszmy teraz jak inne instrukcje korzystają z dodatkowej informacji
(śladu) zawartej w konfiguracjach.
(śladu) zawartej w konfiguracjach.
Oczywiście beneficjentem tej informacji jest instrukcji <math> \mathbf{loop}\, </math>:
Oczywiście beneficjentem tej informacji jest instrukcji <math>\mathbf{loop}\,</math>:


<math>
<math>
Linia 348: Linia 368:


Czyli w zależności od tego, jaki ślad został zarejestrowany
Czyli w zależności od tego, jaki ślad został zarejestrowany
podczas wykonania <math> I </math>, albo kończymy wykonanie  pętli <math> \mathbf{loop}\, </math>,
podczas wykonania <math>I</math>, albo kończymy wykonanie  pętli <math>\mathbf{loop}\,</math>,
albo rozpoczynamy kolejną iterację.
albo rozpoczynamy kolejną iterację.
Zauważmy, że stan <math> s' </math> może być różny od <math> s </math>, ponieważ
Zauważmy, że stan <math>s'</math> może być różny od <math>s</math>, ponieważ
zanim wykonała się ktoraś z instrukcji <math> \mathbf{exit} </math> lub
zanim wykonała się ktoraś z instrukcji <math>\mathbf{exit}</math> lub
<math> \mathbf{continue} </math>, mogły zostać zmienione wartości niektórych zmiennych.
<math>\mathbf{continue}</math>, mogły zostać zmienione wartości niektórych zmiennych.


Oczywiście, jeśli instrukcja wewnętrzna <math> I </math> zakończyła się
Oczywiście, jeśli instrukcja wewnętrzna <math>I</math> zakończyła się
''normalnie'', kontynuujemy wykonanie pętli podobnie jak w przypadku  
''normalnie'', kontynuujemy wykonanie pętli podobnie jak w przypadku  
wywołania <math> \mathbf{continue} </math>:
wywołania <math>\mathbf{continue}</math>:


<math>
<math>
Linia 374: Linia 394:


Okazuje się że nie, ponieważ ślad powinien zostać zawsze
Okazuje się że nie, ponieważ ślad powinien zostać zawsze
''wymazany'' przez pętlę <math> \mathbf{loop}\, </math>.
,,wymazany" przez pętlę <math>\mathbf{loop}\,</math>.
<!--
Poza tym reguły te wykraczałyby poza klasyczna podejście semantyki
Poza tym reguły te wykraczałyby poza klasyczna podejście semantyki
naturalnej, w którym zwykle bezpośrednio definiujemy
naturalnej, w którym zwykle bezpośrednio definiujemy
tranzycje postaci <math> I, s \,\longrightarrow\, s' </math>.
tranzycje postaci <math>I, s \,\longrightarrow\, s'</math>.
-->


Teraz musimy określić zachowanie wszystkich instrukcji w sytuacji,
Teraz musimy określić zachowanie wszystkich instrukcji w sytuacji,
Linia 383: Linia 405:
zaniechać wykonania instrukcji (w przypadku pętli, powinniśmy
zaniechać wykonania instrukcji (w przypadku pętli, powinniśmy
zaniechać dalszego iterowania tej pętli).
zaniechać dalszego iterowania tej pętli).
Oto odpowiednie reguły dla <math> \mbox{było-}\mathbf{exit} </math>:
Oto odpowiednie reguły dla <math>\mbox{było-}\mathbf{exit}</math>:


<math>
<math>
Linia 397: Linia 419:
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, s', \mbox{było-}\mathbf{exit}}
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, s', \mbox{było-}\mathbf{exit}}
\quad \quad
\quad \quad
\frac{b, s \,\longrightarrow\, \mathbf{true} \quad \quad I_2, s \,\longrightarrow\, s', \mbox{było-}\mathbf{exit}}
\frac{b, s \,\longrightarrow\, \mathbf{false} \quad \quad I_2, s \,\longrightarrow\, s', \mbox{było-}\mathbf{exit}}
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, s', \mbox{było-}\mathbf{exit}}
     {\mathbf{if}\, b \,\mathbf{then}\, I_1 \,\mathbf{else}\, I_2, s \,\longrightarrow\, s', \mbox{było-}\mathbf{exit}}
</math>
</math>
Linia 410: Linia 432:
</math>
</math>


Pominęliśmy zupełnie analogiczne reguły dla konfiguracji
Pominęliśmy zupełnie analogiczne reguły dla <math>\mbox{było-}\mathbf{continue}</math>.
<math> s', \mbox{było-}\mathbf{continue} </math>.
Zauważmy, że dla pętli <math>\mathbf{while}\,</math> nie rozpatrujemy przypadku,
Zwróćmy szczególnie uwagę na ostatnią regułę dla pętli <math> \mathbf{while}\, </math>:
gdy dozór <math>b</math> oblicza się do <math>\mathbf{false}</math>, gdyż w tym przypadku
wyraża ona przypadek, gdy ślad <math> \mathbf{exit} </math> został wygenerowany
nie w pierwszym obiegu pętli, ale w którymś z kolejnych.
Musieliśmy rozważyc również ten przypadek, ponieważ wybraliśmy
podejście dużych kroków; w podejściu małych kroków nie byłoby
to zapewne konieczne.
Zauważmy też, że dla pętli <math> \mathbf{while}\, </math> nie rozpatrujemy przypadku,
gdy dozór <math> b </math> oblicza się do <math> \mathbf{true} </math>, gdyż w tym przypadku
nie ma możliwości wygenerowania śladu.
nie ma możliwości wygenerowania śladu.


Linia 425: Linia 440:




</div></div>
}}




{{rozwiazanie||roz3.2|(małe kroki)


==== Rozwiązanie 2 (małe kroki) ====
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
 
 


W semantyce naturalnej musieliśmy napisać wiele reguł aby  
W semantyce naturalnej musieliśmy napisać wiele reguł aby  
Linia 460: Linia 476:
</math>
</math>


Zauważmy, że nie musimy zajmowac się przypadkiem, gdy ślad
Nie musimy zajmowac się przypadkiem, gdy ślad
powstaje w <math> I_2 </math>, bo wybraliśmy podejście mało-krokowe.
powstaje w <math>I_2</math>, bo wybraliśmy podejście mało-krokowe.
Ponadto, nie musimy opisywać instrukcji warunkowej i pętli <math> \mathbf{while}\, </math>,
Ponadto, nie musimy opisywać instrukcji warunkowej i pętli <math>\mathbf{while}\,</math>,
ponieważ ślad nie może powstać podczas oblcizania dozoru!
ponieważ ślad nie może powstać podczas obliczania dozoru!


Wreszcie zobaczmy jak zachowuje się pętla <math> \mathbf{loop}\, </math>:
Wreszcie zobaczmy jak zachowuje się pętla <math>\mathbf{loop}\,</math>:


<math>
<math>
Linia 478: Linia 494:
sytuacji!  
sytuacji!  
Natomiast korzystamy z tego, że w podejściu mało-krokowym zmiana konfiguracji
Natomiast korzystamy z tego, że w podejściu mało-krokowym zmiana konfiguracji
na <math> s', \mbox{było-}\mathbf{exit} </math> czy <math> s', \mbox{było-}\mathbf{continue} </math> jest
na <math>s', \mbox{było-}\mathbf{exit}</math> czy <math>s', \mbox{było-}\mathbf{continue}</math> jest
''natychmiast'' widoczna w instrukcji <math> \mathbf{loop}\, I </math>, nawet jeśli
''natychmiast'' widoczna w instrukcji <math>\mathbf{loop}\, I</math>, nawet jeśli
<math> \mathbf{exit} </math> czy <math> \mathbf{continue} </math> zostało wywołane głęboko wewnątrz
<math>\mathbf{exit}</math> czy <math>\mathbf{continue}</math> zostało wywołane głęboko wewnątrz
<math> I </math>!
<math>I</math>!


Niestety, powyzsze reguły '''nie są poprawne'''!
Niestety powyższe reguły '''nie są poprawne'''!
Dlaczego? Jak zwykle w semantyce małych kroków, wykonując instrukcję
Dlaczego? Jak zwykle w semantyce małych kroków, wykonując instrukcję
wewnętrzną ''zapominamy'' stopniowo jaka była ona na początku.
wewnętrzną ''zapominamy'' stopniowo jaka była ona na początku.
I w związku z tym nie potrafimy poprawnie powrócić do wykonywania
I w związku z tym nie potrafimy poprawnie powrócić do wykonywania
pętli <math> \mathbf{loop}\, </math> po wywołaniu <math> \mathbf{continue} </math>.  
pętli <math>\mathbf{loop}\,</math> po wywołaniu <math>\mathbf{continue}</math>.  


Prostym sposobem poprawienia naszego blędu jest rozszerzenie składni
Prostym sposobem poprawienia naszego blędu jest rozszerzenie składni
tak, aby możliwe było jednorazowe rozwinięcie pętli <math> \mathbf{loop}\, </math>:
tak, aby możliwe było jednorazowe rozwinięcie pętli <math>\mathbf{loop}\,</math>:


<math>
<math>
Linia 496: Linia 512:
</math>
</math>


Teraz możemy zapisać dwie powyższe reguły dla <math> \mathbf{loop}\, </math> w poprawnej
Teraz możemy zapisać dwie powyższe reguły dla <math>\mathbf{loop}\,</math> w poprawnej
wersji, pamiętając o tym, że <math> \mbox{było-}\mathbf{exit} </math> i
wersji, pamiętając o tym, że <math>\mbox{było-}\mathbf{exit}</math> i
<math> \mbox{było-}\mathbf{continue} </math> pojawią się nie w instrukcji wewnętrznej,
<math>\mbox{było-}\mathbf{continue}</math> pojawią się nie w instrukcji wewnętrznej,
ale w jej ''kopii'' umieszczonej przed <math> \,\mathbf{then}\, </math>:
ale w jej ''kopii'' umieszczonej przed <math>\,\mathbf{then}\,</math>:


<math>
<math>
Linia 506: Linia 522:
\quad \quad
\quad \quad
\frac{I', s \,\Longrightarrow\, s', \mbox{było-}\mathbf{continue}}
\frac{I', s \,\Longrightarrow\, s', \mbox{było-}\mathbf{continue}}
    {I; \,\mathbf{then}\, \mathbf{loop}\, I, s \,\Longrightarrow\, \mathbf{loop}\, I, s'}
\quad \quad
\frac{I', s \,\Longrightarrow\, s'}
     {I; \,\mathbf{then}\, \mathbf{loop}\, I, s \,\Longrightarrow\, \mathbf{loop}\, I, s'}
     {I; \,\mathbf{then}\, \mathbf{loop}\, I, s \,\Longrightarrow\, \mathbf{loop}\, I, s'}
</math>
</math>


A ponieważ wewnątrz kopii mogą być zagnieżdzone instrukcje
Potrzebujemy też dodatkowej reguły dla obliczeń wewnątrz instrukcji
<math> \mathbf{loop}\, </math> potrzebujemy dodatkowej reguły:
stojącej przed <math>\,\mathbf{then}\,</math> (w szczególności może ona zawierać
zagnieżdzone pętle <math>\mathbf{loop}\,</math> :


<math>
<math>
Linia 517: Linia 537:
</math>
</math>


Na koniec zauważmy, że stan <math> s' </math> w  
Na koniec zauważmy, że stan <math>s'</math> w  
pierwszych dwóch z powyższych trzech reguł nigdy nie jest różny
pierwszych dwóch z powyższych reguł nigdy nie jest różny
od <math> s </math>. Zatem równoważnie moglibyśmy zamienić <math> s' </math> na <math> s </math>
od <math>s</math>. Zatem równoważnie moglibyśmy zamienić <math>s'</math> na <math>s</math>
w powyższych dwóch regułach. Ale wtedy okazuje się , <math> s </math>
w powyższych dwóch regułach. Ale wtedy okazuje się , <math>s</math>
w parze z <math> \mbox{było-}\mathbf{exit} </math> albo <math> \mbox{było-}\mathbf{continue} </math> jest nadmiarowe
w parze z <math>\mbox{było-}\mathbf{exit}</math> albo <math>\mbox{było-}\mathbf{continue}</math> jest nadmiarowe
i może zostać wyeliminowane.
i może zostać wyeliminowane.


Linia 549: Linia 569:
\quad \quad
\quad \quad
\frac{I', s \,\Longrightarrow\, \mbox{było-}\mathbf{continue}}
\frac{I', s \,\Longrightarrow\, \mbox{było-}\mathbf{continue}}
    {I; \,\mathbf{then}\, \mathbf{loop}\, I, s \,\Longrightarrow\, \mathbf{loop}\, I, s}
\quad \quad
\frac{I', s \,\Longrightarrow\, s'}
     {I; \,\mathbf{then}\, \mathbf{loop}\, I, s \,\Longrightarrow\, \mathbf{loop}\, I, s}
     {I; \,\mathbf{then}\, \mathbf{loop}\, I, s \,\Longrightarrow\, \mathbf{loop}\, I, s}
</math>
</math>
Linia 557: Linia 580:
</math>
</math>


a zbiór konfiguracji poszerzamy tylko o
a zbiór konfiguracji poszerzamy tylko o dwie nowe konfiguracje
<math> \{ \mbox{było-}\mathbf{exit}, \mbox{było-}\mathbf{continue} \} </math>.
<math>\{ \mbox{było-}\mathbf{exit}, \mbox{było-}\mathbf{continue} \}</math>.
 


</div></div>
}}




Linia 568: Linia 592:
==== Zadanie 1 ====
==== Zadanie 1 ====


Zaproponuj semantykę mało-krokową języka z zdania 2.
Zaproponuj semantykę mało-krokową dla rozszerzeń języka Tiny, które
Czy różni się ona istotnie od semantyki naturalnej?
studiowaliśmy powyżej.




==== Zadanie 2 ====
==== Zadanie 2 ====


Napisz semantyję naturalną dla nieznacznie rozszerzonej wersji instrukcji <math> \mathbf{loop}\, </math>:
Napisz semantyję naturalną dla nieznacznie rozszerzonej wersji instrukcji <math>\mathbf{loop}\,</math>:


<math>
<math>
I \, ::= \,\,
I \, ::= \,\,
       x: \mathbf{loop}\, I \,\,|\,\,
       x: \mathbf{loop}\, I \,\,|\,\,
       \mathbf{exit} x \,\,|\,\,
       \mathbf{exit}\, x \,\,|\,\,
       \mathbf{continue} x
       \mathbf{continue}\, x
</math>
</math>


Identyfikator <math> x </math> pełni tutaj rolę etykiety przypisanej
Identyfikator <math>x</math> pełni tutaj rolę etykiety przypisanej
instrukcji <math> \mathbf{loop}\, </math>, jest też parametrem dwóch pozostałych
instrukcji <math>\mathbf{loop}\,</math>, jest też parametrem dwóch pozostałych
instrukcji. <math> \mathbf{exit} x </math> kończy teraz najbliższą otaczającą pętlę <math> \mathbf{loop}\, </math>
instrukcji. <math>\mathbf{exit} x</math> kończy teraz najbliższą otaczającą pętlę <math>\mathbf{loop}\,</math>
o etykiecie <math> x </math>. Podobnie <math> \mathbf{continue} x </math> wznawia najbliższą
o etykiecie <math>x</math>. Podobnie <math>\mathbf{continue} x</math> wznawia najbliższą
pętlę o etykiecie <math> x </math>. Np. program
otaczającą pętlę o etykiecie <math>x</math>.  
 
===== Przykład =====




  x: <math>\mathbf{loop}\,</math>
x: <math>\mathbf{loop}\,</math>
    a := 1;  
  a := 1;  
    y: <math>\mathbf{loop}\,</math>
  y: <math>\mathbf{loop}\,</math>
      <math>\mathbf{exit}</math> x;
    <math>\mathbf{exit}</math> x;
      a := a-10;
    a := a-10;
    a := a+1;
  a := a+1;
  a := a+2;
a := a+2;




kończy działanie z wartością zmiennej <math> a = 3 </math>.
Program kończy działanie z wartością zmiennej <math>a = 3</math>.
Zauważmy, że musieliśmy jakoś określić, do wnętrza której pętli
Za pomocą wcięć określiliśmy, do wnętrza której pętli
<math> \mathbf{loop}\, </math> należą trzy ostatnie instrukcje. Użyliśmy to tego celu
<math>\mathbf{loop}\,</math> należy każda z trzech ostatnich instrukcji przypisania.  
wcięć a niejednoznaczność bierze się oczywiście stąd, że  
Niejednoznaczność bierze się oczywiście stąd, że  
pracujemy ze składnią abstrakcyjną. Składnia konkretna zawierałaby
pracujemy ze składnią abstrakcyjną. Składnia konkretna zawierałaby
prawdopodobnie jakąś konstukcję ''zamykającą'' pętlę <math> \mathbf{loop}\, </math>,
prawdopodobnie jakąś konstukcję ''zamykającą'' pętlę <math>\mathbf{loop}\,</math>,
np. <math> \mathbf{loop}\, I \,\mathbf{end}\mathbf{loop}\, </math>.
np. <math>\mathbf{loop}\, I \,\mathbf{end}\mathbf{loop}\,</math>.




Linia 621: Linia 647:
</math>
</math>


Obliczenie wyrażenia <math> \,\mathbf{do}\, I \,\mathbf{then}\, e </math> polega na wykonaniu <math> I </math>
Obliczenie wyrażenia <math>\,\mathbf{do}\, I \,\mathbf{then}\, e</math> polega na wykonaniu <math>I</math>
a potem na obliczeniu <math> e </math>. Wartość wyrażenia <math> x:= e </math> jest taka
a potem na obliczeniu <math>e</math>. Wartość wyrażenia <math>x:= e</math> jest taka
jak wartość wyrażenia <math> e </math> a efektem ubocznym jest  
jak wartość wyrażenia <math>e</math> a efektem ubocznym jest  
podstawienie tej wartości na zmienną <math> x </math>.
podstawienie tej wartości na zmienną <math>x</math>.

Wersja z 08:12, 8 sie 2006


Zawartość

Kończymy semantykę małych kroków i rozpoczynamy semantykę naturalną (duże kroki). Uzupełnimy semantykę naturalną języka Tiny o semantykę naturalną dla wyrażeń boolowskich i arytmetycznych i semantykę dla błędów wykonania. Wreszcie dodamy nową instrukcję pętli 𝐥𝐨𝐨𝐩 pozwalającą na niestrukturalne przerwanie lub wznowienie iteracji (instrukcje 𝐞𝐱𝐢𝐭 i 𝐜𝐨𝐧𝐭𝐢𝐧𝐮𝐞).


Rozszerzenia semantyki języka Tiny

Ćwiczenie 1

Zdefiniuj znaczenie wyrażeń boolowskich i arytmetycznych w języku Tiny, w stylu dużych kroków (semantyka naturalna).


Rozwiązanie

{{{3}}}


Ćwiczenie 2

Rozważ dodatkowo operację dzielenia:

e::=|e1/e2

i rozszerz semantykę z poprzedniego zadania. Dzielenie przez zero jest błądem i kończy natychmiast wykonanie programu. Oprócz stanu wynikiem programu powinna byc informacja o błędzie, jeśli błąd wystąpił.


Rozwiązanie

{{{3}}}


Ćwiczenie 3

Rozszerz język Tiny o następującą instrukcję pętli:

I::=𝐥𝐨𝐨𝐩I|𝐞𝐱𝐢𝐭|𝐜𝐨𝐧𝐭𝐢𝐧𝐮𝐞

𝐥𝐨𝐨𝐩I to instrukcja pętli, I stanowi instrukcję wewnętrzną. Instrukcja 𝐞𝐱𝐢𝐭 wychodzi z nabliższej pętli 𝐥𝐨𝐨𝐩 i kontynuuje wykonanie programu od pierwszej instrukcji za tą pętlą. Instrukcje 𝐜𝐨𝐧𝐭𝐢𝐧𝐮𝐞 powraca na początek instrukcji wewnętrznej najbliższej pętli.

Pozważ zarówno semantykę naturalną jak i semantykę małych kroków.


Rozwiązanie

{{{3}}}


Rozwiązanie

{{{3}}}


Zadania domowe

Zadanie 1

Zaproponuj semantykę mało-krokową dla rozszerzeń języka Tiny, które studiowaliśmy powyżej.


Zadanie 2

Napisz semantyję naturalną dla nieznacznie rozszerzonej wersji instrukcji 𝐥𝐨𝐨𝐩:

I::=x:𝐥𝐨𝐨𝐩I|𝐞𝐱𝐢𝐭x|𝐜𝐨𝐧𝐭𝐢𝐧𝐮𝐞x

Identyfikator x pełni tutaj rolę etykiety przypisanej instrukcji 𝐥𝐨𝐨𝐩, jest też parametrem dwóch pozostałych instrukcji. 𝐞𝐱𝐢𝐭x kończy teraz najbliższą otaczającą pętlę 𝐥𝐨𝐨𝐩 o etykiecie x. Podobnie 𝐜𝐨𝐧𝐭𝐢𝐧𝐮𝐞x wznawia najbliższą otaczającą pętlę o etykiecie x.

Przykład
x: 𝐥𝐨𝐨𝐩
  a := 1; 
  y: 𝐥𝐨𝐨𝐩
    𝐞𝐱𝐢𝐭 x;
    a := a-10;
  a := a+1;
a := a+2;


Program kończy działanie z wartością zmiennej a=3. Za pomocą wcięć określiliśmy, do wnętrza której pętli 𝐥𝐨𝐨𝐩 należy każda z trzech ostatnich instrukcji przypisania. Niejednoznaczność bierze się oczywiście stąd, że pracujemy ze składnią abstrakcyjną. Składnia konkretna zawierałaby prawdopodobnie jakąś konstukcję zamykającą pętlę 𝐥𝐨𝐨𝐩, np. 𝐥𝐨𝐨𝐩I𝐞𝐧𝐝𝐥𝐨𝐨𝐩.


Zadanie 3

Napisz semantykę naturalną i mało-krokową dla rozszerzenia języka Tiny o wyrażenia z efektami ubocznymi:

e::=|𝐝𝐨I𝐭𝐡𝐞𝐧e|x:=e|x++|

Obliczenie wyrażenia 𝐝𝐨I𝐭𝐡𝐞𝐧e polega na wykonaniu I a potem na obliczeniu e. Wartość wyrażenia x:=e jest taka jak wartość wyrażenia e a efektem ubocznym jest podstawienie tej wartości na zmienną x.