https://github.com/bandysc/binterpreter
Small interpreter for my small language written in Haskell for MIMUW JPP course.
https://github.com/bandysc/binterpreter
Last synced: 9 months ago
JSON representation
Small interpreter for my small language written in Haskell for MIMUW JPP course.
- Host: GitHub
- URL: https://github.com/bandysc/binterpreter
- Owner: BAndysc
- License: unlicense
- Created: 2018-05-15T01:16:02.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2018-05-15T01:37:36.000Z (about 8 years ago)
- Last Synced: 2025-04-12T06:14:37.917Z (over 1 year ago)
- Language: Haskell
- Size: 39.1 KB
- Stars: 3
- Watchers: 3
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Język BK
## Opis rozwiązania
Interpreter opiera się głównie na dwóch monadach: `State` i `Reader`. `Reader` trzyma "środowisko" - mapę nazw zmiennych w ich lokację. `State` trzyma mapę lokacji w wartości "w pamięci" oraz następną wolną "lokację". Nieużywane lokacje nie sa zwalniane.
## Opis plików
* `Types.hs` - wszystkie wykorzystane typy (poza type checkerem), opis w pliku
* `Memory.hs` - pomocnicze funkcje do zarządzania stanem pamięci
* `TypeChecker.hs` - moduł odpowiedzialny za statyczne typowanie
* `Interpreter.hs` - właściwy interpreter
* `main.hs` - plik początkowy interpretera
## Wymagania i kompilacja
Interpreter wymaga biblioteki `mtl`, został przetestowany na wersjach ghc 7.6.3 oraz 8.0.2.
```
cabal update
cabal install mtl
make
./interpreter
```
## Opis jęzka
### Program:
Program jest po prostu listą instrukcji oddzielonych średnikiem.
### Typy:
Dostępne są trzy typy proste: `int` (liczba całkowita), `bool` oraz `string`. Stałe liczbowe to po prostu `\-?[0-9]+`, stałe typu `bool` to `true` i `false`. Literały napisowe zapisujemy w cudzysłowach. Dodatkowo funkcje mogą zwracać typ `void`, czyli tak naprawdę nic nie zwracać.
Listy są typu `List`, gdzie T jest dowolnym innym typem.
Funkcje anonimowe są typu: `Fun<[Typ zwracany]([lista typów przyjmowanych argumentów])>`.
(W kolejnej wersji dostępne będą struktury, ich typ to `struct [IDENTYFIKATOR]`)
Typowanie jest statyczne.
##### Domyślne wartości typów przy inicjalizacji zmiennych:
* `int` -> `0`
* `bool` -> `false`
* `string` -> `""`
* `List` -> `[]`
* `Fun` -> brak (niedopuszczalna deklaracja zmiennej na funkcję bez funkcji)
### Arytmetyka
Operatory arytmetyczne: +, -, *, /, %, minus unarny
Operatory porównania: <, <=, >, >=, ==, !=
Operatory logiczne: and, or, not
### if:
```
if [WARUNEK] then
{
[Stmt]
}
else
{
[Stmt]
}
```
else jest opcjonalny. Warunek jest wyrażeniem, musi być typu `bool`. Nawiasy klamrowe są wymagane (w celu uniknięcia niejednoznaczności przy if _ then if _ then _ else _)
### while
```
while [WARUNEK] do
Stmt
```
Warunek jest sprawdzany *przed* każdym obrotem pętli. Warunek jest wyrażeniem, musi być typu `bool`.
### for
```
for [ZMIENNA] from [WYRAŻENIE [OD]] to [WYRAŻENIE [DO]] do
Stmt
```
Przed uruchomieniem pętli wyliczana jest wartość wyrażeń [od] i [do], muszą być typu int, instrukcja jest wykonywana ([DO] - [OD] + 1) razy, przed wykonaniem instrukcji na [zmienną] przypisana jest wartość wyrażenia. Gdy [DO] < [OD], to pętla nie jest wykonywana ani razu.
### for in
```
for [ZMIENNA] in [WYRAŻENIE]
Stmt
```
[WYRAŻENIE] musi być typu `List`, a [ZMIENNA] typu `T`. Instrukcja jest uruchamiane dla każdego elementu listy, przypisawszy wcześniej wartość tego elementu na [ZMIENNĄ].
### Funkcje
```
function NAZWA([ARGUMENT]) -> TYP_ZWRACANY
{
[Stmt]
}
// ARGUMENT ::= (ref)? T nazwa
```
Funkcje mają nazwę, listę argumentów oddzielonych przecinkami i typ zwracany. Funkcje mogą przyjmować typy `int`, `bool`, `string`, `List`, `struct [Ident]` oraz `Fun`. Takie też typy mogą zwrócić, dodatkowo mogą zwrócić typ `void`, co oznacza, że funkcja nic nie zwraca (jest "procedurą"). Dodatkowo argumenty fukcji mogą być poprzedzone modyfikatorem `ref` oznaczjącym, że argument przekazywany jest przez referencję. Domyślnie argumenty są przykazywane przez *wartość*.
##### Wołanie funkcji
```
nazwa_funkcji([lista argumentów])
```
Wywołujemy funkcję podając jej identyfikator i w nawiasie listę argumentów. Jeśli argument w definicji funkcji poprzedzony jest modyfikatorem `ref`, to także podczas wołania funkcji należy przekazać *zmienną* z modyfikatorem `ref` (i naturalnie nie może to być wtedy wyrażenie, tylko identyfikator!).
##### Funkcje anonimowe
```
Fun = [C] ([S]) -> T { Stmt; }
```
`[S]` to lista argumentów przyjmowanych przez funkcję anonimową, analogicznie jak w funkcjach.
`T` to typ zwracany analogicznie jak w funkcjach.
`C` to lista identyfikatorów, tzw. "Capture Group", których *wartość* będzie widoczna w ciele lambdy. UWAGA: wartość tych zmiennych jest wyliczana w momencie deklaracji lambdy. Zatem kod:
```
int x = 10;
Fun f = [x] () -> void { print x };
x = 20;
f();
```
Spowoduje wypisanie wartości `10`. W ciele lambdy nie można się odwoływać do innych zmiennych niż te z `capture groupy` oraz argumentów.
##### Funkcje zagnieżdżone
Funkcja można zagnieżdżać, tzn. można deklarować funkcje w funkcji. Funkcja zagnieżdżona ma dostęp do `wszystkich` identyfikatorów widocznych w zewnętrzenej funkcji. Funkcje zagnieżdżone naturalnie nie są widoczne poza funkcją zewnętrzną.
### Print, format
Dwie instrukcje wbudowane slużące do wypisywania na ekran.
##### print
```
print [WYRAŻENIE]
```
Wylicza wartość wyrażenia i drukuje na standardowe wyjście.
##### format
```
format [FORMAT_STRING] [WYRAŻENIA...]
```
Pierwszym argumentem jest `string` oznaczjący format. Specjalny znak `_` oznacza wzięcie kolejnego wyrażenia z listy wyrażeń i wypisania właśnie niego. Gdy podane jest więcej wyrażeń niż `_`, nic się nie dzieje, gdy jest mniej - na ekran wypisuje się znak `_`.
```
format "_ + _ = _\n" 1, 2, 1 + 2
// 1 + 2 = 3
format "_ + _ = _\n" 1, 2
// 1 + 2 = _
```
### Obsługa błędów
Występują dwa typy wyjątków:
* typecheck exception - taki wyjątek jest zgłaszany podczas statycznego typowania
* runtime exception - taki wyjątek jest zgłaszany podczas interpretowania programu (np. dzielenie przez 0)
### Listy
```
List lista;
T t;
lista.push t (-> void);
lista::at [Integer] (-> T);
lista::length (-> int);
```
Listy mogą przechowywać dowolny typ (także inne listy). Dostępne są trzy funkcje wbudowane: `push`, `at`, `length`. `Push` wkłada element na koniec listy, `at` zwraca element pod danym indeksem (gdy indeks jest poza zakresem to zgłaszany jest błąd wykonania), `length` zwraca długość listy.
### Struktury
[NIEDOSTĘPNE W TEJ ITERACJI]
```
struct NAZWA
{
TYP_POLA [NAZWA_POLA];
TYP_POLA_2 [NAZWA_POLA_2];
.
.
}
```
Definicja struktury składa się z listy nazwy pól wraz z ich typem.
### Cechy języka
```
15 maja 12 czerwca
1 (dwa typy) int, bool +
2 (arytmetyka, porównania) +
3 (while, if) +
4 (procedury lub funkcje, rekurencja) +
5 (print) +
6 a) (przez zmienną i wartość) +
b) (pętla for) +
7 (statyczne typowanie) +
8 (przesłanianie i statyczne wiązanie) +
9 (obsługa błędów wykonania) +
10 (funkcje zwracające wartość) +
b) (listy) +
c) (rekordy) +
f) (funkcje jako parametry) +
h) (funkcje anonimowe) +
12 (funkcje zagnieżdżone +
ze statycznym wiązaniem)
```