Wprowadzenie
Tematem zadania są drzewa i ich obiegi oraz składnia i semantyka języków programowania.
Program w języku np0 składa się z programu głównego oraz definicji bezparametrowych funkcji, których nazwy są dużymi literami.
Tekstowy zapis programu rozpoczyna się od treści programu głównego, po której następuje, być może pusty, ciąg par: nazwa funkcji oraz jej treść.
Treść programu głównego i treści funkcji są wyrażeniami zbudowanymi z operacji mających zero, jeden lub dwa argumenty. Każda operacja jest reprezentowana przez jeden znak. Wyrażenie jest więc drzewem binarnym znaków, w którym węzły operacji bezargumentowych to liście, operacje jednoargumentowe mają tylko jedno (lewe) poddrzewo niepuste a dwuargumentowe mają oba poddrzewa niepuste.
Tekstowy zapis wyrażenia będzie prefiksowy - najpierw podamy znak operacji w korzeniu, następnie lewe poddrzewo (o ile nie jest puste) i prawe poddrzewo (jeśli nie puste).
Wszystkie wartości, którymi posługujemy się w języku np0, są liczbami całkowitymi. Przechowujemy je w pamięci programu, która składa się z 26 zmiennych o nazwach, będących małymi literami i jednej tablicy
nieograniczonego rozmiaru.
Do elementów tablicy odwołujemy się za pomocą indeksu, który jest dowolną liczbą całkowitą (nie koniecznie nieujemną). Jeśli element tablicy o zadanym indeksie jeszcze nie istnieje, jest tworzony w chwili odwołania
się do niego.
Wartości początkowe wszystkich komórek pamięci, zarówno zmiennych jak i elementów tablicy, są równe 0.
Wykonanie programu w języku np0 oznacza obliczenie wyrażenia, które jest treścią programu głównego. Wartość będąca wynikiem tego obliczenia jest ignorowana.
Poniżej znajduje się spis operacji języka np0 pogrupowanych wg liczby argumentów.
Operacje bezargumentowe:
- ' '
-
wartość 32
- '@'
-
wartość 10
- '0' .. '9'
-
wartości od 0 do 9
- 'a' .. 'z'
-
odwołanie do zmiennej o podanej nazwie. Może wystąpić w miejscu, w którym oczekujemy wartości, a także jako argument operacji wpisującej wartość do komórki pamięci (operacje '(', '{', '[', ']', ':')
- 'A' .. 'Z'
-
wynik funkcji o podanej nazwie, czyli wartość wyrażenia będącego jej treścią. Jeśli funkcja o tej nazwie nie została zdefiniowana, jej wywołanie kończy pracę programu
Operacje jednoargumentowe:
- '('
-
wczytuje z wejścia znak, wpisuje jego kod do komórki pamięci, będącej argumentem i zwraca go jako wynik. Jeśli na wejściu jest koniec danych, zamiast kodu znaku wpisuje i zwraca -1
- '{'
-
wczytuje z wejścia liczbę całkowitą, wpisuje jej wartość do komórki pamięci, będącej argumentem i zwraca ja jako wynik
- ')'
-
wypisuje znak, którego kod jest wartością argumentu i zwraca ten kod jako wynik
- '}'
-
wypisuje liczbę, będącą wartością argumentu i zwraca ją jako wynik
- '$'
-
odwołanie do elementu tablicy o indeksie będącym wartością argumentu. Może wystąpić w miejscu, w którym oczekujemy wartości, a także jako argument operacji wpisującej wartość do komórki pamięci (operacje '(', '{', '[', ']', ':')
- '['
-
zwraca wartość komórki pamięci reprezentowanej przez argument i zwiększa ją o 1 (zwraca wartość, jaką miała przed zwiększeniem)
- ']'
-
zmniejsza o jeden wartość komórki pamięci reprezentowanej przez argument i zwraca ją jako wynik (zwraca wartość, jaką komórka uzyskała po zmniejszeniu)
- '!'
-
zwraca 1, jeśli wartością argumentu jest 0 lub 0, jeśli wartością argumentu nie jest 0
Operacje dwuargumentowe (jeśli liczymy oba argumenty, to robimy to w kolejności: najpierw lewy, później prawy):
- '+'
-
liczy sumę wartości lewego i prawego argumentu
- '-'
-
liczy różnicę wartości lewego i prawego argumentu
- '*'
-
liczy iloczyn wartości lewego i prawego argumentu
- '/'
-
liczy iloraz wartości lewego i prawego argumentu
- '%'
-
liczy resztę z dzielenia wartości lewego i prawego argumentu
- '<'
-
jeśli wartość lewego argumentu jest mniejsza od prawego, daje 1, wpp. 0
- '>'
-
jeśli wartość lewego argumentu jest większa od prawego, daje 1, wpp. 0
- '='
-
jeśli wartość lewego argumentu jest równa wartości prawego, daje 1, wpp. 0
- '#'
-
zwraca wartość 10 * arg1 + arg2, gdzie arg1 to wartość lewego argumentu a arg2 to wartość prawego
- ':'
-
przypisanie do komórki pamięci reprezentowanej przez lewy argument wartości prawego argumentu. Daje przypisywaną wartość.
- ';'
-
daje wartość prawego argumentu (ale liczy także lewy)
- ','
-
daje wartość lewego argumentu (ale liczy także prawy)
- '&'
-
jeśli wartością lewego argumentu jest 0, daje ją, jeśli nie, liczy i daje wartość prawego argumentu
- '|'
-
jeśli wartością lewego argumentu nie jest 0, daje ją, jeśli jest 0, liczy i daje wartość prawego argumentu
- '\'
-
daje wartość lewego argumentu. Dodatkowo, jeśli było nią 0, liczy prawy argument, ale ignoruje jego wartość
- '?'
-
ma dwa warianty, w zależności od postaci prawego argumentu. Jeśli prawym argumentem jest ',', to liczy swój lewy argument i, jeśli jego wartość jest niezerowa, liczy i daje wartość lewego argumentu ',', a wpp. liczy i daje wartość prawego argumentu ','. Jeśli prawym argumentem nie jest ',', to daje wartość lewego argumentu. Dodatkowo, jeśli była niezerowa, liczy prawy argument, ale ignoruje jego wartość
- '^'
-
w pętli, dopóki wartość lewego argumentu jest niezerowa, liczy prawy argument (jak w pętli
while
). Daje wynik ostatniego obliczenia prawego argumentu, lub 0, jeśli nie był on liczony ani razu
- '~'
-
w pętli liczy lewy argument a następnie prawy, dopóki obliczenie prawego daje wartość 0 (jak w pętli
repeat-until
). Daje wynik ostatniego obliczenia lewego argumentu
Polecenie
Napisz interpreter języka np0, czyli program, który wykona program w języku np0 przekazany mu jako argument.
Przykłady
Program wywołany poleceniem:
./zad4 ');)+))+)-)#72373@'
powinien wypisać na wyjście:
Program wywołany poleceniem:
powinien wypisać na wyjście:
1
4
9
16
25
36
49
64
81
100
Program wywołany poleceniem:
powinien skopiować tekst wejściowy na wyjście.
Program wywołany poleceniem:
./zad4 '~;:k9;^]k}%+wk2)@=[w7'
powinien wypisać na wyjście:
01010101
10101010
01010101
10101010
01010101
10101010
01010101
10101010
Program wywołany poleceniem:
./zad4 ';^{$p[p^p), }$]p'
powinien wczytać z wejścia ciąg liczb zakończony zerem i wypisać te liczby na wyjście w kolejności odwróconej.
Program wywołany poleceniem:
./zad4 ';;:f{x^]x:f*fx}f'
powinien wczytać z wejścia liczbę całkowitą i wypisać na wyjście jej silnię.
Program wywołany poleceniem:
./zad4 ';{x}FF?]x,*+1xF1'
powinien zrobić to, co program z poprzedniego przykładu.
Program wywołany poleceniem:
./zad4 ';}{x;)#61;:p2;^>xp?%xp,[p:x/x,}p)#42}x'
powinien wczytać z wejścia liczbę całkowitą i wypisać na wyjście jej rozkład na czynniki pierwsze.
Wskazówka
Do rozwiązania zadania przyda się instrukcja case
.