Kurs REXX cz. 6: Stos

Tym razem w kursie o obsłudze stosu. Operowanie tą strukturą danych w wielu przypadkach może okazać się wręcz niezbędne.

<<Następna część artykułu | Poprzednia część artykułu>>

Wstęp

REXX udostępnia programiście obszar w pamięci do przechowywania tymczasowych danych. Obszar ten możemy obsłużyć na dwa sposoby: jako strukturę LIFO (Last In, First Out):

 

element który zostanie włożony na stos jako ostatni, jest pierwszym, który można z niego wyjąć.

Lub jako strukturę typu FIFO (First In, First Out) w której to elementy dodaje się na koniec, a pobiera z początku.

Obie struktury mają jedną wspólną cechę, a mianowicie elementy mogą być pobierane tylko z góry.

Obsługa struktur w REXX

W Rexxie mamy do dyspozycji trzy podstawowe instrukcje oraz jedną funkcję odpowiadającą za obsługę ww. struktur:

  • Push – wkłada element na górę stosu;
  • Queue – wkłada element na koniec kolejki;
  • Parse Pull – pobiera element z góry kolejki/stosu jednocześnie go usuwając
  • Queued() – funkcja zwraca liczbę elementów w strukturze

Istotnym faktem jest, że to na programiście spoczywa obowiązek prawidłowej obsługi stosu. Musimy pamiętać, że w momencie kiedy stos jest pusty, a my wywołamy kolejną instrukcję Parse Pull, REXX będzie oczekiwał na odpowiedź z terminala, co w większości przypadków nie będzie zamierzonym efektem. Najlepiej od razu wyrobić sobie nawyk, aby pobierać elementy za pomącą pętli:

i=1;
Do While Queued()<>0
Parse Pull stem.i;
i=i+1;
End

 

Stos znajduje się pomiędzy terminalem a programem. To bardzo użyteczna cecha, którą najczęściej wykorzystuje się do symulowania wydawania komend przez użytkownika, jeśli jednak podczas operacji odczytu ze stosu istnieje konieczność pobrania danych od użytkownika możemy to zrobić za pomocą komendy Parse External. Różnica jest taka, że Parse Pull zawsze najpierw odczytuje ze stosu i jeśli ten jest pusty oczekuje na dane z terminala, natomiast Parse External zawsze odczytuje bezpośrednio z terminala.

Kolejną rzeczą o jakiej musimy pamiętać jest to, że jeśli nasz program zakończy działanie pozostawiając na stosie elementy, wszystkie one zostaną potraktowane jako komendy i jeśli nie jest to zamierzone działanie, może to skutkować pojawieniem się komunikatu o błędach:

IKJ56500I COMMAND XXX NOT FOUND

 

Kolejną dobrą praktyką jest czyszczenie stosu przed wyjściem z programu:

Do Queued()
Parse Pull;
End
Komendy REXX TSO/E

Niżej opisane komendy są częścią TSO, ale mogą być użyte tylko w skryptach REXX.

Address TSO ‘NEWSTACK’ – zabezpiecza aktywny stos, zamyka go i tworzy nowy pusty stos. W systemie możemy utworzyć więcej niż jedne stos, ale zawsze tylko jeden może być aktywny!

DELSTACK – usuwa aktywny stos wraz ze wszystkimi elementami oraz przywraca poprzedni! Ze względu na swoją właściwość przywracania poprzedniego stosu lepszą praktyką jest stosowanie pętli

Do Queued()
Parse Pull;
End

 

do usuwania elementów na stosie.

QSTACK – komenda zwraca kod powrotu z ilością aktywnych stosów. Jeśli w naszym programie utworzyliśmy nowy stos komendą ‘NEWSTACK’ kod powrotu z wywołania wyniesie 2 (Pierwszy stos tworzony jest w momencie logowania do systemu).

AddressTSO 'QSTACK';
Say rc;

 

MAKEBUF – podczas tworzenia listy tworzony jest również jej bufor, a konkretnie bufor 0. Kiedy elementy są dokładane, tak naprawdę są dokładane do aktywnego bufora. Nowy bufor tworzymy za pomocą komendy MAKEBUF co spowoduje zmianę kolejności elementów. Zobaczmy to na przykładzie:

/* Odkładamy elementy na stos do bufora 0*/
Queue "Element 1";
Queue "Element 2";
Queue "Element 3";

 

/* Tworzymy nowy bufor */
'MAKEBUF';
Say "Nr utworzonego bufora: " rc; /* rc zwraca nr utworzonego bufora */ 

 

/* Odkładamy elementy na stos do bufora 1*/
Queue "Element 4";
Queue "Element 5";
Queue "Element 6";

 

Do Queued()
Parse Pull i;
Say i;
End

 

Wynik działania naszego programu w z wykorzystaniem MAKEBUF:

Element 4
Element 5
Element 6
Element 1
Element 2
Element 3

 

Bez MAKEBUF wynik byłby następujący:

Element 1
Element 2
Element 3
Element 4
Element 5
Element 6

 

MAKEBUF ma zastosowanie tylko w przypadku kolejki (FIFO)! W przypadku LIFO zastosowanie MAKEBUF nie przyniesie widocznych rezultatów.

QBUF – komenda zwraca kod powrotu z numerem aktywnego bufora:

‚QBUF’

buf_counter = RC;

 

Do Queued()
Parse Pull i;
'QBUF'
If(buf_counter=RC) Then Do
Say "Aktywny bufor: "RC;
buf_counter = buf_counter -1;
End /* (buf_counter=rc) */
Say i;
End /* Queued() */

 

Po dokonaniu powyższych zmian w naszym programie otrzymamy następujący wynik:

Aktywny bufor: 1
Element 4 
Element 5 
Element 6 
Aktywny bufor: 0 
Element 1 
Element 2 
Element 3

 

QELEM – zwraca kod powrotu z ilością elementów w aktywnym buforze utworzonym za pomocą komendy MAKEBUF (jeśli nie utworzymy bufora komenda zwróci 0!):

/* Tworzymy nowy bufor */
'MAKEBUF';
/* Odkładamy elementy na stos do bufora 1*/
Queue "Element 1";
Queue "Element 2";
Queue "Element 3";

 

/* Tworzymy nowy bufor */
'MAKEBUF';
/* Odkładamy elementy na stos do bufora 2*/
Queue "Element 4";
Queue "Element 5";
Queue "Element 6";
Queue "Element 7";

 

/* Tworzymy nowy bufor */
'MAKEBUF';
/* Odkładamy elementy na stos do bufora 3*/
Queue "Element 8";
Queue "Element 9";
Queue "Element 10";

 

'QBUF'
buf_counter = RC;

 

Do Queued()
Parse Pull i;
'QBUF'
active_buf = RC;
If(buf_counter=active_buf) Then Do
Say "Aktywny bufor: "active_buf;
 If (active_buf<>0) Then Do /* Pomija bufor 0 */
'QELEM'
Say "Ilość elementów w buforze: "RC +1 ;
 End /* (active_buf<>0) */
 buf_counter = buf_counter -1;
End /* (buf_counter=RC) */
Say i;
End /* Queued() */

 

Wynik działania naszego programu będzie następujący:

Aktywny bufor: 3 
Ilość elementów w buforze: 3
Element 8 
Element 9 
Element 10 
Aktywny bufor: 2 
Ilość elementów w buforze: 4
Element 4 
Element 5 
Element 6 
Element 7 
Aktywny bufor: 1 
Ilość elementów w buforze: 3
Element 1 
Element 2 
Element 3

 

DROPBUF – komenda służy do usuwania bufora wraz ze wszystkimi elementami. Wywołanie komendy bez parametru usuwa tylko aktywny bufor, natomiast z parametrem usuwa wszystkie bufory od podanego w górę. Wywołanie DROPBUF 0 usunie wszystkie bufory oprócz 0 ponieważ on istnieje tak długo jak istnieje struktura stosu.

/* Usuwamy wcześniejsze bufory */
'DROPBUF 0';

 

/* Tworzymy nowy bufor */
'MAKEBUF';
/* Odkładamy elementy na stos do bufora 1*/
Queue "Element 1";
Queue "Element 2";
Queue "Element 3";

 

/* Tworzymy nowy bufor */
'MAKEBUF';
/* Odkładamy elementy na stos do bufora 2*/
Queue "Element 4";
Queue "Element 5";
Queue "Element 6";
Queue "Element 7";

 

/* Tworzymy nowy bufor */
'MAKEBUF';
/* Odkładamy elementy na stos do bufora 3*/
Queue "Element 8";
Queue "Element 9";
Queue "Element 10";

 

/* Usuwa bufory od drugiego */
'DROPBUF 2'

 

'QBUF';
buf_counter = rc;

 

Do Queued()
Parse Pull i;
'QBUF'
active_buf = rc;
If(buf_counter=active_buf) Then Do
 Say "Aktywny bufor: "active_buf;
 If (active_buf<>0) Then Do /* Pomija bufor 0 */
 'QELEM'
 Say "Ilość elementów w buforze: "rc +1 ;
 End /* (active_buf<>0) */
 buf_counter = buf_counter -1;
 End /* (buf_counter=rc) */
End /* Queued() */

 

W wyniku swojego działania program zwróci:

Aktywny bufor: 1 
Ilość elementów w buforze: 3

 

Stos to potężne narzędzie najczęściej wykorzystywane wszędzie tam gdzie istnieje potrzeba zasymulowania interakcji z użytkownikiem. Świetnie nadaje się do uruchamiana zewnętrznych programów za pomocą komendy EXECIO i przekazywania do nich parametrów.

Autor: Dawid Morawiec

Komentarze

Brak komentarzy

The comments are closed.

Follow

Otrzymuj każdy nowy wpis na swoją skrzynkę e-mail.

Subskrybuj RSS