• Nie Znaleziono Wyników

Metody Realizacji Języków Programowania

N/A
N/A
Protected

Academic year: 2022

Share "Metody Realizacji Języków Programowania"

Copied!
23
0
0

Pełen tekst

(1)

Metody Realizacji J ˛ezyków Programowania

Analiza semantyczna

Marcin Benke

MIM UW

15 listopada 2010

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 1 / 22

(2)

Analiza semantyczna

Analiza nazw

I Czy x jest zadeklarowane przed u˙zyciem?

I Która deklaracja x obowiazuje w danym miejscu programu?

I Czy jakie´s nazwy s ˛a zadeklarowane a nie u˙zywane?

Analiza zgodno´sci typów

I Czy wyra˙zenie e jest poprawne typowo?

I Jakiego typu jest e?

I Czy funkcja zawsze zwraca warto´s´c typu zgodnego z zadeklarowanym?

Identyfikacja operacji

I Jak ˛a operacj ˛e reprezentuje + wyra˙zeniu a + b?

Odpowiedzi na te pytania mog ˛a wymaga´c informacji nielokalnych — kontekstowych. Nie s ˛a to własno´sci bezkontekstowe.

(3)

Tablica symboli

Opis wszystkich bytów (zmienych, funkcji, typów, klas, atrybutów, metod,. . . ) wystepuj ˛acych w programie.

Musi mie´c narzucon ˛a struktur ˛e (mechanizm wyszukiwania), odzwierciedlaj ˛ac ˛a reguły wi ˛azania identyfikatorów w danym j ˛ezyku.

Opis bytu:

I rodzaj definicji

I inne informacje zale˙zne od rodzaju Byty mog ˛a by´c wzajemnie powi ˛azane.

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 3 / 22

(4)

Struktura j ˛ezyka a struktura tablicy symboli

Niektóre konstrukcje j ˛ezykowe narzucaj ˛ace struktur ˛e tablicy symboli:

zagnie˙zdzanie (struktura blokowa) dziedziczenie

sumowanie (moduły) import java.util.*

class A { int a,b;

class B extends A { B() {}

int f() { String a;

} }

(5)

Zasi ˛eg i zakres

Zasi ˛eg definicji identyfikatora to obszar programu, w którym mo˙zemy u˙zy´c identyfikatora w zdefiniowanym znaczeniu. Nie musi by´c ci ˛agły.

Zakres to konstrukcja składniowa, z któr ˛a mog ˛a by´c zwi ˛azane definicje identyfikatorów (funkcja, blok, itp.)

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 5 / 22

(6)

Przykład

void f() { int a;

a = g();

{

string a;

b = a;

}

h(a,b);

}

Zasi ˛eg deklaracji int a jest zaznaczony na czerwono. Jest ona zwi ˛azana z zakresem funkcji f.

(7)

Struktura blokowa

module M;

var a,d : int;

type t = ...

procedure P;

var a,b,e : int procedure Q;

var a,c,d : t;

procedure R;

var a,b,d : real;

end

procedure T;

var a,c,d : int;

end

procedure S;

var a,b,c : int;

d := e+1; // Gdzie s ˛a definicje d i e?

...

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 7 / 22

(8)

Drzewo zagnie˙zd˙ze ´n

Problem: analizujemy w ˛ezeł drzewa struktury, np przypisanie d:=e+1.

Gdzie s ˛a definicje d i e?

M ad

P abe

Q acd

R abd

T acd S abc

(9)

Drzewo zagnie˙zd˙ze ´n

Problem: analizujemy w ˛ezeł drzewa struktury, np przypisanie d:=e+1.

Gdzie s ˛a definicje d i e?

M ad

P abe

Q acd

R abd

T acd S abc

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 8 / 22

(10)

Metoda I: stos tablic symboli

Wyszukiwanie:

przeszukaj zakresy od bie˙z ˛acego do znalezienia lub do ko ´nca, je˙zeli nie znaleziono, to dodaj fikcyjn ˛a definicj ˛e dla unikni ˛ecia kaskady bł ˛edów.

Wej ´scie do zakresu:

połó˙z na stos now ˛a tablic ˛e symboli,

umie´s´c w niej definicje zwi ˛azane z tym zakresem Wyj ´scie z zakresu:

zdejmij ze stosu ostatni ˛a tablic ˛e symboli

(11)

Metoda II: tablica stosów

Dla ka˙zdego identyfikatora tworzymy osobny stos odwoła ´n do jego definicji

Niezmiennik: w trakcie analizy, dla ka˙zdego identyfikatora na szczycie stosu jest odsyłacz do aktualnej definicji (lub stos pusty).

Wej ´scie do zakresu: przechodzimy list ˛e definicji zwi ˛azanych z zakresem i wkładamy odsyłacze do nich na odpowiednie stosy.

Wyj ´scie z zakresu: przechodzimy ponownie list ˛e definicji i zdejmujemy odsyłacze ze stosów.

W porównaniu z Metod ˛a I nieco wi ˛ecej pracy na granicach zakresów, ale za to szybsze wyszukiwanie.

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 10 / 22

(12)

Zagadka

class A { char a;

A() { a = ’A’;}

}

class B { char a;

B() { a = ’B’; } class C extends A {

public char c;

C() { c = a; } }

C C() { return new C(); } }

...

B b = new B(); B.C c = b.C();

(13)

Dziedziczenie

Jak wida´c z powy˙zszego przykładu, dziedziczenie nieco komplikuje wyszukiwanie.

Przy pojedynczym dziedziczeniu mo˙zemy przy wchodzeniu do zakresu podklasy wkłada´c na stos(y) definicje z nadklasy.

Innym rozwi ˛azaniem jest modyfikacja metody I: zamiast stosu - graf acykliczny tablic symboli.

Ka˙zda tablica ma dowi ˛azanie do tablic ewentualnych nadklas i zakresu obejmuj ˛acego.

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 12 / 22

(14)

Przykład

global:

type int

class Object,A,B

Object A:

int a

B:

int a con B() class C C C() C:

int c con C()

(15)

Tablica nazw

Przechowywanie identyfikatorów jako napisów powoduje znacz ˛ace koszty (czasowe, pami ˛eciowe)

Aby tego unikn ˛a´c, ka˙zdy identyfikator zapisujemy w tablicy nazw (tylko raz!), w zamian dostajemy numerek.

Tablica nazw = zbiór napisów + mechanizm wyszukiwania identyfikator → unikalny numerek

Implementacja: np. pula napisów + tablica mieszaj ˛aca (hash table)

Najlepiej zrobi´c to na etapie analizy leksykalnej.

W drzewie struktury identyfikator reprezentowany jest ju˙z przez numerek.

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 14 / 22

(16)

Pula napisów

Du˙za tablica znaków + indeks pierwszego wolnego miejsca Wstawianie napisu s:

I Sprawdzamy czy s jeszcze nie ma w puli (jak? o tym za chwil ˛e)

I Je´sli nie, wstawiamy na koniec

I Przesuwamy znacznik

I Wynik: pozycja wstawionego napisu w tablicy

W puli nie wyszukujemy — dost ˛ep tylko przez indeks.

W zasadzie nigdy nie usuwamy

NB Java udost ˛epnia pul ˛e napisów za po´srednictwem metody String.intern(), ale niezbyt efektywn ˛a.

(17)

Funkcje mieszaj ˛ ace

Funkcja mieszaj ˛aca

h : napis → [0..N − 1]

taka, ˙ze:

1 mo˙zna szybko obliczy´c warto´s´c dla danego napisu

2 małe prawdopodobie ´nstwo kolizji

Funkcje skrótu (MD5, SHA) maj ˛a małe prawdopodobie ´nstwo kolizji ale s ˛a wolne.

Dobre funkcje mieszaj ˛ace u˙zywaj ˛a 3–4 instrukcji procesora na bajt napisu

Zwykle dost ˛epne w bibliotekach.

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 16 / 22

(18)

Prosta tablica mieszaj ˛ aca

Tablica T indeksowana od 0 do N − 1, gdzie N jak w funkcji mieszaj ˛acej.

Elementami s ˛a rekordy (indeks w puli, numerek, nast ˛epny) Inaczej: elementami tablicy s ˛a listy par (indeks, numerek) Mo˙zemy te˙z pój´s´c na skróty i uzywa´c adresów w puli jako numerków

(19)

Przykładowa implementacja (fragment)

const char* Hash::find(const char* s,int len) const {

unsigned h = hash(s,len);

iterator i = T[h].begin();

for(;i!= T[h].end(); i++) if(!strcmp(s,*i)) return *i;

return 0;

}

const char* Hash::insert(const char* s, int len) {

unsigned h = hash(s,len);

T[h].push_front(s);

return s;

}

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 18 / 22

(20)

const char* NameTab::insert(const char* s, int len) { const char* ns;

if(ns = hashTab->find(s,len)) { repeated++;

return ns;

}else{

ns = stringPool->add(s,len);

if(ns)

hashTab->insert(ns,len);

else

return 0;

} }

(21)

Wariacje na temat

Otwarte adresowanie: zamiast list, przechowujemy pojedyncze elementy, w razie kolizji (adres zaj ˛ety) wyliczamy nowy adres.

Metoda młotka: je´sli w bibiotece mamy młotek (słownik), to u˙zywamy słownika napis 7→ numerek . Efekt: oszcz ˛edno´s´c czasu programisty, ale wi ˛eksze (ok 2x) zu˙zycie pami ˛eci oraz (ok 4x) czasu procesora.

Szczególne traktowanie krótkich (np. jednoznakowych)

identyfikatorów — analizator leksykalny przydziela im numerek od razu, np.

[A-Za-z] { yylval = int(*yytext);

return IDENTYFIKATOR; }

Warte rozwa˙zenia, zwłaszcza, ˙ze takie identyfikatory s ˛a cz ˛este.

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 20 / 22

(22)

Benchmark (∼ 10

6

linii kodu)

Pula napisów, tablica mieszaj ˛aca

benke@students$ find /usr/include -name \*.h

| xargs cat | /usr/bin/time ./pooled Identifier lexems: 11992028

Repeats: 11239094

8.71user 0.26system 0:09.02elapsed 99%CPU

0inputs+0outputs (0major+7626minor)pagefaults 0swaps Słownik, bez puli

benke@students$ find /usr/include -name \*.h

| xargs cat | /usr/bin/time ./mapped Identifier lexems: 11992028

Repeats: 11239094

38.09user 0.29system 0:38.44elapsed 99%CPU

(23)

Kod benchmarku

void test() { NameTab nameTab;

int identifiers = 0;

int shorts = 0;

while(yylex()) { identifiers ++;

if(!nameTab.insert(yytext,yyleng)) abort("FATAL: memory exhausted");

}

cout << "Identifier lexems: "

<< identifiers << endl;

cout << "Repeats: " << nameTab.repeated << endl;

}

Cwiczenie: zaimplementuj swoj ˛´ a tablic ˛e nazw i przetestuj j ˛a.

Marcin Benke (MIM UW) Metody Realizacji J ˛ezyków Programowania 15 listopada 2010 22 / 22

Cytaty

Powiązane dokumenty

Sterowanie wentylatorem zrealizowane w języku drabinkowym (LD) - sterownik WAGO... Język schematów drabinkowych LD Język schematów

Stałe to obiekty programu, których wartość w trakcjie realizacji programu NIE MOŻE ulec zmianie. Zmienne - wartość może

Ochrona danych poprzez argumenty typu static. Przeładowanie operatora

Kompilator – program przetwarzający kod źródłowy na kod wynikowy (kod pośredni w języku maszynowym, który jest zrozumiały dla komputera).. Interpretator –

Typ definiuje zakres lub zbiór dopuszczalnych wartości zmiennych, stałych i funkcji, zbiór dopuszczalnych operacji wykonywanych na tych wartościach

Wyrażenia są budowane w oparciu o stałe, zmienne, operatory, nazwy funkcji i zbiorów oraz nawiasy okrągłe. Wyrażenia zapisujemy w jednym wierszu, bez opuszczania znaku mnożenia,

Jeśli wartość wyrażenia_logicznego jest prawdą (TRUE), to wykonana zostanie instrukcja_1. W przeciwnym wypadku instrukcja_1 zostanie opuszczona i wykonana

Pomoc na temat konkretnej procedury uzyskuje się przez ustawienie kursora na pierwszej literze nazwy procedury i wciśnięcie Ctrl-F1.. Opracować program drukujący napis: