CSL-CROOK - Struktura programu
Działania oraz bieg czasu
Część programu reprezentująca dynamiczne działanie modelu składa się z listy działań. Każde działanie jest odcinkiem programu, który dokonuje szeregu zmian w modelu, o ile spełnione są określone warunki początkowe. Działanie jest zatem zazwyczaj poprzedzone jedną lub kilkoma instrukcjami testów, które decydują czy dane działanie może zostać wykonane. Jeżeli testy te nie dadzą wyniku pozytywnego, wówczas dokonywany jest skok do następnego działania. Skok ten jest zazwyczaj wykonywany automatycznie przy pomocy pustej części adresowej. Jedna realizacja programu modelującego składa się najczęściej ze znacznej liczby "przejść" przez listę działań. Przy każdym "przejściu" każde działanie wykonywane jest tylko przy spełnieniu warunków początkowych. Większość układów analizowanych na drodze modelowania, to układy uwarunkowane czasowo. W języki CSL przewidziano zatem mechanizm dla reprezentowania upływu czasu. Mimo ,że zmiany w układzie rzeczywistym mogą zachodzić w sposób ciągły, to w modelu opisanym przy pomocy języka CSL, przyjmie się, że zmiany zachodzą natychmiastowo w dyskretnych momentach czasu. W odcinkach czasu między tymi momentami, żadne zmiany nie występują. Tak więc upływ czasu następuje dyskretnymi odcinkami i jest realizowany następująco. Początkowo oraz w interwałach podczas wykonywania programu, jeden lub więcej atrybutów czasowych zdefiniowanych w modelu ma przypisane pewne wartości. Każda z tych wartości reprezentuje czas, jaki musi upłynąć przed zmianą stanu obiektu lub przed rozpoczęciem jakiegoś procesu. Program realizujący bieg czasu sprawdza wszystkie atrybuty czasowe i wybiera z nich najmniejszą wartość dodatnią, ignorując zero i wartości ujemne. Znaleziona w ten sposób wartość reprezentuje czas, jaki powinien upłynąć przed pojawieniem się jakiejkolwiek zmiany w modelu. Tak więc "czas modelowy" musi zostać zwiększony o tę wartość. Czas modelowy reprezentuje zmienna o nazwie CLOCK (zegar), która nie musi być definiowana w programie, lecz w razie potrzeby może być w programie użyta. Zmienna CLOCK ma początkowo wartość równą zero, a następnie przy każdym przyroście czasu jest zwiększana o znalezioną wartość, która jest równocześnie odejmowana od wartości wszystkich dodatnich atrybutów czasowych, tak że wartość wybranego atrybutu czasowego staje się w tym momencie równa zeru. Opisany "bieg czasu" jest realizowany przy końcu każdego przejścia przez listę działań, aż do momentu, w którym przy wykonaniu działania pojawia się instrukcja EXIT lub RECYCLE lub wartość wszystkich atrybutów czasowych są niedodatnie. W tym ostatnim przypadku następuje zakończenie obliczeń, sygnalizowane komunikatem na końcówce użytkownika:
EXIT - CLOCK
Działanie instrukcji EXIT i RECYCLE opisano w dalszej części niniejszego rozdziału.
ACTIVITIES - działanie
Instrukcja:
- ACTIVITIES
określa początek odcinka programu zawierającego działania. Instrukcja ta sygnalizuje translatorowi, że należy włączyć do generowanego programu instrukcje biegu czasu i powtarzania. Pozostała część programu, aż do końcowej instrukcji END, jest traktowana jako lista działań, i jest wykonywana wielokrotnie.
BEGIN - początek
Rozpoczęcie każdego działania jest określone instrukcją:
- BEGIN <identyfikator>
Głównym zadaniem tej instrukcji jest określenie adresu dla każdej pustej części adresowej w poprzednim działaniu. Po słowie BEGIN może następować identyfikator zawierający do 18 znaków (łącznie ze spacjami). Identyfikator ten może być wyprowadzany jako informacja diagnostyczna przy każdym wykonaniu danej czynności. W pierwszym działaniu instrukcja BEGIN może być pominięta.
RECYCLE
Może się zdarzyć,że jedno działanie dokonuje takich zmian w modelu, które umożliwiają wykonanie poprzednich działań. Jeśli sytuacja taka jest możliwa, to do działania można włączyć instrukcję:
- RECYCLE <identyfikator>
Jeśli podczas realizacji działań napotkana zostanie jedna lub więcej instrukcji RECYCLE, wówczas przed następnym przyrostem czasu zostaje ponownie przetworzona cała lista działań. Instrukcja RECYCLE może występować w programie dowolną ilość razy. Powtarzanie listy działań kontynuuje się do momentu, gdy podczas powtórzenia nie spotka się żadnej instrukcji RECYCLE. Uważa się wówczas,że nie może już wykonać dalszych zmian, po czym wprowadza się kolejny przyrost czasu. Po instrukcji RECYCLE może występować do 18 znaków (łącznie ze spacjami), które mogą być wyprowadzone jako informacja diagnostyczna przy każdym napotkaniu tej instrukcji.
EXIT - wyjście
Instrukcja:
- EXIT
jest używana do zakończenia wykonywania programu. Jeśli zostanie napotkana instrukcja EXIT na monitorze użytkownika pojawia się komunikat:
EXIT - OK
POSTMORTEM
W odcinku programu następującym po instrukcji ACTIVITIES może występować dowolna ilość fragmentów post-mortem. Zadaniem tych działań jest zawarcie instrukcji, które powinny być wykonane w przypadku przekłamań lub innych nieprzewidzianych zdarzeń w czasie wykonywania programu lub na zakończenie jego wykonywania, ale ignorowanych w innych przypadkach. Działanie post-mortem jest deklarowane instrukcją:
- POSTMORTEM <identyfikator>
i ulega zakończeniu przy pomocy instrukcji:
- PMEND
Instrukcja POSTMORTEM musi być opatrzona etykietą. Działanie POSTMORTEM nie jest, jak inne działania, uruchamiane automatycznie. Istnieją dwa sposoby uruchamiania tego działania:
- może być dokonany skok do instrukcji POSTMORTEM, jednak pod warunkiem, że instrukcja skoku określa wyraźnie etykietę instrukcji POSTMORTEM. Pusta część adresowa w działaniu poprzedzającym nie spowoduje skoku do instrukcji POSTMORTEM;
- etykieta instrukcji POSTMORTEM może być określona jako miejsce wejścia do programu.
Jeżeli zostanie napotkana instrukcja PMEND, wówczas program zatrzyma się a na monitorze pojawi się komunikat:
HALTED: - PM
Segmentacja programów
Program w języku CSL może być pisany i kompilowany segmentami w taki sposób jak program w FORTRANIE. Rozróżniamy cztery rodzaje segmentów:
- segment MASTER
- segment SUBROUTINE
- segment FUNCTION
- segment BLOCK DATA
Segmenty mogą być zapisywane w języku FORTRAN lub języku CSL. Jedynie segment BLOCK DATA może być pisany wyłącznie w języku FORTRAN. Dokładny opis tego segmentu użytkownik znajdzie w opisie języka FORTRAN.
Segment MASTER
Każdy program w języku CSL musi zawierać jeden i tylko jeden segment MASTER. Segment ten rozpoczyna się instrukcją:
- MASTER <nazwa>
gdzie nazwa może być dowolnym ciągiem znaków. Podobnie jak wszystkie inne segmenty segment MASTER musi kończyć się instrukcją:
- END
Segment MASTER jest segmentem sterującym programu, ale może on być też jedynym segmentem w programie. Realizacja programu zaczyna się od pierwszej wykonalnej instrukcji w segmencie MASTER. Może być następnie wykonany skok do innych segmentów za pomocą instrukcji CALL (wołanie) lub wywołań segmentów FUNCTION. W wyniku działania segmentu SUBROUTINE i FUNCTION może być dokonany skok z powrotem do segmentu MASTER może być dokonany skok do innych segmentów, ale nie może być dokonany skok z powrotem do segmentu MASTER w sposób inny niż przy użyciu instrukcji RETURN.
Segment SUBROUTINE
Segment SUBROUTINE musi mieć postać kompletnego niezależnego programu w tym sensie, że wszystkie występujące w nim zmienne typu REAL, klasy, zbiory, tablice, rozkłady lub histogramy muszą być określone w ramach segmentu poprzez odpowiednie instrukcje definiujące. Wartości związane z każdą z tych pozycji mogą być przesyłane do segmentu z innych segmentów poprzez umieszczenie tych pozycji we wspólnym określonym instrukcją COMMON bloku pamięciowym lub poprzez specyfikację ich jako argumentów instrukcji SUBROUTINE. Segment SUBROUTINE może zawierać dowolne instrukcje z wyjątkiem MASTER, SUBROUTINE, FUNCTION i BLOCK DATA. Segment SUBROUTINE musi kończyć się instrukcją:
- END
Pierwszą instrukcją segmentu SUBROUTINE musi być instrukcja SUBROUTINE (podprogram) następującej postaci:
- SUBROUTINE $<nazwa> (<parametry>)
gdzie nazwa jest dowolną nazwą segmentu i musi być poprzedzona znakiem "$". Po każdym ciągu znaków numerycznych (napisie) występującym w nazwie musi także następować znak "$". Parametry są argumentami formalnymi; podczas wykonywania segmentu programu każdy z tych argumentów jest zastępowany przez odpowiednie argumenty aktualne określane w instrukcji CALL.
Skok do segmentu SUBROUTINE jest dokonywany za pomocą instrukcji CALL wołanie o postaci:
- CALL $<nazwa> (<parametry>)
gdzie nazwa jest nazwą wołanego segmentu SUBROUTINE, natomiast parametry są argumentami aktualnymi, które mają zastąpić odpowiadające im argumenty formalne w obrębie segmentu SUBROUTINE. Argumenty aktualne muszą odpowiadać pod względem ilości, porządku oraz typu argumentom formalnym, które mają zastąpić.
Przykłady:
SUBROUTINE $PODPRO $(A, B, X, Y) CALL $PODPRO (ZMIENNA, MAT1, XXX, Y)
Instrukcja:
- RETURN
występuje normalnie co najmniej jeden raz w każdym segmencie SUBROUTINE. W wyniku działania tej instrukcji dokonywany jest skok do instrukcji następującej bezpośrednio po instrukcji CALL w segmencie wywołującym.
Przykład:
SUBROUTINE WYDRUK (ZBIORA) CLASS X.20 SET ZBIORA FOR I=ZBIORA WRITE(3,10)I 10 FORMAT(1X, I4) RETURN END
Podprogram ten powoduje wydrukowanie indeksów obiektów elementów wyspecyfikowanego zbioru. Klasa X została wymyślona jedynie dla nadania wymiaru zbiorowi formalnemu ZBIORA; argumentem aktualnym dla programu może być każdy zbiór. Podprogram ten może być wywoływany przykładowo instrukcją:
- CALL $WYDRUK (WOLLA)
i zostanie następnie wykonany z operowaniem na elementach zbioru WOLLA.
Segment FUNCTION
Segment FUNCTION jest podobny do segmentu SUBROUTINE z wyjątkiem tego, że daje on tylko pojedynczy wynik liczbowy. Następuje skok do segmentu FUNCTION zawsze wtedy, gdy pojawia się nazwa funkcji; funkcja jest wówczas obliczana, a otrzymany wynik liczbowy zostaje podstawiony w miejsce nazwy funkcji w punkcie jej występowania w segmencie wywołującym. Nazwa funkcji może też występować w wyrażeniach wszędzie tam, gdzie dopuszczalne jest występowanie nazwy zmiennej.
Tak więc, jeśli w programie wystąpi instrukcja następująca:
A-X+$FUNKCJA (X, Y)
wówczas dokonywany jest skok do segmentu FUNCTION o nazwie $FUNKCJA. Segment $FUNKCJA dokonuje odpowiednich operacji na bieżących wartościach X i Y w celu otrzymania wyniku liczbowego; tak uzyskana wartość zostanie następnie podstawiona na miejsce $funkcja w powyższym wyrażeniu. Dopiero po tym zostanie w normalny sposób obliczona wartość całego wyrażenia. Segment funkcyjny musi rozpoczynać się instrukcją:
- FUNCTION $<NAZWA> (<PARAMETRY>)
gdzie nazwa jest dowolną nazwą funkcji używanej w wyrażeniu. Bezpośrednio po każdym ciągu znaków cyfrowych występujących w nazwie musi być umieszczony następny znak "$". Typ funkcji, tzn. fakt czy wynik będzie typu REAL czy też typu INTEGER jest oznaczony pierwszą literą nazwy. Jeśli wynik ma być typu INTEGER, wówczas pierwszą literą nazwy musi być I, J, K, L, M lub N; każda inna litera początkowa oznacza wynik typu REAL. Parametry są argumentami formalnymi, które po obliczeniu funkcji są zastępowane argumentami aktualnymi. W instrukcji musi występować co najmniej jeden argument. Wartość otrzymana z segmentu FUNCTION jest podstawiana w segmencie wywołującym w miejsce, gdzie występuje wywołanie zdefiniowanej funkcji. Dla zrealizowania tego podstawienia nazwa funkcji jest traktowana jako nazwa zmiennej w segmencie FUNCTION i musi mieć przyporządkowaną wartość w instrukcji podstawienia.
Przykład:
FUNCTION $FUNKCJA (X, Y) ....... ....... $FUNKCJA=3*Y+4*X-(X+Y) RETURN END
Słowo RETURN musi wystąpić w celu dokonania skoku z powrotem do segmentu wywołującego, natomiast słowo END musi być ostatnią instrukcją w segmencie.
Wspólny obszar pamięci
Instrukcja ma następującą postać:
- COMMON /nblock/lista [/nblock/lista/]...
gdzie nblock jest nazwą bloku COMMON, natomiast lista jest listą zmiennych. Instrukcja COMMON pozwala programiście w taki sposób przydzielać pewne obszary w pamięci, aby były one dostępne dla więcej niż jednego segmentu, tak że wartości otrzymane w jednym mogą być użyte w innym. Nazwa bloku musi składać się ze znaków literowych w liczbie do 12. Każda lista zmiennych może zawierać tablice, klasy, zbiory oraz tablice-T pod warunkiem, że są one zdefiniowane odpowiednimi instrukcjami deklarującymi przed instrukcją COMMON w tych segmentach, w których one występują. Każda nowa nazwa bloku występująca w instrukcji COMMON definiuje wspólny obszar pamięci zawierający odpowiednią listę zmiennych wyspecyfikowanych po tej nazwie bloku. Jeżeli ta sama nazwa bloku wystąpi w instrukcji COMMON innego segmentu, wówczas zmienne na nowej liście są przyporządkowane temu samemu obszarowi pamięci. Nowa lista może zawierać zmienne o różnych nazwach i różnych typach , jeśli to potrzebne; wykorzystywanie tego udogodnienia wymaga jednak szczególnej uwagi ze strony programisty. Dopuszcza się istnienie jednego bloku wspólnego o pustej nazwie zdefiniowanego w instrukcji COMMON przy pomocy dwóch pisanych obok siebie (bez spacji) kresek pochyłych. Jeżeli pustą ma być pierwsza nazwa bloku w instrukcji COMMON, wówczas symbole "/" mogą być opuszczone.
Przykład:
jeżeli instrukcja:
COMMON A, B, C/CSL/D, E, F
występuje w jednym segmencie programu a instrukcje:
ARRAY Z(3), Y(3) COMMON //Z/CSL/Y
występują w innym segmencie, wówczas Z(1) oraz A mogą być przydzielone do tego samego obszaru pamięci, Z(2) oraz B mogą mieć też wspólną lokację w pamięci.
Wartości początkowe
Instrukcja DATA jest instrukcją nie przeznaczoną do wykonywania, lecz używaną do deklarowania wartości początkowych poszczególnych zmiennych. Instrukcja ta ma następującą postać:
- DATA a1/d1/ [, a2/d2/....]
gdzie każde a jest listą zmiennych a każde d jest listą wartości, które mają być tym zmiennym przyporządkowane. Lista zmiennych może zawierać atrybuty i atrybut czasu. Ograniczenia dotyczące listy wartości są takie same jak w FORTRANIE-CROOK.
Przykład:
DATA A, B(1), T. C/2*1,99/ , STATEK.1(1)/20/ ARRAY E(5) DATA E/3*0,2*1/
Segment BLOCK DATA
Segment BLOCK DATA jest używany dla nadania wartości początkowych pozycjom w blokach COMMON za pośrednictwem instrukcji DATA. Segment BLOCK DATA musi zaczynać się instrukcją:
- BLOCK DATA
a kończyć instrukcją:
- END
Oprócz wyżej wymienionych w segmencie BLOCK DATA mogą występować tylko i wyłącznie następujące instrukcje:
- ARRAY, FLOAT, CLASS, COMMON, DATA
Należy zwrócić uwagę, że segment BLOCK DATA jest jedynie środkiem dostarczania informacji dla translatora programu; nie jest on nigdy wywoływany i może nie zawierać żadnej instrukcji wykonawczej.
Przykład:
BLOCK DATA CLASS TIME STATEK.4(3) ARRAY WODA(4) FLOAT X COMMON /CSL1/STATEK, T. STATEK/CSL2/WODA, X DATA STATEK/12*1/, T. STATEK.2, T. STATEK.3/1,2/ DATA WODA/2*1, 2*2/, X/3.2/ END
Źródło: Translator języka CSL-CROOK dla minikomputera MERA-400 w systemie operacyjnym CROOK-4, Instrukcja Programisty (wersja-17/2), Janusz Gocałek, Jacek Klauziński, Poznań, 1985