Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Generowanie kodu pośredniego Java ML Pascal C C++ Alpha Pentium Sparc Java ML Pascal C C++ Alpha Pentium Sparc MIPS IR IR – intermediate representation.

Podobne prezentacje


Prezentacja na temat: "Generowanie kodu pośredniego Java ML Pascal C C++ Alpha Pentium Sparc Java ML Pascal C C++ Alpha Pentium Sparc MIPS IR IR – intermediate representation."— Zapis prezentacji:

1 Generowanie kodu pośredniego Java ML Pascal C C++ Alpha Pentium Sparc Java ML Pascal C C++ Alpha Pentium Sparc MIPS IR IR – intermediate representation kod pośredni Wykład maja 2004

2 Cechy kodu pośredniego Z poprzedniej strony wynikają różne ważne wnioski m.in. - nawet gdy nasz kompilator ma tylko jeden front-end i tylko jedną maszynę docelową to warto starannie dobrać sposób reprezentowania kodu pośredniego, - kod pośredni powinien być łatwy w produkcji, - powinno się zapewnić łatwą translację na kod realnej maszyny docelowej, - każda konstrukcja powinna mieć jasne i proste znaczenie (ma to znaczenie dla procesu ulepszania kodu) Kod pośredni w maja

3 Drzewa jako reprezentacja kodu Oczywiście, można uznać, że reprezentacją kodu jest drzewo składniowe. 1 assign | | id a + | | * | | id b uminus | | id c * | | id b uminus | | id c a := b*-c + b*-c Kod pośredni w maja-2004

4 Drzewa jako reprezentacja kodu II Oczywiście, można uznać, że reprezentacją kodu jest drzewo składniowe. Przestaje to być zaskakujące gdy drzewo takie zapiszemy liniowo. 1 assign | | id a + | | * | | id b uminus | | id c * | | id b uminus | | id c 0 id b 1 id c 2 uminus 1 3 * id b 5 id c 6 uminus 1 7 * id a 10 assign Kod pośredni w maja-2004

5 Dagi jako reprezentacja kodu Zamiast drzew możemy użyć dagów tzn directed acyclic graphs czyli grafów skierowanych acyklicznych. 1 assign | | id a + | | * | | id b uminus | | id c 0 id b 1 id c 2 uminus 1 3 * id a 6 assign Kod pośredni w maja-2004

6 “Czwórki” czyli kod trójadresowy Po udekorowaniu drzewa składniowego odpowiednimi atrybutami np. typy, offsety nazw lokalnych, apetyt na wielkości tymczasowe,... można zapisać drzewo (lub dag) w postaci liniowej. Kod czwórkowy jest ciągiem instrukcji o jednej operacji op i trzech adresach. Ogólna postać instrukcji jest: x := y op z x, y i z są stałymi, nazwami albo wygenerowanymi przez kompilator zmiennymi tymczasowymi bądź etykietami, op oznacza operator arytmetyczny, relacyjny bądź logiczny. 1 Kod pośredni w maja-2004

7 Repertuar instrukcji trójadresowych 1. instrukcje przypisania x := y op z 2. instrukcje przypisania x := op z 3. instrukcje kopiujące x := y 4. skoki bezwarunkowe goto L 5. skoki warunkowe if x oprel y goto L 6. instrukcje sekwencji wywołujących param x i call p, n oraz return y 7. operacje na tablicach x :=a[i] oraz a[i] := x 8. operacje na wskaźnikach x := &y, x := *y, *x :=y ____ Jest to przykład. Zestaw operatorów i repertuar instrukcji zależy od języka źródłowego i od zbioru maszyn docelowych. 1 Kod pośredni w maja-2004

8 Przykład Generowanie kodu pośredniego może odbywać się dzięki akcjom semantycznym operującym na atrybutach węzłów drzewa składniowego. Gramatyka S  id:=E E  E 1 +E 2 E  E 1 * E 2 E  - E 1 E  (E 1 ) E  id Atrybutami nieterminali niech będą E.pozycja i E.kod oraz S.kod. Metoda nowatymcz obiektu g klasy GeneratorTymcz zwraca w kolejnych wywołaniach nowe nazwy t 1, t 2,... 1 Kod pośredni w maja-2004

9 Przykład c.d. Produkcja Reguła semantyczna S  id:=E S.kod := E.kod ^ gen( id.pozycja ':=' E.pozycja) E  E 1 +E 2 E.pozycja := g.nowatymcz; E.kod := E 1.kod ^ E 2.kod ^ gen(E.pozycja ':=' E 1.pozycja '+' E 2.pozycja) E  E 1 * E 2 E.pozycja := g.nowatymcz; E.kod := E 1.kod ^ E 2.kod ^ gen(E.pozycja ':=' E 1.pozycja '*' E 2.pozycja) E  - E 1 E.pozycja := g.nowatymcz; E.kod := E 1.kod ^ gen(E.pozycja ':=' '-' E 2.pozycja) E  (E 1 ) E.pozycja := E 1.pozycja; E.kod := E 1.kod E  id E.pozycja := id.pozycja; R.kod := ' ' 1 Kod pośredni w maja-2004

10 Przykład - zastosowanie Zastosowanie tych produkcji wraz z odpowiadającymi im regułami semantycznymi daje dla drzewa składniowego ze str. 3 następujący ciąg instrukcji kodu pośredniego t1 := - c t2 := b * t1 t3 := - c t4 := b * t3 t5 := t2 + t4 a := t5 Uwaga. W większości kompilatorów ten kod zapisywany jest na pliku. 1 Kod pośredni w maja-2004

11 Kod instrukcji sterujących Zobaczmy jak wygląda generowanie kodu pośredniego dla instrukcji while. Potrzebne nam są teraz dwa atrybuty: S.początek i S.wyjście. Produkcja Reguła semantyczna S  while E do S 1 S.początek := nowaEtykieta; S.wyjście := nowaEtykieta; S.kod := gen(S.początek ':') ^ E.kod ^ gen('if' E.pozycja=0 'goto' S.wyjście) ^ S1.kod ^ gen('goto' S.początek) ^ gen(S.wyjście ':') Daje to następujący obraz 1 Kod pośredni w maja-2004

12 Kod instrukcji sterujących II 1 S.początek: S.wyjście: E.kod if E.pozycja = 0 goto S.wyjście S 1.kod goto S.początek Kod pośredni w maja-2004

13 Metoda genkod w obiektach-węzłach Jest oczywiste, że tworząc kod pośredni przy pomocy metod programowania obiektowego jesteśmy skłonni raczej posłużyć się metodami wirtualnymi niż wykorzystywać reguły semantyczne. Istota algorytmu pozostaje bez zmian, inaczej tylko go zapisujemy. W każdej podklasie klasy Expression deklarujemy odpowiednią metodę genkod w taki sposób, że w klasach Suma i Iloczyn pojawią się metody genkod różniące się wygenerowaną instrukcją trójadresową: gen(E.pozycja ':=' E 1.pozycja '+' E 2.pozycja) w węźle sumy, i gen(E.pozycja ':=' E 1.pozycja '*' E 2.pozycja) w węźle iloczynu. 1 Kod pośredni w maja-2004

14 Szkic obiektowego generowania kodu class Expression () { Expression left, right; KodPośredni kod; Adres pozycja; void genkod(){} } // Expression; class Suma extends Expression() { void genkod() { left.gencod(); right.gencod(); t = g.nowaTymczas; gen('t := left.pozycja '+' right.pozycja); } } // Suma class Iloczyn extends Expression () { // podobnie } 1 Kod pośredni w maja-2004

15 Oszczędne używanie nazw tymczasowych Możemy przyjąć, że szafujemy nazwami tymczasowymi bez ograniczeń, że jest ich dowolnie dużo do naszej dyspozycji. Tak postępujemy w przypadku kompilatorów optymalizujących bo... Możliwe są dwa podejścia: najpierw wygenerować wiele nazw tymczasowych, a potem umieszczać kilka nazw tymczasowych pod jednym adresem – sprowadza się to do kolorowania pewnego grafu. Inne podejście polega na obserwacji, że wiele nazw tymczasowych jest tworzonych dla jednokrotnego wykorzystania. Przykład oblicz wartość wyrażenia E1 i zapisz w t1 oblicz wartość wyrażenia E2 i zapisz w t2 t3 := t1 + t2 Te zmienne nie będą używane w żadnym innym miejscu programu! 1 Kod pośredni w maja-2004

16 Przykład dyscypliny stosowej Rozpatrzmy instrukcję x := a*b+c*d-e*f Przyjmijmy, że zmienne tymczasowe mają tę samą szerokość. Utrzymujemy licznik zmiennych tymczasowych L. Za każdym razem gdy potrzebna jest nowa zmienna użyjemy nazwy $L. Za każdym razem gdy użyjemy zmiennej tymczasowej zmniejszamy licznik o jeden L := L-1. Instrukcja Wartość L 0 $0:=a*b 1 $1:=c*d 2 $0:=$0+$1 1 użyto dwu zmiennych jako argumentów $1:=e*f 2 $0:=$0-$1 1 x := $0 0 1 Kod pośredni w maja-2004

17 Adresowanie elementów w tablicy W niemal każdym języku programowania elementy w tablicy zajmują kolejne miejsca w pamięci. Wynika stąd, że można szybko do nich dotrzeć element jego adres A[i] baza+(i – lower(A) * w gdzie baza – adres pamięci zarezerwowanej dla tablicy w - szerokość elementu w tablicy A, zależy od typu, lower(A) – dolne ograniczenie indeksów tablicy A UWAGA. Kompilator, który nie dodaje sprawdzenia zakresu indeksu i jest niedobrym produktem. Dlaczego? Jak zapewnić sprawdzanie zakresów indeksów? 1 Kod pośredni w maja-2004

18 Adresowanie tablic dwuwymiarowych W wielu kompilatorach tablice dwuwymiarowe umieszczane są w tablicy jednowymiarowej. Zachodzą wtedy dwa wypadki: tablica przechowywana jest wierszami np. Pascal, C, A[i,j] ma adres baza+((i-dół wierszy )*n2+j-dół kolumn )*w gdzie n2 = góra kolumn – dół kolumn +1 baza = adres początku tablicy w pamięci, albo tablica przechowywana jest kolumnami np. Fortran. A[i,j] baza+((j-dół kolumn )*n1+i-dół wierszy )*w Zauważ, że zastosowano schemat Hoernera, co jest ważne w przypadku tablic więcej wymiarowych. 1 Kod pośredni w maja-2004

19 Adresowanie tablic dwuwymiarowych II W Loglanie i w Javie tablice są pewnego rodzaju obiektami. Tablice jednowymiarowe adresuje się tak samo. Tablice dwu- i więcej wymiarowe traktuje się jak tablice jednowymiarowe tablic o n-1 wymiarach. Czyli zapis A[i,j] jest skrótem dla A[i][j]. 1 Kod pośredni w maja-2004

20 Tworzenie kodu dla wyrażeń logicznych I 1 Kod pośredni w maja-2004 Dwie możliwości: A) obliczenia “numeryczne”wartości wyrażeń boolowskich, B) wykorzystanie skoków warunkowych A) wartością wyrażenia jest albo 1(true) albo 0(false) wyrażenie a or b and not c zostaje przetłumaczone na ciąg instrukcji t1 := not c t2 := b and t1 t3 := a or t2 Wartości atomowych wyrażeń boolowskich obliczamy przy pomocy skoków warunkowych [100] if a

21 Tworzenie kodu dla wyrażeń logicznych II 1 Kod pośredni w maja-2004 Produkcja Reguła semantyczna S  id:=E S.kod := E.kod ^ gen( id.pozycja ':=' E.pozycja) E  E 1 or E 2 E.pozycja := g.nowatymcz; E.kod := E 1.kod ^ E 2.kod ^ gen(E.pozycja ':=' E 1.pozycja 'or' E 2.pozycja) E  E 1 and E 2 E.pozycja := g.nowatymcz; E.kod := E 1.kod ^ E 2.kod ^ gen(E.pozycja ':=' E 1.pozycja 'and' E 2.pozycja) E  not E 1 E.pozycja := g.nowatymcz; E.kod := E 1.kod ^ gen(E.pozycja ':=' '-' E 2.pozycja) E  (E 1 ) E.pozycja := E 1.pozycja; E.kod := E 1.kod E  id E.pozycja := id.pozycja; E.kod := ' '

22 Tworzenie kodu dla wyrażeń logicznych III 1 Kod pośredni w maja-2004 Produkcja Reguła semantyczna E  id 1 relop id 2 E.pozycja := g.nowatymcz; E.kod := gen('if' id 1.pozycja 'relop' id 2.pozycja 'goto' nextstat+3)^ gen(E.pozycja:=0)^gen(goto nextstat+2)^ gen(E.pozycja:=1) E  true E.pozycja := g.nowatymcz; E.kod := gen(E.pozycja ':='1' ) E  false E.pozycja := g.nowatymcz; E.kod := gen(E.pozycja ':=' 0 ')

23 Tworzenie kodu dla wyrażeń logicznych IV Wyrażenia logiczne realizowane przez skoki warunkowe 1 Kod pośredni w maja-2004 B) wartość wyrażenia jest reprezentowana przez pozycję w kodzie W poniższym przykładzie wiadomo, że gdy program osiągnie instrukcję 101-szą to wartością zmiennej t jest fałsz, a gdy osiągnie instrukcję 103-cią to wartością zmiennej t jest true. [100] if a

24 Instrukcje sterujące I Produkcja Reguły semantyczne S  if E then S 1 E.true := new label; E.false := S.next; S 1.next := S.next; S.code := E.code^gen(E.true ':')^ S 1.code S  if E then S 1 E.true := new label; E.false := new label; else S 2 S 1.next := S.next; S 2.next := S.next; S.code := E.code ^ gen(E.true ':')^ S 1.code^ gen(goto S.next)^ gen(E.false':') ^S 2.code S  while E do S 1 S.begin := new label; E.true := new label; E.false := S.next; S 1.next := S.begin; S.code := gen(S.begin ':')^ E.code ^ gen(E.true ':')^ S 1.code ^ gen(goto S.begin) 1 Kod pośredni w maja-2004

25 Instrukcje sterujące II 1 Kod pośredni w maja-2004 Kod instrukcji if E then S1: E.code goto E.true goto E.false E.true: E.false: S 1.code

26 Instrukcje sterujące III 1 Kod pośredni w maja-2004 Kod instrukcji while E do S 1 : E.code goto E.true goto E.false E.true: E.false: S 1.code S.begin: goto S.begin

27 Instrukcje sterujące IV 1 Kod pośredni w maja-2004 Kod instrukcji if E then S 1 else S 2 : E.code goto E.true goto E.false E.true: E.false: S 1.code S 2.code S.next: goto S.next

28 Wyrażenia logiczne realizowane przez skoki warunkowe 1 Kod pośredni w maja-2004

29 Backpatching p 1 Kod pośredni w maja-2004

30 Wywołania procedur Rozważmy gramatykę instrukcji procedury S  call id ( Elist) Elist  Elist, E | E Jak pamiętamy z poprzedniego wykładu instrukcja procedury tłumaczy się na sekwencję wywołującą złożoną z ciągu poleceń obliczających kolejne parametry aktualne i przekazujących je instrukcją param x, oraz z instrukcji call p, n która wywołuje procedurę biblioteki wspomagania przetwarzania (run-time system, lub maszyna wirtualna). Polecenie call ma dwa argumenty: pierwszym jest informacja związana z nazwą procedury, drugim jest liczba n przekazywanych argumentów. 1 Kod pośredni w maja-2004

31 Wywołania procedur II Rozpatrzmy prosty przykład: instrukcja procedury postaci id(E, E,...,E) załóżmy, że parametry są przekazywane przez referencję trzeba więc wygenerować kod pośredni prowadzący do obliczenia tych argumentów, które nie są nazwami prostymi, a po nich umieścić instrukcje param, po jednej dla każdego argumentu. Można to zrobić posługując się kolejką. Akcja semantyczna dla Elist -> Elist będzie zawierała krok zapamiętujący atrybut E.pozycja w kolejce kolejka. Akcja semantyczna dla S -> call id (Elist) wygeneruje instrukcję param dla każdego elementu z kolejka 1 Kod pośredni w maja-2004

32 Wywołania procedur III p 1 Kod pośredni w maja-2004

33 p p 1

34 p p 1

35 p p 1


Pobierz ppt "Generowanie kodu pośredniego Java ML Pascal C C++ Alpha Pentium Sparc Java ML Pascal C C++ Alpha Pentium Sparc MIPS IR IR – intermediate representation."

Podobne prezentacje


Reklamy Google