bc - instrukcja obsługi, opcje, przykłady poleceń


NAZWA

bc - Dowolny język kalkulatora precyzji

SKŁADNIA

bc [ -hlwsqv ] [long-options] [ file ... ]

OPIS

bc to język obsługujący liczby o dowolnej precyzji z interaktywnym wykonywaniem instrukcji. Istnieją pewne podobieństwa w składni do języka programowania C. Standardowa biblioteka matematyczna jest dostępna przez opcję wiersza poleceń. Na żądanie biblioteka matematyczna jest definiowana przed przetwarzaniem jakichkolwiek plików. bc rozpoczyna się od przetworzenia kodu ze wszystkich plików wymienionych w wierszu poleceń w podanej kolejności. Po przetworzeniu wszystkich plików bc odczytuje ze standardowego wejścia. Cały kod jest wykonywany tak, jak jest czytany. (Jeśli plik zawiera polecenie zatrzymania procesora, bc nigdy nie odczyta ze standardowego wejścia).

Ta wersja bc zawiera kilka rozszerzeń wykraczających poza tradycyjne implementacje bc i wersję roboczą standardu POSIX. Opcje wiersza poleceń mogą powodować, że te rozszerzenia wyświetlają ostrzeżenie lub są odrzucane. Ten dokument opisuje język akceptowany przez ten procesor. Rozszerzenia zostaną oznaczone jako takie.

OPCJE

-h, --help

Wydrukuj użycie i wyjdź.

-i, --interactive

Wymuś tryb interaktywny.

-l, --mathlib

Zdefiniuj standardową bibliotekę matematyczną.

-w, --warn

Ostrzegaj przed rozszerzeniami POSIX bc.

-s, --standard

Przetwarzaj dokładnie język POSIX bc.

-q, --quiet

Nie drukuj normalnego powitania GNU bc.

-v, --version

Wydrukuj numer wersji i prawa autorskie i wyjdź.

LICZBY

Najbardziej podstawowym elementem w bc jest liczba. Liczby są liczbami o dowolnej precyzji. Ta precyzja dotyczy zarówno części całkowitej, jak i części ułamkowej. Wszystkie liczby są reprezentowane wewnętrznie w systemie dziesiętnym, a wszystkie obliczenia są wykonywane w systemie dziesiętnym. (Ta wersja obcina wyniki operacji dzielenia i mnożenia.) Istnieją dwa atrybuty liczb, długość i skala. Długość to całkowita liczba cyfr dziesiętnych używanych przez bc do przedstawienia liczby, a skala to całkowita liczba cyfr dziesiętnych po przecinku. Na przykład:

 .000001 has a length of 6 and scale of 6.
 1935.000 has a length of 7 and a scale of 3.

ZMIENNE

Liczby są przechowywane w dwóch typach zmiennych, prostych zmiennych i tablicach. Nazywane są zarówno zmienne proste, jak i zmienne tablicowe. Nazwy zaczynają się od litery, po której następuje dowolna liczba liter, cyfr i podkreśleń. Wszystkie litery muszą być małe. (Pełne nazwy alfanumeryczne są rozszerzeniem. W POSIX bc wszystkie nazwy są pojedynczą małą literą.) Typ zmiennej jest jasny z kontekstu, ponieważ wszystkie nazwy zmiennych tablicowych będą poprzedzone nawiasami kwadratowymi ( []).

Istnieją cztery zmienne specjalne: scale, ibase, obase, i last. skala określa sposób, w jaki niektóre operacje wykorzystują cyfry po przecinku. Domyślna wartość scale to 0. ibase i obase definiują podstawę konwersji dla liczb wejściowych i wyjściowych. Wartością domyślną dla wejścia i wyjścia jest podstawa 10. last (rozszerzenie) to zmienna, która ma wartość ostatniej wydrukowanej liczby. W stosownych przypadkach zostaną one omówione bardziej szczegółowo. Wszystkie te zmienne mogą mieć przypisane wartości, jak również mogą być używane w wyrażeniach.

UWAGI

Komentarze w bc zaczynają się od znaków /* i kończą się znakami */. Komentarze mogą zaczynać się w dowolnym miejscu i pojawiać się jako pojedyncza spacja w danych wejściowych. (Powoduje to, że komentarze oddzielają inne elementy wejściowe. Na przykład komentarza nie można znaleźć w środku nazwy zmiennej.) Komentarze obejmują wszystkie nowe wiersze (koniec wiersza) między początkiem a końcem komentarza.

Aby umożliwić korzystanie ze skryptów dla bc, jako rozszerzenie dodano jednowierszowy komentarz. Komentarz jednowierszowy zaczyna się od znaku # i przechodzi do następnego końca wiersza. Znak końca wiersza nie jest częścią komentarza i jest przetwarzany normalnie.

WYRAŻENIA

Liczbami manipuluje się za pomocą wyrażeń i instrukcji. Ponieważ język został zaprojektowany jako interaktywny, instrukcje i wyrażenia są wykonywane tak szybko, jak to możliwe. Nie ma programu „głównego”. Zamiast tego kod jest wykonywany w miarę napotkania. (Funkcje, omówione szczegółowo później, są definiowane po napotkaniu.)

Proste wyrażenie jest tylko stałą. bc konwertuje stałe na wewnętrzne liczby dziesiętne przy użyciu bieżącej podstawy wprowadzania określonej przez zmienną ibase. (Istnieje wyjątek w funkcjach.) Dozwolone wartości ibase to od 2 do 36. (Podstawy większe niż 16 są rozszerzeniem). Przypisywanie wartości spoza tego zakresu do ibase > da w wyniku wartość 2 lub 36. Wprowadzane liczby mogą zawierać znaki 0-9 i A-Z. (Uwaga: muszą to być wielkie litery. Małe litery to nazwy zmiennych). Liczby jednocyfrowe zawsze mają wartość cyfry, niezależnie od wartości ibase. (tj. A=10.) W przypadku liczb wielocyfrowych bc zmienia wszystkie cyfry wejściowe większe lub równe ibase na wartość ibase-1. To sprawia, że liczba ZZZ będzie zawsze największą trzycyfrową liczbą podstawy wprowadzania.

Pełne wyrażenia są podobne do wielu innych języków wysokiego poziomu. Ponieważ istnieje tylko jeden rodzaj liczb, nie ma żadnych zasad dotyczących mieszania typów. Zamiast tego istnieją reguły dotyczące skali wyrażeń. Każde wyrażenie ma skalę. Wynika to ze skali oryginalnych liczb, wykonanej operacji iw wielu przypadkach wartości zmiennej skala. Dozwolone wartości zmiennej skala to 0 do maksymalnej liczby reprezentowanej przez liczbę całkowitą C.

W poniższych opisach wyrażeń prawnych „wyrażenie” odnosi się do pełnego wyrażenia, a „zmienna” odnosi się do zmiennej prostej lub tablicy. Prosta zmienna to po prostu a

name

a zmienna tablicowa jest określona jako

name[expr]

O ile nie zaznaczono inaczej, skala wyniku jest maksymalną skalą użytych wyrażeń.

- expr

Wynikiem jest negacja wyrażenia.

++ var

Zmienna jest zwiększana o jeden, a nowa wartość jest wynikiem wyrażenia.

-- var

Zmienna jest zmniejszana o jeden, a nowa wartość jest wynikiem wyrażenia.

var ++

Wynikiem wyrażenia jest wartość zmiennej, a następnie zmienna jest zwiększana o jeden.

var --

Wynikiem wyrażenia jest wartość zmiennej, a następnie zmienna jest zmniejszana o jeden.

expr + expr

Wynikiem wyrażenia jest suma dwóch wyrażeń.

expr - expr

Wynikiem wyrażenia jest różnica dwóch wyrażeń.

expr * expr

Wynikiem wyrażenia jest iloczyn dwóch wyrażeń.

expr / expr

Wynikiem wyrażenia jest iloraz dwóch wyrażeń. Skala wyniku jest wartością zmiennej skala.

expr % expr

Wynikiem wyrażenia jest „reszta” i jest ona obliczana w następujący sposób. Aby obliczyć a%b, najpierw a/b jest obliczane na skalę cyfr. Ten wynik jest używany do obliczenia a-(a/b)*b do skali maksimum skala+skala(b) i skala(a). Jeśli skala jest ustawiona na zero i oba wyrażenia są liczbami całkowitymi, to wyrażenie jest funkcją reszty całkowitej.

expr ^ expr

Wynikiem wyrażenia jest wartość pierwszego podniesiona do drugiego. Drugie wyrażenie musi być liczbą całkowitą. (Jeśli drugie wyrażenie nie jest liczbą całkowitą, generowane jest ostrzeżenie, a wyrażenie jest obcinane w celu uzyskania wartości całkowitej). Skala wyniku to skala, jeśli wykładnik jest ujemny. Jeśli wykładnik jest dodatni, skala wyniku jest iloczynem minimum skali pierwszego wyrażenia i wartości wykładnika oraz maksimum skali i skali pierwszego wyrażenia. (np. scale(a^b)=min(scale(a)*b, max( scale, scale(a))).) Należy zauważyć, że expr^0 zawsze zwróci wartość z 1.

( expr )

Zmienia to standardowy priorytet wymuszania oceny wyrażenia.

var = expr

Zmiennej przypisywana jest wartość wyrażenia.

var <op>= expr

Jest to równoważne z „var=var expr” z wyjątkiem tego, że część „var” jest oceniana tylko raz. Może to mieć znaczenie, jeśli „var” jest tablicą.

Wyrażenia relacyjne są szczególnym rodzajem wyrażeń, które zawsze dają wynik 0 lub 1, 0, jeśli relacja jest fałszywa, i 1, jeśli relacja jest prawdziwa. Mogą one występować w dowolnym wyrażeniu prawnym. (POSIX bc wymaga, aby wyrażenia relacyjne były używane tylko w instrukcjach if, while i for oraz aby można było w nich przeprowadzić tylko jeden test relacyjny.) Operatory relacji to

expr1 < expr2

Wynikiem jest 1, jeśli wyrażenie1 jest dokładnie mniejsze niż wyrażenie2.

expr1 <= expr2

Wynikiem jest 1, jeśli wyrażenie1 jest mniejsze lub równe wyraż2.

expr1 > expr2

Wynikiem jest 1, jeśli wyrażenie1 jest ściśle większe niż wyrażenie2.

expr1 >= expr2

Wynikiem jest 1, jeśli wyrażenie1 jest większe lub równe wyraż2.

expr1 == expr2

Wynikiem jest 1, jeśli wyrażenie1 jest równe wyraż2.

expr1 != expr2

Wynikiem jest 1, jeśli wyrażenie1 nie jest równe wyraż2.

Operacje logiczne są również dozwolone. (POSIX bc NIE ma operacji boolowskich). Wynikiem wszystkich operacji boolowskich są 0 i 1 (dla fałszu i prawdy), jak w wyrażeniach relacyjnych. Operatory boolowskie to:

!expr

Wynikiem jest 1, jeśli wyrażenie wynosi 0.

expr && expr

Wynikiem jest 1, jeśli oba wyrażenia są niezerowe.

expr || expr

Wynikiem jest 1, jeśli jedno z wyrażeń jest niezerowe.

Priorytet wyrażenia jest następujący: (od najniższego do najwyższego)

|| operator, left associative
&& operator, left associative
! operator, nonassociative
Relational operators, left associative
Assignment operator, right associative
+ and - operators, left associative
*, / and % operators, left associative
^ operator, right associative
unary - operator, nonassociative
++ and -- operators, nonassociative

Ten priorytet został wybrany, aby programy bc zgodne z POSIX działały poprawnie. Spowoduje to, że użycie operatorów relacyjnych i logicznych będzie zachowywać się nietypowo w przypadku użycia z wyrażeniami przypisania. Rozważ wyrażenie:

a = 3 < 5

Większość programistów C założyłaby, że przypisuje to wynik „3 < 5” (wartość 1) zmiennej „a”. To, co robi w bc, to przypisanie wartości 3 do zmiennej „a”, a następnie porównanie 3 z 5. Najlepiej jest używać nawiasów, gdy używamy operatorów relacyjnych i logicznych z operatorami przypisania.

W bc jest jeszcze kilka wyrażeń specjalnych. Mają one związek z funkcjami zdefiniowanymi przez użytkownika i funkcjami standardowymi. Wszystkie są wyświetlane jako „nazwa(parametry)”. Zobacz sekcję dotyczącą funkcji dla funkcji zdefiniowanych przez użytkownika. Standardowe funkcje to:

length ( expression )

Wartością funkcji długości jest liczba cyfr znaczących w wyrażeniu.

read ( )

Funkcja read (rozszerzenie) odczyta liczbę ze standardowego wejścia, niezależnie od tego, gdzie ta funkcja występuje. Uwaga, może to powodować problemy z mieszaniem danych i programu na standardowym wejściu. Najlepszym zastosowaniem tej funkcji jest wcześniej napisany program, który wymaga wprowadzenia danych przez użytkownika, ale nigdy nie pozwala na wprowadzenie kodu programu przez użytkownika. Wartością funkcji read jest liczba odczytana ze standardowego wejścia przy użyciu aktualnej wartości zmiennej ibase dla podstawy konwersji.

scale ( expression )

Wartość funkcji skali to liczba cyfr po przecinku w wyrażeniu.

sqrt ( expression )

Wartością funkcji sqrt jest pierwiastek kwadratowy z wyrażenia. Jeśli wyrażenie jest ujemne, generowany jest błąd czasu wykonywania.

SPRAWOZDANIA

Instrukcje (jak w większości języków algebraicznych) zapewniają sekwencjonowanie oceny wyrażeń. W bc instrukcje są wykonywane „tak szybko, jak to możliwe”. Wykonanie ma miejsce, gdy napotkano znak nowej linii i istnieje jedna lub więcej kompletnych instrukcji. Dzięki temu natychmiastowemu wykonaniu znaki nowej linii są bardzo ważne w bc. W rzeczywistości zarówno średnik, jak i znak nowej linii są używane jako separatory instrukcji. Niewłaściwie umieszczona nowa linia spowoduje błąd składni. Ponieważ znaki nowej linii są separatorami instrukcji, możliwe jest ukrycie nowej linii za pomocą znaku ukośnika odwrotnego. Sekwencja „\”, gdzie to znak nowej linii, wygląda na bc jako spacja zamiast nowej linii. Lista instrukcji to seria instrukcji oddzielonych średnikami i znakami nowej linii. Poniżej znajduje się lista instrukcji bc i ich działania: (Rzeczy ujęte w nawiasy kwadratowe ([]) są opcjonalnymi częściami instrukcji.)

expression

To stwierdzenie robi jedną z dwóch rzeczy. Jeśli wyrażenie zaczyna się od " ...", jest uważane za instrukcję przypisania. Jeśli wyrażenie nie jest instrukcją przypisania, jest obliczane i drukowane na wyjściu. Po wydrukowaniu numeru drukowana jest nowa linia. Na przykład „a=1” to instrukcja przypisania, a „(a=1)” to wyrażenie z osadzonym przypisaniem. Wszystkie drukowane liczby są drukowane w podstawie określonej przez zmienną obase. Dozwolone wartości dla obase to 2 do BC_BASE_MAX. (Patrz rozdział OGRANICZENIA.) Dla baz od 2 do 16 używana jest zwykła metoda zapisu liczb. Dla podstaw większych niż 16, bc używa wieloznakowej metody drukowania liczb, w której każda wyższa cyfra bazowa jest drukowana jako liczba podstawowa 10. Cyfry wieloznakowe są oddzielone spacjami. Każda cyfra zawiera liczbę znaków wymaganych do przedstawienia wartości dziesiętnej „obase-1”. Ponieważ liczby mają dowolną precyzję, niektóre liczby mogą nie nadawać się do wydrukowania w jednym wierszu wyjściowym. Te długie liczby zostaną podzielone między wiersze przy użyciu „\” jako ostatniego znaku w wierszu. Maksymalna liczba znaków drukowanych w linii wynosi 70. Ze względu na interaktywny charakter bc, wydrukowanie liczby powoduje efekt uboczny przypisania drukowanej wartości do specjalnej zmiennej last . Pozwala to użytkownikowi odzyskać ostatnią wydrukowaną wartość bez konieczności ponownego wpisywania wyrażenia, które wydrukowało liczbę. Przypisanie do last jest dozwolone i spowoduje zastąpienie ostatniej wydrukowanej wartości przypisaną wartością. Nowo przypisana wartość pozostanie do momentu wydrukowania następnej liczby lub przypisania innej wartości do last. (Niektóre instalacje mogą zezwalać na użycie pojedynczej kropki (.), która nie jest częścią liczby, jako krótkiej notacji dla ostatni.)

string

Ciąg jest drukowany na wyjściu. Łańcuchy zaczynają się od znaku podwójnego cudzysłowu i zawierają wszystkie znaki aż do następnego znaku podwójnego cudzysłowu. Wszystkie znaki są traktowane dosłownie, łącznie z każdą nową linią. Po łańcuchu nie jest drukowany żaden znak nowej linii.

print list

Instrukcja print (rozszerzenie) zapewnia inną metodę wyjścia. „Lista” to lista ciągów znaków i wyrażeń oddzielonych przecinkami. Każdy ciąg lub wyrażenie jest drukowane w kolejności na liście. Nie jest drukowany kończący znak nowej linii. Wyrażenia są oceniane, a ich wartość jest drukowana i przypisywana do zmiennej last. Ciągi w instrukcji print są drukowane na wyjściu i mogą zawierać znaki specjalne. Znaki specjalne zaczynają się od znaku ukośnika odwrotnego (\). Znaki specjalne rozpoznawane przez bc to „a” (alarm lub dzwonek), „b” (cofnięcie), „f” (wysunięcie strony), „n” (nowa linia), „r” (karetka return), „q” (podwójny cudzysłów), „t” (tabulacja) i „\” (ukośnik odwrotny). Każdy inny znak następujący po odwrotnym ukośniku zostanie zignorowany.

{ statement_list }

To jest zdanie złożone. Pozwala na grupowanie wielu instrukcji w celu wykonania.

if ( expression ) statement1 [else statement2]

Instrukcja if ocenia wyrażenie i wykonuje instrukcję1 lub instrukcję2 w zależności od wartości wyrażenia. Jeśli wyrażenie jest niezerowe, wykonywana jest instrukcja1. Jeśli występuje instrukcja2, a wartość wyrażenia wynosi 0, wykonywana jest instrukcja2. (Klauzula else jest rozszerzeniem.)

while ( expression ) statement

Instrukcja while wykona instrukcję, gdy wyrażenie jest niezerowe. Ocenia wyrażenie przed każdym wykonaniem instrukcji. Zakończenie pętli jest spowodowane zerową wartością wyrażenia lub wykonaniem instrukcji break.

for ( [expression1] ; [expression2] ; [expression3] ) statement

Instrukcja for steruje wielokrotnym wykonywaniem instrukcji. Wyrażenie1 jest oceniane przed pętlą. Wyrażenie2 jest oceniane przed każdym wykonaniem instrukcji. Jeśli jest różna od zera, instrukcja jest oceniana. Jeśli wynosi zero, pętla jest zakończona. Po każdym wykonaniu instrukcji wyrażenie3 jest oceniane przed ponowną oceną wyrażenia2. Jeśli brakuje wyrażenia 1 lub wyrażenia 3, nic nie jest oceniane w momencie, w którym byłyby oceniane. Jeśli brakuje wyrażenia2, jest to równoznaczne z zastąpieniem wyrażenia2 wartością 1. (Opcjonalne wyrażenia są rozszerzeniem. POSIX bc wymaga wszystkich trzech wyrażeń.) Poniżej znajduje się równoważny kod instrukcji for:

expression1;
while (expression2) {
   statement;
   expression3;
}
break

Ta instrukcja powoduje wymuszone wyjście z ostatniej dołączającej instrukcji while lub for.

continue

Instrukcja continue (rozszerzenie) powoduje, że najnowsza instrukcja dołączająca for rozpoczyna następną iterację.

halt

Instrukcja halt (rozszerzenie) jest wykonywaną instrukcją, która powoduje zamknięcie procesora bc tylko wtedy, gdy jest wykonywana. Na przykład „if (0 == 1) halt” nie spowoduje zakończenia bc, ponieważ zatrzymanie nie jest wykonywane.

return

Zwróć wartość 0 z funkcji. (Patrz rozdział poświęcony funkcjom).

return ( expression )

Zwróć wartość wyrażenia z funkcji. (Zobacz rozdział poświęcony funkcjom.) Jako rozszerzenie, nawiasy nie są wymagane.

Pseudostwierdzenia

Te stwierdzenia nie są stwierdzeniami w tradycyjnym znaczeniu. Nie są to wykonywane instrukcje. Ich funkcja jest wykonywana w czasie „kompilacji”.

limits

Wydrukuj lokalne limity narzucone przez lokalną wersję bc. To jest rozszerzenie.

quit

Kiedy instrukcja quit jest odczytywana, procesor bc zostaje zakończony, niezależnie od tego, gdzie znajduje się instrukcja quit. Na przykład „if (0 == 1) quit” spowoduje zakończenie działania bc.

warranty

Wydrukuj dłuższą informację o gwarancji. To jest rozszerzenie.

FUNKCJE

Funkcje zapewniają metodę definiowania obliczeń, które można wykonać później. Funkcje w bc zawsze obliczają wartość i zwracają ją wywołującemu. Definicje funkcji są „dynamiczne” w tym sensie, że funkcja jest niezdefiniowana, dopóki na wejściu nie zostanie napotkana definicja. Ta definicja jest następnie używana, dopóki nie zostanie napotkana inna funkcja definicji dla tej samej nazwy. Nowa definicja zastępuje starszą definicję. Funkcja jest zdefiniowana w następujący sposób:

define name ( parameters ) { newline
    auto_list   statement_list }

Wywołanie funkcji to po prostu wyrażenie w postaci „nazwa(parametry)”.

Parametry to liczby lub tablice (rozszerzenie). W definicji funkcji zero lub więcej parametrów definiuje się poprzez podanie ich nazw oddzielonych przecinkami. Wszystkie parametry są parametrami wywołania według wartości. Tablice są określone w definicji parametru za pomocą zapisu „nazwa[]”. W wywołaniu funkcji rzeczywiste parametry są pełnymi wyrażeniami dla parametrów liczbowych. Ta sama notacja jest używana do przekazywania tablic, jak do definiowania parametrów tablicy. Nazwana tablica jest przekazywana przez wartość do funkcji. Ponieważ definicje funkcji są dynamiczne, podczas wywoływania funkcji sprawdzane są numery i typy parametrów. Jakakolwiek niezgodność w liczbie lub typach parametrów spowoduje błąd w czasie wykonywania. W przypadku wywołania niezdefiniowanej funkcji wystąpi również błąd wykonania.

auto_list to opcjonalna lista zmiennych do użytku „lokalnego”. Składnia listy automatycznej (jeśli istnieje) to „auto nazwa, ... ;”. (Średnik jest opcjonalny.) Każdy nazwa jest nazwą zmiennej automatycznej. Tablice mogą być określone przy użyciu tej samej notacji, co w parametrach. Wartości tych zmiennych są umieszczane na stosie na początku funkcji. Zmienne są następnie inicjowane na zero i używane podczas wykonywania funkcji. Przy wyjściu z funkcji zmienne te są usuwane, aby przywrócić pierwotną wartość (w momencie wywołania funkcji) tych zmiennych. Parametry są tak naprawdę zmiennymi automatycznymi, które są inicjowane wartością podaną w wywołaniu funkcji. Zmienne automatyczne różnią się od tradycyjnych zmiennych lokalnych, ponieważ jeśli funkcja A wywołuje funkcję B, B może uzyskać dostęp do zmiennych automatycznych funkcji A, używając tej samej nazwy, chyba że funkcja B nazwała je zmiennymi automatycznymi. Ze względu na fakt, że zmienne i parametry auto są umieszczane na stosie, bc obsługuje funkcje rekurencyjne.

Ciało funkcji to lista instrukcji bc. Ponownie instrukcje są oddzielone średnikami lub znakami nowej linii. Instrukcje return powodują zakończenie funkcji i zwrócenie wartości. Istnieją dwie wersje instrukcji return. Pierwsza postać, „return”, zwraca wartość 0 do wyrażenia wywołującego. Druga postać, „return ( expression )”, oblicza wartość wyrażenia i zwraca tę wartość do wyrażenia wywołującego. Na końcu każdej funkcji znajduje się domniemany „return (0)”. Pozwala to funkcji zakończyć i zwrócić 0 bez jawnej instrukcji return.

Funkcje zmieniają również użycie zmiennej ibase. Wszystkie stałe w ciele funkcji zostaną przekonwertowane przy użyciu wartości ibase w momencie wywołania funkcji. Zmiany ibase będą ignorowane podczas wykonywania funkcji, z wyjątkiem standardowej funkcji read, która zawsze użyje bieżącej wartości ibase dla konwersja liczb.

Do funkcji dodano kilka rozszerzeń. Po pierwsze, format definicji został nieco złagodzony. Norma wymaga, aby otwierający nawias klamrowy znajdował się w tej samej linii co słowo kluczowe define, a wszystkie pozostałe części w kolejnych liniach. Ta wersja bc zezwala na dowolną liczbę znaków nowej linii przed i po nawiasie otwierającym funkcji. Na przykład następujące definicje są legalne.

define d (n) { return (2*n); }
define d (n)
  { return (2*n); }

Funkcje można zdefiniować jako void. Funkcja void nie zwraca żadnej wartości i dlatego nie może być używana w żadnym miejscu, które wymaga wartości. Funkcja void nie generuje żadnych danych wyjściowych, gdy jest wywoływana sama w linii wejściowej. Słowo kluczowe void jest umieszczane pomiędzy słowem kluczowym define a nazwą funkcji. Rozważmy na przykład następującą sesję.

define py (y) { print "--->", y, "<---", "\n"; }
define void px (x) { print "--->", x, "<---", "\n"; }
py(1)
--->1<---
0
px(1)
--->1<---

Ponieważ py nie jest funkcją typu void, wywołanie funkcji py(1) powoduje wyświetlenie żądanego wyniku, a następnie wydrukowanie drugiego wiersza, który jest wartością funkcji. Ponieważ wartość funkcji, której nie podano jawnej instrukcji return, wynosi zero, wypisywane jest zero. Dla px(1) żadne zero nie jest drukowane, ponieważ funkcja jest pustą funkcją.

Dodano również wywołanie przez zmienną dla tablic. Aby zadeklarować wywołanie przez tablicę zmiennych, deklaracja parametru tablicy w definicji funkcji wygląda następująco: „*nazwa[]”. Wywołanie funkcji pozostaje takie samo jak wywołanie tablic wartości.

BIBLIOTEKA MATEMATYCZNA

Jeśli bc zostanie wywołane z opcją -l, biblioteka matematyczna zostanie wstępnie załadowana, a domyślna skala zostanie ustawiona na 20. Funkcje matematyczne obliczą swoje wyniki zgodnie ze skalą ustawioną w czas ich wezwania. Biblioteka matematyczna definiuje następujące funkcje:

s (x)

Sinus x, x jest w radianach.

c (x)

Cosinus x, x jest w radianach.

a (x)

Arcus tangens x, arcus tangens zwraca radiany.

l (x)

Logarytm naturalny x.

e (x)

Funkcja wykładnicza podnoszenia e do wartości x.

j (n,x)

Funkcja Bessela rzędu liczb całkowitych n od x .

PRZYKŁADY

W /bin/sh następujące polecenie przypisze wartość „pi” do zmiennej powłoki pi.

pi=$(echo "scale=10; 4*a(1)" | bc -l)

Poniżej znajduje się definicja funkcji wykładniczej używanej w bibliotece matematycznej. Ta funkcja jest napisana w POSIX bc.

scale = 20

/* Uses the fact that e^x = (e^(x/2))^2
   When x is small enough, we use the series:
     e^x = 1 + x + x^2/2! + x^3/3! + ...
*/

define e(x) {
  auto  a, d, e, f, i, m, v, z

  /* Check the sign of x. */
  if (x<0) {
    m = 1
    x = -x
  } 

  /* Precondition x. */
  z = scale;
  scale = 4 + z + .44*x;
  while (x > 1) {
    f += 1;
    x /= 2;
  }

  /* Initialize the variables. */
  v = 1+x
  a = x
  d = 1

  for (i=2; 1; i++) {
    e = (a *= x) / (d *= i)
    if (e == 0) {
      if (f>0) while (f--)  v = v*v;
      scale = z
      if (m) return (1/v);
      return (v/1);
    }
    v += e
  }
}

Poniżej znajduje się kod, który wykorzystuje rozszerzone funkcje bc do implementacji prostego programu do obliczania sald na książeczce czekowej. Ten program najlepiej przechowywać w pliku, aby można go było używać wiele razy bez konieczności ponownego wpisywania go przy każdym użyciu.

scale=2
print "\nCheck book program!\n"
print "  Remember, deposits are negative transactions.\n"
print "  Exit by a 0 transaction.\n\n"

print "Initial balance? "; bal = read()
bal /= 1
print "\n"
while (1) {
  "current balance = "; bal
  "transaction? "; trans = read()
  if (trans == 0) break;
  bal -= trans
  bal /= 1
}
quit

Poniżej znajduje się definicja rekurencyjnej funkcji silni.

define f (x) {
  if (x <= 1) return (1);
  return (f(x-1) * x);
}

OPCJE READLINE I LIBEDIT

GNU bc można skompilować (za pomocą opcji konfiguracyjnej), aby używać biblioteki GNU readline lub biblioteki BSD libedit. Pozwala to użytkownikowi na edycję linii przed wysłaniem ich do bc. Pozwala również na historię wcześniej wpisywanych wierszy. Gdy ta opcja jest zaznaczona, bc ma jeszcze jedną specjalną zmienną. Ta specjalna zmienna, historia, to liczba zachowanych wierszy historii. Dla readline wartość -1 oznacza, że zachowywana jest nieograniczona liczba linii historii. Ustawienie wartości historia na liczbę dodatnią ogranicza liczbę wierszy historii do podanej liczby. Wartość 0 wyłącza funkcję historii. Wartość domyślna to 100. Więcej informacji można znaleźć w instrukcjach obsługi bibliotek GNU readline, history i BSD libedit. Nie można jednocześnie włączyć readline i libedit.

RÓŻNICE

Ta wersja bc została zaimplementowana z wersji roboczej POSIX P1003.2/D11 i zawiera kilka różnic i rozszerzeń w stosunku do wersji roboczej i tradycyjnych implementacji. Nie jest implementowany w tradycyjny sposób przy użyciu dc(1). Ta wersja jest pojedynczym procesem, który analizuje i przeprowadza translację kodu bajtowego programu. Istnieje opcja „nieudokumentowana” (-c), która powoduje, że program wysyła kod bajtowy na standardowe wyjście zamiast go uruchamiać. Był używany głównie do debugowania parsera i przygotowywania biblioteki matematycznej.

Głównym źródłem różnic są rozszerzenia, w przypadku których funkcja jest rozszerzana w celu dodania większej funkcjonalności, oraz dodatki, w których dodawane są nowe funkcje. Poniżej znajduje się lista różnic i rozszerzeń.

LANG environment

Ta wersja nie jest zgodna ze standardem POSIX w przetwarzaniu zmiennej środowiskowej LANG i wszystkich zmiennych środowiskowych zaczynających się od LC_.

names

Tradycyjny i POSIX bc mają jednoliterowe nazwy funkcji, zmiennych i tablic. Zostały one rozszerzone do nazw wieloznakowych, które zaczynają się od litery i mogą zawierać litery, cyfry i znak podkreślenia.

Strings

Ciągi nie mogą zawierać znaków NUL. POSIX mówi, że wszystkie znaki muszą być zawarte w łańcuchach.

last

POSIX bc nie ma zmiennej last. Niektóre implementacje bc używają kropki (.) w podobny sposób.

comparisons

POSIX bc pozwala na porównania tylko w instrukcji if, while i drugim wyrażeniu instrukcji for. Ponadto w każdej z tych instrukcji dozwolona jest tylko jedna operacja relacyjna.

if statement, else clause

POSIX bc nie ma klauzuli else.

for statement

POSIX bc wymaga, aby wszystkie wyrażenia były obecne w instrukcji for.

&&, ||, !

POSIX bc nie ma operatorów logicznych.

read function

POSIX bc nie ma funkcji odczytu.

print statement

POSIX bc nie ma instrukcji print .

continue statement

POSIX bc nie ma instrukcji continue.

return statement

POSIX bc wymaga nawiasów wokół wyrażenia zwracanego.

array parameters

POSIX bc nie obsługuje (obecnie) w pełni parametrów tablicowych. Gramatyka POSIX dopuszcza tablice w definicjach funkcji, ale nie zapewnia metody określania tablicy jako rzeczywistego parametru. (Najprawdopodobniej jest to przeoczenie w gramatyce.) Tradycyjne implementacje bc mają tylko parametry tablicy typu wywołanie według wartości.

function format

POSIX bc wymaga nawiasu otwierającego w tym samym wierszu co słowo kluczowe define i instrukcji auto w następnym wierszu.

=+, =-, =*, =/, =%, =^

POSIX bc nie wymaga definiowania tych „starych” operatorów przypisania. Ta wersja może zezwalać na te przypisania „w starym stylu”. Użyj oświadczenia o ograniczeniach, aby sprawdzić, czy zainstalowana wersja je obsługuje. Jeśli obsługuje operatory przypisania „starego stylu”, instrukcja „a =- 1” zmniejszy a o 1 zamiast ustawiania a na wartość -1.

spaces in numbers

Inne implementacje bc dopuszczają spacje w liczbach. Na przykład „x=1 3” przypisze zmiennej x wartość 13. Ta sama instrukcja spowodowałaby błąd składni w tej wersji bc.

errors and execution

Ta implementacja różni się od innych implementacji pod względem tego, jaki kod zostanie wykonany, gdy w programie zostaną znalezione błędy składniowe i inne. Jeśli w definicji funkcji zostanie znaleziony błąd składniowy, funkcja odzyskiwania po błędzie spróbuje znaleźć początek instrukcji i kontynuować analizę funkcji. Po znalezieniu błędu składni w funkcji funkcja nie będzie wywoływalna i stanie się niezdefiniowana. Błędy składniowe w interaktywnym kodzie wykonania spowodują unieważnienie bieżącego bloku wykonania. Blok wykonania kończy się końcem wiersza, który pojawia się po pełnej sekwencji instrukcji. Na przykład,

a = 1
b = 2

ma dwa bloki wykonawcze i

{ a = 1
  b = 2 }

ma jeden blok wykonawczy. Każdy błąd w czasie wykonywania spowoduje przerwanie wykonywania bieżącego bloku wykonawczego. Ostrzeżenie w czasie wykonywania nie zakończy bieżącego bloku wykonania.

Interrupts

Podczas sesji interaktywnej sygnał SIGINT (zwykle generowany przez znak control-C z terminala) spowoduje przerwanie wykonywania bieżącego bloku wykonawczego. Wyświetli się błąd „runtime” wskazujący, która funkcja została przerwana. Po wyczyszczeniu wszystkich struktur środowiska uruchomieniowego zostanie wydrukowana wiadomość informująca użytkownika, że bc jest gotowy do wprowadzenia dalszych danych. Wszystkie wcześniej zdefiniowane funkcje pozostają zdefiniowane, a wartością wszystkich zmiennych innych niż auto są wartości w punkcie przerwania. Wszystkie zmienne automatyczne i parametry funkcji są usuwane podczas procesu czyszczenia. Podczas sesji nieinteraktywnej sygnał SIGINT zakończy cały przebieg bc.

GRANICE

Poniżej przedstawiono ograniczenia obowiązujące obecnie dla tego procesora bc. Niektóre z nich mogły zostać zmienione przez instalację. Użyj instrukcji limitów, aby zobaczyć rzeczywiste wartości.

BC_BASE_MAX

Maksymalna podstawa wyjściowa jest obecnie ustawiona na 999. Maksymalna podstawa wejściowa to 16.

BC_DIM_MAX

Obecnie jest to arbitralny limit 65535 zgodnie z dystrybucją. Twoja instalacja może wyglądać inaczej.

BC_SCALE_MAX

Liczba cyfr po przecinku jest ograniczona do INT_MAX cyfr. Również liczba cyfr przed przecinkiem jest ograniczona do INT_MAX cyfr.

BC_STRING_MAX

Limit liczby znaków w łańcuchu wynosi INT_MAX znaków.

exponent

Wartość wykładnika w operacji podnoszenia (^) jest ograniczona do LONG_MAX.

variable names

Obecny limit liczby unikalnych nazw wynosi 32767 dla każdej z prostych zmiennych, tablic i funkcji.

ZMIENNE ŚRODOWISKA

bc przetwarza następujące zmienne środowiskowe:

POSIXLY_CORRECT

Jest to to samo, co opcja -s.

BC_ENV_ARGS

Jest to kolejny mechanizm uzyskiwania argumentów do bc. Format jest taki sam jak argumentów wiersza poleceń. Argumenty te są przetwarzane jako pierwsze, więc wszystkie pliki wymienione w argumentach środowiskowych są przetwarzane przed plikami argumentów wiersza poleceń. Pozwala to użytkownikowi ustawić „standardowe” opcje i pliki, które mają być przetwarzane przy każdym wywołaniu bc. Pliki w zmiennych środowiskowych zazwyczaj zawierają definicje funkcji, które użytkownik chce zdefiniować przy każdym uruchomieniu bc.

BC_LINE_LENGTH

Powinna to być liczba całkowita określająca liczbę znaków w linii wyjściowej dla liczb. Obejmuje to ukośnik odwrotny i znaki nowej linii dla długich liczb. Jako rozszerzenie wartość zero wyłącza funkcję wielowierszową. Każda inna wartość tej zmiennej, która jest mniejsza niż 3, ustawia długość linii na 70.

DIAGNOSTYKA

Jeśli nie można otworzyć żadnego pliku w wierszu poleceń, bc zgłosi, że plik jest niedostępny i zakończy działanie. Istnieją również diagnostyka czasu kompilacji i wykonywania, która powinna być oczywista.

BŁĘDY

Odzyskiwanie błędów nie jest jeszcze bardzo dobre.

Wysyłaj raporty o błędach na adres bug-bc@gnu.org. Pamiętaj, aby umieścić słowo ``bc'' gdzieś w polu ``Temat:''.

AUTOR

Philip A. Nelson
philnelson@acm.org

PODZIĘKOWANIE

Autor pragnie podziękować Steve'owi Sommarsowi (Steve.Sommars@att.com) za jego rozległą pomoc w testowaniu implementacji. Padło wiele świetnych sugestii. To dużo lepszy produkt dzięki jego zaangażowaniu.