ZA kompilator jest program co przekłada się na czytelność dla człowieka kod źródłowy w wykonywalny komputerowo kod maszynowy. Aby to zrobić pomyślnie, kod czytelny dla człowieka musi być zgodny z składnia zasady dowolnego języka programowania, w którym jest napisane. Kompilator jest tylko programem i nie może naprawić twojego kodu za ciebie. Jeśli popełnisz błąd, musisz poprawić składnię, bo inaczej się nie skompiluje.
Co się stanie, gdy skompilujesz kod?
Złożoność kompilatora zależy od składni języka i ilości abstrakcji ten język programowania zapewnia. Kompilator C jest znacznie prostszy niż kompilator dla C ++ lub C #.
Analiza leksykalna
Podczas kompilacji kompilator najpierw odczytuje strumień znaków z pliku kodu źródłowego i generuje strumień tokenów leksykalnych. Na przykład kod C ++:
int C = (A * B) +10;
mogą być analizowane jako te tokeny:
- wpisz „int”
- zmienna „C”
- równa się
- lewy wspornik
- zmienna „A”
- czasy
- zmienna „B”
- prawy wspornik
- plus
- dosłowne „10”
Analiza składniowa
Wyjście leksykalne trafia do części kompilatora analizatora składniowego, który korzysta z reguł gramatyki, aby zdecydować, czy dane wejściowe są poprawne, czy nie. Chyba że
zmienne A i B zostały wcześniej zadeklarowane i były w zakresie, kompilator mógłby powiedzieć:- „A”: niezadeklarowany identyfikator.
Jeśli zostały zadeklarowane, ale nie zainicjowane. kompilator wydaje ostrzeżenie:
- zmienna lokalna „A” używana bez inicjalizacji.
Nigdy nie należy ignorować ostrzeżeń kompilatora. Mogą złamać kod w dziwny i nieoczekiwany sposób. Zawsze naprawiaj ostrzeżenia kompilatora.
Jeden przejazd czy dwa?
Niektóre języki programowania są napisane, więc kompilator może odczytać kod źródłowy tylko raz i wygenerować kod maszynowy. Pascal jest jednym z takich języków. Wiele kompilatory wymagają co najmniej dwóch podań. Czasami dzieje się tak z powodu deklaracji forward Funkcje lub zajęcia.
W C ++ klasę można zadeklarować, ale nie można jej zdefiniować do późniejszego. Kompilator nie jest w stanie obliczyć, ile pamięci potrzebuje klasa, dopóki nie skompiluje treści klasy. Musi ponownie odczytać kod źródłowy przed wygenerowaniem poprawnego kodu maszynowego.
Generowanie kodu maszynowego
Zakładając, że kompilator pomyślnie zakończy analizy leksykalne i syntaktyczne, ostatnim etapem jest wygenerowanie kodu maszynowego. Jest to skomplikowany proces, szczególnie w przypadku nowoczesnych procesorów.
Szybkość skompilowanego wykonywalny kod powinien być tak szybki, jak to możliwe i może się znacznie różnić w zależności od jakości generowanego kodu i żądanej optymalizacji.
Większość kompilatorów pozwala określić stopień optymalizacji - zwykle znanej z szybkiego kompilowania debugowania i pełnej optymalizacji wydanego kodu.
Generowanie kodu jest trudne
Pisarz kompilatora napotyka wyzwania podczas pisania generatora kodu. Wiele procesorów przyspiesza przetwarzanie przy użyciu
- Rurociąg instrukcji
- Wewnętrzny skrytki.
Jeśli wszystkie instrukcje w kodzie pętla może odbyć się w procesor pamięć podręczną, wtedy ta pętla działa znacznie szybciej niż wtedy, gdy procesor musi pobrać instrukcje z głównej pamięci RAM. Pamięć podręczna procesora to blok pamięci wbudowany w procesor procesora, do którego dostęp jest znacznie szybszy niż danych w głównej pamięci RAM.
Skrytki i kolejki
Większość procesorów ma kolejkę pobierania wstępnego, w której procesor odczytuje instrukcje do pamięci podręcznej przed ich wykonaniem. Jeśli zdarzy się oddział warunkowy, procesor musi ponownie załadować kolejkę. Kod powinien zostać wygenerowany w celu zminimalizowania tego.
Wiele procesorów ma osobne części dla:
- Arytmetyka liczb całkowitych (liczby całkowite)
- Arytmetyka zmiennoprzecinkowa (liczby ułamkowe)
Te operacje mogą często przebiegać równolegle w celu zwiększenia prędkości.
Kompilatory zwykle generują kod maszynowy w plikach obiektowych, które są wtedy połączony razem przez program łączący.