Wykład pierwszy: Składnia języka occam cz.1

Transkrypt

Wykład pierwszy: Składnia języka occam cz.1
Occam
Wykład pierwszy
Motto:
„Nie należy mnożyć bytów ponad miarę”
William of Occam
1
Historia języka
Język occam powstał w roku 1983. Jego autorem był David May, pracownik firmy Inmos. Jest to język programowania współbieżnego, pierwotnie przeznaczony dla
transputerów. Model współbieżności operaty jest na języku formalnym CSP (ang. Communicating Sequential Processes) opracowanym przez C.A.R Hoare'a. Zakłada on
wymianę informacji między procesami wyłącznie za pomocą przekazywania komunikatów (ang. message passing). Obecnie rozwojem tego języka zajmuje się
Uniwersytet w Kent. Najnowsza z wersji occama opracowana w tym ośrodku zawiera rozszerzenia zainspirowane tak zwanym rachunkiem pi. W chwili obecnej occam
dostępny jest również na inne platformy niż tansputery.
2
Główne cech języka
Occam jest językiem służącym do programowania aplikacji współbieżnych (CSP). Charakteryzuje się prostą składnią i łatwością oprogramowywania komunikacji
międzyprocesowej, szczególnie nadaje się do celów edukacyjnych związanych z nauczaniem programowania współbieżnego.
3
Podstawowe pojęcia i elementy języka
Occam jest językiem rozpoznającym wielkość liter (ang. case sensitive).
1
Proces jest podstawowym pojęciem dotyczącym składni occama. Proces możemy traktować jak „czarną skrzynkę” wykonującą pewne operacje
i komunikującą się z pozostałymi procesami poprzez kanały. Procesami prostymi są instrukcje przypisania, instrukcje wysyłania i odbioru przez kanał
oraz procesy SKIP i STOP. Occam umożliwia tworzenie grup procesów, które mogą wykonywać się sekwencyjnie lub współbieżnie (równolegle).
Instrukcja przypisania zapisywana jest przy pomocy tego samego symbolu co w języku Pascal (:=). Po jej prawej stronie występuje zmienna określonego
typu, po jej lewej stronie może występować wartość (literał) lub wyrażenie. Kolejność działań musi być określona przy pomocy nawiasów okrągłych np.: z:=
(4*x)+2
Kanał jest specjalnym rodzajem zmiennej, która stanowi połączenie typu punkt – punkt między dwoma procesami współbieżnymi. Procesy te mogą być
wykonywane zarówno w obrębie jednego procesora, jak i w obrębie dwóch różnych procesorów. Komunikacja przez kanały jest niebuforowana i zachodzi
tylko wtedy, kiedy obydwa procesy są gotowe. Instrukcja odbioru jest oznaczana symbolem pytajnika (?), natomiast operacja nadawania przez kanał jest
oznaczana symbolem wykrzyknika (!). Przykład: kan?x kan!x
Proces SKIP jest prostym procesem, który rozpoczyna się, nie wykonuje żadnej operacji i kończy się (odpowiednik rozkazu NOP w procesorach Intela),
proces STOP rozpoczyna się, nic nie wykonuje i nigdy się nie kończy.
Konstruktory SEQ i PAR służą odpowiednio do tworzenia zbioru procesów, które będą się wykonywać sekwencyjnie i zbioru procesów, które będą się
wykonywać współbieżnie (równolegle). Zapis:
SEQ
x:=5
y:=x*4
2
oznacza, że obie instrukcje (procesy) wykonają się „jedna po drugiej”. Do określania bloku instrukcji w occamie służy wcięcie na dwie spacje . Instrukcje nie
są zakończone średnikiem ani innym znakiem oprócz znaku końca wiersza. Zapis:
PAR
x:=2
y:=5
oznacza, że obie instrukcje (procesy) zostaną wykonane „jednocześnie”. Proces PAR zostanie zakończony w momencie zakończenia działania ich obu.
Procesy zamknięte w bloku PAR nie mają wspólnych zmiennych i nie mogą się przez nie komunikować. Komunikacja musi odbywać się przez kanały. Do
komunikacji dwukierunkowej należy użyć dwóch kanałów. Należy uważać, aby nie napisać kodu, który powodowałby zakleszczenie, np.:
PAR
SEQ
kan1?x
kan2!y
SEQ
kan2?y
kan1!5
1
2
Komentarze w occamie rozpoczynają się ciągiem dwóch minusów (--) i kończą wraz z końcem linii, w której się znajdują.
Pojęcie procesu w occamie jest trochę inne od tego, które znamy z systemów operacyjnych. W przypadku occama o procesie możemy myśleć jako o działaniu (akcji), które
musi zostać wykonane.
Nie jest to cecha tylko occama. Taka metoda oznaczania bloków instrukcji jest stosowana również w takich językach jak Haskell i Python. Wymusza to na programiście
automatyczne formatowanie kodu.
1
Occam
Zmienne i kanały muszą być zadeklarowane. W occamie istnieją następujące typy proste: BOOL (typ boolowski), BYTE (typ bajtowy), INT16, INT32,
INT64 (typy całkowite, odpowiednio szesnasto-, trzydziestodwu- i sześćdziesięcioczterobitowe), REAL32 i REAL64 (typy zmiennoprzecinkowe odpowiednio
trzydziestodwu- i sześćdziesięcioczterobitowe). Możemy również użyć typu INT, który w zależności od rodzaju transputera będzie oznaczał typ całkowity
szesnasto- lub trzydziestodwubitowy. Przykład deklaracji zmiennej:
INT16 x:
Kanały deklarowane są w trochę odmienny sposób, np.:
CHAN OF REAL64 k1:
Occam pozwala również na deklarowanie tablic:
[10] BYTE wektor:
[10][10] BYTE macierz:
Odwołanie do pojedynczego elementu tablicy wykonywane jest następująco: wektor[5]. Elementy tablic są indeksowane od 0, a liczba w nawiasach
kwadratowych w definicji tablicy określa liczbę jej elementów. Zmienne widoczne są w obszarze bloku, w którym zostały zadeklarowane.
Pętle w occamie tworzymy przy pomocy słowa kluczowego WHILE, np.:
INT16 x:
SEQ
x:=0
WHILE x>=0
SEQ
in?x
out!x
Procesy warunkowe są tworzone w occamie przy pomocy instrukcji IF. Należy pamiętać, aby uwzględnić w niej wszystkie możliwe warunki, inaczej ta
instrukcja zamieni się w proces STOP. Niepoprawnym jest więc zapis:
IF
x>y
k!1
Aby go poprawić trzeba napisać:
IF
x>y
k1!5
TRUE
SKIP
Instrukcje IF mogą być zagnieżdżone.
W occamie istnieje również instrukcja wielokrotnego wyboru CASE, np.:
CASE direction
up
x:=x+1
down
x:=x-1
Podobną w zapisie do instrukcji CASE, ale odmienną w działaniu jest instrukcja ALT. Dotyczy ona kanałów i umożliwia dokonanie wyboru w zależności od
stanu kanału, np.:
CHAN OF INT16 k1,k2,k3:
INT x:
ALT
k1?x
k3!x
k2?x
k3!x
Jeśli gotów jest kanał „k1”, to z niego zostanie odebrana wartość i przesłana kanałem „k3”, jeśli pierwszy będzie jednak gotów kanał „k2”, to informacja
odebrana z niego zostanie wysłana przez „k3”. Jeśli oba kanały są równocześnie gotowe, to wybierany jest jeden z nich. Aby ustalić priorytety kanałów
można użyć instrukcji PRI, która działa również z konstruktorem PAR.
Istnieje możliwość konstruowania tzw. instrukcji powtarzalnych PAR, SEQ, ALT i IF, np.:
[5] CHAN OF INT32 kan:
[5] INT32 x:
2
Occam
PAR i=0 FOR 5
kan[i]!x[i]
Liczba występująca po słowie kluczowym FOR oznacza liczbę powtórzeń instrukcji.
Literały (wartości stałe) mogą być zapisywane zarówno jako wartości dziesiętne jak i szesnastkowe. W przypadku tych ostatnich przed wartością
umieszcza się znak „#”. Liczby zmiennoprzecinkowe mogą być zapisywane w „zwykłej” notacji z kropką lub w notacji wykładniczej. W obu przypadkach
należy za literałem, w nawiasach okrągłych umieścić nazwę typu. W przypadku liczb całkowitych domyślnie przyjmowany jest INT. Znaki są zapisywane
w apostrofach, w zmiennych typu BYTE. Jeśli trzeba zapisać znak specjalny stawia się gwiazdkę przed nim np.: '*c' oznacza powrót karetki. Łańcuchy są
zapisywane w tablicach bajtów i ujmowane są w cudzysłów. Zmienne boolowskie przyjmują tylko dwie wartości: TRUE i FALSE.
Pole jest skończonym ciągiem elementów jednakowego typu. Polem jest również tablica. Można wyznaczyć również wycinek pola, np.: [tablica FROM 3 TO
5] lub bezpośrednio wymienić wartości należące do pola, np.: [1, 2, 3].
W occamie istnieją następujące operatory: „-” zmiana wartości liczby całkowitej na przeciwną, „~” - negacja bitowa liczby całkowitej, NOT – negacja
logiczna, SIZE – odczyt wielkości pola (liczby jego elementów), MOSTPOS i MOSTNEG – największa i najmniejsza wartość liczby całkowitej, za operandem
powinna znaleźć się nazwa typu całkowitego, „\” i REM - reszta z dzielenia, „+”, „-”, „*”, „/” - operacje arytmetyczne z testowaniem przepełnienia, PLUS,
n
MINUS, TIMES – opracje arytmetyczne modulo 2 , gdzie „n” jest liczbą bitów operandu całkowitego, „/\”, „\/”, „><”, odpowiednio AND, OR i XOR bitowy
dla liczb całkowitych, „<<”, „>>”, przesunięcie bitowe w lewo i prawo, AND i OR logiczne (oba operandy typu BOOL), „=”, „<>”, „<”, „>”, „<=”, „>=” operatory relacyjne, AFTER – operator „później” dla wskaźników czasu.
Konwersja typu REAL32 na REAL64 zachodzi automatycznie, w drugą stronę za wartością, którą chcemy skonwertować należy umieścić nazwę typu
w nawiasach okrągłych. Do konwersji liczby zmiennoprzecinkowej na całkowitą służą instrukcje ROUND – zaokrąglenia i TRUNC – odcięcia części
ułamkowej.
W occamie istnieje specjalny typ TIMER. Zmienne tego typu są nazwane wskaźnikami czasu i można je traktować jako kanały do zegarów
poszczególnych procesów. Impuls zegara dla procesów niskopriorytetowych wynosi 64 µs, a dla procesów wysokopriorytetowych 1µs. Wartości odczytane ze
wskaźnika czasu są traktowane jako INT. Z wskaźnikami czasu można stosować operator AFTER, konstruując odpowiednie instrukcje opóźniające.
Za pomocą protokołów określa się typ i strukturę przesyłanych danych. Dane te mogą być prostych typów jak np.: BYTE lub mogą być złożone, np.:
CHAN OF [10] BYTE. W szczególnych przypadkach typ kanału może być nieokreślony, wówczas stosujemy słowo kluczowe ANY. Jeśli kanał jest
wykorzystywany do przesyłania pól różnej długości, ale tego samego typu, to stosuje się tablice zliczające, np.:
CHAN OF INT::[BYTE] dane:
wówczas wysłanie przez taki kanał ma postać dane!:12::”Ala ma kota.”
Protokołów można definiować, np. w ten sposób:
PROTOCOL complex IS REAL32; REAL32:
Occam pozwala również na definiowanie protokołów z wariantami, np.:
PROTOCOL zbiory
CASE
start;BYTE
nazwa;[20] BYTE
rekord;INT32;int16;::[]BYTE
stop
:
3

Podobne dokumenty