Metody realizacji języków programowania/MRJP Laboratorium/Semantyka Kotka

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania

Semantyka języka

Poniżej omówione są najważniejsze cechy semantyki języka Kotek. Jeśli jakaś konstrukcja nie jest omówiona, to jej semantyka nie różni się od semantyki analogicznych konstrukcji w innych językach programowania.

Widoczność deklaracji

Wykonywana instrukcja ma dostęp do wszystkich deklaracji funkcji w której była zadeklarowana (lub do deklaracji głównego programu, jeśli instrukcja występuje bezpośrednio w programie), włącznie z deklaracjami parametrów funkcji, oraz do wszystkich deklaracji z wyższego poziomu. Zadeklarowanie zmiennej o nazwie takiej jak jakaś zmienna z wyższego poziomu przesłania zmienną z wyższego poziomu. Nie ma możliwości odwołania się do przysłoniętej zmiennej. Zabroniona jest deklaracja zmiennej o nazwie takiej jak któryś parametr funkcji w której (bezpośrednio) występuje deklaracja. Przyjrzyjmy się przykładowej deklaracji funkcji.

function f(var x: int) : void
   function a(var s : string) : string
   {                             // deklaracja parametru s przysłania deklarację
                                 // z funkcji f
      if x == 0 then
         return "x jest zerem";
      else
         return b();
      endif
   }
   function b() : string
       var x : string;
   {
      return s;            // zwróci zmienną lokalną funkcji f
   }
   var s : string;
{
   s = "napis";
   print a("inny napis");        
}

W funkcji a widoczna są:

  • funkcja b (mimo, że została zadeklarowana później),
  • zmienna x - parametr funkcji f,
  • zmienna s - parametr funkcji a.

W funkcji b widoczne są:

  • zmienna x - lokalna zmienna funkcji b, przysłaniająca parametr funkcji f (zauważ, że przysłaniająca zmienna może być dowolnego typu),
  • zmienna s - lokalna zmienna funkcji f,
  • funkcja a.

W funkcji f widoczne są:

  • funkcja a,
  • funkcja b,
  • zmienna s - zadeklarowana lokalnie w f,
  • zmienna x - parametr f.


Zasady widoczności w przypadku lokalnych deklaracji obiektów są pozostawione jako ćwiczenie.

Alokacja obiektów, rekordów i tablic

Obiekty, rekordy oraz tablice są tworzone dynamicznie na stercie, za pomocą operatora 'new, na przykład:

new int[100];

zwróci tablicę 100 liczb całkowitych,

new mojRekord;

zwróci nowy rekord typu mojRekord, a

new mojObiekt[10];

zwróci tablicę 10 obiektów klasy mojObiekt.

Wywołanie operatora new bez podania rozmiaru tablicy alokuje pojedynczy element. Takie wywołanie jest dozwolone tylko dla typów rekordowych i obiektowych. Tworzenie wielowymiarowych tablic jest możliwe przez zadeklarowanie typu tablicowego:

type tabl = arrayof int;

i alokacja tablicy tego typu:

tablicaTablic = new tabl[10];

i poszczególnych elementów tablicy:

tabl[0] = new int[10];
// ...

Zmienne o typie tablicowym, rekordowym lub obiektowym przechowują referencję do tablicy, rekordu lub obiektu (odpowiednio). Przekazywanie tablic do funkcji, zwracanie ich z funkcji oraz przypisywanie do zmiennej odbywa się przez referencję. Oznacza to, że zmiany elementów tablicy w funkcji do której tablica została przekazana będą zachowane również po powrocie z tej funkcji. Przypisanie tablicy do nowej zmiennej nie kopiuje jej, ale nowa zmienna wskazuje na tą samą tablicę. Dokładnie tak samo jest w przypadku rekordów i obiektów.

Zwalnianie elementów zaalokowanych operatorem new odbywa się przy pomocy operatora delete. Jedynym parametrem delete jest referencja do zaalokowanego elementu (czyli wartość zmiennej wskazującej na element). Nie należy podawać rozmiaru w przypadku tablic. Każde wywołanie delete usuwa dokładnie jeden element zaalokowany operatorem new.

Kontrola typów

Typy są sprawdzane w czasie kompilacji.

Równoważność typów jest przez nazwę.

Semantyka wyrażeń logicznych

Język Kotek nie przewiduje oddzielnego typu logicznego. Zamiast tego w wyrażeniach logicznych używane są zwykłe wyrażenia arytmetyczne. Jeśli wartość wyrażenia jest niezerowa, to jego logiczną wartością jest prawda (reprezentowana jako 1), a jeśli wyrażenie zostanie wyliczone do zera, to wartością logiczną jest fałsz (reprezentowany przez 0). Uwaga: jeśli wyrażenie logiczne jest w postaci czysto arytmetycznej (bez operatorów logicznych), to jego wartość nie może się zmienić, np. wartością wyrażenia 2+2 jest zawsze 4, niezależnie od tego, czy jest to wyrażenie logiczne, czy nie. Natomiast wartością logiczną 2 || 2 jest 1. Ściśle mówiąc, zmiana wartości wyrażenia na binarną (0 lub 1) odbywa się tylko gdy używane są operatory logiczne.

Wyrażenia logiczne wyliczane są w sposób leniwy, od lewej do prawej. To znaczy jeśli wartość wyrażenia jest zdeterminowana już po obliczeniu jego pierwszej części (np. 0 && 1 lub 1 || 1 - wynik jest znany już po wyliczeniu pierwszej wartości), to druga część nie jest wyliczana.

Odwołania do pól rekordów i obiektów (operator kropka)

Semantyka kropki jest identyczna jak w językach Java, czy C++. Kropka może być aplikowana tylko do typów obiektowych lub rekordowych.

Stringi

Ciągi napisowe są w języku dostępne tylko statycznie (nie ma na przykład operacji konkatenacji) i są niezmienialne.