BCPL

BCPL
Pojawienie się

1967

Paradygmat

wieloparadygmatowy (strukturalny, imperatywny, proceduralny)

Typowanie

brak

Twórca

Martin Richards

BCPL (Basic Combined Programming Language) – język programowania zaprojektowany przez Martina Richardsa na Uniwersytecie w Cambridge w 1967 roku[1] jako wynik problemów z jego poprzednikiem - językiem CPL - w latach sześćdziesiątych. Pierwszy kompilator BCPL Richards napisał wiosną 1967 w czasie pobytu w MIT. Język został opisany w artykule zaprezentowanym na Spring Joint Computer Conference w 1969 roku. Na podstawie BCPL Dennis Ritchie później zaprojektował język programowania C.

BCPL powstał jako narzędzie do pisania kompilatorów, choć jednocześnie, w celu umożliwienia jego stosowania w programowaniu systemowym, zadecydowano, by jego składnia była prostsza niż miało to miejsce w przypadku CPL[2].

BCPL posiadał jeden typ danychsłowo maszynowe, którego długość w bitach zależała od docelowej architektury i była niezmienna w jej obrębie. Najczęściej zawierała się w zakresie od 16 do 36 bitów. Wszystkie wyrażenia i zmienne w języku przyjmowały wartość tego typu, która jednak mogła być odmiennie interpretowana w zależności od kontekstu[3].

Kompilator BCPL, również napisany w tym języku, składa się z trzech komponentów, które po kolei uczestniczą w kompilacji kodu. Pierwsze dwa (analizator składniowy i moduł tłumaczący) są prawie całkowicie niezależne od docelowej architektury. Ich wynikiem jest kod pośredni (nazywany OCODE). Za jego przetłumaczenie na kod maszynowy odpowiada ostatni komponent kompilatora – generator kodu, który musi być przystosowany do architektury docelowego komputera[2].

Stosowany przez kompilator kod pośredni był niezależny od docelowej architektury komputera. Można go porównać do języka asemblera dla pewnej abstrakcyjnej maszyny stosowej, na której opiera się definicja języka[4].

Składnia

Program w języku BCPL składa się z instrukcji, zwykle każda w osobnej linii. Umieszczenie kilku poleceń w tej samej linii kodu źródłowego jest możliwe, jeśli instrukcje rozdzieli się znakiem średnika[5]. W dowolnym miejscu, w którym można wstawić instrukcję prostą, dozwolone jest umieszczenie instrukcji złożonej (nazywanej blokiem, jeśli zaczyna się od deklaracji). Jej ogranicznikami są tzw. nawiasy sekcji, tradycyjnie oznaczane $( i $). W późniejszych wersjach języka w tej roli zalecane są nawiasy klamrowe[6][7]. Na niektórych architekturach dopuszczano również nawiasy kwadratowe jako oznaczenie początku i końca sekcji[8].

Nawiasy sekcji mogą być etykietowane dowolną sekwencją złożoną z liter, cyfr i kropki, występujących bezpośrednio po nawiasie. Wszystkie bloki kodu wewnątrz etykietowanego zostaną domknięte automatycznie, wraz z końcem bloku nadrzędnego[9].

Komentarze wprowadza się sekwencją //. Trwają one od miejsca jej wystąpienia aż do końca linii[10].

Zmienne

Zmienne dynamiczne (lokalne) w BCPL deklaruje się z użyciem słowa kluczowego LET, po którym występuje co najmniej jedna nazwa, następnie znak równości oraz lista wartości, którymi zmienne zostaną zainicjalizowane. Inicjalizacja w momencie deklaracji jest obowiązkowa[11]. Nazwa zmiennej może zawierać wielkie litery, cyfry i kropkę, choć musi zaczynać się od litery. Niektóre implementacje dopuszczają również małe litery i/lub użycie znaku podkreślenia zamiast kropki[5]. Identyfikator może mieć dowolną długość i wszystkie znaki są istotne[12]. Zmiennym nie określa się typu danych[10].

Zmienne dynamiczne są widoczne w obrębie bloku programu, w którym nastąpiła ich deklaracja i nie mogą być wykorzystywane w zagnieżdżonych w nim podprogramach[13].

Przypisanie wartości do zmiennej odbywa się z użyciem operatora :=. Pojedynczy symbol = oznacza operator porównania[14].

W góry instrukcja deklaracji wektora: LET V = VEC 5. Obok sześć prostokątów ułożonych jeden pod drugim, opisanych po kolei od V!0 do V!5. Po lewej stronie prostokąt opisany literą V, ze strzałką od V do V!0.
Wynik deklaracji 6-elementowego wektora w BCPL – sześć zarezerwowanych komórek pamięci oraz wskaźnik na pierwszą z nich.

BCPL pozwala również na tworzenie jednowymiarowych tablic, nazywanych wektorami. Do ich deklarowania służy składnia LET V = VEC n, gdzie n musi być wyrażeniem stałym i oznacza indeks ostatniego elementu. Ponieważ pozycje w tablicy numerowane są od zera, przytoczona instrukcja tworzy n+1-elementowy wektor. Dostęp do poszczególnych składowych jest możliwy z użyciem składni postaci V!i, gdzie i to indeks. Nie ma możliwości inicjalizacji zawartości tablicy przy jej tworzeniu[15].

W momencie tworzenia wektora, oprócz zarezerwowania odpowiedniej liczby komórek pamięci, rezerwowana jest również komórka z adresem zerowego elementu tablicy. Wskaźnik ten jest dostępny pod nazwą tablicy[16].

Wskaźnikiem w BCPL nazywany jest adres słowa w pamięci. Pozyskać go można z użyciem jednoargumentowego operatora @. Dostęp pośredni umożliwia operator !. Poniższy przykładowy kod pobiera adres zmiennej A i umieszcza go w B, a następnie zapisuje do A wartość 5 (pośrednio, poprzez wskaźnik)[17]:

LET A, B = 0, 0
B := @A
!B := 5

Następujące po sobie komórki pamięci posiadają adresy różniące się o 1[17].

Zmienne statyczne

W przeciwieństwie do zmiennych dynamicznych, statyczne istnieją przez cały czas wykonywania programu. Ich wartości są inicjalizowane w momencie uruchomienia i pozostają zachowane po wyjściu z zakresu widoczności danej zmiennej. Wprowadza je deklaracja STATIC $( ... $). Zmienne statyczne nie są widoczne dla innych modułów programu[18].

Zmienne globalne

Zmienne globalne w BCPL deklaruje się za pośrednictwem tzw. wektora globalnego. Jest on przechowywany w stałym miejscu pamięci operacyjnej i współdzielony ze wszystkimi, oddzielnie kompilowanymi, modułami programu. Każdej zmiennej globalnej przypisuje się lokalizację w wektorze za pomocą składni GLOBAL $( ... $). Część lokalizacji pamięci jest wykorzystywana przez implementację, dlatego aby uniknąć konfliktów, indeksy komórek pamięci w kodzie były typowo niemniejsze od 100. Deklarację zmiennej globalnej można przysłonić, tworząc zmienną lokalną o tej samej nazwie[19].

GLOBAL $( NUMBER:100; COUNTER:101 $)

W powyższym przykładzie zmienne NUMBER i COUNTER zostaną przypisane do, odpowiednio, setnej i sto pierwszej komórki wektora globalnego[19].

Stałe

W podobny sposób do deklarowania zmiennych globalnych zdefiniować można stałe. Służy do tego konstrukcja MANIFEST $( ... $). Tworzone w niej stałe nie zajmują miejsca w pamięci operacyjnej, bowiem ich nazwy są zastępowane wartościami na etapie kompilacji[20].

Instrukcje warunkowe

W BCPL dostępne są cztery rodzaje instrukcji warunkowych[21]:

  • IF warunek THEN jesli.prawda – pozwala na sprawdzenie warunku i wykonanie pewnych instrukcji, gdy jest prawdziwy,
  • UNLESS warunek DO jesli.falsz – jak wyżej, ale instrukcje zostaną wykonane, gdy warunek jest fałszywy,
  • TEST warunek THEN jesli.prawda ELSE jesli.falsz – dokonuje się sprawdzenie warunku i wybór jednego z dwóch zestawów instrukcji do wykonania (jeden dla warunku prawdziwego, drugi dla fałszywego),
  • SWITCHON wartosc INTO blok.case – oblicza wartość wyrażenia i porównuje je z podanymi w etykietach CASE w ramach instrukcji złożonej blok.case.

Słowa THEN i DO są traktowane jako synonimy i mogą być pominięte, jeśli bezpośrednio po nich następuje słowo kluczowe[22].

Ciało instrukcji SWITCHON może zawierać dowolną liczbę etykiet postaci CASE x: (gdzie x oznacza stałą) oraz opcjonalnie DEFAULT:. Jeżeli testowana wartość odpowiada tej podanej przy którejkolwiek etykiecie, wykonane zostaną instrukcje począwszy od tej etykiety. W przeciwnym wypadku, sterowanie zostanie przeniesione do DEFAULT lub, jeśli tej etykiety nie ma, poza SWITCHON. Napotkanie kolejnej etykiety CASE nie przerywa wykonywania instrukcji SWITCHON. Aby wymusić wyjście z bloku, należy skorzystać ze słowa ENDCASE[23].

Pętle

BCPL udostępnia sześć rodzajów pętli[24]:

  • WHILE warunek DO instrukcja – wykonuje instrukcję tak długo, jak warunek jest prawdziwy,
  • instrukcja REPEATWHILE warunek – jak wyżej, ale warunek sprawdza dopiero po wykonaniu instrukcji,
  • UNTIL warunek DO instrukcja – wykonuje instrukcję tak długo jak warunek jest fałszywy,
  • instrukcja REPEATUNTIL warunek – jak wyżej, ale warunek sprawdza dopiero po wykonaniu instrukcji,
  • instrukcja REPEAT – powtarza instrukcję w nieskończoność,
  • FOR zmienna = od TO do BY krok DO instrukcja – tworzy zmienną kontrolowaną o nazwie zmienna i inicjalizuje wartością od; przy każdej iteracji do zmiennej kontrolowanej dodawana jest wartość krok; pętla się przerywa, gdy zmienna kontrolowana przekroczy wartość do (będzie większa lub mniejsza, zależnie od znaku krok); podanie kroku jest opcjonalne, domyślnie przyjmuje się że wynosi 1.

Dodatkową kontrolę nad przepływem sterowania w pętli dają słowa kluczowe: BREAK (wychodzi z pętli) i LOOP (kończy bieżącą iterację i przechodzi do miejsca sprawdzenia warunku)[25].

Instrukcja skoku

Za realizację skoków w BCPL odpowiada instrukcja GOTO, po której następuje wyrażenie. W momencie napotkania tej komendy, wartość wyrażenia jest obliczana i oznacza miejsce w programie, do którego należy przekazać sterowanie. Zazwyczaj po słowie GOTO występuje nazwa etykiety, od której powinno się rozpocząć dalszą część wykonywania programu[26].

Etykiety w BCPL są traktowane jak zmienne, to znaczy można je w szczególności przypisywać do innych zmiennych oraz przekazywać jako argument do podprogramów[27]. Deklaracja etykiety składa się z identyfikatora oraz następującego po nim dwukropka i może występować przed poleceniem oraz deklaracją innej etykiety. Niedopuszczalne jest natomiast etykietowanie innych rodzajów deklaracji[27].

Podprogramy

Język BCPL wyróżnia dwa rodzaje podprogramów: procedury i funkcje. Zasadniczą różnicą między nimi jest fakt, że tylko te drugie mogą zwracać wartość. Oba deklaruje się w podobny sposób, z użyciem słowa LET, po którym następuje nazwa podprogramu i lista argumentów w nawiasach okrągłych[11]:

// Deklaracja funkcji: zwraca sumę trzech liczb
LET FUNKCJA(ARG0, ARG1, ARG2) = ARG0 + ARG1 + ARG2

// Deklaracja procedury: wypisuje na ekran sumę trzech liczb
LET PROCEDURA(ARG0, ARG1, ARG2) BE WRITEN(ARG0 + ARG1 + ARG2)

Po znaku równości musi znaleźć się wyrażenie, którego wartość zostanie zwrócona jako wartość funkcji. Z kolei po słowie BE umieszcza się instrukcję, wykonywaną przy wywołaniu procedury[11]. Liczba argumentów w wywołaniu podprogramu nie musi być równa liczbie formalnych parametrów. W sytuacji, gdy przekazane zostanie za dużo argumentów, nadmiarowe są obliczane a następnie odrzucane. Z kolei, jeśli w wywołaniu umieści się mniej wartości niż oczekuje podprogram, pozostałe pozostają niezainicjalizowane[28].

Przekazywanie parametrów w BCPL odbywa się na ogół przez wartość. Wyjątkiem są przekazywane przez referencję wektory[29].

Blok zwracający wartość

W przypadku, gdy funkcja jest definiowana z użyciem instrukcji złożonej, wykorzystuje się konstrukcję VALOF, po której następuje blok kodu. W tym bloku musi się znaleźć przynajmniej jedna instrukcja RESULTIS, która przerywa wykonywanie instrukcji złożonej i zwraca wartość do miejsca, gdzie wystąpiło słowo VALOF[30][31].

Wykorzystanie i implementacje

To właśnie w BCPL napisano oryginalny program Hello world. Pierwszy MUD także powstał w BCPL.[32]

Kilka z systemów operacyjnych zostało napisanych częściowo lub w całości w BCPL (dla przykładu TRIPOS i wczesne wersje AmigaDOS - fragment AmigaOS). Był to także język używany jako pierwszy w projekcie Xerox PARC Alto - projekcie pierwszego współczesnego komputera osobistego. System obróbki dokumentów "Bravo" to kolejny przykład aplikacji napisanej w BCPL.

Wczesny kompilator, uruchomiony w 1969 roku poprzez puszczenie w obieg taśmy papierowej z O-kodem kompilatora Atlas 2, zaprojektowany był dla ICT 1900. Maszyny różniły się długością słowa (48 a 24 bity), kodowaniem znaków i różnymi reprezentacjami spakowanych ciągów znaków. Udany rozruch zwiększył wiarę w jego praktyczność zastosowania.

W późnych latach 70. istniały implementacje dla Honeywell 635, Honeywell 645, IBM 360, PDP-10, TX-2, CDC-6400, UNIVAC 1108, PDP-9, KDF 9 i Atlas 2. W 1974 roku w BBN przygotowano dialekt BCPL, który nie wykorzystywał O-kodu. Wstępna implementacja była cross-kompilowana na PDP-10 należących do BBN i służyć miała wykorzystaniu na PDP-11, wykorzystywanych w BBN-owskiej implementacji drugiej generacji IMP obsługujących ARPANET.

Istniała także wersja dla BBC Micro opracowana w połowie lat 80. przez Richards Computer Products, firmę pod dyrektorstwem Johna Richardsa, brata dr. Martina Richardsa. Projekt BBC Domesday oparty był na BCPL. Pewne warianty BCPL dla Amstrad CPC oraz Amstrad PCW ujrzały światło dzienne w 1986 roku poprzez Arnor Ltd. MacBCPL został wydany dla Apple Macintosh w 1985 przez Topexpress Ltd.

W 1979 istniały implementacje BCPL dla 25 architektur, ale obecnie się go już nie używa. Jego następca, C, jest językiem, w którym tworzy się systemy operacyjne.

Budowa BCPL mocno wpłynęła na język B, który następnie wpłynął na język C.

Przypisy

  1. Richards i Whitby-Strevens 1979 ↓, s. ix.
  2. a b Richards i Whitby-Strevens 1979 ↓, s. 1.
  3. Richards i Whitby-Strevens 1979 ↓, s. 1-2.
  4. Richards i Whitby-Strevens 1979 ↓, s. 125-126.
  5. a b Richards i Whitby-Strevens 1979 ↓, s. 8.
  6. Richards i Whitby-Strevens 1979 ↓, s. 14.
  7. Richards 2022 ↓, s. 16.
  8. Martin Richards i inni, BCPL Manual, Bolt Beranek and Newman Inc., wrzesień 1974, s. 44 [dostęp 2022-09-13] (ang.).
  9. Richards i Whitby-Strevens 1979 ↓, s. 150.
  10. a b Richards i Whitby-Strevens 1979 ↓, s. 9.
  11. a b c Richards i Whitby-Strevens 1979 ↓, s. 158.
  12. Richards i Whitby-Strevens 1979 ↓, s. 3.
  13. Richards i Whitby-Strevens 1979 ↓, s. 26, 38.
  14. Richards i Whitby-Strevens 1979 ↓, s. 9, 13.
  15. Richards i Whitby-Strevens 1979 ↓, s. 20-21.
  16. Richards i Whitby-Strevens 1979 ↓, s. 31.
  17. a b Richards i Whitby-Strevens 1979 ↓, s. 30.
  18. Richards i Whitby-Strevens 1979 ↓, s. 44-45.
  19. a b Richards i Whitby-Strevens 1979 ↓, s. 25.
  20. Richards i Whitby-Strevens 1979 ↓, s. 10.
  21. Richards i Whitby-Strevens 1979 ↓, s. 13, 17, 27.
  22. Richards i Whitby-Strevens 1979 ↓, s. 161.
  23. Richards i Whitby-Strevens 1979 ↓, s. 27.
  24. Richards i Whitby-Strevens 1979 ↓, s. 15-17.
  25. Richards i Whitby-Strevens 1979 ↓, s. 39.
  26. Richards i Whitby-Strevens 1979 ↓, s. 41.
  27. a b Richards i Whitby-Strevens 1979 ↓, s. 159.
  28. Richards 2022 ↓, s. 34.
  29. Richards i Whitby-Strevens 1979 ↓, s. 23.
  30. Richards i Whitby-Strevens 1979 ↓, s. 22, 154.
  31. Richards 2022 ↓, s. 24.
  32. Introduction to MUDs (ang.)

Bibliografia

  • Martin Richards, Colin Whitby-Strevens, BCPL – the language and its compiler, Cambridge: Cambridge University Press, 1979, ISBN 0-521-21965-5 [zarchiwizowane 2019-09-24] (ang.).
  • Martin Richards, The BCPL Cintsys and Cintpos User Guide, Computer Laboratory, University of Cambridge, 19 lipca 2022 [dostęp 2022-09-13] (ang.).
  • BCPL - a tool for compiler writing and systems programming, Richards, M. Proceedings of the Spring Joint Computer Conference, vol 34, pp 557-566, 1969.

Linki zewnętrzne

Media użyte na tej stronie

BCPL pointer to vector.svg
Autor: Msz2001, Licencja: CC0
Wynik deklaracji 6-elementowego wektora w BCPL: sześć ponumerowanych komórek pamięci oraz wskaźnik na zerowy element tablicy