Semantyka i weryfikacja programów/Ćwiczenia 6: Różnice pomiędzy wersjami
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 1: | Linia 1: | ||
== | == Zawartość == | ||
Ostatnie | Ostatnie zajęcia poświęcone semantyce naturalnej. | ||
Rozszerzymy | Rozszerzymy język Tiny o deklaracje zmiennych i procedur z jednym | ||
parametrem. | parametrem. | ||
Rozważymy statyczną i dynamiczną widoczność (wiązanie) | |||
identyfikatorów oraz | identyfikatorów oraz różne mechanizmy przekazywania | ||
parametrów. | parametrów. | ||
Pracujemy ze | Pracujemy ze środowiskami i stanami. | ||
Linia 17: | Linia 17: | ||
{{cwiczenie|1 (procedury)|cw1| | {{cwiczenie|1 (procedury)|cw1| | ||
Rozszerzmy | Rozszerzmy język Tiny o deklaracje i wywołania procedur: | ||
<math> | <math> | ||
Linia 33: | Linia 33: | ||
</math> | </math> | ||
Konstrukcja <math>\mathbf{proc}\, x_1(x_2)</math> deklaruje | Konstrukcja <math>\mathbf{proc}\, x_1(x_2)</math> deklaruje procedurę o nazwie | ||
<math>x_1</math>, której parametrem formalnym jest <math>x_2</math>. | <math>x_1</math>, której parametrem formalnym jest <math>x_2</math>. | ||
Zakładamy statyczne wiązanie identyfikatorów i przekazywanie | |||
parametrów przez | parametrów przez zmienną (to znaczy, że w momencie wywołania | ||
procedury, powinna | procedury, powinna zostać | ||
przekazana lokacja | przekazana lokacja odpowiadająca parametrowi aktualnemu). | ||
Instrukcja <math>\mathbf{call}\, x_1(x_2)</math> | Instrukcja <math>\mathbf{call}\, x_1(x_2)</math> wywołuje procedurę <math>x_1</math> | ||
z parametrem aktualnym <math>x_2</math>. | z parametrem aktualnym <math>x_2</math>. | ||
}} | }} | ||
Linia 48: | Linia 48: | ||
<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"> | ||
Użyjemu środowisk <math>E \in \mathbf{Env}</math> i stanów <math>s \in \mathbf{Store}</math>: | |||
<math> | <math> | ||
Linia 58: | Linia 58: | ||
Nowym elementem jest zbiór <math>\mathbf{Proc}</math>, potrzebny nam do | Nowym elementem jest zbiór <math>\mathbf{Proc}</math>, potrzebny nam do | ||
przechowywania informacji o procedurach. | przechowywania informacji o procedurach. | ||
Informacja nt procedury, | Informacja nt procedury, którą musimy przechowywać, to: | ||
* nazwa parametru formalnego, | * nazwa parametru formalnego, | ||
* | * ciało procedury (instrukcja <math>I \in \mathbf{Stmt}</math>) oraz | ||
* '' | * ''środowisko'', w którym procedura została zadeklarowana. | ||
Zauważmy, że nie musimy (i nie powinniśmy) pamiętać stanu | |||
z momentu deklaracji, czyli konkretnych | z momentu deklaracji, czyli konkretnych wartości zmiennych | ||
wówczas zadeklarowanych. | wówczas zadeklarowanych. Pamiętamy tylko środowisko, | ||
które wyznacza nam '' | które wyznacza nam ''wiązanie'' identyfikatorów (nazw | ||
zmiennych i procedur) | zmiennych i procedur) występujących w ciele procedury z | ||
lokacjami (lub opisami procedur z <math>\mathbf{Proc}</math>), a | lokacjami (lub opisami procedur z <math>\mathbf{Proc}</math>), a więc z konkretnymi | ||
zmiennymi (lub procedurami). | zmiennymi (lub procedurami). | ||
Widać tutaj jasno, jak elegancki i wygodny jest podział na środowisko | |||
i stan. | i stan. | ||
Linia 77: | Linia 77: | ||
Czyli znów zbiór <math>\mathbf{Env}</math> zadany jest przez równanie. | Czyli znów zbiór <math>\mathbf{Env}</math> zadany jest przez równanie. | ||
Nasze tranzycje | Nasze tranzycje będą następujących postaci: | ||
<math> | <math> | ||
Linia 91: | Linia 91: | ||
</math> | </math> | ||
Na | Na uwagę zasługuje ostatnia postać tranzycji: deklaracja, | ||
w | w odróżnieniu od instrukcji, może zmieniać środowisko. | ||
Umówmy | Umówmy się, że środowisko <math>E'</math> będzie rozszerzało <math>E</math> o informację | ||
o nowych identyfikatorach, tzn. tych zadeklarowanych w <math>d</math>. | o nowych identyfikatorach, tzn. tych zadeklarowanych w <math>d</math>. | ||
Zajmijmy | Zajmijmy się najpierw deklaracjami zmiennych: | ||
<math> | <math> | ||
Linia 114: | Linia 114: | ||
</math> | </math> | ||
Zauważmy, że deklaracja procedury nie zmienia stanu, tylko środowisko, | |||
w | w odróżnieniu od deklaracji zmiennej. | ||
W | W środowisku pamiętamy trójkę <math>\langle x_2, I, E \rangle</math> zawierającą | ||
nazwę parametru formalnego, ciało procedury oraz ''środowisko | |||
deklaracji procedury''. | deklaracji procedury''. | ||
To ostatnie determinuje statyczne | To ostatnie determinuje statyczne wiązanie identyfikatorów: | ||
wiązanie identyfikatorów występującuch w ciele procedury jest | |||
jakby ,, | jakby ,,zamrożone'' (ustalone) w momencie deklaracji procedury. | ||
Aby | Aby dokończyć semantykę deklaracji potrzebujemy jeszcze jednej reguły: | ||
<math> | <math> | ||
Linia 131: | Linia 131: | ||
</math> | </math> | ||
która opisuje | która opisuje sekwencyjną ,,kumulację" modyfikacji dokonanych w deklaracjach. | ||
'''Pytanie:''' czy | '''Pytanie:''' czy kolejność poszczególnych deklaracji ma znaczenie? | ||
Teraz | Teraz określimy semantykę bloku: | ||
<math> | <math> | ||
Linia 144: | Linia 144: | ||
</math> | </math> | ||
Czyli instrukcja | Czyli instrukcja wewnętrzna wykonywana jest w środowisku (i stanie) | ||
''wytworzonym'' (rozszerzonym) przez | ''wytworzonym'' (rozszerzonym) przez deklarację <math>d</math>. | ||
Stan | Stan końcowy po wykonaniu bloku to po prostu stan końcowy <math>s''</math> | ||
po wykonaniu instrukcji | po wykonaniu instrukcji wewnętrznej. | ||
Może się to wydawać niepokojące, gdyż oznacza, że nowe lokacje, | |||
powołane podczas deklaracji <math>d</math>, zachowują przechowywaną wartość | |||
również po wyjściu z bloku. Na szczęście wykonanie | |||
bloku nie ma | bloku nie ma wpływu na środowisko, a to ono decyduje, które | ||
identyfikatory | identyfikatory są widoczne (zadeklarowane) i ogólniej, które lokacje | ||
są przypisane identyfikatorom. A więc deklaracja <math>d</math> | |||
nie ma | nie ma wpływu na środowisko, w którym zostaną wykonane kolejne | ||
instrukcje. | instrukcje. | ||
Widać to jasno w regule dla złożenia sekwencyjnego: | |||
<math> | <math> | ||
Linia 166: | Linia 166: | ||
Pozostało nam jeszcze określenie semantyki wywołania procedury: | |||
<math> | <math> | ||
Linia 176: | Linia 176: | ||
</math> | </math> | ||
Czyli uruchamiane jest | Czyli uruchamiane jest ciało <math>I</math> procedury, | ||
w | w środowisku <math>E'</math> z miejsca deklaracji tej procedury | ||
zmodyfikowanym o przypisanie <math>x \mapsto l</math> | zmodyfikowanym o przypisanie <math>x \mapsto l</math> | ||
lokacji <math>l</math> do parametru formalnego <math>x</math> procedury. | lokacji <math>l</math> do parametru formalnego <math>x</math> procedury. | ||
Stan, w którym uruchomione jest <math>I</math> to po prostu | Stan, w którym uruchomione jest <math>I</math> to po prostu | ||
stan | stan bieżący z miejsca wołania procedury; o prawidłowe | ||
wiązanie identyfikatorów ,,troszczy" się wyłącznie | |||
środowisko <math>E'</math>. | |||
'''Pytanie:''' czy | '''Pytanie:''' czy powyższa reguła dopuszcza rekurencyjne wywołania procedury? | ||
Okazuje | Okazuje się, że niestety nie, gdyż w środowisku | ||
<math>E'[x \mapsto l]</math> nie ma informacji o procedurze <math>x_1</math>, | <math>E'[x \mapsto l]</math> nie ma informacji o procedurze <math>x_1</math>, którą | ||
właśnie wołamy. Może się zdarzyć, że <math>E'[x \mapsto l] \in \mathbf{Proc}</math>, ale | |||
oznacza to tylko, | oznacza to tylko, że w miejscu deklaracji procedury <math>x_1</math> | ||
była już wcześniej (statycznie) zadeklarowana inna procedura | |||
o tej samej nazwie. | o tej samej nazwie. | ||
Aby | Aby umożliwić rekurencję, powinniśmy zadbać sami o to, aby | ||
środowisko, w którym wykonujemy <math>I</math> zawierało informację | |||
o naszej procedurze: | o naszej procedurze: | ||
Linia 205: | Linia 205: | ||
</math> | </math> | ||
Zauważmy, że przypisanie <math>x_1 \mapsto \langle x, I, E' \rangle</math> | |||
dodane do <math>E'</math> wystarcza na tylko jedno | dodane do <math>E'</math> wystarcza na tylko jedno wywołanie rekurencyjne | ||
( | (licząc w głąb). Ale każde kolejne wywołanie dodaje tę informację, | ||
czyli | czyli każde wywołanie procedury przygotowuje środowisko dla | ||
następnego. | |||
I to jest | I to jest wystarczające. | ||
'''Pytanie:''' czy | '''Pytanie:''' czy możliwa jest rekurencja wzajemna? | ||
Pozostaje jeszcze jedna kwestia: dodajemy do | Pozostaje jeszcze jedna kwestia: dodajemy do środowiska <math>E'</math> | ||
dwa przypisania: | dwa przypisania: | ||
<math>x \mapsto l</math> oraz <math>x_1 \mapsto \langle x, I, E' \rangle</math>, | <math>x \mapsto l</math> oraz <math>x_1 \mapsto \langle x, I, E' \rangle</math>, | ||
ale dlaczego w takiej | ale dlaczego w takiej kolejności. | ||
'''Pytanie:''' co | '''Pytanie:''' co się stanie, gdy zamienimy tę kolejność: | ||
<math> | <math> | ||
Linia 229: | Linia 229: | ||
</math> | </math> | ||
Czy obydwie semantyki | Czy obydwie semantyki są sobie równoważne? | ||
Okazuje | Okazuje się, że tak nie jest, oto dwa kontrprzykłady: | ||
Linia 252: | Linia 252: | ||
Każdy z tych programów uruchomi się poprawnie w dokładnie | |||
jednym z wariantów semantyki. | jednym z wariantów semantyki. | ||
'''Pytanie:''' Który w którym? | '''Pytanie:''' Który w którym? | ||
Semantyka | Semantyka pozostałych instrukcji i wyrażeń języka Tiny pozostaje bez zmian. | ||
Rozważmy na koniec problem dealokacji. | |||
Linia 266: | Linia 266: | ||
<br> | <br> | ||
Chcemy, aby ,, | Chcemy, aby ,,posprzątano" po zakończeniu wykonania bloku, | ||
tzn. aby zwolniono te lokacje, które | tzn. aby zwolniono te lokacje, które były używane tylko w tym bloku | ||
i w | i w związku z tym nie będą już potrzebne. | ||
Oznacza to, | Oznacza to, że powinniśmy przywrócić nieokreśloność stanu dla | ||
wszystkich tych lokacji, które | wszystkich tych lokacji, które były użyte podczas deklaracji <math>d</math>. | ||
Jest wiele | Jest wiele możliwości wyrażenia tego dodatkowego warunku, | ||
np. | np. możemy dodać do powyższej reguły | ||
<math> | <math> | ||
Linia 283: | Linia 283: | ||
dodatkowy warunek postaci <math>\mbox{ gdzie } \bar{s} = \ldots</math>. | dodatkowy warunek postaci <math>\mbox{ gdzie } \bar{s} = \ldots</math>. | ||
Proponujemy tu | Proponujemy tu rozwiązanie ciut bardziej eleganckie. | ||
Zacznijmy od tranzycji | Zacznijmy od tranzycji dokonujących dealokacji, | ||
które | które mogą być np. postaci: <math>s'', L \,\longrightarrow\, \bar{s}</math>. | ||
Zakładamy tutaj, że znamy | |||
zbiór nowo zaalokowanych lokacji <math>L \subseteq \mathbf{Loc}</math>. | zbiór nowo zaalokowanych lokacji <math>L \subseteq \mathbf{Loc}</math>. | ||
Linia 294: | Linia 294: | ||
\frac{s \setminus \{ (l, s(l)) \} , L \setminus \{ l \} \,\longrightarrow\, s'} | \frac{s \setminus \{ (l, s(l)) \} , L \setminus \{ l \} \,\longrightarrow\, s'} | ||
{s, L \,\longrightarrow\, s'} | {s, L \,\longrightarrow\, s'} | ||
\quad \mbox{ o ile } l \in L \mbox{ i } s(l) \mbox{ jest | \quad \mbox{ o ile } l \in L \mbox{ i } s(l) \mbox{ jest określone} | ||
</math> | </math> | ||
Teraz albo napiszemy w dodatkowym warunku, | Teraz albo napiszemy w dodatkowym warunku, że | ||
<math>L = \mathrm{dom}(s'') \setminus \mathrm{dom}(s)</math>: | <math>L = \mathrm{dom}(s'') \setminus \mathrm{dom}(s)</math>: | ||
Linia 309: | Linia 309: | ||
</math> | </math> | ||
albo | albo możemy poprosić o pomoc w posprzątaniu tego, kto ,,nabałaganił", czyli | ||
deklarację <math>d</math>. | |||
Niech deklaracja zwraca, oprócz pary <math>(E', s')</math>, | Niech deklaracja zwraca, oprócz pary <math>(E', s')</math>, | ||
dodatkowo zbiór <math>L</math>. | dodatkowo zbiór <math>L</math>. | ||
Oto poprawione | Oto poprawione reguły dla deklaracji: | ||
Linia 337: | Linia 337: | ||
</math> | </math> | ||
Wtedy ostatecznie | Wtedy ostatecznie reguła dla bloku wygląda następująco: | ||
<math> | <math> | ||
Linia 350: | Linia 350: | ||
}} | }} | ||
{{cwiczenie|2 ( | {{cwiczenie|2 (wiązanie dynamiczne)|cw2| | ||
Zastanówmy | Zastanówmy się, jakich modyfikacji wymaga nasza semantyka, | ||
aby | aby wiązanie identyfikatorów było dynamiczne, zamiast statycznego. | ||
Rozumiemy przez to, | Rozumiemy przez to, że w przypadku odwołania do zmiennej | ||
wewnątrz procedury, odwołujemy się do środowiska w miejscu | |||
wywołania tej procedury, zamiast do środowiska z miejsca | |||
deklaracji jak dotychczas. | deklaracji jak dotychczas. | ||
Tak samo powinno | Tak samo powinno być w przypadku wywołania innej procedury | ||
wewnątrz procedury, czyli wiązanie dynamiczne dotyczy i zmiennych | |||
i procedur. | i procedur. | ||
}} | }} | ||
Linia 380: | Linia 380: | ||
Wartość końcowa zmiennej <math>z = 10</math>. | |||
Gdyby | Gdyby wiązanie zmiennej <math>x</math> było statyczne, to wartość ta | ||
wynosiłaby <math>1</math>. Podobnie dla procedur: | |||
Linia 398: | Linia 398: | ||
Wartość końcowa zmiennej <math>z = 8</math>. | |||
Gdyby | Gdyby widoczność procedury <math>q</math> była statyczna, to wartość ta | ||
wynosiłaby <math>4</math>. | |||
A oto | A oto przykład programu, który nie wykonałby się poprawnie | ||
przy | przy wiązaniu statycznych, a wykonuje się poprawnie przy | ||
dynamicznym: | dynamicznym: | ||
Linia 420: | Linia 420: | ||
Wartość końcowa zmiennej <math>z</math> wynosi <math>14</math>. | |||
Procedura <math>p</math> | Procedura <math>p</math> wywołuje procedurę <math>q</math>, | ||
,, | ,,przekazując" jej również środowisko z miejsca wołania, | ||
zawierające informację o procedurze <math>r</math>. Ta ostatnia | |||
przy | przy widoczności statycznej byłaby lokalna, a teraz nie jest. | ||
Linia 431: | Linia 431: | ||
<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"> | ||
Spójrzmy na | Spójrzmy na regułę dla wywołania procedury: | ||
<math> | <math> | ||
Linia 441: | Linia 441: | ||
</math> | </math> | ||
O | O statyczności decyduje to, że wnętrze procedury <math>I</math> | ||
wykonywane jest w | wykonywane jest w środowisku zmiejsca deklaracji <math>E'</math>. | ||
Wystarczy | Wystarczy więc, jeśli zignorujemy to środowisko, a zamiast | ||
niego | niego użyjemy bieżącego środowiska <math>E</math> (czyli środowiska | ||
z miejsca | z miejsca wywołania): | ||
<math> | <math> | ||
Linia 455: | Linia 455: | ||
</math> | </math> | ||
Oczywiście w takim przypadku w środowiskach | |||
wystarczy | wystarczy przechowywać dla procedur pary <math>\langle x, I \rangle</math>. | ||
Zastanówmy | Zastanówmy się teraz, jak uwzględnić rekurencję? Oczywiście | ||
moglibyśmy postąpić tak jak poprzednio, np. | |||
<math> | <math> | ||
Linia 469: | Linia 469: | ||
</math> | </math> | ||
ale | ale jeśli uważnie przyjrzymy się tej regule, to okazuje się, | ||
że ,,przelewamy z pustego w próżne". Sciślej, | |||
dodajemy do <math>E</math> | dodajemy do <math>E</math> parę <math>x_1 \mapsto \langle x, I \rangle</math>, | ||
która | która już tam tak naprawdę jest! | ||
Okazuje | Okazuje się, że dzięki dynamicznemu wiązaniu identyfikatorów ,,za | ||
darmo" otrzymujemy rekurencje! Tak jest na | darmo" otrzymujemy rekurencje! Tak jest na przykład w programie: | ||
Linia 485: | Linia 485: | ||
ponieważ w momencie wywołania rekurencyjnego <math>\mathbf{call}\, p(x)</math>, | |||
w | w środowisku jest już informacja nt. procedury <math>p</math>! | ||
</div></div> | </div></div> | ||
Linia 492: | Linia 492: | ||
{{cwiczenie|3 ( | {{cwiczenie|3 (różne mechanizmy przekazywana parametru)|cw3| | ||
Rozważ inne mechanizmy przekazywania parametru (wiązanie statyczne): | |||
* przez | * przez wartość | ||
<!-- | <!-- | ||
* przez | * przez nazwę leniwie (jak przez wartość, ale leniwa strategia ewaluacji parametru aktualnego) | ||
* przez | * przez nazwę dynamicznie (dynamiczne wiązanie identyfikatorów podczas obliczania wartości parametru aktualnego) | ||
--> | --> | ||
* in-out | * in-out | ||
Należy wyjaśnić ostatni mechanizm (in-out). | |||
Parametrem aktualnym jest zmienna, której | Parametrem aktualnym jest zmienna, której wartość jest | ||
przypisywana parametrowi formalnemu (tak jak przy przekazywaniu | przypisywana parametrowi formalnemu (tak jak przy przekazywaniu | ||
przez | przez wartość, gdy parametrem aktualnym jest zmienna). | ||
Ale po | Ale po zakończeniu procedury, wartość parametru formalnego, | ||
która | która mogła zmienić się w czasie dzialania procedury, jest | ||
spowrotem przypisywana na | spowrotem przypisywana na zmienną będącą parametrem aktualnym | ||
(a | (a więc podobnie do przekazywania przez zmienną). | ||
Parametr formalny jest traktowany jak zmienna lokalna procedury. | Parametr formalny jest traktowany jak zmienna lokalna procedury. | ||
}} | }} | ||
{{rozwiazanie|(przekazywanie parametru przez | {{rozwiazanie|(przekazywanie parametru przez wartość)|roz1| | ||
<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"> | ||
Omówimy tylko | Omówimy tylko instrukcję wywołania procedury, której składnia jest | ||
teraz szersza | teraz szersza niż poprzednio: | ||
<math> | <math> | ||
Linia 528: | Linia 528: | ||
</math> | </math> | ||
Przed | Przed wywołaniem procedury należy zaalokować nową lokację, | ||
którą przypiszemy parametrowi formalnemu; następnie obliczamy | |||
wartość parametru aktualnego i umieszczamy ją w tej lokacji: | |||
<math> | <math> | ||
Linia 549: | Linia 549: | ||
<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"> | ||
Początkowo postępujemy tak jak w przypadku przekazywania przez | |||
wartość: alokujemy nową lokację <math>l</math>, którą przypiszemy | |||
parametrowi formalnemu, i umieszczamy w niej | parametrowi formalnemu, i umieszczamy w niej wartość zmiennej | ||
(<math>x_2</math> w regule | (<math>x_2</math> w regule poniżej) będącej parametrem aktualnym. | ||
Zasadnicza | Zasadnicza różnica widoczna jest po zakończeniu procedury: wartość z lokacji | ||
<math>l</math> powinna | <math>l</math> powinna zostać spowrotem przypisana zmiennej <math>x_2</math>. | ||
Oto | Oto reguła: | ||
<math> | <math> | ||
Linia 562: | Linia 562: | ||
\quad \mbox{ o ile } | \quad \mbox{ o ile } | ||
E(x_2) = l_2 \in \mathbf{Loc} \mbox{ i } | E(x_2) = l_2 \in \mathbf{Loc} \mbox{ i } | ||
s(l_2) \mbox{ jest | s(l_2) \mbox{ jest określone i } | ||
E(x_1) = \langle x, I, E' \rangle \in \mathbf{Proc} \mbox{ i } | E(x_1) = \langle x, I, E' \rangle \in \mathbf{Proc} \mbox{ i } | ||
l = \mathtt{newloc}(s) | l = \mathtt{newloc}(s) | ||
Linia 576: | Linia 576: | ||
{{cwiczenie|1|cw1.dom| | {{cwiczenie|1|cw1.dom| | ||
Zaadaptuj | Zaadaptuj semantykę ,,deklaracji równoległych" | ||
dla rekurencji wzajemnej | dla rekurencji wzajemnej wewnątrz jednej deklaracji równoległej. | ||
To znaczy, | To znaczy, że procedury zadeklarowane w jednej deklaracji równoległej | ||
mogą się wzajemniej wywoływać bez żadnych ograniczeń. | |||
}} | }} | ||
Linia 585: | Linia 585: | ||
{{cwiczenie|2|cw2.dom| | {{cwiczenie|2|cw2.dom| | ||
Zamiast procedur, | Zamiast procedur, rozważ funkcje z pojedynczym parametrem | ||
przekazywanym przez | przekazywanym przez zmienną. | ||
Wywołanie funkcji może teraz pojawić się wewnątrz wyrażenia: | |||
<math> | <math> | ||
Linia 606: | Linia 606: | ||
{{cwiczenie|3|cw3.dom| | {{cwiczenie|3|cw3.dom| | ||
Rozważ następujące warianty: | |||
* | * wiązanie zmiennych jest statyczne a procedur dynamiczne | ||
* | * wiązanie zmiennych jest dymamiczne a procedur statyczne. | ||
}} | }} | ||
Linia 615: | Linia 615: | ||
{{cwiczenie|4|cw4.dom| | {{cwiczenie|4|cw4.dom| | ||
Rozszerz | Rozszerz semantykę procedur tak, aby parametrem aktualnym procedury | ||
mogła być procedura. | |||
}} | }} |
Wersja z 08:11, 10 sie 2006
Zawartość
Ostatnie zajęcia poświęcone semantyce naturalnej. Rozszerzymy język Tiny o deklaracje zmiennych i procedur z jednym parametrem. Rozważymy statyczną i dynamiczną widoczność (wiązanie) identyfikatorów oraz różne mechanizmy przekazywania parametrów. Pracujemy ze środowiskami i stanami.
Semantyka naturalna procedur
Ćwiczenie 1 (procedury)
Rozszerzmy język Tiny o deklaracje i wywołania procedur:
Konstrukcja deklaruje procedurę o nazwie , której parametrem formalnym jest . Zakładamy statyczne wiązanie identyfikatorów i przekazywanie parametrów przez zmienną (to znaczy, że w momencie wywołania procedury, powinna zostać przekazana lokacja odpowiadająca parametrowi aktualnemu). Instrukcja wywołuje procedurę z parametrem aktualnym .
Rozwiązanie
Ćwiczenie 2 (wiązanie dynamiczne)
Zastanówmy się, jakich modyfikacji wymaga nasza semantyka, aby wiązanie identyfikatorów było dynamiczne, zamiast statycznego. Rozumiemy przez to, że w przypadku odwołania do zmiennej wewnątrz procedury, odwołujemy się do środowiska w miejscu wywołania tej procedury, zamiast do środowiska z miejsca deklaracji jak dotychczas. Tak samo powinno być w przypadku wywołania innej procedury wewnątrz procedury, czyli wiązanie dynamiczne dotyczy i zmiennych i procedur.
Przykład
Spójrzmy na kilka prostych programów.
x = 1; p(y); y := y+x; x = 10; z = 0; p(z);
Wartość końcowa zmiennej .
Gdyby wiązanie zmiennej było statyczne, to wartość ta
wynosiłaby . Podobnie dla procedur:
q(x); x := x+1; p(y); q(y); q(y); q(x); x := x+x; z = 2; p(z);
Wartość końcowa zmiennej .
Gdyby widoczność procedury była statyczna, to wartość ta
wynosiłaby .
A oto przykład programu, który nie wykonałby się poprawnie
przy wiązaniu statycznych, a wykonuje się poprawnie przy
dynamicznym:
q(x); r(x); p(y); r(x); x := x+x; q(x); z = 7; p(z);
Wartość końcowa zmiennej wynosi .
Procedura wywołuje procedurę ,
,,przekazując" jej również środowisko z miejsca wołania,
zawierające informację o procedurze . Ta ostatnia
przy widoczności statycznej byłaby lokalna, a teraz nie jest.
Rozwiązanie
Ćwiczenie 3 (różne mechanizmy przekazywana parametru)
Rozważ inne mechanizmy przekazywania parametru (wiązanie statyczne):
- przez wartość
- in-out
Należy wyjaśnić ostatni mechanizm (in-out). Parametrem aktualnym jest zmienna, której wartość jest przypisywana parametrowi formalnemu (tak jak przy przekazywaniu przez wartość, gdy parametrem aktualnym jest zmienna). Ale po zakończeniu procedury, wartość parametru formalnego, która mogła zmienić się w czasie dzialania procedury, jest spowrotem przypisywana na zmienną będącą parametrem aktualnym (a więc podobnie do przekazywania przez zmienną). Parametr formalny jest traktowany jak zmienna lokalna procedury.
Rozwiązanie (przekazywanie parametru przez wartość)
Rozwiązanie (przekazywanie parametru in-out)
Zadania domowe
Ćwiczenie 1
Zaadaptuj semantykę ,,deklaracji równoległych" dla rekurencji wzajemnej wewnątrz jednej deklaracji równoległej. To znaczy, że procedury zadeklarowane w jednej deklaracji równoległej mogą się wzajemniej wywoływać bez żadnych ograniczeń.
Ćwiczenie 2
Zamiast procedur, rozważ funkcje z pojedynczym parametrem przekazywanym przez zmienną. Wywołanie funkcji może teraz pojawić się wewnątrz wyrażenia:
Wewnatrz funkcji jej nazwa mozna poslugiwac sie jak zmienna lokalna. Wynik zwracany przez funkcje to wartosc tej zmiennej w momencie wyjscia z funkcji.
Uwaga na efekty uboczne!
Ćwiczenie 3
Rozważ następujące warianty:
- wiązanie zmiennych jest statyczne a procedur dynamiczne
- wiązanie zmiennych jest dymamiczne a procedur statyczne.
Ćwiczenie 4
Rozszerz semantykę procedur tak, aby parametrem aktualnym procedury mogła być procedura.