7

Czy każdy, w prostych słowach, może wyjaśnić, co oznacza "Tłumaczenie na podstawie składni"? Zacząłem czytać temat od Dragon Book, ale nie mogłem tego zrozumieć. The Wiki article też nie pomogło.Co oznacza tłumaczenie kierowane na składnię?

+0

http://en.wikipedia.org/wiki/Syntax-directed_translation –

+1

@ 500-InternalServerError dzięki. Ale już przeczytałem ten artykuł. Nie zrozumiałem tego. – saplingPro

Odpowiedz

17

W najprostszym ujęciu "Tłumaczenie podające składnię" oznacza sterowanie całym procesem kompilacji (tłumaczeniem) za pomocą modułu rozpoznawania składni (analizatora składni).

Konceptualnie proces kompilowania programu (tłumaczenie z kodu źródłowego na kod maszynowy) rozpoczyna się od parsera, który tworzy drzewo parse, a następnie przekształca to drzewo parsetu za pomocą sekwencji przekształceń drzewa lub wykresu, z których każdy jest w dużej mierze niezależny, w wyniku czego powstaje ostateczne uproszczone drzewo lub wykres, który jest przesuwany w celu wytworzenia kodu maszynowego.

Ten widok, choć sympatyczny teoretycznie, ma tę wadę, że jeśli spróbujesz zaimplementować go bezpośrednio, potrzebna jest wystarczająca ilość pamięci do przechowywania co najmniej dwóch kopii całego drzewa lub wykresu. Kiedy napisano Smoczą księgę (i kiedy wiele teorii zostało wymieszanych), pamięć komputera była mierzona w kilobajtach, a 64K było dużo. Kompilowanie dużych programów może być trudne.

Dzięki translacji składni, organizujesz wszystkie przekształcenia wykresów wokół kolejności, w której analizator składni rozpoznaje drzewo analizy. Zamiast tworzyć pełne drzewo parse, twój parser buduje jego małe fragmenty, a następnie przekazuje te bity do kolejnych przebiegów kompilatora, ostatecznie tworząc mały fragment kodu maszynowego, przed kontynuowaniem procesu analizowania w celu zbudowania następnego fragmentu. drzewo. Ponieważ w danym momencie istnieją tylko niewielkie ilości drzewa analizy (lub kolejnych wykresów), potrzeba znacznie mniej pamięci. Ponieważ rozpoznawanie składni jest głównym sekwenserem kontrolującym to wszystko (decydującym o kolejności zdarzeń), jest to nazywane Syntax Directed Translation.

Ponieważ jest to bardzo skuteczny sposób na ograniczenie wykorzystania pamięci, ludzie nawet przeprojektowali języki, aby ułatwić sobie pracę - idealnym rozwiązaniem jest posiadanie kompilatora "Single Pass", który w rzeczywistości może wykonać cały proces od analizy do generowania kodu maszynowego w jednym przebiegu.

W dzisiejszych czasach pamięć nie ma tak wysokiej jakości, więc nie ma takiej presji, aby wymusić wszystko w jednym przejściu. Zamiast tego zazwyczaj używasz Syntax Direct Translation tylko dla interfejsu, parsowania składni, wykonywania typecheckingu i innych semantycznych sprawdzeń oraz kilku prostych transformacji z parsera i tworzenia wewnętrznej formy (trzy kod adresu, drzewa lub dagy jakiegoś rodzaju), a następnie oddzielne optymalizacje i przekazy końcowe, które są niezależne (a więc nie są kierowane składnią). Nawet w tym przypadku możesz twierdzić, że te późniejsze podania są co najmniej częściowo skierowane na składnię, ponieważ kompilator może być zorganizowany tak, aby działał na dużych fragmentach danych wejściowych (takich jak całe funkcje lub moduły), przepychając wszystkie przejścia przed kontynuowaniem następny kawałek wejścia.

Narzędzia takie jak yacc są zaprojektowane wokół idei Przekierowanie składni - narzędzie tworzy syntaktor rozpoznający, który bezpośrednio uruchamia fragmenty kodu ("akcje" w żargonie narzędzi), gdy produkcje (fragmenty drzewa analizy) są rozpoznawane , nigdy nie tworząc rzeczywistego "drzewa". Te działania mogą bezpośrednio wywoływać to, co jest logicznie późniejsze, w kompilatorze, a następnie powracać, aby kontynuować przetwarzanie. Najważniejszą pętlą, która napędza to wszystko, jest maszyna stanu odczytu tokenu parsera.

+0

Czy większość interpretowanych języków jest zaimplementowana w ten sposób? – Josh

+0

@ Jos: Wiele interpretowanych języków najpierw tłumaczy tekst źródłowy na kod bajtowy lub inną wewnętrzną postać. Często w tym etapie stosuje się translację ukierunkowaną na składnię. –

+0

Właściwie nie musisz trzymać drzewa; po prostu musisz poprowadzić tłumaczenie ze składni. Jest to naprawdę proste do zrobienia, używając stosu parsowania jako substytutu drzewa (przynajmniej lewy kontekst). Minusem jest to, że generator kodu nie może być tak dobry. –

1

Przed Smoczą księgą były kompilatory kompilatora ukierunkowane na składni. META II i TREE META zostały opracowane w 1960 roku. Są to kompilatory języków (metakompilatory). Są to parsery odgórne, które przyjmują zestaw reguł parsowania, które są w rzeczywistości funkcją zwracającą sukces niepowodzenia. Każda reguła jest logicznym wyrażeniem analizy. Górna reguła jazdy zdefiniowała zawartość pliku źródłowego. Na przykład język programowania może składać się z szeregu deklaracji.Tak więc górna reguła jazdy będzie wyglądać następująco:

program = $declarations; 

$ oznacza zero lub więcej. $ deklaracje określają, że kompilowane źródło składa się z pewnej liczby deklaracji. deklaracje określają następnie rodzaje deklaracji. Możesz potrzebować deklaracji powiązań zewnętrznych, deklaracji danych, deklaracji funkcji lub procedur.

declarations = linkage_decl | data_decl | code_decl; 

Rodzaje deklaracji, z których każda jest osobną regułą. Składnia będzie kontrolować podczas generowania kodu. Metakompilatory kontrolowały przetwarzanie semantyczne na podstawie reguł składniowych. Na początku w zasadzie to jaźń. Później przekształcili źródło w drzewo i sporządzili listę struktur i przekazali je do reguł semantycznych, które wytworzyły ich wyniki. Na przykład arytmetyczna instrukcja przypisania może zostać przekształcona i przekazana do reguły semantycznej.

asign = id '=' expr ';' :ASSIGN!2 arith_gen(*1); 
expr = term $(('+':ADD | '-':SUB) term !2); 
term = factor $(('*':MPY | '//' :REM | '/':DIV) factor!2); 
factor = id | number | '(' expr ')'; 

Mówiono, że te języki były podobne. Ale tak nie jest. Są analityczne analizatory składni z góry do dołu. arith_gen zostałby wtedy zakodowany, aby rozpoznać struktury drzewa wygenerowane przez osadzone drzewo, ":" i "!" operatorów. Stosowana notacja drzewa to węzeł, po którym następują gałęzie drzew zawarte w "[" i "]" i oddzielone ",". Powyższa składnia analityczna definiuje matematyczną hierarchię wyrażenia. mnożenie, dzielenie i pozostałe czynności wykonywane przed dodaniem lub odejmowaniem. Arytmetyczne wyrażenie przypisania przekształcone na wyrażenie listy funkcjonalnej. Składnia kieruje transformacją danych wejściowych do notacji funkcjonalnej.

x = a + (b - c)/d; 

wywołuje funkcjonalną notacji drzewa: ASSIGN [X, ADD [a, strefa [SUB [b, c], d]]]

Te stare metacompilers nie odpowiada dokładnie bieżącej terminologii.

tematyką Wiki metacompiler META II i drzewa meta i to jest strona dyskusji o więcej informacji