Jakie są fazy projektowania kompilatora?
Kompilator działa w różnych fazach, każda faza przekształca program źródłowy z jednej reprezentacji na inną. Każda faza pobiera dane wejściowe z poprzedniego etapu i przekazuje dane wyjściowe do następnej fazy kompilatora.
Kompilator składa się z 6 faz. Każda z tych faz pomaga w konwersji języka wysokiego poziomu do kodu maszynowego. Fazy kompilatora to:
- Analiza leksykalna
- Analiza składni
- Analiza semantyczna
- Generator kodu pośredniego
- Optymalizator kodu
- Generator kodów
Wszystkie te fazy konwertują kod źródłowy, dzieląc go na tokeny, tworząc drzewa parsowania i optymalizując kod źródłowy według różnych faz.
W tym samouczku dowiesz się:
- Jakie są fazy projektowania kompilatora?
- Faza 1: Analiza leksykalna
- Faza 2: Analiza składni
- Faza 3: Analiza semantyczna
- Faza 4: Generowanie kodu pośredniego
- Faza 5: Optymalizacja kodu
- Faza 6: Generowanie kodu
- Zarządzanie tabelą symboli
- Procedura obsługi błędów:
Faza 1: Analiza leksykalna
Analiza leksykalna to pierwsza faza, w której kompilator skanuje kod źródłowy. Ten proces można od lewej do prawej, znak po znaku i pogrupować te znaki w żetony.
Tutaj strumień znaków z programu źródłowego jest pogrupowany w znaczące sekwencje poprzez identyfikację tokenów. Wprowadza odpowiednie bilety do tablicy symboli i przekazuje ten żeton do następnej fazy.
Podstawowe funkcje tej fazy to:
- Zidentyfikuj jednostki leksykalne w kodzie źródłowym
- Klasyfikuj jednostki leksykalne w klasy, takie jak stałe, słowa zastrzeżone i wprowadzaj je do różnych tabel. Zignoruje komentarze w programie źródłowym
- Zidentyfikuj token, który nie jest częścią języka
Przykład :
x = y + 10
Tokeny
X | identyfikator |
= | Operator przypisania |
Y | identyfikator |
+ | Operator dodawania |
10 | Numer |
Faza 2: Analiza składni
Analiza składni polega na odkrywaniu struktury w kodzie. Określa, czy tekst jest zgodny z oczekiwanym formatem. Głównym celem tej fazy jest upewnienie się, że kod źródłowy został napisany przez programistę jest poprawny, czy nie.
Analiza składni opiera się na regułach opartych na konkretnym języku programowania poprzez konstruowanie drzewa parsowania za pomocą tokenów. Określa również strukturę języka źródłowego i gramatykę lub składnię języka.
Oto lista zadań wykonywanych w tej fazie:
- Uzyskaj tokeny z analizatora leksykalnego
- Sprawdza, czy wyrażenie jest poprawne składniowo, czy nie
- Zgłaszaj wszystkie błędy składniowe
- Skonstruuj strukturę hierarchiczną znaną jako drzewo analizy
Przykład
Każdy identyfikator / numer jest wyrażeniem
Jeśli x jest identyfikatorem, a y + 10 jest wyrażeniem, to x = y + 10 jest instrukcją.
Rozważmy drzewo analizy dla następującego przykładu
(a+b)*c
W drzewie analizy
- Węzeł wewnętrzny: rekord z wpisem operatora i dwoma plikami dla dzieci
- Liść: rekordy z 2 lub więcej polami; jeden na token i inne informacje o tokenie
- Upewnij się, że komponenty programu są do siebie odpowiednio dopasowane
- Zbiera informacje o typie i sprawdza zgodność typów
- Operandy sprawdzające są dozwolone w języku źródłowym
Faza 3: Analiza semantyczna
Analiza semantyczna sprawdza spójność semantyczną kodu. Używa drzewa składni z poprzedniej fazy wraz z tablicą symboli, aby sprawdzić, czy dany kod źródłowy jest semantycznie spójny. Sprawdza również, czy kod przekazuje odpowiednie znaczenie.
Analizator semantyczny sprawdzi niezgodności typów, niezgodne operandy, funkcję wywoływaną z niewłaściwymi argumentami, niezadeklarowaną zmienną itp.
Funkcje fazy analiz semantycznych to:
- Pomaga w przechowywaniu zebranych informacji o typach i zapisywaniu ich w tabeli symboli lub drzewie składni
- Umożliwia sprawdzenie typu
- W przypadku niezgodności typu, gdy nie ma dokładnych reguł korekcji typu, które spełniają żądaną operację, wyświetlany jest błąd semantyczny
- Zbiera informacje o typie i sprawdza zgodność typu
- Sprawdza, czy język źródłowy zezwala na operandy, czy nie
Przykład
float x = 20.2;float y = x*30;
W powyższym kodzie analizator semantyczny przerzuci liczbę całkowitą 30 do liczby zmiennoprzecinkowej 30.0 przed pomnożeniem
Faza 4: Generowanie kodu pośredniego
Po zakończeniu fazy analizy semantycznej kompilator generuje kod pośredni dla maszyny docelowej. Reprezentuje program dla jakiejś abstrakcyjnej maszyny.
Kod pośredni znajduje się między językiem wysokiego poziomu a językiem maszynowym. Ten kod pośredni należy wygenerować w taki sposób, aby można było go łatwo przetłumaczyć na docelowy kod maszynowy.
Funkcje dotyczące generowania kodu pośredniego:
- Powinien być wygenerowany z semantycznej reprezentacji programu źródłowego
- Przechowuje wartości obliczone podczas procesu tłumaczenia
- Pomaga przetłumaczyć kod pośredni na język docelowy
- Pozwala zachować pierwszeństwo w języku źródłowym
- Przechowuje prawidłową liczbę argumentów instrukcji
Przykład
Na przykład,
total = count + rate * 5
Kod pośredni przy pomocy metody kodu adresowego to:
t1 := int_to_float(5)t2 := rate * t1t3 := count + t2total := t3
Faza 5: Optymalizacja kodu
Następna faza to optymalizacja kodu lub kod pośredni. Ta faza usuwa niepotrzebne linie kodu i porządkuje sekwencję instrukcji, aby przyspieszyć wykonanie programu bez marnowania zasobów. Głównym celem tej fazy jest udoskonalenie kodu pośredniego w celu wygenerowania kodu, który działa szybciej i zajmuje mniej miejsca.
Podstawowe funkcje tej fazy to:
- Pomaga ustalić kompromis między szybkością wykonywania i kompilacji
- Poprawia czas działania programu docelowego
- Generuje usprawniony kod nadal w reprezentacji pośredniej
- Usuwanie nieosiągalnego kodu i pozbycie się nieużywanych zmiennych
- Usuwanie instrukcji, które nie są zmieniane z pętli
Przykład:
Rozważmy następujący kod
a = intofloat(10)b = c * ad = e + bf = d
Może zostać
b =c * 10.0f = e+b
Faza 6: Generowanie kodu
Generowanie kodu to ostatnia i ostatnia faza kompilatora. Pobiera dane wejściowe z faz optymalizacji kodu i w rezultacie tworzy kod strony lub kod wynikowy. Celem tej fazy jest przydzielenie pamięci i wygenerowanie relokowalnego kodu maszynowego.
Przydziela również lokalizacje pamięci dla zmiennej. Instrukcje w kodzie pośrednim są konwertowane na instrukcje maszynowe. Ta faza powoduje ukrycie kodu optymalizacji lub kodu pośredniego w języku docelowym.
Językiem docelowym jest kod maszynowy. Dlatego wszystkie lokalizacje pamięci i rejestry są również wybierane i przydzielane w tej fazie. Kod wygenerowany w tej fazie jest wykonywany w celu pobrania danych wejściowych i wygenerowania oczekiwanych wyników.
Przykład:
a = b + 60,0
Prawdopodobnie zostałby przetłumaczony na rejestry.
MOVF a, R1MULF #60.0, R2ADDF R1, R2
Zarządzanie tabelą symboli
Tablica symboli zawiera rekord dla każdego identyfikatora z polami na atrybuty identyfikatora. Ten składnik ułatwia kompilatorowi wyszukiwanie rekordu identyfikatora i szybkie pobieranie go. Tabela symboli pomaga również w zarządzaniu zakresem. Tablica symboli i program obsługi błędów współdziałają ze wszystkimi fazami i odpowiednio aktualizują tablicę symboli.
Procedura obsługi błędów:
W procesie projektowania kompilatora może wystąpić błąd we wszystkich podanych poniżej fazach:
- Analizator leksykalny: nieprawidłowo napisane tokeny
- Analizator składni: brak nawiasu
- Generator kodu pośredniego: niezgodne operandy dla operatora
- Optymalizator kodu: gdy instrukcja jest nieosiągalna
- Generator kodu: nieosiągalne instrukcje
- Tabele symboli: błąd wielu zadeklarowanych identyfikatorów
Najczęstsze błędy to nieprawidłowa sekwencja znaków w skanowaniu, nieprawidłowe sekwencje tokenów w typie, błąd zakresu i analiza semantyczna.
Błąd może wystąpić w dowolnej z powyższych faz. Po znalezieniu błędów faza musi zająć się błędami, aby kontynuować proces kompilacji. Te błędy muszą być zgłaszane do programu obsługi błędów, który obsługuje błąd w celu wykonania procesu kompilacji. Generalnie błędy zgłaszane są w formie komunikatu.
Podsumowanie
- Kompilator działa w różnych fazach, każda faza przekształca program źródłowy z jednej reprezentacji na inną
- Sześć faz projektowania kompilatora to 1) Analiza leksykalna 2) Analiza składni 3) Analiza semantyczna 4) Pośredni generator kodu 5) Optymalizator kodu 6) Generator kodu
- Analiza leksykalna to pierwsza faza, w której kompilator skanuje kod źródłowy
- Analiza składni polega na odkrywaniu struktury w tekście
- Analiza semantyczna sprawdza spójność semantyczną kodu
- Po zakończeniu fazy analizy semantycznej kompilator wygeneruje kod pośredni dla maszyny docelowej
- Faza optymalizacji kodu usuwa niepotrzebną linię kodu i porządkuje kolejność instrukcji
- Faza generowania kodu pobiera dane wejściowe z fazy optymalizacji kodu i generuje w rezultacie kod strony lub kod obiektowy
- Tablica symboli zawiera rekord dla każdego identyfikatora z polami na atrybuty identyfikatora
- Procedura obsługi błędów obsługuje błędy i raporty na wielu etapach