Wprowadzenie
Tematem zadania jest interpreter, czyli "program wykonujący programy" w języku Malina ("MAłe LItery i NAwiasy klamrowe").
Składnia programów w Malinie opisana jest gramatyką:
Program -> CiągInstrukcji
CiągInstrukcji -> ε | CiągInstrukcji Instrukcja
Instrukcja -> InstrukcjaOdejmowania | InstrukcjaPętli
InstrukcjaOdejmowania -> Zmienna Zmienna
InstrukcjaPętli -> Zmienna { CiągInstrukcji }
Zmienna -> ZmiennaZwykła | ZmiennaSpecjalna
ZmiennaZwykła -> a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x
ZmiennaSpecjalna -> y|z
ε jest tu oznaczeniem słowa pustego a małe litery i nawiasy klamrowe to symbole końcowe gramatyki. Oprócz małych liter i klamerek, żadne inne znaki, nawet spacje, w programie nie mogą wystąpić.
Program w Malinie jest ciągiem instrukcji, które wykonujemy w kolejności od pierwszej do ostatniej.
Mamy dwa rodzaje instrukcji: odejmowanie i pętlę.
Instrukcja odejmowania postaci Zmienna Zmienna
odejmuje wartość drugiej zmiennej od pierwszej. Np. instrukcji Maliny postaci ab
odpowiada w Pascalu a := a - b
.
Instrukcja pętli postaci Zmienna { CiągInstrukcji }
wykonuje ciąg instrukcji w klamerkach dopóki wartość zmiennej przed klamerką otwierającą jest większa od zera. Np. instrukcji Maliny postaci a{...}
odpowiada w Pascalu while a > 0 do begin ... end
.
Program w Malinie ma dostęp do 26 zmiennych o nazwach od a
do z
. Zmienne od a
do w
mają wartości początkowe 0, a zmienna x
ma wartość początkową 1. Dwie zmienne, y
i z
, mają specjalne znaczenie. Zmienna y
służy do realizacji wejścia/wyjścia liczbowego (od
"lYczby"), a zmienna z
do realizacji wejścia/wyjścia znakowego (od "Znaki").
Jeśli zmienna y
wystąpiła na drugiej pozycji w instrukcji przypisania lub przed klamerką otwierającą w pętli, pobranie jej wartości powoduje odczytanie z wejścia liczby całkowitej. Np. instrukcja
ay
wczytuje z wejścia liczbę i odejmuje ją od wartości zmiennej a
.
Jeśli zmienna y
wystąpiła na pierwszej pozycji w instrukcji odejmowania, wykonanie instrukcji powoduje wypisanie na wyjście liczby będącej wartością zmiennej z drugiej pozycji. Np. instrukcja ya
wypisuje na wyjście wartość zmiennej a
.
Jeśli zmienna z
wystąpiła na drugiej pozycji w instrukcji przypisania lub przed klamerką otwierającą w pętli, pobranie jej wartości powoduje odczytanie z wejścia znaku i przekazanie jego kodu. Gdyby na wejściu znaków nie było, przekazaną wartością będzie -1
. Np. instrukcja
az
wczytuje z wejścia znak i odejmuje jego kod od wartości zmiennej a
.
Jeśli zmienna z
wystąpiła na pierwszej pozycji w instrukcji odejmowania, wykonanie instrukcji powoduje wypisanie na wyjście znaku o kodzie, będącym wartością zmiennej z drugiej pozycji tej instrukcji. Np. instrukcja za
wypisuje na wyjście znak, którego kod jest zapisany na
zmiennej a
.
Polecenie
Napisz interpreter programów w języku Malina.
Interpreter powinien sprawdzić, czy argument, z którym został wywołany, jest poprawnym składniowo programem w Malinie i jeśli tak, wykonać go, a jeśli nie, wypisać odpowiedni komunikat o błędzie.
Przykłady programów w Malinie
Wczytanie liczby i wypisanie liczby o 1 większej:
Sumowanie wyrazów ciągu nieujemnych liczb zakończonego zerem:
Wypisywanie liczb od 10 do 1:
./malina axaxbaabaxcacac{yccx}
Wyznaczanie algorytmem Euklidesa NWD dwóch liczb wczytanych z wejścia:
./malina aybycac{dddcdbd{baddcc}c{abcc}ca}vbyv
Wypisanie na wyjście wiersza o treści Hello
:
./malina axaxbabacbcbdcdcededfefefczffafbfxfezffcfxzfzffcfbfxzfbcbxbxzb
Rozwiązanie zadania laboratoryjnego o medianie trzech liczb:
./malina aybycyeafbefe{dagbaaagbbbdee}haibjckjkawxlwk{yhkkll}l{mjmbnwm{yjmmnn}n{yinn}ll}
Rozwiązanie zadania laboratoryjnego o choince:
./malina axaxbabacbcbdcdcededsegegcgaucuanyini{kkkijkjxj{zsjx}jnjij{zgzgjx}zgzuix}icibixi{jnjxjxj{zsjx}zgzgzgzuix}
Informacje uzupełniające
Do rozwiązania zadania będzie potrzebnych kilka nowych funkcji standardowych. Przedstawimy je na przykładzie programu realizującego "szyfr" ROT13 (zastępowanie litery literą, która jest w alfabecie o 13 pozycji dalej, cyklicznie). Dla uproszczenia, poniższy program zajmuje się tylko małymi literami (rot13.pas):
program rot13;
var s : String;
i : Integer;
c : Char;
begin
if paramCount <> 1 then begin
writeln('Program oczekuje jednego argumentu');
halt
end;
s := paramStr(1);
for i := 1 to length(s) do begin
c := s[i];
if ('a' <= c) and (c <= 'z') then
write(chr(((ord(c) - ord('a') + 13) mod 26) + ord('a')))
else
write(c)
end;
writeln
end.
Mamy tu:
-
funkcje
paramCount()
i paramStr()
-
procedurę
halt
-
typ
String
, funkcję length()
, odczytywanie znaków napisu
-
typ
Char
, funkcje chr()
i ord()
Przyda się też wczytywanie z wejścia pojedynczych znaków za pomocą operacji read()
z argumentem będącym zmienną typu Char
oraz funkcja eof()
, której bezparametrowy wariant sprawdza, czy na wejściu jest koniec danych.