Laboratorium
MRJP - projekt zaliczeniowy
Drugi projekt zaliczeniowy obejmuje implementację kompilatora
dla prostego jezyka imperatywnego Latte.
Etapy
Projekt składa się z trzech etapów (daty orientacyjne, wiążące
terminy w moodle)
- Frontend - termin 28. listopada.
- Generator kodu dla LLVM albo x86. Termin 6 stycznia.
- (opcjonalnie) Ewentualne rozszerzenia. Termin 20
stycznia.
Prowadzący grupę może wyznaczyć inne terminy, w szczególności
wymagać osobistej prezentacji projektu. Niezależnie od dodatkowych
wymagań prowadzącego, projekt musi być oddany za pośrednictwem
moodle.
Punktacja
Łącznie do zdobycia jest maksymalnie 29 punktów, które liczą
się do ostatecznej oceny z przedmiotu. Dla zaliczenia laboratorium
(i dopuszczenia do egzaminu) należy oddać zadowalające
implementacje wszystkich obowiązkowych elementów i uzyskać łącznie
z Zadaniem 1 co najmniej 18p.
Punkty mozna uzyskać za:
- front-end (4)
- back-end LLVM (8) albo x86 (10)
- użycie rejestrów i phi zamiast alloc w LLVM - dodatkowo
2p
- wykorzystanie rejestrów dla x86 - dodatkowo do 5p (na 5p pełna
alokacja rejestrów)
- optymalizacje - do 10p
- LCSE/GCSE - 3/5p
- optymalizacja pętli (zmienne indukcyjne i redukcja mocy)
2p
- function inlining 1-3p (proszę zawczasu przedyskutować z
prowadzącym)
- optymalizacja wywołań końcowych (rekursja ogonowa) 3p (raczej
x86 - dla LLVM nieoczywiste, proszę zawczasu przedyskutować z
prowadzącym)
- Rozszerzenia (notacja x/y oznacza punkty za backend w wersji
odpowiednio LLVM/x86); szczegółowy opis rozszerzeń zawarty jest w
opisie języka.
- tablice (1)
- struktury (2)
- obiekty (atrybuty, metody, dziedziczenie bez zastępowania
metod) - dodatkowo (3/4)
- metody wirtualne - dodatkowo (3/4), czyli za obiekty z
metodami wirtualnymi mozna uzyskać 8/10 punktów.
- Zaawansowane rozszerzenia (brak przykładów):
- zagnieżdzone funkcje z dostępem do zmiennych nielokalnych
(raczej x86, dla LLVM nieoczywiste) 4p
- odśmiecanie (2)
- zarządzanie pamięcią a la Rust (2) (wyklucza się z
odśmiecaniem)
Struktury/obiekty oznaczają też zagnieżdżone struktury/obiekty
oraz dostęp do pól/metod postaci foo.bar.baz
.
Żeby uzyskać punkty za tablice i struktury/obiekty wymagane są
tablice struktur i tablice jako elementy struktur.
Punkty za frontend są przyznawane pod warunkiem oddania
(nietrywialnego i działającego) backendu.
Uwaga: podane liczby punktów są wartościami
maksymalnymi, sprawdzający może przydzielić mniejsza liczbę
punktów w zależności od jakości rozwiązania i generowanego kodu.
Oczekujemy, że kod będzie generowany zgodnie z regułami sztuki
poznanymi na zajęciach (albo lepiej).
Spóźnienia, termin
poprawkowy
Programy oddane po terminie będą obciążane karą 2p za każdy
(rozpoczęty) tydzień opóźnienia. Ostatecznym terminem, po którym
programy nie będą przyjmowane (“termin poprawkowy”) jest 6
lutego.
Zasady
Projekt zaliczeniowy ma być pisany samodzielnie. Wszelkie
przejawy niesamodzielności będą karane. W szczególności:
- nie wolno oglądać kodu innych studentów, pokazywać, ani w
jakikolwiek sposób udostępniać swojego kodu
- wszelkie zapożyczenia powinny być opisane z podaniem źródła;
dotyczy to także kodu wygenerowanego/zasugerowanego przez
narządzia AI i pokrewne (VS Code, Copilot, Claude, ChatGPT
itp.).
Wymagania techniczne
- Projekt powinien być oddany w postaci spakowanego archiwum TAR
(.tar.gz lub .tgz)
- W korzeniu projektu muszą się znajdować co najmniej:
- Plik tekstowy README opisujący szczegóły
kompilacji i uruchamiania programu, używane narzędzia i
biblioteki, zaimplementowane rozszerzenia, strukturę katalogów
projektu, ewentualnie odnośniki do bardziej szczegółowej
dokumentacji.
- Plik
Makefile
(lub skrypt build
)
pozwalający na zbudowanie programu.
- katalog src zawierający wyłącznie pliki
źródłowe projektu (plus ewentualnie dostarczony przez nas plik
Latte.cf); pliki pomocnicze takie jak biblioteki itp powinny być
umieszczone w inych katalogach.
- Program musi się kompilować na students poleceniem
make
(ewentualnie ./build
), uruchamianym
w katalogu, w którym rozpakowano archiwum (czyli np.
tar xf foo.tgz; make
).
- Wszelkie używane biblioteki (poza biblioteką standardową
używanego jezyka programowania) muszą być opisane w README
- Po zbudowaniu kompilatora, w korzeniu musi się znajdować plik
wykonywalny o nazwie latc (może być skryptem
uruchamiającym inne programy)
- Kompilator musi akceptować wszystkie programy testowe z
katalogu good i odrzucać ze stosownym komunikatem
wszystkie programy z katalogu bad.Komunikaty o
błędach muszą umożliwiać lokalizację błędu (przez numer linii lub
kontekst). Dla rozszerzeń musi akceptować wszystkie programy z
odpowiednich podkatalogów extension. Uruchomienie
poprawnego programu testowego ma dawać wyjście takie jak w
odpowiednim pliku .output (dla wejścia zawartego
w odpowiednim pliku .input, o ile istnieje)
- Gdy kompilator akceptuje program, musi wypisać w pierwszej
linii stderr napis OK (
"OK\n"
). Dalsze linie i stdout
- dowolne. Kompilator musi się w takiej sytuacji zakończyć z kodem
powrotu 0.
- Gdy kompilator odrzuca program musi wypisać w pierwszej linii
stderr napis ERROR (
"ERROR\n"
). Dalsze linie powinny
zawierać stosowne informacje o błędach. Kompilator musi się w
takiej sytuacji zakończyć z kodem powrotu różnym od 0.
- Rowiązania wymagające stosowania niestandardowego
oprogramowania proszę uzgadniać ze sprawdzającymi.
Generacja kodu LLVM
- Po zbudowaniu, w korzeniu projektu ma się znajdować program
wykonywalny latc_llvm
- Wykonanie latc_llvm foo/bar/baz.lat dla
poprawnego programu wejściowego baz.lat ma
stworzyć pliki baz.ll (kod LLVM) oraz
baz.bc (bitkod LLVM wykonywalny przy uzyciu
lli) w katalogu foo/bar.
- Ewentualne funkcje biblioteczne (printInt
etc.) należy umieścić w pliku runtime.bc w
katalogu lib (dodatkowo proszę zamieścić jego
źródło)
Generacja kodu asemblera
- Po zbudowaniu, w korzeniu projektu ma się znajdować program
wykonywalny latc_ARCH gdzie ARCH to x86 lub
x86_64
- Wykonanie latc_ARCH foo/bar/baz.lat dla
poprawnego programu wejściowego baz.lat ma
stworzyć pliki baz.s (kod asemblera) oraz
wykonywalny baz w katalogu
foo/bar.
- Ewentualne funkcje biblioteczne (printInt
etc.) należy umieścić w pliku runtime.o w
katalogu lib (dodatkowo proszę zamieścić jego
źródło)
Testy
Archiwum z programami testowymi:
lattests251016.tgz
Dla optymalizacji i alokacji rejestrów należy także napisać
testy pokazujące ich działanie. Podobnie dla funkcji
zagnieżdżonych.
Oczywiście można stworzyć własne testy także dla innych
elementów kompilatora.
Dodatkowe
testy (ułożone przez studentów, całkowicie nieoficjalne).