Osnova dnešní přednášky Inkrementální překlad Teorie programovacích jazyků Ing. Pavel Haluza, Ph.D. ústav informatiky PEF MENDELU v Brně haluza@mendelu.cz 1 Motivace pro využití inkrementálního překladu 2 Inkrementální syntaktická analýza rozdělení derivačního stromu interpretační rekurzivní sestup rozšířená metoda datové struktury pro ukládání osahu zásoníku 3 Inkrementální sémantická analýza konstrukce sémantického stromu příklad řešení 4 Jazyky s volnou množinou lexikálních jednotek základní terminologie inkrementální překlad TEXu Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 2 / 41 Proč inkrementální překlad Analýza liovolné textové informace patří ke každodenní rutině moderního informatika Přestože dnes není prolém pracovat s výkonným hardwarovým vyavením, stále je co zlepšovat Typickým příkladem operace s velkými nároky na rychlost provádění je překlad zdrojového kódu v programovacím jazyku Jediná droná změna v rozsáhlém kódu může (ale nemusí) znamenat kompletní změnu činnosti programu Není vždy nezytně nutné překládat celý zdrojový kód skládající se z mnoha tisíců řádků znovu změna v komentáři nemá vliv na výsledky překladu změna v jediné proměnné může vyvolat řetězec chy ve většině případů následky mezi těmito extrémy Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 3 / 41 Základní myšlenka Široce rozšířen v editorech se zvýrazňováním syntaxe Řeší prolém rekonstrukce derivačního stromu poté, co je věta xyz změněna na xỹz Máme-li derivační strom T věty xyz generovaný ezkontextovou gramatikou G a větu ỹ, inkrementální překladač se snaží vytvořit nový derivační strom T věty xỹz s co nejmenším počtem kroků Ay ylo možné uplatnit inkrementální překlad, musíme mít k dispozici výsledky předchozího překladu včetně stavu zásoníku v jednotlivých krocích překladu Výpočetní složitost inkrementálního překladače do značné míry závisí na zvolené metodě implementace a na datové struktuře pro ukládání informací nezytných pro nový ěh překladače Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 4 / 41
Dvě úrovně prolému 1 Inkrementální syntaktický analyzátor (parser) řeší pouze změny v syntaxi, nikoli v sémantice jednodušší implementace, celkem ěžný výskyt programové editory pro arevné zvýrazňování syntaxe 2 Inkrementální sémantický procesor (celý překladač) kromě změn v syntaxi musí řešit i změny v sémantice prolém v provázanosti syntaktické a sémantické analýzy (syntaxí řízené překladové schéma) Původní zdrojový text: var a: integer; egin read(a); if a mod 2 = 0 then write(a, je sudé ) end. Zdrojový text po droné úpravě: var a: char; egin read(a); if a mod 2 = 0 then write(a, je sudé ) end. Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 5 / 41 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 6 / 41 řešení Při použití překladače zahrnujícího inkrementální syntaktický i sémantický analyzátor musíme řešit dva prolémy: najít změněný uzel v derivačním stromu a nahradit jej upraveným podstromem (syntaktická analýza) najít všechny místa ve zdrojovém kódu, které mohou ýt touto změnou dotčeny (sémantická analýza) Oě fáze překladu musejí ýt inkrementální a musejí ýt vzájemně propojeny Náš upravený text je syntakticky v pořádku, ale je operace modulo nad znakovou proměnnou správně také sémanticky? Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 7 / 41 Informační zdroje F, M. V., D, B. A. (1994): Efficient Incremental Parsing for Context-Free Languages. Proceedings of the 5th IEEE International Conference on Computer Languages, pp. 241 252 L, W. X. (1995): A Simple and Efficient Incremental LL(1) Parsing. Lecture Notes in Computer Science, Vol. 1012 L, W. X. (1996): Building Efficient LL Incremental Parsers y Augmenting LL Tales and Threading Parse Trees. Computer Languages, Vol. 22, No. 4, pp. 225 35 M, B., V, L. (2008): Compiler Construction. M, A. M., P, Y. V., S, Y. N. (1990): Incremental Recursive Descent Parsing. Computer Languages, Vol. 15, No. 4, pp. 193 204 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 8 / 41
Inkrementální syntaktická analýza Mějme ezkontextovou gramatiku G a věty w = xyz, w = xỹz LG. Věta w již yla překladačem analyzována, větu w je možné získat nahrazením symolu y za ỹ. Jak moc podoné udou derivační stromy vět w a w? S x y z S x ỹ z1 z0 w = xyz w = xỹz, z = z1z0 Pokud x = z0 = ϵ, derivační stromy udou zcela odlišné. Pokud ale můžeme identifikovat podřetězec z1, jsme schopni získat derivační strom věty w pouze analýzou podřetězce ỹz1 s využitím zývajících částí stromu věty w. Inkrementální syntaktická analýza Předpokládejme větu i + i + i, ve které dojde ke změně na i + i i. Dostáváme x = i + i, y = +, z = i, ỹ =. Tato úprava změní pouze y, podstromy související s x a z mohou ýt zachovány. Algoritmus rozdělení stromu v uzlu t do podstromů 1 Položíme n = t a opakujeme kroky 2 a 3, dokud neexistuje žádné takové n. 2 Přesuneme n do jeho pravého sourozence, pokud existuje; v opačném případě do pravého sourozence nejližšího předchůdce, který má pravého sourozence. 3 Prořezáváme podstrom s kořenem v n ze stromu T. Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 9 / 41 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 10 / 41 Inkrementální překlad pokračování E E E T T E T E F T ǫ F T + T E F T + T E i ǫ i ǫ F T + T E i ǫ F T F T i ǫ ǫ i i ǫ (a) derivační strom věty i+i+i () částečný X-strom (c) Z-podstromy programovacích jazyků Přednáška 10: Inkrementální Teorie překlad 11 / 41 Stromy a částečné podstromy Částečný X-strom věty xyz neúplný derivační strom v okamžiku analýzy posledního terminálu z x S částečným X-stromem tak můžeme získat osah zásoníku, který tvoří listy následující za posledním terminálem z x Z-podstromy pro xyz jsou definovány jako stromy prořezané z operace dělení na posledním terminálu z y, s výjimkou stromů osahujících ϵ neo potomky s ϵ Inkrementální překladač může přímo použít částečný X-strom jako výchozí strukturu, základním prolémem je nalezení způsou použití Z-podstromů neo jejich komponent tradiční metodou překladu LL(1) jazyků Často musí inkrementální překladač vytvářet podstromy, které v Z-podstromech již existují Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 12 / 41
Inkrementální překladač Kořenové symoly Z-podstromů jsou tvořeny neterminálními a terminálními symoly Efektivní metoda y rozhodovala o další činnosti pouze ze znalosti těchto kořenových neterminálních symolů Pro konstrukci rozkladové taulky osahující ve sloupcích i neterminální symoly upravíme definice FIRST a FOLLOW FIRST (α) = {X (N Σ) α Xβ} {ϵ α ϵ} FOLLOW (A) = {X (N Σ) S + γaxβ} {ϵ S γa} Algoritmus překladu začíná s částečným X-stromem, podřetězec ỹ ude analyzován tradičně Poté algoritmus zkusí znovu použít Z-podstromy neo jejich komponenty Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 13 / 41 Interpretační rekurzivní sestup Při překladu metodou neexistují prostředky pro ukládání osahu zásoníku ěhem překladu Prolém řeší algoritmus interpretačního rekurzivního sestupu (IRD), který explicitně manipuluje se zásoníkem a umožňuje tak uchovávat osah zásoníku v každém okamžiku překladu Pro účely implementace IRD překladače upravíme původní LL(1) gramatiku G na rozšířenou LL(1) gramatiku G = (N {S }, Σ { A, #}, P, S ), kde P = {S S A } {B β# B β P} S N (nový startovací symol) A Σ (akceptační symol) # Σ (symol označující konec pravé strany pravidla) Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 14 / 41 Interpretační rekurzivní sestup IRD překladač využívá rozkladovou taulku definovanou jako zorazení M : N (Σ {ϵ}) {X, error}, kde X je ukazatel na začátek pravé strany pravidla Metoda konstrukce rozkladové taulky je stejná jako ve standardním případě IRD překladač používá aktuální ukazatel AP, který ukazuje na konkrétní symol pravé strany přepisovacího pravidla Symol, na který ukazatel ukazuje, je aktuálním symolem Pokud aktuální ukazatel ukazuje na symol X v pravidle A αxβ, kde X N Σ { A, #}, jeho hodnota je vyjádřena jako A α.xβ Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 15 / 41 Založena na ukládání osahu zásoníku do podoy cesty v derivačním stromu od aktuálního symolu ke kořeni Vstupem je rozkladová taulka M, rozšířená gramatika G a vstupní věta w Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 16 / 41
Algoritmus 1 Polož AP := S.S A. 2 Polož s := FIRST(w). 3 Opakuj kroky 4, 5, 6, 7, dokud není vstupní řetězec akceptován, neo není ohlášena chya. 4 Srovnání: Pokud aktuální symol je terminální symol a pokud je stejný jako symol s, posuň aktuální ukazatel na další symol, přečti další symol ze vstupního řetězce a nastav s := FIRST(zytek vstupního řetězce). Jestliže aktuální symol není stejný jako s, ohlaš chyu. Formálně: (ax, γ, A α.aβ) (x, γ, A αa.β) neo (ax, γ, A α.β) error. Algoritmus pokračování 5 Expanze: Pokud aktuální symol je neterminální symol, nastav r := M(aktuální symol,s). Vlož aktuální ukazatel do zásoníku. Jestliže r = error, ohlaš chyu, jinak nastav AP := r. Formálně: (x, γ, A α.bβ) (x, γa αb.β, B.δ) neo (x, γ, A α.bβ) error. 6 Konec pravidla: Jestliže aktuální symol je #, odeer aktuální ukazatel ze zásoníku a posuň jej na další symol. Formálně: (x, γa α.bβ, B δ.#) (x, γ, A αb.β). 7 Akceptace: Jestliže aktuální symol je A (accept), skonči překlad a výsledek je ano. Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 17 / 41 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 18 / 41 Gramatika G = ({E, E, T, T, F}, {+,,, /, (, ), i}, P, E) s pravidly: E TE E +TE TE ϵ T FT T FT /FT ϵ F (E) i Rozšířená gramatika G = ({S, E, E, T, T, F}, Σ { A, #}, P, S): S E A E TE # E +TE # TE # ϵ# T FT # T FT # /FT # ϵ# F (E)# i# pokračování Výpočet množin FIRST a FOLLOW : FIRST (S) = {(, i} FIRST (E) = {T, F, (, i} FIRST (E ) = {ϵ, +, } FIRST (T) = {F, (, i} FIRST (T ) = {, ϵ} FIRST (F) = {(, i} FOLLOW (E) = {), ϵ} FOLLOW (E ) = {), ϵ} FOLLOW (T) = {), ϵ, +,, E } FOLLOW (T ) = {), ϵ, +,, E } FOLLOW (F) = {), ϵ, +,,, /, E, T } Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 19 / 41 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 20 / 41
pokračování Rozkladová taulka: i + / ( ) ϵ E E T T F S E A E A E TE # TE # TE # TE # E +TE # TE # ϵ# ϵ# T FT # FT # FT # T ϵ# ϵ# FT # /FT # ϵ# ϵ# ϵ# F i# (E)# Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 21 / 41 pokračování (i + i i, ϵ, S.E A ) (i + i i, S E. A, E.TE #) (i + i i, S E. A E T.E #, T.FT #) (i + i i, S E. A E T.E # T F.T #, F.i#) (+i i, S E. A E T.E # T F.T #, F i.#) (+i i, S E. A E T.E #, T F.T #) (+i i, S E. A E T.E # T FT.#, T.#) (+i i, S E. A E T.E #, T FT.#) (+i i, S E. A, E T.E #) (+i i, S E. A E TE.#, E. + TE #) (i i, S E. A E TE.#, E +.TE #) (i i, S E. A E TE.# E +T.E #, T.FT #) (i i, S E. A E TE.# E +T.E # T F.T #, F.i#) ( i, S E. A E TE.# E +T.E # T F.T #, F i.#) ( i, S E. A E TE.# E +T.E #, T F.T #) ( i, S E. A E TE.# E +T.E # T FT.#, T. FT #) (i, S E. A E TE.# E +T.E # T FT.#, T.FT #) (i, S E. A E TE.# E +T.E # T FT.# F.i#) T F.T #, (ϵ, S E. A E TE.# E +T.E # T FT.# T F.T #, F i.#) (ϵ, S E. A E TE.# E +T.E # T FT.#, T F.T #) (ϵ, S E. A E TE.# E +T.E # T FT.# T.#) T FT.#, (ϵ, S E. A E TE.# E +T.E # T FT.#, T FT.#) (ϵ, S E. A E TE.# E +T.E #, T FT.#) (ϵ, S E. A E TE.#, E +T.E #) (ϵ, S E. A E TE.# E +TE.#, E.#) (ϵ, S E. A E TE.#, E +TE.#) (ϵ, S E. A, E TE.#) (ϵ, ϵ, S E. A ) Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 22 / 41 Datové struktury pro ukládání zásoníku Stromová struktura pro liovolnou LL(1) gramatiku Lineární seznam s offsety užitečné pro q-gramatiky Lineární seznam s offsety 0 a 1 pro q-gramatiky s nejméně jedním terminálním symolem před každým neterminálním Lineární seznam modifikovaný překladač pro q-gramatiky s nejméně jedním terminálním symolem před každým neterminálním symolem Lineární seznam s ukazateli na výše stojící neterminální symol modifikovaný překladač pro q-gramatiky s terminálem pouze na začátku pravých stran Volíme kompromis mezi prostorovou složitostí gramatiky a prostorovou složitostí datové struktury pro ukládání osahu zásoníku Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 23 / 41 Inkrementální sémantická analýza Využijeme metodu interpretačního založenou na skutečnosti, že výstupem inkrementální syntaktické analýzy je derivační strom reprezentující poslední úpravu zdrojového kódu, která je vstupem sémantického analyzátoru Chceme-li propojit fáze syntaktické a sémantické analýzy v okamžiku konstrukce nového derivačního stromu, nutně musíme mít k dispozici informace o vzájemných vazách mezi jednotlivými částmi zdrojového kódu Informace o sémantických vazách můžeme propojit s pravidly gramatiky daného jazyka podoným způsoem, jako jsou propojeny sémantické akce, vytváříme tím sémantický strom závislostí Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 24 / 41
Konstrukce sémantického stromu Definice Nechť p1, p2 P jsou dvě pravidla gramatiky G, X je množina sémantických akcí, X1, X2 X jsou dvě sémantické akce v pravidlech p1 a p2 tak, že pravidlo p1 je ve tvaru N1 αx1β a pravidlo p2 je N2 γx2δ, kde N1, N2 N, α, β, γ, δ (N Σ X). Vazu X2 X1 můžeme reprezentovat novou sémantickou akcí B(X1) v pravidle p2 ve tvaru N2 γx2b(x1)δ. Přítomnost sémantické akce B(X1) v pravidle způsoí nutnost nového překladu konstrukce popsané pravidlem osahujícím akci X1 na pravé straně Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 25 / 41 Možné důsledky změn ve zdroji Změna datového typu proměnné může ovlivnit celou deklarační část programu Změna deklarační části programu může ovlivnit hodnoty všech deklarovaných proměnných Změna hodnoty deklarované proměnné může ovlivnit hodnoty všech výrazů, ve kterých se proměnná vyskytuje Změna hodnoty výrazu může ovlivnit výsledky volání funkcí, které tyto výrazy osahují v parametrech Změna hodnoty výrazu může také ovlivnit podmíněné příkazy, které tyto výrazy osahují v podmínkách Změna ve vyhodnocení podmínky může ovlivnit všechny příkazy cyklu, které jsou touto podmínkou řízeny Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 26 / 41 Graf závislostí ve zdrojovém kódu Graf závislostí ve zdrojovém kódu data type of variales declaration of variales s of variales ofthe expressions with variales conditional statements expressions inthe parameters of functions cycle statements Mějme zdrojový kód v následující podoě: var a,,c:integer; egin a:=10; :=5; c:=a+*3; write(a,,c); :=a+c; write() end. Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 27 / 41 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 28 / 41
Krok 1: Deklarace proměnných Krok 2: Přiřazení hodnoty do proměnných declaration INITLIST decitem ; decitem decitem var : id SAVETYPE declaration INITLIST decitem ; decitem decitem var : id SAVETYPE BIND(INITLIST) integer integer integer assignment id LVALUE := expr factor ( expr ) id RVALUE factor num assignment id LVALUE := expr factor ( expr ) id RVALUE BIND(LVALUE) factor num BIND(LVALUE) integer integer integer 10 5 + 3 of of Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 29 / 41 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 30 / 41 Krok 3: Výpis hodnoty proměnné Krok 4: Přiřazení hodnoty do proměnných expr INITEXP term expr factor ( expr ) id RVALUE factor num expr INITEXP term expr factor ( expr ) id RVALUE BIND(INITEXP) factor num BIND(INITEXP) integer integer integer 10 5 + 3 a of assign. to + c integer integer integer 10 5 + 3 a c of Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 31 / 41 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 32 / 41
Krok 5: Výpis hodnoty proměnné Změna ve zdrojovém kódu integer integer integer 10 5 + 3 a of assign. to + c Původní zdrojový kód: var a,,c:integer; egin a:=10; :=5; c:=a+*3; write(a,,c); :=a+c; write() end. Upravený zdrojový kód: var a,,c:integer; egin a:=4; :=5; c:=a+*3; write(a,,c); :=a+c; write() end. Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 33 / 41 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 34 / 41 Závislosti při překladu upraveného kódu Množiny lexikálních jednotek integer integer integer 4 5 + 3 a of assign. to + c Pevná množina lexikálních jednotek ěžné programovací a skriptovací jazyky, které mohou ýt popsány ezkontextovou gramatikou každý vstupní symol je při analýze rozpoznán, výstupem analyzátoru je informace o typu tokenu každý znak je jednoznačně přiřazen k lexikální jednotce daného typu a toto přiřazení je po celou dou konstantní implementace známou a osvědčenou metodou Volná množina lexikálních jednotek množina přiřazení vstupních symolů k typu lexikální jednotky, v průěhu překladu může ýt proměnlivé možnost změny významu liovolného znaku ěhem překladu, často navíc jen po určitou omezenou dou platnosti Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 35 / 41 Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 36 / 41
Jazyky s volnou množinou lex. jednotek Typickým zástupem typografický systém TEX Proces analýzy vstupního textu značně odlišný od ěžných programovacích jazyků Činnost TEXu je rozdělena do jednotlivých procesorů input procesor čte ze vstupu řádky, upravuje je a připravuje pro další fázi, výstupem je vnitřní datová struktura společná pro všechny implementace TEXu token procesor zpracovává řádky upravené input procesorem a poskytuje posloupnost lexikálních jednotek ve tvaru uspořádané dvojice (ASCII kód, kategorie) neo řídicí sekvence expand procesor zajišťuje expanzi (použití) maker, zamění řídicí sekvenci na vstupu za posloupnost tokenů daného makra hlavní procesor řídí činnost TEXu, sestavuje výsledek Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 37 / 41 Kategorie znaků v TEXu kategorie význam výchozí přiřazení 0* uvození řídicí sekvence \ 1 otevření skupiny { (plain) 2 zavření skupiny } (plain) 3 přepínač matematického módu $ (plain) 4 separátor v taulkách & (plain) 5* konec řádku ^^M (ASCII 13) 6 označení parametrů maker # (plain) 7 konstruktor mocniny ^ (plain) 8 konstruktor indexu _ (plain) 9* znak, který se ignoruje ^^@ (ASCII 0, plain) 10 mezera 11 písmeno A až Z, a až z 12 ostatní znaky zylé znaky 13 aktivní znaky ~, ^^L (plain) 14* uvození komentáře na začátku % 15* nedovolený znak ^^? (ASCII 127) jazyků Přednáška 10: Inkrementální překlad Teorie programovacích 38 / 41 Lexikální analýza TEXu Lexikální analyzátor v systému TEX představuje funkce, která plní input procesor a token procesor Konkrétní podoa vlastní procedury závisí na zvoleném programovacím jazyku a prostředí, takže mohou vzniknout různé varianty procedury, které v konečné podoě pracují stejně V rámci lexikální analýzy je nutné přiřadit každému znaku jeho kategorii prolém v okamžiku, kdy se kategorie změní Změnu kategorie umožňuje makro \catcode, projeví se okamžitě a je platná do konce skupiny neo souoru, pokud není platnost vymezena skupinou Je tedy potřea při změně znovu analyzovat dotčenou skupinu, příp. zytek souoru, není-li skupina vymezena Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 39 / 41 Inkrementální překlad TEXu Rozkladová taulka zůstává i po změně kategorie znaku eze změn, neoť není závislá na vstupu, ale na konstantní množině povolených lexikálních jednotek Změna musí nastat na úrovni lexikální analýzy v input procesoru Potřeujeme datovou strukturu osahující informace o aktuálních kategoriích jednotlivých znaků Při použití makra \catcode uložíme novou informaci o změně kategorie znaku Lexikální analyzátor při určování kategorie přečteného znaku musí vycházet z aktuálních uložených informací Další fáze překladu zůstávají eze změn Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 40 / 41
Inkrementální překlad TEXu VSTUP posloupnost jednotlivých znaků ze vstupu INPUT PROCESOR aktuální kategorie znaků posloupnost znaků s přiřazenou kategorií TOKEN PROCESOR posloupnost lexikálních jednotek(tokenů) EXPAND PROCESOR posloupnost tokenů s expandovanými makry aktuální informace o kategoriích znaků po zpracování\catcode HLAVNÍ PROCESOR zpracovaný dokument VÝSTUP Teorie programovacích jazyků Přednáška 10: Inkrementální překlad 41 / 41