CSL-CROOK - Operacje wejścia/wyjścia
W języku CSL dostępny jest cały system wejścia/wyjścia języka FORTRAN-CROOK. Podstawowe cechy tego systemu są opisane opisane w niniejszym rozdziale głównie na użytek czytelników nie znających dokładnie języka FORTRAN. Instrukcje wejścia/wyjścia (wprowadzania i wyprowadzania danych) służą do przesyłania danych pomiędzy pamięcią wewnętrzną maszyny a urządzeniami i pamięciami zewnętrznymi. Dane poza pamięcią przekazywane są w formie zbiorów. Zbiór podzielony jest na rekordy (tzn na pewną elementarną porcję danych, jaka może być jednorazowo przesłana pomiędzy zbiorem a pamięcią) W języku FORTRAN wyróżniamy następujące postacie rekordów:
- zredagowane czyli rekordy znakowe alfanumeryczne, formatowe. Stosowane są w przypadku wszystkich rodzajów urządzeń i pamięci zewnętrznych. Zawierają one dane w postaci ciągu znaków mających reprezentację maszynową lub ich kodów. Rekord zredagowany składa się z pól. Każde pole reprezentuje wartość zmiennej, elementu tablicy lub ciągu znaków tekstu. Udostępnienie takiego rekordu do obliczeń wymaga przekształcenia zapisanych w nim danych z postaci znakowej na dwójkową i odwrotnie. W przypadku przesyłania rekordów zredagowanych jest niezbędne podanie informacji o zewnętrznej postaci tych rekordów . Dokonuje się tego zazwyczaj za pomocą specyfikacji formatu;
- niezredagowane czyli binarne, dwójkowe, bezformatowe mogą być przechowywane w pamięciach zewnętrznych. Dane zapisane są w nich w postaci dwójkowej, a więc takiej samej, jak w pamięci wewnętrznej maszyny. Zbiory zawierające tego typu rekordy charakteryzują się dużą zawartością zapisu i wymagają niewielkiej ilości przekształceń dla przesyłania ich do pamięci wewnętrznej. W praktyce tworzone są one dla dużej ilości wyników pośrednich;
Instrukcje we/wy odwołują się do zbiorów lub urządzeń poprzez tzw numer programowy zbioru (urządzenia) zwany strumieniem logicznym, dostępnym na poziomie OSL-a. Strumienie te są określone przez liczbę całkowitą zawartą w przedziale od 0 do 20. Przywiązanie numeru programowego (strumienia) z konkretnym zbiorem lub urządzeniami dokonywane jest zleceniem Języka Operatora.
Instrukcje READ i WRITE
Podstawowymi instrukcjami we/wy są instrukcje READ i WRITE. Instrukcja READ służy do wprowadzania (odczytu) rekordów ze zbioru do pamięci wewnętrznej (operacyjnej), natomiast instrukcja WRITE do wyprowadzania (zapisu) rekordów z pamięci do zbioru. Instrukcje te mają następujące postacie:
- zredagowane:
READ (u, f [ END=e1 [ ERR=e2 ]]) [lista] WRITE (u, f [ END=e1 [ ERR=e2 ]]) [lista]
- niezredagowane:
READ (r) lista WRITE (r) lista
W tych instrukcjach parametr <u> oznacza numer programowy (strumień), a <f> jest etykietą odwołującą się do specyfikacji (instrukcji FORMAT) formatu. Parametr ten może być zerem. Oznacza to format swobodny. Dla przesyłania rekordów niezredagowanych parametr <r> określa numer rekordu logicznego (szczegółowy opis tych instrukcji ww. opisie języka FORTRAN-CROOK). Lista we/wy określa miejsca pamięci wewnętrznej, uczestniczące w operacjach we/wy. Poszczególne elementy listy oddzielone są od siebie przecinkami. Elementem listy może być:
- nazwa zmiennej;
- nazwa elementu tablicy;
- nazwa tablicy;
- DO - implikowane;
Kolejność występowania elementów w liście we/wy decyduje o kolejności przesyłania wartości pomiędzy tymi elementami a rekordem. Istnieją programowe środki umożliwiające określenie własnego postępowania w przypadku wykrycia końca zbioru lub błędów w czytaniu lub zapisie rekordów. Służą do tego parametry END i ERR. Użycie parametru END powoduje przejście do wykonania instrukcji oznaczonej etykietą e1, gdy w trakcie czytania wykryty zostanie koniec zbioru. Podobnie użycie parametru ERR powoduje przeniesienie wykonania do instrukcji oznaczonej etykietą e2, gdy wykryty zostanie błąd. Parametry te mogą wystąpić w dowolnej kolejności i nie koniecznie obydwa jednocześnie. Etykiety e1 i e2 muszą natomiast występować w tym samym segmencie co instrukcje READ i WRITE, w których zostały użyte. Jeżeli w instrukcjach READ i WRITE w miejscu przeznaczonym na numer programowy urządzenia lub zbiorów, wystąpi liczba równa zero (0), to wydruk wyników (instrukcja WRITE) pojawi się na monitorze końcówki, z której został uruchomiony program. Natomiast jeżeli zero pojawi się w instrukcji czytania (READ), to dane należy podawać z klawiatury końcówki. Sygnalizowane jest to znakiem ">".
Instrukcja FORMAT
Instrukcja FORMAT opisuje wzorzec wg. którego są deklarowane konwersje danych w czasie realizacji instrukcji WE/WY. Specyfikacja formatu składa się z szeregu opisów pól. Stanowi ona opis jednego lub kilka wprowadzonych lub wyprowadzanych rekordów. Kompletne specyfikacje zamyka się w nawiasy. Instrukcja ma następującą postać:
- e FORMAT (s)
gdzie:
- e - etykieta (musi wystąpić)
- s - specyfikacja formatu
Specyfikacja formatu stanowi opis jednego lub kilku wprowadzonych lub wyprowadzonych rekordów. Może ona składać się z następujących elementów:
- opisy pól
- przecinki;
- ukośne kreski;
- okrągłe nawiasy;
- liczby powtórzeń;
- współczynnik skali;
Kolejne opisy pól muszą być oddzielone przecinkiem, ukośną kreską lub ciągiem ukośnych kresek. Przecinek oznacza koniec pola. Ukośna kreska oznacza koniec pola i koniec rekordu. Ukośne kreski mogą występować między opisami pól, mogą też poprzedzać lub kończyć ciąg opisów pól.
Opisy pól
Opisy pól są używane do określenia postaci pól w rekordzie. Duże litery I, L, F, E, D itd. są nazywane kodami konwersji, które wskazują w jaki sposób rekord ma być przetworzony z postaci znakowej na wewnętrzną maszynową-przy wprowadzaniu, lub z wewnętrznej postaci maszynowej na postać znakową przy wyprowadzaniu. Ogólna postać formatu kodów konwersji:
- <kod konwersji> <szerokość pola> [.<dokładność>]
- <szerokość pola> - jest to liczba całkowita bez znaku określająca pełną szerokość pola rekordu w znakach;
- <kod konwersji> - oznaczane są przez duże litery. Określają one odpowiedni kod konwersji logicznej, numerycznej lub znakowej;
- <dokładność> -jest liczbą pozycji cyfr znaczących w polu;
We wszystkich opisach pól wprowadzono następujące oznaczenia:
- w - szerokość pola w znakach;
- d - liczba pozycji liczb po przecinku;
Opis pola I
Opisu pola I używa się do przesyłania wartości typu INTEGER. Postać opisu pola:
- [<p>]I<w>
Odpowiadający deskryptorowi I element listy we/wy musi być typu INTEGER. Deskryptor I związany z instrukcją wejścia powoduje pobranie dokładnie <w> kolejnych znaków z wczytanego rekordu, przeprowadzenie ich konwersji na postać wewnętrzną (binarną) i zapamiętanie tak uzyskanej wartości w stowarzyszonym z deskryptorem elemencie listy we/wy. Pobrany ciąg znaków musi mieć postać stałej całkowitej i może zawierać jedynie (w wymienionej kolejności) spacje wiodące, znak + lub - i cyfry dziesiętne lub spacje. Spacje wiodące i znak + są ignorowane; znak - spowoduje, że wczytana wartość będzie ujemna. Wszystkie spacje występujące po znaku + lub - albo po cyfrach są traktowane jak zero (0). Przekroczenie zakresu liczby typu INTEGER [-32768; +32767] lub wystąpienie w polu wejściowym innego niż wymienione znaki, spowoduje zapalenie wskaźnika błędu.
Przykład:
...... I=-3762 J=+4 K=-13 WRITE(2,10)I, J, K 1 0 FORMAT(I5, I5, I4) ......
Wydruk wyników:
-3762 +4 -13
Opis pola F
Opis pola F jest przeznaczony do konwersji danych rzeczywistych, części rzeczywistej lub urojonej danych zespolonych. Postać deskryptora F jest następująca:
- [<p>]F<w>.<d>
Odpowiadający deskryptorowi element listy we/wy musi być typu rzeczywistego. Na wejściu, deskryptor F pobiera <w> kolejnych znaków z wczytanego rekordu, dokonuje ich konwersji zgodnie z typem elementu listy na daną binarną typu rzeczywistego i podstawia tak uzyskaną wartość do odpowiedniego elementu listy. Pobrany ciąg znaków musi mieć postać stałej całkowitej, stałej rzeczywistej; stałe te mogą być poprzedzone spacjami. Spacje występujące po znaku + lub - (jeżeli występuje) albo po cyfrach interpretowane są jako zero (0). Jeżeli w pobranym polu są same spacje, to sygnalizowany będzie błąd. Przekroczenie zakresu liczby lub błędny zapis liczby w polu wejściowym spowoduje zasygnalizowanie błędu.
Opis pola E
Opis pola E, podobnie jak opis F, służy do konwersji danych rzeczywistych oraz części rzeczywistej i urojonej danych zespolonych. Postać deskryptora jest następująca:
- [<p>]E<w>.<d>
Odpowiadający deskryptorowi element listy we/wy musi być typu rzeczywistego. Na wejściu, deskryptor E działa tak samo jak F. Na wyjściu deskryptor E zmienia wartość odpowiadającego mu elementowi listy we/wy na ciąg <w> znaków i umieszcza je w odpowiednim polu rekordu wyjściowego.
Przykład:
...... READ(3,20)A, B, C 2 0 FORMAT(E9.3, F5.2, E10.3) ......
dane:
+6.47E-01,-2.36,+5.321E+02 9 znaków 5 10
Opis pola tekstu
Do przesyłania ciągów znakowych podanych w specyfikacji formatu używa się opisów pól wykorzystujących kod konwersji H i opisy pól literali. Opisy pól mają następującą postać:
- <w>H<ciąg znaków>
- '<ciąg znaków>'
- "<ciąg znaków>"
gdzie:
- w - szerokość pola w znakach.
W przypadku kodu konwersji H wszystkie znaki, łącznie ze spacjami, muszą być włączone do liczby znaków <w>. Współczynnik skali nie daje żadnych efektów.
Przykład a:
...... A=1.5 WRITE(2,80)A 8 0 FORMAT (2X,6H LM =, F5.2,2X)
wydruk:
___LM_=_1.50__
Przykład b:
...... WRITE(0,10) 1 0 FORMAT (1X,' END FILE ',2X,/ & " END 'OF' FILE ") ......
wydruk:
__END_FILE___ _END_'OF'_FILE_
Opis pola X
Opis pola X używa się do pomijania znaków w rekordzie wejściowym a przede wszystkim do wyprowadzania znaków spacji w rekordzie wyjściowym. Opis pola ma następującą postać:
- <w>X
Liczba całkowita <w> określa liczbę znaków, która ma być pominięta lub liczbę spacji, które mają być wyprowadzone.
Przykład:
..... A=-342.743 B=1.53190 J=22 WRITE(6,10)A, B, J 1 0 FORMAT (1X, F9.4,4X, F7.5,4X, I3) .....
wydruk:
_-342.7430____1.53190_____22
Sterowanie wydrukiem
Przy wyprowadzaniu tekstu na drukarkę, przejście do nowej strony oraz do następnych wierszy uzyskuje się przez znak sterujący występujący jako pierwszy w instrukcji FORMAT. Znak ten ma tylko znaczenie kontrolne i nie jest wyprowadzany. Rozróżniamy następujące znaki sterujące:
- 1H^ - nowa strona
- 1H_ - bez przejścia do następnego wiersza
- / - przejście do nowego wiersza
11.5. Format swobodny
Dopuszcza się swobodną konwersję danych. Polega ona na tym, że dane czytane z, lub wyprowadzane na numery programowe urządzeń lub zbiorów, w postaci znakowej instrukcjami WRITE, READ będą realizować swobodną konwersję danych. Swobodna konwersja danych możliwa będzie tylko wtedy, gdy w instrukcji FORMAT w miejscu odwołania do specyfikacji wzorca wystąpi pseudoetykieta zero (0) lub etykieta odwołująca się do instrukcji FORMAT, w której opisy pól (szerokość pola i liczba znaków części ułamkowej jest równa zero) są następującej postaci:
- I0, F0.0, E0.0, G0.0, D0.0;
Jeżeli pewna ilość kolejnych pól rekordu zewnętrznego ma być przetwarzana przy pomocy takiego samego opisu pola (za wyjątkiem opisu H i '<ciąg znaków>'), można wtedy zastosować licznik powtórzeń.
Przykłady:
Poszczególne dwa fragmenty programu pokazują różne sposoby użycia formatu swobodnego i posiadają takie samo znaczenie:
........ READ(0,0)X, Y READ(3,0)(K(I), I=1,10) ........ WRITE(0,0)X, Y WRITE(4,0)K(1), K(2) ........
........ READ(0,10)X, Y 10 FORMAT(2F0.0) READ(0,20)(K(I), I=1,10) 20 FORMAT(10I0) ........ WRITE(0,30)X, Y 30 FORMAT(F0.0, E0.0) WRITE(4,40)K(1), K(2) 40 FORMAT(I0, I0) ........
Histogramy
Jedna realizacja programu modelującego składa się zazwyczaj z dużej liczby powtórzeń procedury modelowania, a uzyskiwane zestawy wyników mogą się charakteryzować przypadkowymi wahaniami. Bardziej celowe jest zatem rejestrowanie w postaci histogramów (wykresów słupkowych) liczby zdarzeń, gdy wyniki zawierają się w określonych przedziałach wartości, niż drukowanie wyników uzyskiwanych przy każdym powtórzeniu procedury.
HIST (histogram)
Instrukcja HIST określa jeden lub więcej histogramów. Ma ona następującą postać ogólną:
- HIST hname (n1, n2, n3), hname2(n4, n5, n6), ...
gdzie hname1, hname2, ... Są nazwami języka CSL, a n1, n2, ... Są nieoznakowanymi (a zatem nieujemnymi) stałymi typu INTEGER. Pierwszy histogram jest określony hname1 i posiada n1 przedziałów. W pierwszym przedziale są przechowywane zdarzenia, ze wynik zawiera się w przedziale od -nieskończoności do n2; w następnych (n1-2) przedziałach odnotowywane są zdarzenia dotyczące kolejnych przedziałów wartości o szerokości n3 a w przedziale ostatnim - zdarzenia, ze wynik zawiera się w przedziale od górnej granicy wartości przedziału przedostatniego do +nieskończoności. Wiele histogramów może być określonych przy użyciu tej samej nazwy, przy czym należy stosować odpowiedni indeks w następujący sposób:
- HIST hname1. M1(n1, n2, n3), hname2. M2(n4, n5, n6)...
gdzie m1, m2, ... są liczbami całkowitymi.
Instrukcja ta definiuje m1 histogramów oznaczonych hname1.1, hname2.2, ..., hname1. M1, m2 histogramów oznaczonych hname2.1, hname2.2, ..., hname2. M2 itd.
ADD (dodaj)
Instrukcja ta ma następującą postać:
- ADD <wyrażenie>,<hname>
Gdzie wyrażenie jest dowolnym wyrażeniem dającym wynik typu INTEGER, a hname jest nazwą histogramu. Wykonanie tej instrukcji powoduje zwiększenie o 1 zawartości tej komórki histogramu, w której zakresie zawiera się bieżąca wartość wyrażenia.
Przykład:
ADD A, HISTA ADD T. STATEK.1, HISTOGRAM ADD STATEK. N(3)-ZEGAR, QCZAS
YIELD (wydaj)
YIELD jest funkcją typu INTEGER. Instrukcja ma następującą postać ogólną:
- zmienna = YIELD (hname, przedział)
gdzie hname jest nazwą histogramu, a przedział jest zmienną lub stałą typu INTEGER. Instrukcja taka przyporządkowuje zmiennej wartość całkowitą, równą liczbie obserwacji zarejestrowanych w komórce histogramu hname obejmującej wartość przedziału.
Przykład:
Przypuśćmy, że w histogramie HISTB zarejestrowano dziesięć obserwacji w przedziale 7 do 11. Wówczas instrukcja:
X=YIELD (HISTB,7)
spowoduje przypisanie zmiennej X wartości 10.
OUTPUT (wydruk)
Instrukcja ta ma następującą postać ogólną:
- OUTPUT <hname1>,<hname2>,...
gdzie hname1, hname2, ... są nazwami histogramów. Instrukcja ta powoduje wyprowadzenie na standardowe urządzenie wyjściowe (monitor użytkownika) zawartości wymienionych histogramów. Histogram jest wyprowadzany w następującej postaci. Dla każdego przedziału, a więc jednej komórki histogramu, przeznaczony jest jeden wiersz. Każdy wiersz ma postać:
- n1 m1 / m2
gdzie n1 jest liczbą operacji zarejestrowanych w przedziale m1 do m2. Obie kolumny informacji opatrzone są nagłówkami COUNT i RANGE. Na wyjściu nie jest drukowany żaden identyfikator histogramu; jeśli więc potrzebne są nazwy histogramów, to muszą być one wyprowadzone za pomocą normalnej instrukcji WRITE, poprzedzającej instrukcję wyprowadzania histogramu.
CLEAR (usuń)
Instrukcja ta ma następującą postać ogólną:
- CLEAR hname1, hname2, ...
gdzie hname1, hname2, ... są nazwami histogramów.
Powoduje ona wyzerowanie wyspecyfikowanych histogramów. Struktura histogramów nie ulega przy tym zmianie, tak że po wyzerowaniu mogą być one dalej używane bez ponownego definiowania.
Przykład:
CLEAR HISTA, HISTB, HISTC
W przykładzie tym dokonuje się zerowania wszystkich liczb obserwacji zarejestrowanych w histogramach HISTA, HISTB, HISTC. Należy zwrócić uwagę, że wprawdzie histogram przypomina rozkład częstości, to jednak nie można prowadzić próbkowania z danych zawartych w histogramie.
Wyjścia diagnostyczne
CHECK (sprawdź)
Instrukcja ta ma postać:
- CHECK name1, name2,...
lub
- CHECK (j) name1, name2,...
gdzie name1, name2, ... są nazwami zmiennych, elementów tablic, atrybutów obiektów lub atrybutów czasowych, zdefiniowanych gdziekolwiek w programie. Zmienna j jest liczbą całkowitą z zakresu od 1-15. Instrukcja ta powoduje wyprowadzanie na standardowe urządzenia wyjściowe bieżącej wartości każdej wyspecyfikowanej pozycji, poprzedzając ją 8 znakami nazwy. Każda pozycja wyprowadzana jest w nowym wierszu. Instrukcja CHECK jest wykonywana tylko wówczas, gdy jest opuszczony klucz (na pulpicie maszyny) o numerze j. Jeśli w instrukcji nie podano numeru klucza, to przyjmuje się, że jest to klucz nr. 1.
Przykład:
CHECK (5) A, T. STATEK. A, STATEK. A(5)
Pod warunkiem , że klucz 5 jest opuszczony, instrukcja ta wyprowadzi informację w postaci następującej:
A = 205 T. STATEK = 355 STATEK. A = 0
PRISET
Postać ogólna tej instrukcji jest następująca:
- PRISET zname1, zname2,....
lub
- PRISET(j) zname1, zname2,....
Gdzie j jest liczbą całkowitą zawartą w przedziale 1-15, a name1, name2, .... są nazwami zbiorów.
Instrukcja ta powoduje wyprowadzenie na standardowe urządzenie wyjściowe zawartości zbiorów - zname1, zname2, ... wg. następującego formatu:
SET NAME zname SIZE n MEMBERS i1, i2, i3,.... in
gdzie zname - jest nazwą zbioru, n - jest aktualną liczbą elementów tego zbioru, a i1, i2, ...., in - są indeksami obiektów kolejnych elementów zbioru. Indeksy obiektów drukowane są w takim porządku, w jakim występują one w zbiorze. Są one drukowane po 10 w jednym wierszu. Instrukcja wykonywana jest tylko wówczas gdy opuszczony jest klucz nr. j (jeśli nie podano numeru klucza - to przyjmuje się, że jest to klucz nr. 1).
Instrukcja:
PRISET(2) WMORZU
może spowodować następujący wydruk:
SET NAME WMORZU SIZE 8 NAMBERS 3, 5, 9, 13, 10, 15, 12, 7.
Ź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