2 Formální jazyky a gramatiky 2.1 Úvod Teorie formálních gramatik a jazyků je důležitou součástí informatiky. Její využití je hlavně v oblasti tvorby překladačů, kompilátorů. Vznik teorie se datuje přibližně do roku 1956, kdy matematik polského původu Noam Chomsky na základě studia a výzkumu zákonitostí v přirozených jazycích vytvořil matematický model gramatiky. V dalším období se ukázala úzká souvislost mezi teorií formálních jazyků a teorií automatů. Chomsky vytvořil klasifikaci formálních jazyků a gramatik, přičemž je rozdělil, jak si ukážeme v této kapitole, do čtyř skupin. Co je to vlastně jazyk? Naučný Websterův slovník jej definuje jako soubor slov a metod skládání slov, které chápe a používá dostatečně velká společnost lidí. S touto definici samozřejmě pro naše účely nevystačíme. Pro potřeby matematické teorie jazyků je třeba definovat formální jazyk abstraktně jako matematický systém. 2.2 Základní pojmy V této části uvedeme základní pojmy z teorie formálních jazyků a gramatik. Podobně jako je tomu u přirozených jazyků, budeme i ve formálních jazycích používat pojmy jako jsou písmeno, slovo, věta. Abeceda A je konečná množina symbolů, ze kterých se v daném jazyku vytváření vyšší významové celky. Příklad 1. {a, b, c, d,... z, A, B, C,... Z} písmena (velké i malé) {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} číslice {+ - * /., : = { } [ ] ( ) < >} speciální znaky {and, array, begin, case,..., var, while, with} vyhrazené slova Pascalu Řetězec w je libovolná konečná posloupnost symbolů dané abecedy A. Délka řetězce w je definovaná jako počet symbolů v řetězci w. V jazyku je možné teoreticky odvodit různé řetězce různé délky až po nekonečné řetězce. Z praktických důvodů mají však význam řetězce konečné délky. Zvláštní postavení má tzv. prázdný řetězec. Prázdny řetězec ε je řetězec s nulovou délkou. Obrácený řetězec wr je řetězec obsahující symboly původního řetězce v opačném pořadí. Pokud máme řetězec w = a 1 a 2 a 3... a n, tak k němu obrácený řetězec je w R = a n a n-1... a 3 a 2 a 1 Příklad 2. Nechť je řetězec x 1 = automobil jeho délka je x 1 = 9 obrácený řetězec x R 1 = libomotua Zřetězení je operace. definovaná na množině řetězců dané abecedy takto: Pokud u = a 1 a 2... a k, v = b 1 b 2... b l jsou řetězce nad danou abecedou, tak u.v = a 1 a 2... a k b 1 b 2... b l je nový řetězec uv. Zápisy u.v a uv jsou ekvivalentní. Příklad 3. Nechť x 1 = abc a x 2 = de. Potom x 1.x 2 = abcde a x 2.x 1 = deabc. Pro pojmy v následujících definicích použijeme řetězce x, y a z nad určitou abecedou. Řetězce w 1 =xy, w 2 =yz a w 3 =xyz jsou řetězce, které vznikly jejich zřetězením. Řetězec x je prefix nebo předpona řetězce w 1 i řetězce w 3. Řetězec y je postfix nebo přípona řetězce w 2. Řetězec x, y i z jsou podřetězce řetězců w 1, w 2 i w 3. Množinu všech řetězců nad abecedou A (t.j. řetězců, ve kterých se nacházejí jen znaky, které jsou prvky abecedy A) budeme označovat A *. 1. 3. 2007-14:41 Benedikovič 1 / 6
Množinu všech řetězců bez prázdného řetězce nad abecedou budeme označovat A +. Příklad 4. Nech x = abc. prefixy - ε, a, ab, abc postfixy - ε, c, bc, abc podreťazce - ε, a, b, c, ab, bc, abc Nech A={a, b, c}, potom: A * - {ε, a, b, c, aa, ab, ac, ba, bb, bc, ca, cb, cc, aaa, aab,...} A + - {a, b, c, aa, ab, ac, ba, bb, bc, ca, cb, cc, aaa, aab,...} Na tomto místě máme všechny potřebné informace k tomu, abychom uvedli první, zatím ještě příliš všeobecnou definici formálního jazyka. Nechť A je abeceda. Potom formální jazyk nad abecedou A definujeme jako libovolnou podmnožinu množiny A *. Tato definice však umožňuje popsat samotný jazyk takovým způsobem, že vyjmenujeme všechny možné řetězce, které mají být prvky daného jazyka. Představme si však případ, kdy bychom měli tímto způsobem definovat nějaký programovací jazyk (Pascal nebo C a pod.). Vidíme, že pro tyto účely je tato základní definice prakticky nepoužitelná. Musíme hledat nějaký mechanismus, který daný jazyk úplným způsobem popíšeme. Z uvedených definicí vidíme, že abeceda i jazyk jsou množiny. Můžeme na ní tedy použít množinové operace. Nechť tedy platí, že A 1 a A 2 jsou abecedy a L 1 A * 1 a L 2 A * 2 jsou jazyky, potom A 1 A 2 = { x x A 1 x A 2 } L 1 L 2 = { y y L 1 y L 2 } A 1 A 2 = { x x A 1 x A 2 } L 1 L 2 = { y y L 1 y L 2 } A 1 - A 2 = { x x A 1 x A 2 } L 1 - L 2 = { y y L 1 y L 2 } Nad jazykem se setkáváme i s následujícími operacemi: Nechť L 1 a L 2 jsou jazyky. Potom jejich zřetězením voláme jazyk L s vlastnostmi: L = { xy x L 1 y L 2 } Příklad 5. L 1 = { a, b,... z, A,... Z }, L 2 = { a,... z, A,...Z, 0, 1,... 9 }*. L = L 1 L 2 je jazyk řetězců složený z písmen a číslic, které začínají písmenem. Pokud L je jazyk, tak jeho n-tou mocninu definujeme takto: L 0 = { ε } L n = L.L n-1 pre n 1 Uzávěr jazyka L je množina L * = L i pro i 0 Pozitivní uzávěr jazyka L je množina L + = L i pro i 1 2.3 Gramatika Již jsme zmínili, že první definice formálního jazyka uvedená v předcházející části není vhodná pro praktické použití v souvislosti s popisem nějakého programovacího jazyka. Vyžaduje vyjmenování všech možných řetězců. Potřebujeme vytvořit nějaký mechanismus vyčerpávajícím způsobem popisující daný jazyk. Tímto mechanismem je tzv. gramatika. Představuje systém syntaktických pravidel, pomocí kterého je možné vygenerovat libovolný řetězec jazyka, případně je možné zjistit, či daný řetězec do jazyka patří nebo ne. V definici gramatiky se vyskytují následující pojmy: Terminál nebo terminální symbol je prvotní symbol daného jazyka. Jde o symbol z množiny symbolů jazyka, který už v procesu analýzy nenahrazujeme. Jde o cílový termín, který je součástí nějakého řetězce jazyka. Neterminál nebo neterminální symbol je symbol definovaný pomocí pravidel jazyka. 1. 3. 2007-14:41 Benedikovič 2 / 6
Začátečný symbol (také startovací) je jeden z neterminálních symbolů, ze kterého začíná generování vět jazyka, případně analýza věty. Přepisovací pravidlo nebo vytvářecí pravidlo, produkce je předpis, který určuje způsob náhrady neterminálu jiným podřetězcem. Následuje všeobecná definice gramatiky, na základě které se vykonává analýza věty, t.j. zjišťuje se, zda analyzovaná věta ( může to být například program v programovacím jazyce) vyhovuje syntaktickým pravidlům jazyka. Gramatika určuje jen syntaxi jazyka přípustnou strukturu vět. Významem věty je zabývá sémantika. Syntakticky správná věta ještě nemusí být správná z významového, sémantického hlediska. Gramatika je definovaná jako čtveřice G = ( N, T, P, S ), kde N konečná množina neterminálních symbolů, T konečná množina terminálních symbolů, N T =, S začáteční symbol, S N, (musí byť pouze jeden!). P konečná množina přepisovacích pravidel z (N T) * N (N T) * x (N T) * Stručně si vysvětlíme význam a použití symbolů v definice. Pro odlišení neterminálů (množiny N) od terminálů (množina T) často používáme v praxi zápis neterminálu uzavřeného v lomených závorkách, například <identifikátor>. Slovo identifikátor se může vyskytnout i přímo jako součást řetězce, tedy jako terminál. Pokud je uvedené v ostrých závorkách, potom vyjadřuje neterminál zastupující celou množinu pojmů splňujících určité vlastnosti. O které konkrétní pojmy jde, určují pravidla z množiny P. Lomené závorky použijeme pro jasné odlišení terminálů a neterminálů. Tam můžeme použít stejné slovo ve dvou významech a přitom zaručíme požadovanou disjunktnost množin N a T. Přepisovací pravidla jsou základem pro generování vět jazyka. V definici gramatiky jsou vyjádřené jako kartézský součin. Jeden konkrétní případ kartézského součinu množiny P představuje přepisovací pravidlo, ve kterém na levé musí být alespoň jeden neterminál, kvůli kterému se náhrada vykonává. Před ním a za ním můžou (ale nemusí) být řetězce složené z terminálů a neterminálů. Na pravé straně pravidla je nějaký řetězec terminálů a neterminálů (obecně může být i prázdný). Pro levé a pravé strany přepisovacího pravidla, produkce budeme někdy používat zkratky: LHS z anglického left hand side a RHS right hand side. Nad množinou řetězců terminálů a neterminálů definujeme relaci derivace nebo relaci odvození. Mějme gramatiku G = ( N, T, S, P ). Relace odvození - derivace ( značíme ji G ) definovaná nad množinou (N T) * je definovaná takto: Pokud αβγ (N T) * a αδγ (N T) *, potom dané řetězce jsou relací αβγ G αδγ tehdy, kdy v množině P existuje přepisovací pravidlo β δ Můžeme též používat následující pojmy. V případě, že pro řetězce α a β platí, že jsou v relaci derivace α G β, hovoříme také, že z α můžeme přímo derivovat β, nebo β můžeme derivovat z α. Inverzní relaci k derivaci nazýváme redukce. Tuto relaci používáme například při analýze, ve které vycházíme z analyzovaného řetězce a postupnými redukcemi se snažíme dosáhnout začáteční symbol (v tomto případě ho můžeme nazývat cílový symbol) a tím vyhlásit původní řetězec za přijatý. Nechť G = ( N, T, S, P ) je gramatika a mějme řetězce α i (N T) * pro i = 0, 1, 2,... k. Říkáme, že α k se dá derivovat z α 0, pokud platí α i G α i+1 pro i = 0, 1, 2,... k-1. Posloupnost řetězců α 0, α 1,... α k nazýváme odvození - derivace α k z α 0 Jde vlastně o posloupnost řetězců složených z terminálů a neterminálů dané gramatiky. Následující definice nám říká o skutečnosti, že ne každý řetězec (!!!) skládající se jen ze symbolů (terminálů a neterminálů) gramatiky také do této gramatiky patří! Množinu řetězců α (N T) * gramatiky G = ( N, T, S, P ), které jsou derivovatelné ze začátečního symbolu S nazýváme množina větních forem. Formální zápis: V = { α S * α, α (N T) * } 1. 3. 2007-14:41 Benedikovič 3 / 6
Teď máme pohromadě vlastně všechny potřebné pojmy pro to, abychom uvedli definici jazyka, která popisuje množinu vlastních řetězců pomocí stejného systému pravidel gramatiky. Nechť G = ( N, T, S, P ) je gramatika. Jazyk L(G) specifikovaný gramatikou G je množina řetězců složených pouze z terminálních symbolů, pro které existuje derivace ze začátečního symbolu gramatiky. Formální zápis: L(G) = { w S * w, w T * } Všimněte si zásadního rozdílu od definice větné formy (vidět ho i ve formálním zápise). Řetězec jazyka je také větnou formou, ale opačně to neplatí. 2.4 Zápis syntaxe pravidel V dalším textu budeme používat následující dohodu pro zápis pojmů: Pojem Všeobecný popis Konkrétnejší popis a) neterminální symboly velká latinská písmena A, B, C, název terminálu uzavřený v lomených závorkách ve tvaru <jméno neterminálu> b) terminální symboly malá latinská písmena a, b, c,... přímo koncové symboly popisovaného jazyka c) slova složená z terminálních malá řecká písmena α, β, γ,... skutečný řetězec a neterminálních symbolů d) slova složená jen malá latinská písmena, pokud to skutečný řetězec z terminálních symbolů z kontextu není jasné, s upozorněním, že je to řetězec e) přepisovací pravidla ve tvaru α β BNF, Conwayův diagram (viz dále) f) přepisovací pravidla se stejnou pravou stranou α β 1, α β 2, α β 3,... α β 1 budeme zapisovat jako α β 1 β 2 β 3... β n 2.4.1 Backusova Naurova forma, BNF Zápis pravidel v tomto systémů je charakterizován tímto tvarem: <neterminální symbol> ::= α 1 α 2... α n kde všechny α i jsou řetězce neterminálních a terminálních symbolů nebo prázdný řetězec, kterými je definován řetězec uvedený na LHS. Neterminál na levé straně pravidla LHS je jednotka, kterou definujeme řetězcem RHS. Metasymbol ::= můžeme číst například jako definujeme jako.... Tento systém je určen na popis přepisovacích pravidel gramatiky. Je to vlastně také jazyk. Protože však popisuje vlastnosti jazyka určeného pro popis jiného jazyka, budeme mu pracovně říkat metajazyk, jeho symbolům metasymboly a jeho případným předpisům metapříkazy. V BNF použijeme následující metasymboly: metasymbol: význam metasymbolu: ::= definice symbol nahrazení levé strany (LHS) pravou stranou pravidla (RHS) při derivaci (= definuj jako... ) alternativa metaoperátor výběru jedné varianty z uvedených pravých stran (= nebo ). sekvence metaoperátor zřetězení operandů v zápise pravidla (= následuje") * mocnina metaoperátor opakování výskytů metaoperandu, (..) prázdného počtu výskytů (= opakuj ) ( ) Změna priority metaoperátorů < > Čitelné vyjádření symbolu, který nazýváme neterminál + Mocnina typu alespoň jedenkrát 1. 3. 2007-14:41 Benedikovič 4 / 6
Metaoperátor opakování metaoperandů s povinným výskytem (= opakuj alespoň jednou ) Příklad 6. <identifikátor> ::= <písmeno>. ( <písmeno> <číslice> ) * <celé číslo> ::= ( <znaménko> ε ). <číslice >. <číslice> * Zápis <číslice >. <číslice> * možno zkrátit na: <číslice> + ( znaky hvězdička a plus) V uvedeném příkladě je definovaný identifikátor pro většinu běžných programovacích jazyků. Na pravé straně je zřetězením. určené, že identifikátor začíná písmenem, za kterým následuje libovolný počet znaků s tím, že každý z nich je buď písmeno nebo číslice. Metaoperátor * vyvolává opakované použití daného metaoperandu (možný je i prázdný řetězec). Mocnina má vyšší prioritu než alternativa, proto je nutné použít závorky pro změnu priority zpracovávání metaoperátorů. Zamyslete se nad případem, ve kterém by jsme s touto definicí vynechali závorky. Priorita metaoperátorů: * + nejvyšší priorita. nejnižší priorita V současnosti se používá pro zápis syntaxe i rozšířená verze Backusovej Naurovej formy(ebnf), ve které jsou na místo metaoperátoru * používají složené závorky {... } s následujícím významem: BNF EBNF význam α* { α } libovolný počet opakování řetězce α vrácení prázdného řetězce --- { α } n m řetězec α se může vyskytnout od m-krát do n-krát --- { α } 1 [ α ] Oba dva zápisy jsou ekvivalentní Řetězec α se vyskytuje maximálně 1-krát Definice identifikátoru z předcházejícího příkladu bude v zápise EBNF vypadat takto: Příklad 7. <identifikátor> ::= <písmeno>. { <písmeno> <číslice> } <celé číslo> ::= [ <znaménko> ]. <číslice >. { <číslice> } < znamienko > ::= ( + - ) 2.4.2 Syntaktický diagram Conwayův diagram Grafické vyjádření vztahů mezi neterminály a terminály uvnitř přepisovacího pravidla. Při zobrazování platí následující pravidla: terminální symbol: a (kroužek alebo ovál) alternativa: a b... A a neterminální symbol: A ĺ A a b... A zřetězení: ab... c a b... c mocnina * : α * mocnina + : α + α α 1. 3. 2007-14:41 Benedikovič 5 / 6
Příklad 8. Na tomto příkladu jsou demonstrovány pravidla z předcházejícího příkladu: identifikátor Písmeno celé číslo Číslica Písmeno Znamienko Číslica 2.5 Klasifikace gramatik Gramatiky je možné z hlediska podmínek, kladených na přepisovací pravidla rozdělit do více skupin. Umožňuje to při přípravě analyzátoru použít více, či méně úspěšně, příslušné techniky a nástroje. V současnosti se nejčastěji používá rozdělení gramatik podle Chomského. Vycházíme z definice gramatiky, přičemž Chomského klasifikace rozlišuje čtyři skupiny gramatik: Typ Název Pravidlo Omezující podmínky 0 Frázová-neomezená α β bez omezení 1 Kontextová α β α (N T) * N (N T) * a β (N T) + a platí α β 2 Bezkontextová A β A N ; α (N T) * 3 Regulární A β A N ; β = bb nebo β = b, ( kde b T a B N ) Poznámky k tabulce: ( LHS=levá, RHS=pravá strana pravidla ) 1) U kontextové gramatiky existuje alespoň jedno pravidlo, ve kterém je na levé straně (LHS) řetězec složený z více symbolů, přičemž v každém pravidle musí být v LHS jeden neterminál A, kterého se pravidlo týká. Před ním nebo za ním můžou být nějaké neprázdné podřetězce α, β, přičemž derivace neterminálu se vykonává jen v kontextu s nimi. LHS tohoto pravidla nechť je tedy ve tvaru αaβ, přičemž alespoň jeden z podřetězců α, β není prázdný. Na pravé straně (RHS) každého pravidla je neprázdný řetězec terminálů a neterminálů. Na pravé straně pravidla musí být alespoň tolik symbolů jako na levé straně. Žádné pravidlo tedy nesmí(!) větní formu zkracovat! 2) Bezkontextová gramatika se vyznačuje vlastností, že v každém pravidle je na LHS samostatně stojící neterminál. Na RHS je libovolný řetězec terminálů a neterminálů (...) prázdného řetězce. 3) V regulární gramatice existují jen pravidla s jedním neterminálem na LHS a jednoduchou pravou stranou. Na RHS může být buď samostatně umístěný jeden terminál nebo jeden terminál následovaný jedním terminálem. Na tomto rozdělení gramatik si můžeme všimnout, že platí: každá regulární gramatika je současně bezkontextovou, každá bezkontextová kontextovou a každá kontextová je gramatikou bez omezení. Obráceně to ovšem neplatí! Gramatika je systémem pravidel, pomocí kterých je možné odvozovat řetězce vyhovující této gramatice. Proto je součástí jazyka, který je charakterizovaný vlastnostmi své gramatiky. Jazyk nazýváme regulární, resp. bezkontextový, resp. kontextový, resp. bez omezení (frázový), pokud jej můžeme generovat příslušnou gramatikou (regulární, resp. bezkontextovou, resp....) Vztah mezi jednotlivými typy jazyků je analogický vztahu mezi jeho gramatikami. Ještě něco pro nepozorné gramatika je systém pravidel, jazyk je množina řetězců. 1. 3. 2007-14:41 Benedikovič 6 / 6