W poprzednich punktach zaprezentowaliśmy, jak sobie z tym poradzić umożliwiając stosowanie nakładkowania procedur. Naszym zdaniem jest to najefektywniejszy sposób nakładkowania, bowiem stwarza dodatkowo możliwość przygotowania biblioteki niezależnych modułów, które mogą być wykorzystywane w następnych programach.
W niektórych dialektach BASICa lub implementacjach Pascala (np. w Turbo Pascalu) starano się problem zbyt małej pamięci roboczej rozwiązać poprzez tzw. łańcuchowanie programów (BASIC) lub procedur (Turbo Pascal). Typową instrukcją służącą do tych celów jest w dialektach BASICa instrukcja CHAIN. CHAIN użyte na końcu programu aktualnie rezydującego w pamięci komputera powoduje wczytanie z taśmy lub z dyskietki innego programu. Do rozwiązania pozostaje tylko problem komunikacji między kolejnymi ogniwami nakładkowanymi w pamięci operacyjnej. Oczywiście ogniwa mogłyby wymieniać między sobą dane za pośrednictwem pamięci zewnętrznej. Wymaga to jednak więcej czasu niż sposób, który wykorzystuje w tym celu pamięć komputera. Otóż w tym przypadku najwygodniej jest umieścić dane do przekazania w zbiorze zmiennych zwanym wspólnym blokiem. To, co przechowamy we wspólnym bloku, będzie można wykorzystać w następnym ogniwie. To, co jest niepotrzebne czyli wszystkie zmienne lokalne, zostanie usunięte i zwolni pamięć.
Ponieważ łańcuchowanie programów może okazać się przydatne w praktycznym programowaniu, to również Warsaw BASIC wyposażyliśmy w instrukcję CHAIN. Oryginalnie działa w systemie WB instrukcja COMMON, która służy do tworzenia wspólnego bloku zmiennych. COMMON przenosi do tego bloku wszystkie zmienne i tablice, które zostały zadeklarowane przed użyciem tej instrukcji. Zachowują one tam swoje nazwy z tym, że aby ich użyć, należy poprzedzać je znakiem wykrzyknika. Za to można ich używać nie tylko w kolejnych ogniwach nakładkowanych przez CHAIN, ale również we wszystkich procedurach na każdym z 8 poziomów zagnieżdżenia. Poza tym takie rozwiązanie pozwala na używanie w nazwach zmiennych lokalnych tych samych identyfikatorów, co w nazwach zmiennych ze wspólnego bloku. Wspólny blok można skasować (COMMON OFF), w jego miejscu utworzyć następny, itd.
Inne podejście do problemu komunikacji między ogniwami prezentuje standardowy dla C-64 interpreter CBM v.2.0. Rolę CHAIN pełni tu instrukcja LOAD. LOAD użyte w trybie programowym powoduje, że po załadowniu wyspecyfikowanego zbioru sterowanie zostanie przekazane do pierwszej instrukcji wczytanego programu. Wczytany program korzysta z tego samego zbioru zmiennych co jego poprzednik. Innymi słowy mówiąc, wszystkie zmienne w kolejnych ogniwach są globalne. W czasie używania LOAD w roli CHAIN należy zachować ostrożność. Wszystko jest w porządku dopóki każde następne ogniwo jest nie większe niż pierwsze. Jeśli zdarzy się, że jedno z ogniw przekroczy objętość ogniwa inaugurującego, to zniszczony zostanie zbiór zmiennych i tablic, co uniemożliwi korzystanie z danych zgromadzonych przez poprzednie ogniwa. Ponieważ jednocześnie nie ulegną zmianie zmienne systemowe odpowiedzialne za konfigurację pamięci roboczej BASICa, to użycie zmiennej, której nie można zidentyfikować w nieaktualnym już zbiorze danych spowoduje jej umiejscowienie tam, gdzie poprzednio kończył się zbiór zmiennych. To z kolei może zniszczyć dopiero co załadowane ogniwo.
Do stosowania odpowiednich reguł, które wykluczałyby opisane powyżej przypadki, można się przyzwyczaić, albo tak zmienić interpreter, aby nie trzeba było tych reguł stosować. W interpreterze rozbudowanym dla Czytelników „Bajtka” zastosowaliśmy to drugie rozwiązanie (por. program 1). Podprogram obsługujący łańcuchowanie korzysta z programu wywołującego procedury przedstawionego w jednym z poprzednich odcinków teo cyklu. Różnica polega na tym, że CHAIN zapamiętuje na stosie tylko adres (2 bajty) początku programu wywołującego (por. LDA #$02 w linii $C8D8 programu 1). Składnia CHAIN w interpreterze rozbudowanym dla Czytelników „Bajtka” ma postać:
£A „nazwa programu”, nr urządzenia
£A tym różni się od instrukcji łańcuchowania z Warsaw BASICa, że kolejne ogniwa nakładkuje nie na poziomie programu wywołującego, ale bezpośrednio za zbiorem danych tego poziomu, tam gdzie umieszczane są procedury wywołane przez CALL. Chroni to zbiór danych przed zniszczeniem i udostępnia go w całości wywołanemu ogniwu. Ceną, jaką trzeba za to zapłacić, jest to, że kolejne ogniwa mogą korzystać tylko ze zmiennych zadeklarowanych w programie wywołującym. Ogniwo wywołane i wywołujące mają ten sam zbiór zmiennych. Oczywiście numery linii w ogniwie wywołanym mogą być takie same jak w programie wywołującym.
Wykonanie ogniwa wywołanego przez £A kończy instrukcja £F. Powoduje ona ponowne przełączenie się do programu wywołującego. £F korzysta z procedur instrukcji £E kończącej wykonanie procedury, dlatego program 2 zawiera tylko wstawienie na listę adresów interpretera adresu £F (por. POKE x+11, 199 i POKE x+10, 186 w liniach 906 i 908).
W ogniwach nakładkowanych przez £A nie można wywoływać procedur. W procedurach natomiast można korzytać z łańcuchowania. Próby nielegalnego wywoływania są sygnalizowane komunikatem ILLEGAL DIRECT.
Ogniwo wywoływane przez instrukcję £A można zaopatrzyć w nagłówek:
£H"nazwa programu
Spowoduje to, że powtórne wywołanie tego ogniwa, o ile nie zostanie zniszczone, nie będzie wymagało ładowania z pamięci zewnętrznej.
Artykuł poświęcony łańcuchowaniu programów kończy prezentację Warsaw BASICa jako systemu programowania proceduralnego. Wypada więc i nam kończyć ten cykl artykułów. Zanim to nastąpi, dla najwytrwalszych Czytelników mamy jeszcze jedną niespodziankę. A więc do następnego numeru.
Krzysztof Gajewski, Bogusław Radziszewski



