Semantyka i weryfikacja programów/Ćwiczenia 2: Różnice pomiędzy wersjami
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 1: | Linia 1: | ||
== | == Zawartość == | ||
Ćwiczymy dalej semantykę małych kroków. | |||
Uzupełnimy semantykę języka Tiny o semantykę operacyjną | |||
wyrażeń boolowskich i arytmetycznych. | |||
Następnie rozszerzymy nasz język o róznorodne konstrukcje iteracji. | |||
Na koniec zdefiniujemy operacje arytmetyczne liczb binarnych. | Na koniec zdefiniujemy operacje arytmetyczne liczb binarnych. | ||
== Rozszerzenia semantyki | == Rozszerzenia semantyki języka Tiny == | ||
{{cwiczenie|1|cw1| | {{cwiczenie|1|cw1| | ||
Semantyka | Semantyka języka Tiny z wykładu używała funkcji semantycznych | ||
<math> | <math> | ||
B, E : State \to State | B, E : State \to State | ||
</math> | </math> | ||
dla | dla określenia znaczenia wyrażeń boolowskich i arytmetycznych. | ||
Zdefiniuj znaczenie | Zdefiniuj znaczenie wyrażeń za pomocą semantyki operacyjnej, | ||
w stylu | w stylu małych kroków. | ||
}} | }} | ||
Linia 29: | Linia 29: | ||
<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"> | ||
Przypomnijmy | Przypomnijmy składnię wyrażeń boolowskich i arytmetycznych: | ||
<math> | <math> | ||
Linia 60: | Linia 60: | ||
</math> | </math> | ||
Niech <math>\mathbf{BExp}</math> oznacza zbiór | Niech <math>\mathbf{BExp}</math> oznacza zbiór wyrażeń boolowskich, | ||
<math>b \in \mathbf{BExp}</math>. | <math>b \in \mathbf{BExp}</math>. | ||
Chcemy, aby tranzycje dla | Chcemy, aby tranzycje dla wyrażeń były postaci: | ||
<math> | <math> | ||
Linia 68: | Linia 68: | ||
</math> | </math> | ||
i podobnie dla | i podobnie dla wyrażeń boolowskich: | ||
<math> | <math> | ||
Linia 75: | Linia 75: | ||
gdzie <math>s \in \mathbf{State}</math>. | gdzie <math>s \in \mathbf{State}</math>. | ||
Dodatkowo | Dodatkowo będziemy potrzebować również tranzycji postaci: | ||
<math> | <math> | ||
Linia 84: | Linia 84: | ||
b, s \,\Longrightarrow\, l | b, s \,\Longrightarrow\, l | ||
</math> | </math> | ||
gdzie <math>n \in</math> jest | gdzie <math>n \in</math> jest liczbą całkowitą, | ||
<math>n \in \mathbf{Num}</math>, a <math>l \in \mathbf{Bool} = \{ \mathbf{true}, \mathbf{false} \}</math>. | <math>n \in \mathbf{Num}</math>, a <math>l \in \mathbf{Bool} = \{ \mathbf{true}, \mathbf{false} \}</math>. | ||
Formalnie, zbiór konfiguracji dla semantyki | Formalnie, zbiór konfiguracji dla semantyki całego języka Tiny to | ||
<math> | <math> | ||
Linia 93: | Linia 93: | ||
</math> | </math> | ||
a konfiguracje | a konfiguracje końcowe to <math>\mathbf{State}</math>; aczkolwiek | ||
konfiguracje ze zbioru <math>\mathbf{Num} \, \cup \, \mathbf{Bool}</math> | konfiguracje ze zbioru <math>\mathbf{Num} \, \cup \, \mathbf{Bool}</math> pełnią podobną rolę | ||
dla | dla wyrażeń arytmetycznych i boolowskich jako konfiguracje końcowe dla | ||
instrukcji. | instrukcji. | ||
Przypomnijmy, | Przypomnijmy, że <math>\mathbf{Stmt}</math> oznacza zbiór instrukcji, <math>I \in \mathbf{Stmt}</math>. | ||
Zacznijmy od (chyba najprostszych) tranzycji dla | Zacznijmy od (chyba najprostszych) tranzycji dla stałych boolowskich i liczbowych: | ||
<math> | <math> | ||
Linia 107: | Linia 107: | ||
</math> | </math> | ||
Podobnie jak poprzednio, | Podobnie jak poprzednio, zakładamy tutaj dla wygody, że | ||
<math>\mathbf{Num} \subseteq \mathbf{Exp}</math> oraz <math>\mathbf{Bool} \subseteq \mathbf{BExp}</math>. | <math>\mathbf{Num} \subseteq \mathbf{Exp}</math> oraz <math>\mathbf{Bool} \subseteq \mathbf{BExp}</math>. | ||
Pozwala nam to nie | Pozwala nam to nie odróżniać stałych występujących w wyrażeniach | ||
a zatem | a zatem pojawiających się po lewej stonie tranzycji | ||
od | od wartości im odpowiadających pojawiających się po prawej stronie. | ||
Przejdźmy do spójników logicznych, powiedzmy <math>b_1 \land b_2</math>. | |||
Ponieważ opisujemy teraz pojedyncze (małe) kroki składające się na | |||
wykonanie programu, musimy | wykonanie programu, musimy podać w jakiej kolejności będą się | ||
obliczać <math>b_1</math> i <math>b_2</math>. Zacznijmy od strategii lewostronnej: | |||
<math> | <math> | ||
Linia 129: | Linia 129: | ||
</math> | </math> | ||
Możemy zaniechać obliczania | |||
<math>b_2</math> | <math>b_2</math> jeśli <math>b_1</math> oblicza się do false. | ||
Oto odpowiednio zmodyfikowane | Oto odpowiednio zmodyfikowane reguły: | ||
<math> | <math> | ||
Linia 142: | Linia 142: | ||
</math> | </math> | ||
Analogicznie | Analogicznie reguły prawostronne to: | ||
<math> | <math> | ||
Linia 153: | Linia 153: | ||
</math> | </math> | ||
Reguły ''równoległe'' otrzymujemy jako sumę reguł lewo- i | |||
prawostronnych (w sumie 6 | prawostronnych (w sumie 6 reguł). Zauważmy, że obliczanie | ||
wyrażeń <math>b_1</math> i <math>b_2</math> odbywa się teraz | |||
w twz. \''przeplocie": Pojedynczy krok polega na wykonaniu | w twz. \''przeplocie": Pojedynczy krok polega na wykonaniu | ||
jednego kroku obliczenia <math>b_1</math> albo jednego kroku | jednego kroku obliczenia <math>b_1</math> albo jednego kroku | ||
obliczenia <math>b_2</math>. | obliczenia <math>b_2</math>. | ||
Zwróćmy też uwagę, że nasze tranzycje nie posiadają teraz | |||
własności ''determinizmu'': wyrażenie <math>b_1 \land b_2</math> | |||
może wyewoluować w pojedyńczym kroku albo do | |||
<math>b'_1 \land b_2</math> albo do <math>b_1 \land b'_2</math>. | <math>b'_1 \land b_2</math> albo do <math>b_1 \land b'_2</math>. | ||
Na | Na szczęście, końcowy wynik, do jakiego oblicza się wyrażenie | ||
jest zawsze taki sam, | jest zawsze taki sam, niezależnie od przeplotu. | ||
Oto | Oto reguły dla negacji: | ||
<math> | <math> | ||
Linia 177: | Linia 177: | ||
</math> | </math> | ||
Reguły dla <math>e_1 \leq e_2</math> są następujące: | |||
<math> | <math> | ||
Linia 193: | Linia 193: | ||
</math> | </math> | ||
Reguły powyższe zależą od semantyki wyrażen arytmetycznych. | |||
Zauważmy, że ponownie pozostawiliśmy dowolność jeśli chodzi o | |||
kolejność obliczania wyrażeń arytmetycznych <math>e_1</math> i <math>e_2</math>. | |||
Jako | Jako pierwszą z instrukcji rozważmy przypisanie. | ||
Najpierw obliczamy | Najpierw obliczamy wyrażenie po prawej stronie przypisania, | ||
a gdy | a gdy wyrażenie to wyewoluuje do stałej (obliczy się), modyfikujemy | ||
stan: | stan: | ||
Linia 209: | Linia 209: | ||
</math> | </math> | ||
Rozważmy teraz instrukcję warunkową i instrukcję pętli. | |||
Najpierw obliczamy | Najpierw obliczamy wartość dozoru: | ||
<math> | <math> | ||
Linia 221: | Linia 221: | ||
</math> | </math> | ||
a gdy dozór jest | a gdy dozór jest już obliczony, podejmujemy decyzję. | ||
W przypadku instrukcji warunkowej | W przypadku instrukcji warunkowej reguły są oczywiste: | ||
<math> | <math> | ||
Linia 230: | Linia 230: | ||
</math> | </math> | ||
Gorzej jest w przypadku instrukcji | Gorzej jest w przypadku instrukcji pętli. Reguła mogłaby wyglądać tak: | ||
<math> | <math> | ||
Linia 237: | Linia 237: | ||
</math> | </math> | ||
ale nie wiemy | ale nie wiemy już, jaki był dozór pętli (widzimy tylko wynik | ||
obliczenia tego dozoru w stanie s, czyli <math>\mathbf{true}</math>). | obliczenia tego dozoru w stanie s, czyli <math>\mathbf{true}</math>). | ||
Możemy odwołać się do tranzytywnego domknięcia relacji | |||
<math>\,\Longrightarrow\,</math> (czyli w zadadzie do semantyki | <math>\,\Longrightarrow\,</math> (czyli w zadadzie do semantyki dużych kroków): | ||
<math> | <math> | ||
Linia 251: | Linia 251: | ||
</math> | </math> | ||
Takie | Takie rozwiązanie nie jest zatem ''czystą'' semantyką | ||
małych kroków. | |||
Istnieją inne możliwe rozwiązania w stylu małych kroków. | |||
Jedno z nich oparte jest na | Jedno z nich oparte jest na pomyśle, aby ''rozwinąc'' pętlę | ||
<math>\mathbf{while}\,</math>, zanim obliczymy | <math>\mathbf{while}\,</math>, zanim obliczymy wartość dozoru <math>b</math>. | ||
Jedyną reguła dla pętli <math>\mathbf{while}\,</math> byłaby wtedy reguła: | |||
<math> | <math> | ||
Linia 262: | Linia 262: | ||
</math> | </math> | ||
Dzięki temu obliczany warunek logiczny <math>b</math> jest zawsze | |||
''jednorazowy''. | ''jednorazowy''. | ||
Znalezienie innych | Znalezienie innych rozwiązań, np. opartych na rozszerzeniu składni, | ||
pozostawiamy dociekliwemu Czytelnikowi. | pozostawiamy dociekliwemu Czytelnikowi. | ||
Reguły dla operacji arytmetycznych również pozostawiamy do napisania Czytelnikowi. | |||
</div></div> | </div></div> | ||
Linia 275: | Linia 275: | ||
{{cwiczenie|2|cw2| | {{cwiczenie|2|cw2| | ||
Rozszerzmy | Rozszerzmy język Tiny o następujące dobrze znane konstrukcje iteracji: | ||
<math> | <math> | ||
Linia 285: | Linia 285: | ||
</math> | </math> | ||
Napisz | Napisz semantykę małych kroków dla powyższych konstrukcji. | ||
}} | }} | ||
Linia 296: | Linia 296: | ||
<br> | <br> | ||
Zacznijmy od | Zacznijmy od pętli <math>\mathbf{repeat}\, I \,\mathbf{until}\, b</math>. | ||
Przyjrzyjmy | Przyjrzyjmy się dwóm podejściom, które zastosowaliśmy dla | ||
pętli <math>\mathbf{while}\,</math> w poprzednim zadaniu. | |||
Po pierwsze | Po pierwsze rozwinięcie: | ||
<math> | <math> | ||
Linia 305: | Linia 305: | ||
</math> | </math> | ||
Po drugie, spróbujmy | Po drugie, spróbujmy odwołać się do <math>\,\Longrightarrow\,^{*}</math> dla dozoru pętli <math>b</math>: | ||
<math> | <math> | ||
Linia 320: | Linia 320: | ||
</math> | </math> | ||
Okazuje | Okazuje się, że jest jeszcze gorzej niż w przypadku pętli <math>\mathbf{while}\,</math>: | ||
nie | nie pamiętamy już, jaka była instrukcja wewnętrzna naszej pętli! | ||
Czyli takie | Czyli takie podejście jest teraz nieskuteczne. | ||
Linia 329: | Linia 329: | ||
<br> | <br> | ||
Pętla <math>\,\mathbf{do}\, e \,\mathbf{times}\, I</math>, w stanie <math>s</math>, oznacza wykonianie instrukcji <math>I</math> | |||
<math>n</math> razy, gdzie <math>n</math> to | <math>n</math> razy, gdzie <math>n</math> to wartość, do której oblicza się | ||
<math>e</math> w stanie <math>s</math>. | <math>e</math> w stanie <math>s</math>. | ||
Czyli najpierw obliczmy <math>e</math> przy pomocy | Czyli najpierw obliczmy <math>e</math> przy pomocy reguły: | ||
<math> | <math> | ||
Linia 345: | Linia 345: | ||
</math> | </math> | ||
Teraz jest juz | Teraz jest juz łatwo: | ||
<math> | <math> | ||
Linia 362: | Linia 362: | ||
<br> | <br> | ||
W przypadku | W przypadku pętli <math>\mathbf{for}\,</math> przyjmijmy, że wartości wyrażeń | ||
<math>e_1</math> i <math>e_2</math> obliczane | <math>e_1</math> i <math>e_2</math> obliczane są przed pierwszą iteracją | ||
pętli. | |||
Dodatkowo ustalmy, | Dodatkowo ustalmy, że <math>e_1</math> będzie obliczone jako pierwsze. | ||
Czyli: | Czyli: | ||
Linia 378: | Linia 378: | ||
</math> | </math> | ||
Zatem zakres zmiennej <math>x</math> mamy | Zatem zakres zmiennej <math>x</math> mamy już obliczony, tzn. jesteśmy | ||
w konfiguracji | w konfiguracji | ||
Linia 385: | Linia 385: | ||
</math> | </math> | ||
Dalsze | Dalsze reguły mogą być podobne do reguł dla pętli <math>\,\mathbf{do}\, n \,\mathbf{times}\, I</math>: | ||
<math> | <math> | ||
Linia 398: | Linia 398: | ||
Zauważmy, wartość zmiennej <math>x</math> po zakończeniu pętli | |||
wynosi albo <math>n_2</math> albo pozostaje niezmieniona. | wynosi albo <math>n_2</math> albo pozostaje niezmieniona. | ||
Ponieważ nie zostało wyspecyfikowane jaka | |||
powinna | powinna być wartość tej zmiennej, możemy taką semantykę uznać | ||
za | za poprawną. | ||
'''Pytanie:''' | '''Pytanie:''' | ||
A | A gdybyśmy jednak zażądali przywrócenia na koniec wartości zmiennej <math>x</math> | ||
sprzed | sprzed pętli? | ||
Jak | Jak należałoby zmienić nasze reguły? | ||
Semantykę dla <math>\,\mathbf{do}\, I \, \mathbf{while}\, b</math> pozostawiamy Czytelnikowi jako | |||
proste | proste ćwiczenie. | ||
Oczywiście minimalistyczne rozwiązanie to | |||
<math> | <math> | ||
Linia 427: | Linia 427: | ||
{{cwiczenie|3|cw3| | {{cwiczenie|3|cw3| | ||
Rozważmy następujący język wyrażeń (liczby binarne z dodawaniem): | |||
<math> | <math> | ||
Linia 437: | Linia 437: | ||
</math> | </math> | ||
<math>\epsilon</math> oznacza | <math>\epsilon</math> oznacza słowo puste, czyli np. <math>\epsilon 1 0 1 1</math> | ||
oznacza | oznacza binarną liczbę 1011. | ||
Napisz | Napisz semantykę operacyjną obliczającą wartość wyrażeń. | ||
}} | }} | ||
Linia 447: | Linia 447: | ||
<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"> | ||
Składnia wyrażeń pozwala na wygodny dostęp do najmniej znaczącego | |||
bitu liczby. Spróbujmy zatem | bitu liczby. Spróbujmy zatem zastosować metodę dodawania | ||
pisemnego: | pisemnego: | ||
Linia 463: | Linia 463: | ||
</math> | </math> | ||
Ale co | Ale co zrobić z przeniesieniem? | ||
<math> | <math> | ||
Linia 469: | Linia 469: | ||
</math> | </math> | ||
Podstawowy | Podstawowy pomysł polega na potraktowaniu przeniesienia jak dodatkowego składnika: | ||
<math> | <math> | ||
Linia 475: | Linia 475: | ||
</math> | </math> | ||
Zauważmy, że w składni dopuszcza się dowolne przeplatanie operatora dodawania | |||
i bitów <math>0, 1</math>. | i bitów <math>0, 1</math>. Tę dowolność wykorzystaliśmy właśnie w regułach | ||
powyżej. Gdyby nasz język ograniczyć tylko do składni | |||
<math> | <math> | ||
Linia 492: | Linia 492: | ||
</math> | </math> | ||
(nazwijmy | (nazwijmy ją ''składnią ograniczoną'') to powyższe reguły byłyby niepoprawne. | ||
Zanim dopiszemy | Zanim dopiszemy pozostałe reguły, określmy zbiór konfiguracji jako | ||
zbiór | zbiór wyrażeń. Konfiguracje końcowe to wyrażenia bez operatora dodawania | ||
(liczby binarne). Nasz | (liczby binarne). Nasz pomysł jest taki, że tranzycje stopniowo przesuwają | ||
operator dodawania w lewo, | operator dodawania w lewo, aż się go ostatecznie ''pozbędą''. | ||
Gdy obydwa | Gdy obydwa składniki mają tyle samo cyfr, do zakończenia dodawania | ||
potrzebujemy | potrzebujemy reguły: | ||
<math> | <math> | ||
Linia 506: | Linia 506: | ||
</math> | </math> | ||
Gdy jeden ze | Gdy jeden ze składników ma mniej cyfr niż drugi, potrzebujemy reguł: | ||
<math> | <math> | ||
Linia 522: | Linia 522: | ||
</math> | </math> | ||
Niestety, nie | Niestety, nie możemy użyć reguły przemienności: | ||
<math> | <math> | ||
Linia 528: | Linia 528: | ||
</math> | </math> | ||
gdyż spowodowałaby ona możliwość ''pętlenia się'', a zatem braku wyniku obliczenia. | |||
Na koniec dodajemy typowe | Na koniec dodajemy typowe reguły opisujące jak krok podwyrażenia indukuje | ||
krok | krok całego wyrażenia: | ||
<math> | <math> | ||
Linia 554: | Linia 554: | ||
{{cwiczenie|4|cw4| | {{cwiczenie|4|cw4| | ||
Rozszerzmy | Rozszerzmy składnię o jeden symbol <math>p</math> oznaczający | ||
'' | ''przepełnienie'': | ||
<math> | <math> | ||
Linia 566: | Linia 566: | ||
</math> | </math> | ||
Na | Na przykład <math>p 1 0 1</math> oznacza tę samą liczbę co <math>\epsilon 1 0 1 | ||
</math>, ale z | </math>, ale z dodatkową informacją, że podczas jej obliczania nastąpiło | ||
'' | ''przepełnienie''. | ||
Rozumiemy przez to | Rozumiemy przez to sytuację, gdy wynik ma więcej cyfr niż każdy z | ||
argumentów. Cyfry zero z lewej strony (najbardziej | argumentów. Cyfry zero z lewej strony (najbardziej znaczące) również | ||
uważamy za pełnoprawne cyfry, nie należy ich usuwać ani dodawać | |||
nowych. | nowych. | ||
Napisz | Napisz semantykę operacyjną obliczającą wartość wyrażenia wraz z | ||
informacja o ewentualnym | informacja o ewentualnym przepełnieniu. | ||
Wynik powinien byc poprawny przynajmniej dla | Wynik powinien byc poprawny przynajmniej dla wyrażeń <math>e</math> w składni | ||
ograniczonej: | ograniczonej: | ||
Linia 598: | Linia 598: | ||
<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"> | ||
Zadanie dotyczy w zasadzie | Zadanie dotyczy w zasadzie składni ograniczonej, ale jako konfiguracji | ||
pośrednich będziemy zapewne potrzebować wyrażeń wykraczających poza | |||
tę składnię, np. <math>(e_1 + e_2) 0</math>, podobnie jak w poprzednim | |||
zadaniu. Zatem mamy tu do czynienia z typowym zabiegiem rozszerzania | zadaniu. Zatem mamy tu do czynienia z typowym zabiegiem rozszerzania | ||
składni na użytek semantyki operacyjnej (z tym, że rozszerzenie jest | |||
dane z góry i nie musimy go | dane z góry i nie musimy go wymyślać :) | ||
Przyjmijmy, | Przyjmijmy, że konfiguracjami są dowolne wyrażenia, a konfiguracjami | ||
końcowymi wyrażenia bez operatora dodawania (ale teraz mogą to być | |||
np. | np. wyrażenia postaci <math>p 1 0 0</math>). | ||
Spróbujmy | Spróbujmy pozostawić wszystkie reguły z poprzedniego zadania. | ||
Dodamy tylko kilka nowych | Dodamy tylko kilka nowych reguł, odpowiedzialnych za przepełnienie. | ||
Zacznijmy od najprostszej sytuacji, gdy jeden ze | Zacznijmy od najprostszej sytuacji, gdy jeden ze składników ma mniej | ||
cyfr, i to ten | cyfr, i to ten właśnie składnik odnotował przepełnienie: | ||
<math> | <math> | ||
Linia 624: | Linia 624: | ||
</math> | </math> | ||
W takiej sytuacji | W takiej sytuacji oczywiście informacja o przepełnieniu zostaje | ||
wymazana. | wymazana. | ||
Jeśli przepełnienie zostało odnotowane w składniku o większej liczbie | |||
cyfr, to | cyfr, to reguły | ||
<math> | <math> | ||
Linia 639: | Linia 639: | ||
</math> | </math> | ||
z poprzedniego zadania | z poprzedniego zadania są wystarczające. | ||
Rozważmy teraz przypadek, gdy obydwa składniki mają tę samą liczbę | |||
cyfr. | cyfr. | ||
Jeśli obydwa odnotowały przepełnienie, to oczywiście informacja ta | |||
powinna | powinna zostać zachowana: | ||
<math> | <math> | ||
Linia 650: | Linia 650: | ||
</math> | </math> | ||
Ale co | Ale co należy zrobić, gdy tylko jeden ze składników odnotował | ||
przepełnienie? <math>p + \epsilon \,\Longrightarrow\, ?</math> | |||
Oczywiście, w tej sytuacji żadnego przepełnienia nie ma, ponieważ | |||
drugi | drugi składnik ma wystarczająco dużo cyfr by je przesłonić. | ||
Oto odpowiednie | Oto odpowiednie reguły: | ||
<math> | <math> | ||
Linia 662: | Linia 662: | ||
</math> | </math> | ||
Na koniec | Na koniec zostało najważniejsze: kiedy powinniśmy generować sygnał o | ||
przepełnieniu? | |||
Przypomnijmy sobie | Przypomnijmy sobie reguły dla dadawania pisemnego w poprzednim | ||
zadaniu. | zadaniu. | ||
Jeśli nie ma przeniesienia, to przepełnienie nie może powstać. | |||
Natomiast | Natomiast jeśli jest przeniesienie, to stanowi ono ''potencjalne | ||
przepełnienie''. | |||
Odpowiednia | Odpowiednia reguła to | ||
<math> | <math> | ||
Linia 675: | Linia 675: | ||
</math> | </math> | ||
Nowy sztuczny | Nowy sztuczny składnik <math>p 1</math> zawiera jakby na wszelki wypadek | ||
informacje o potencjalnym | informacje o potencjalnym przepełnieniu. | ||
Jeśli którykolwiek z pozostałych składników <math>e_1</math> i <math>e_2</math> | |||
ma przynajmniej | ma przynajmniej jedną cyfrę, | ||
to <math>p</math> zostanie | to <math>p</math> zostanie usunięte. W przeciwnym wypadku symbol <math>p</math> | ||
i przetrwa i | i przetrwa i będzie poprawnie informował o sytuacji przepełnienia. | ||
Linia 692: | Linia 692: | ||
{{cwiczenie|1|cw1.dom| | {{cwiczenie|1|cw1.dom| | ||
Podaj | Podaj przykład wyrażenia boolowskiego, które nie policzy się | ||
ani przy | ani przy użyciu strategii lewo- ani prawostronnej, a policzy się przy strategii | ||
równoległej. | |||
}} | }} | ||
Linia 700: | Linia 700: | ||
{{cwiczenie|2|cw2.dom| | {{cwiczenie|2|cw2.dom| | ||
Zmodyfikuj | Zmodyfikuj semantykę wyrażeń następująco: dla każdego podwyrażenia niedeterministycznie | ||
wybierana jest albo strategia lewo- albo prawostronna, ale | wybierana jest albo strategia lewo- albo prawostronna, ale | ||
niedozwolony jest ,,przeplot". | niedozwolony jest ,,przeplot". | ||
Linia 708: | Linia 708: | ||
{{cwiczenie|3|cw3.dom| | {{cwiczenie|3|cw3.dom| | ||
Rozważ inną semantykę pętli <math>\mathbf{for}\, x = e_1 \,\mathbf{to}\, e_2 \,\mathbf{do}\, I</math>, | |||
w której | w której wyrażenie <math>e_2</math> jest obliczane na nowo | ||
przed | przed każdą iteracją pętli. | ||
Napisz | Napisz reguły semantyczne dla tej instrukcji, nie odwołując | ||
się do innych istrukcji pętli. | |||
}} | }} | ||
Linia 718: | Linia 718: | ||
{{cwiczenie|4|cw4.dom| | {{cwiczenie|4|cw4.dom| | ||
Dodaj do | Dodaj do wyrażeń binarnych operację odejmowania. | ||
}} | }} | ||
Linia 724: | Linia 724: | ||
{{cwiczenie|5|cw15.dom| | {{cwiczenie|5|cw15.dom| | ||
Zaproponuj | Zaproponuj semantykę przypisania równoległego w języku Tiny: | ||
<math> | <math> | ||
Linia 730: | Linia 730: | ||
</math> | </math> | ||
polegającego na obliczeniu najpierw wartości wyrażeń | |||
<math>e_1, \ldots, e_n</math> a | <math>e_1, \ldots, e_n</math> a następnie na podstawieniu | ||
tych | tych wartości na zmienne <math>x_1, \ldots, x_n</math>. | ||
}} | }} |
Wersja z 08:04, 10 sie 2006
Zawartość
Ćwiczymy dalej semantykę małych kroków. Uzupełnimy semantykę języka Tiny o semantykę operacyjną wyrażeń boolowskich i arytmetycznych. Następnie rozszerzymy nasz język o róznorodne konstrukcje iteracji. Na koniec zdefiniujemy operacje arytmetyczne liczb binarnych.
Rozszerzenia semantyki języka Tiny
Ćwiczenie 1
Semantyka języka Tiny z wykładu używała funkcji semantycznych dla określenia znaczenia wyrażeń boolowskich i arytmetycznych. Zdefiniuj znaczenie wyrażeń za pomocą semantyki operacyjnej, w stylu małych kroków.
Rozwiązanie
Ćwiczenie 2
Rozszerzmy język Tiny o następujące dobrze znane konstrukcje iteracji:
Napisz semantykę małych kroków dla powyższych konstrukcji.
Rozwiązanie
Kalkulator binarny
Ćwiczenie 3
Rozważmy następujący język wyrażeń (liczby binarne z dodawaniem):
oznacza słowo puste, czyli np. oznacza binarną liczbę 1011. Napisz semantykę operacyjną obliczającą wartość wyrażeń.
Rozwiązanie
Ćwiczenie 4
Rozszerzmy składnię o jeden symbol oznaczający przepełnienie:
Na przykład oznacza tę samą liczbę co , ale z dodatkową informacją, że podczas jej obliczania nastąpiło przepełnienie. Rozumiemy przez to sytuację, gdy wynik ma więcej cyfr niż każdy z argumentów. Cyfry zero z lewej strony (najbardziej znaczące) również uważamy za pełnoprawne cyfry, nie należy ich usuwać ani dodawać nowych.
Napisz semantykę operacyjną obliczającą wartość wyrażenia wraz z informacja o ewentualnym przepełnieniu. Wynik powinien byc poprawny przynajmniej dla wyrażeń w składni ograniczonej:
Rozwiązanie
Zadania domowe
Ćwiczenie 1
Podaj przykład wyrażenia boolowskiego, które nie policzy się ani przy użyciu strategii lewo- ani prawostronnej, a policzy się przy strategii równoległej.
Ćwiczenie 2
Zmodyfikuj semantykę wyrażeń następująco: dla każdego podwyrażenia niedeterministycznie wybierana jest albo strategia lewo- albo prawostronna, ale niedozwolony jest ,,przeplot".
Ćwiczenie 3
Rozważ inną semantykę pętli , w której wyrażenie jest obliczane na nowo przed każdą iteracją pętli. Napisz reguły semantyczne dla tej instrukcji, nie odwołując się do innych istrukcji pętli.
Ćwiczenie 4
Dodaj do wyrażeń binarnych operację odejmowania.
Ćwiczenie 5
Zaproponuj semantykę przypisania równoległego w języku Tiny:
polegającego na obliczeniu najpierw wartości wyrażeń a następnie na podstawieniu tych wartości na zmienne .