Egzamin+18.06.2008

...

Zad 1. 2008 code enum Leksem dajLeksem { char znak = 'a'; while(isspace(znak)) znak = getchar; switch(znak) { case '0': return ZERO; case '1': return JEDEN; case '\': return dajLeksemBackslash; case '/': return dajLeksemSlash; case EOF: return LEK_EOF; default: return ERR; } }

enum Leksem dajLeksemBackslash { char znak = getchar; if(znak == '/') return BACKSLASH_SLASH; ungetc(znak); return BACKSLASH; }

enum Leksem dajLeksemSlash { char znak = getchar; case(znak) { case '\': return SLASH_BACKSHLASH; case '/': while(znak != '\n' && znak != EOF) znak = getchar; ungetc(znak); return dajLeksem; default: return ERR; } }

code w funkcji dajLeksemBackslash nie przewidujesz, że '/' może być początkiem komentarza

leksery dzialaja zachalnnie, wiec nie przewiduje, bo poprostu nie ma prawa byc

ungetc nie zwroci EOF'a na strumien wejsciowy

...

Zapomnialem o stanie [ A -> q* (11)] wychodzacym z (0). Wczytujemy z wejscia : qpupvx 1. [ ] (0) 2. [ q ] (11) redukcja A -> q 3. [ A ] (3) 4. [ A p ] (7) 5. [ A p u ] (8) redukcja C -> u 6. [ A p C ] (10) redukcja A -> ApC 7. [ A p ] (7) 8. [ A p v ] (9) redukcja C -> v 9. [ A p C ] (10) redukcja A -> ApC 10. [ A x ] (6) redukcja S -> Ax 11. [ S ]

Nie jestem pewien czy to wystarczajacy (i dobry) opis. Redukcja jest w stanach 4, 5, 6, 8, 9, 10 niewiem jednak co ma sie dziac w stanach 0 i 1 dla B -> *epsilon... Trzeba by redukować B -> eps w tych stanach, jeśli na wejściu jest coś z Follow(B).

Rozwijając od końca: code return 42; code 12. Eliminacja martwego kodu code return 42; code 11. Propagacja stałej code x = 42; code //Mam co do tego wątpliwości. Tak jak propagacja stałej była pokazana na slajdach, to przypisanie x=42, powinno zostać wycięte.// //Ostatecznie jak zamienimy wszystkie wystąpienia x na stałą, to samo x=42 staje się martwym kodem (zmienna x nie jest żywa po nim), więc po co mielibyśmy to trzymać?//
 * x = 42;**
 * return x;**

Odp: Kierowałem się tym przykładem [|MRJP ważniak]. Rzeczywiście x = 42 stanie się martwym kodem i tak właśnie powinno być. //"W wyniku propagacji stałych instrukcja definiująca stałą staje się [|martwym kodem], który można usunąć w trakcie eliminacji martwego kodu."//

10. Zwijanie stałej code return x; code 9. Eliminacja martwego kodu code v = 7; z = 21; y = 21;** x = 21 + 21; return x; code 8. Propagacja stałej (najpierw propagacja z, potem propagacja y) code c = 3; v = 7; z = 21; x = y + z;** return x; code 7. Zwijanie stałej code c = 3; v = 7; y = z; x = y + z; return x; code 6. Propagacja stałej code c = 3; v = 7; y = z; x = y + z; return x; code 5. Zwijanie stałej code c = 3; z = 3 * v; y = z; x = y + z; return x; code 4. Propagacja stałej code c = 3; z = 3 * v; y = z; x = y + z; return x; code 3. Eliminacja wspólnych podwyrażeń code c = 3; v = c + 4; z = 3 * v; x = y + z; return x; code 2. Eliminacja martwego kodu code c = 3; v = c + 4; z = 3 * v; y = 3 * v; x = y + z; return x;
 * x = 21 + 21;**
 * c = 3;
 * y = z;
 * z = 3 * 7;**
 * z = 3 * v;**
 * v = 3 + 4;**
 * v = c + 4;**
 * y = 3 * v;**
 * t = v;**

code 1. Propagacja kopii code c = 3; v = c + 4; z = 3 * t; y = 3 * t;** x = y + z; return x;
 * t = v;

code Poprawki naniesione. W razie nowych uwag piszcie.

... Zad. 4 2008 Czy ktoś wie, co to znaczy, że zmienna jest żywa po wykonaniu kodu (na koniec bloku prostego)?
 * Instr. || R0 || R1 || Zywe || Wygen. instr ||
 * x := a |||| a || {a,b} || R1 = a; x = R1 ||
 * a := b/a || b || a || {a,b,x} || R0 = b; R1 = R1 / R0 ||
 * b := a-x || x || b || {a,x} || R0 = x; R1 = R1-R0; b = R1 ||
 * a := b/x || a || x || {a,b} || R1 = R1 / R0; a = R1 ||

Tak na pale - poprostu zmienne beda jeszcze pozniej wykorzystywane i nie mozesz sobie np. nadpisac ich pamieci, albo poprostu ich wyoptymalizowac.

O ile zrozumialem definicje zywotnosci zmiennej, to zmienna jest zywa jesli bedzie potrzebna jej wartosc, czyli jesli nie ma po drodze do jej uzycia redefinicji tej zmiennej. Tutaj wiemy, ze a i b maja byc zywe czyli gdzies dalej w niepokazanym kodzie bylyby uzyte ich wartosci, natomiast wartosc x juz nie. Po za tym wg mnie po kazdej z tych instrukcji inny powinien byc zbior zywych (instrukcji i={1,2,3,4}): 1. = {b,x}(a ma redef w 2) 2. = {a,x}(b ma redef w 3) 3. = {b,x}(a ma redef w 4) 4. = {a,b}(x juz nie potrzebny).

Wg mnie w tabelce jest bląd, w pierwszej linni a jest w R1 a nie w R0 potem w 2 linni istrukcja jest wykonana na odwrot powinno byc: R0 = R0/R1 itd... Mnie wyszlo tak: Jednak nie jestem przekonany jak sie powinno wypelniac tabelke
 * Instrukcja || R0 || R1 || Wygenerowano ||
 * x := a || x || - || R0 = a ; x = R0 ||
 * a := b / a || x || a || R1 = b ; R1 = R1 / R0 ||
 * b := a - x || x || b || R1 = R1 - R0 ; b = R1 ||
 * a := b / x || a || x || R1 = R1 / R0 ; a = R1 ||

Moim zdaniem jest ok, za wyjątkiem zawartości rejestrów na końcu. Musiało Ci się pomylić. W R0 jest x, w R1 jest a. I jeszcze mam pytanie. Czy skoro x nie musi być żywe, to czy konieczna jest instrukcja x = R0? - Jarek

Rzeczywiscie x nie musi byc zywe, wiec jesli ma to byc "mozliwie dobry kod", czyli rozumiem ze zoptymalizowany, to mozna x = R1 wywalic.