Semantyka i weryfikacja programów/Ćwiczenia 6
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.
Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{begin}\} , Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{var}\} , x = 1; Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{proc}\} , p(y); y := y+x; Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{begin}\} , Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{var}\} , x = 10; Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{var}\} , z = 0; Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{call}\} , p(z);
Wartość końcowa zmiennej .
Gdyby wiązanie zmiennej było statyczne, to wartość ta wynosiłaby . Podobnie dla procedur:
Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{begin}\} , Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{proc}\} , q(x); x := x+1; Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{proc}\} , p(y); Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{call}\} , q(y); Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{call}\} , q(y); Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{begin}\} , Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{proc}\} , q(x); x := x+x; Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{var}\} , z = 2; Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{call}\} , 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:
Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{begin}\} , Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{proc}\} , q(x); Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{call}\} , r(x); Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{proc}\} , p(y); Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{begin}\} , Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{proc}\} , r(x); x := x+x; Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{call}\} , q(x); Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{var}\} , z = 7; Parser nie mógł rozpoznać (błąd składni): {\displaystyle \mathbf{call}\} , 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 z powrotem 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:
Wewnątrz funkcji jej nazwą można posługiwać się jak zmienną lokalną. Wynik zwracany przez funkcję to wartość tej zmiennej w momencie wyjścia 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 dynamiczne, a procedur statyczne.
Ćwiczenie 4
Rozszerz semantykę procedur tak, aby parametrem aktualnym procedury mogła być procedura.