BAĞLAMDAN BAĞIMSIZ VE BAĞLAMDAN BAĞIMSIZ OLMAYAN DİLLER (CONTEXT-FREE AND NON-CONTEXT-FREE LANGUAGES) Context-free dillerin üretilmesi için context-free gramer ler kullanılmaktadır. Context-free dillerin tanınması için pushdown otomatlar kullanılmaktadır. Context-free gramer in ürettiği dili tanıyan bir pushdown otomat oluşturulabilir. Bir dilin context-free veya non-context-free olduğunu belirlemek için yöntemler vardır. Closure properties ve pumping lemma iki farklı yöntem olarak regular dillerde olduğu gibi kullanılabilir. Teorem: Context-free diller union, concatenation ve Kleene star işlemleri için kapalıdır. İspat: G 1 = (V 1, 1, R 1, S 1 ) ve G 2 = (V 2, 2, R 2, S 2 ) iki farklı gramer olsun. Bu iki gramer için nonterminal kümeleri disjoint olsun. (V 1 1 ) (V 2 2 ) = Union S yeni bir sembol, G = (V 1 V 2 {S}, 1 2, R, S) ve R = R 1 R 2 {S S 1, S S 2 } olsun. 1 Yrd.Doç.Dr.Hacer KARACAN
Amaç L(G) = L(G 1 ) L(G 2 ) olduğunu göstermektir. Herhangi bir w string i için ( S S 1, S S 2 olduğundan) S * G w olur eğer sadece ve sadece S 1 * G w veya S 2 * G w ise. Nonterminaller kümeleri disjoint olduğu için ilk kuralla S 1 veya S 2 ye geçildikten sonra diğerine tekrar dönülmez. Concatenation G = (V 1 V 2 {S}, 1 2, R 1 R 2 {S S 1 S 2 }, S) şeklinde tanımlanan bir gramer le L(G 1 )L(G 2 ) dili oluşturulabilir. Birinci gramer deki nonterminaller (S 1 içindeki) terminallere dönüştürüldükten sonra ikinci gramer deki nonterminaller (S 2 içindeki) terminallere dönüştürülür. Kleene star G = (V 1 {S}, 1, R 1 {S e, S SS 1 }, S) şeklinde tanımlanan bir gramer le L(G 1 ) * dili oluşturulabilir. S SS 1 kuralının tekrarı ile dildeki kuralın (S S 1 ) tekrarı istenen sayıda yapılabilir. 2 Yrd.Doç.Dr.Hacer KARACAN
Tanımlar: G = (V,, R, S) bir context-free gramer olsun. G nin fanout değeri (G) olarak gösterilir ve R kurallar kümesinde sağ kısmı en uzun olan kuralın sağ kısmındaki sembol sayısıdır. Bir parse tree üzerinde path root node ile yaprak node arasında farklı node lardan geçilerek elde edilen sıradır. Yolun length değeri üzerindeki çizgi sayısıdır. Bir parse tree için height en uzun yolun length değeridir. Lemma: G gramer ine ait h height değerine sahip bir parse tree nin ürettiği string in uzunluğu en çok (G) h olabilir. İspat: h = 1 için parse tree gramer içinde bir kuraldır (2.durum). Ençok (G) h = (G) uzunluğunda string üretilir. (S abc, S abcabcabc) h 1 olan her h değeri için yeni bir root oluşur h-1 yüksekliğindeki parse tree leri birbirine bağlar. h+1 için yüksekliği ençok h olan enfazla (G) adet parse tree birbirine bağlanır (3.durum). Her parse tree (G) h uzunluğunda string oluşturur ve toplam en çok (G) h+1 uzunluğunda string oluşur. 3 Yrd.Doç.Dr.Hacer KARACAN
R 1 = (A ababa, A aba,...), S R 2 = (S AAA, A ababa,...) h= 1 A A A A a b a b a a b a b a a b a b a a b a b a Pumping Teoremi: G = (V,, R, S) bir CFG olsun. Uzunluğu (G) V- dan büyük her w L(G) string i w = uvxyz şeklinde yazılabilir. Tüm n 0 değerleri için v veya y den birisi boş olmamak kaydıyla uv n xy n z L(G) olur. Bunu sağlamayan non-context-free dildir. Örnek: L = {a n b n c n : n 0} dili non-context-free dir. Bir CFG G = (V,, R, S) için L = L(G) olduğunu düşünelim. w = a n b n c n dile ait olmalıdır ve w = uvxyz şeklinde gösterilebilmelidir. Burada v veya y den en az birisi boş olamaz ve tüm n 0 için uv n xy n z L(G) olmalıdır. Eğer vy string i a, b ve c lerin üçünüde içerirse v ve y den birisi en az ikisini (ab, bc) içerir. uv 2 xy 2 z string i a,b,c lerin sırasını bozar. b lerden sonra a veya c lerden sonra b gelir. Eğer vy string i a, b ve c lerin bir kısmını içerirse uv 2 xy 2 z string i eşit olmayan sayıda a, b ve c ler üretir. 4 Yrd.Doç.Dr.Hacer KARACAN
Teorem: Context-free diller complementation ve intersection için kapalı değildir. İspat: {a n b n c m : m,n 0} ile {a m b n c n : m,n 0} dilleri context-free dir. Bu iki dilin kesişimi {a n b n c n : n 0} olur. Bu dil non-context-free dir. L 1 L2 L1 L2 kesişim için de kapalı olurdu. olduğu için eğer complementation için kapalı olsaydı Determinizm ve Parsing Context-free diller programlama dillerinin syntax analizinde yoğun bir şekilde kullanılmaktadır. Programlama dili için geliştirilmiş bir compiler bir parser oluşturmak zorundadır. Parser girilen bir string in ilgili dile ait olup olmadığını belirler. Dile aitse o string için bir parse tree oluşturur. Compiler daha sonra parse tree yi assembly dili gibi temel bir dildeki programa dönüştürür. Compiler için parser oluşturmada en başarılı sonuçlar pushdown otomat ile alınmaktadır. Ancak PDA lar deterministik değildir ve deterministik olarak çalıştırılması zorunludur. Bir pushdown otomat deterministik tir (DPDA) eğer herbir configuration için kendisini izleyen sadece bir configuration varsa. İki transition relation ((p, a, β), (q, γ)) ve ((p, a, β ), (q, γ )) compatible dır eğer ikisinide kabul eden bir durum varsa. 5 Yrd.Doç.Dr.Hacer KARACAN
Eğer M pushdown otomat deterministik ise iki farklı compatible geçiş olamaz. Örnek: L = {wcw R : w {a, b} * } dilini kabul eden aşağıdaki PDA deterministik tir M = ( K,, Γ, Δ, s, F), K = {s, f}, = {a, b, c}, Γ = {a, b}, F = {f} Δ toplam 5 adet geçiş ilişkisine sahip olsun; 1. ((s, a, e), (s, a)) 2. ((s, b, e), (s, b)) 3. ((s, c, e), (f, e)) 4. ((f, a, a), (f, e)) 5. ((f, b, b), (f, e)) Herbir durum ve giriş sembolü için sadece bir geçiş vardır. Örnek: L = {ww R : w {a, b} * } dilini kabul eden aşağıdaki PDA deterministik değildir M = ( K,, Γ, Δ, s, F), K = {s, f}, = {a, b}, Γ = {a, b}, F = {f} Δ toplam 5 adet geçiş ilişkisine sahip olsun; 1. ((s, a, e), (s, a)) 2. ((s, b, e), (s, b)) 3. ((s, e, e), (f, e)) 4. ((f, a, a), (f, e)) 5. ((f, b, b), (f, e)) Transition 3, 1 ve 2 ile compatible dır. Ayrıca string in orta noktası tahmin edilmektedir. Deterministik context-free diller DPDA tarafından kabul edilir. 6 Yrd.Doç.Dr.Hacer KARACAN
Deterministik context-free diller giriş string inin sonunu gösterebilmelidirler. L * deterministik context-free dildir eğer DPDA M için L$ = L(M) ise. Burada $ işareti string in sonunu göstermektedir ve $ dir. $ işareti tüm string lere otomatik olarak eklenmiştir. Top-Down Parsing Örnek : L = {a n b n : n 0 } context-free dildir ve G = ({a, b, S}, {a, b}, R, S) gramer i tarafından üretilir. R = (S e, S asb) kurallarına sahiptir. Önce bir PDA oluşturalım. M 1 = ({p, q}, {a, b}, {a, b, S}, Δ 1, p, {q}). Δ 1 ={((p, e, e), (q, S)), ((q, e, S), (q, asb)), ((q, e, S), (q, e)), ((q, a, a), (q, e)), ((q, b, b), (q, e))} M 1 otomatı deterministik hale dönüştürülebilir ve L$ dilini kabul eder. M 2 =({p, q, q a, q b, q $ }, {a, b}, {a, b, S}, Δ 2, p, {q $ }) Δ 2 ={((p, e, e), (q, S)), (1) ((q b, e, b), (q, e)), (5) ((q, a, e), (q a, e)), (2) ((q, $, e), (q $, e)), (6) ((q a, e, a), (q, e)), (3) ((q a, e, S), (q a, asb)), (7) ((q, b, e), (q b, e)), (4) ((q b, e, S), (q b, e)) } (8) M 2 q durumundayken stack ta işlem yapmadan girişten bir sembol okur ve q a, q b veya q $ durumlarından birisine geçer. Böylece compatible iki geçiş olan ((q, e, S), (q, asb)) ve ((q, e, S), (q, e)) geçişlerini ayırır. 7 Yrd.Doç.Dr.Hacer KARACAN
DPDA M 2 nin ab$ için geçişleri aşağıda verilmiştir. M 2, L = {a n b n } diline ait string leri tanımak için deterministik olarak çalışır. M 2 giriş string ini leftmost derivation ile üretir. Örnekteki 3. ve 6. adımlar parse tree nin oluşturulduğu adımlardır. M 2 string in dile ait olup olmadığını bulur, aynı anda parse tree oluşturur. Parse tree compiler ların kullandığı parser larda assembly dilinde program oluşturmak için kullanılmaktadır. 8 Yrd.Doç.Dr.Hacer KARACAN
M 2 top-down parser dır, parse tree top-down ve left-to-right yaklaşımıyla oluşur. Örnek: Daha önce doğru yazılmış aritmetik ifadeler için oluşturulmuş gramer e F (E), şeklinde bir kural ekleyelim. Bu yeni kural fonksiyon çağırmalarını sağlar. (Örn.: sqrt(x * x + 1) ) Bu gramer için bir top-down parser oluşturalım. M 3 = ({p, q},, Γ, Δ, p, {q}), = {(, ), +, *, id}, Γ = {E, T, F} Δ= 0. ((p, e, e), (q, E)) 1. ((q, e, E), (q, E+T)) 2. ((q, e, E), (q, T)) 3. ((q, e, T), (q, T*F)) 4. ((q, e, T), (q, F)) 5. ((q, e, F), (q, (E))) 6. ((q, e, F), (q, id)) 7. ((q, e, F), (q, id(e))) ve son olarak tüm a için ((q, a, a), (q, e)) Δ olsun. 9 Yrd.Doç.Dr.Hacer KARACAN
Bu otomatta nondeterminizm 1-2, 3-4 ve 5-6-7 kurallarından kaynaklanmaktadır. Transition 6 ve 7: M 3 otomatının (q, id, F) konfigürasyonunda olduğunu düşünelim. M 3 bu durumda 5, 6 veya 7 geçişlerinden birisini seçebilir. Input string teki bir sonraki sembole (id) bakarak 5 elenir. Transition 5 te (()bir sonraki semboldür. Ancak bir sonraki sembol 6 ve 7 için aynıdır (id). Bu problem sağ tarafı aynı olmasada ilk sembolü aynı olan F id ve F id(e) kurallarından kaynaklanmaktadır. F id ve F id(e) kurallarının yerine F ida, A e ve A (E) kuralları konularak giderilebilir. Burada A yeni bir nonterminaldir. Transition 6 ve 7 yerine aşağıdaki kurallar konur; 6. ((q, e, F), (q, ida)) 7. ((q, e, A), (q, e)) 8. ((q, e, A), (q, (E))) Geçişler (q, id(id), F) M (q, id(id), ida) M (q, (id), A) M (q, (id), (E)) M... olur. Nondeterminismi ortadan kaldırmak için kullanılan bu teknik left factoring olarak adlandırılır. Aşağıdaki kural ile özetlenebilir; Heuristic Rule 1: Eğer A αβ 1, A αβ 2,..., A αβ n şeklinde kurallar varsa ve α e ve n 2 ise, bu kurallar A αa, A β i kurallarıyla değiştirilir. A yeni nonterminaldir. 10 Yrd.Doç.Dr.Hacer KARACAN
Transition 1 ve 2: Eğer M 3 otomatı bir sonraki input sembol için id görürse, ve stack taki E ise birkaç farklı işlem yapılabilir. Transition 2 yapılarak E yerine T yazılır. Girişin sadece id olması durumunda bu geçerlidir. Transition 1 kullanılarak E yerine E + T yazılır. Girişin id + id olması durumunda geçerlidir. Transition 1 iki defa ve Transition 2 bir defa kullanılabilir. Girişin id + id + id olması durumunda geçerlidir. Burada sağ taraftaki işlemin kaç defa tekrarlanacağının sınırı belli değildir. Bu olay left recursion olarak adlandırılır. Bu problem E E + T kuralından kaynaklanmaktadır. Soldaki nonterminal sağdaki ilk semboldür. E E + T ve E T kuralları yerine E TE, E +TE ve E e kuralları konularak giderilebilir. Burada E yeni bir nonterminaldir. Aynı işlem T T * F, T F içinde yapılır. T FT, T *FT ve T e Örnekteki gramer in son şekli aşağıdaki gibi olur. G = (V,, R, E), V = {E, E, T, T, F, A}, R = 1. E TE 6. T e 2. E +TE 7. F (E) 3. E e 8. F ida 4. T FT 9. A e 5. T *FT 10. A (E) 11 Yrd.Doç.Dr.Hacer KARACAN
Nondeterminizmi ortadan kaldırmak için kullanılan bu left recursion tekniği aşağıdaki kural ile özetlenebilir; Heuristic Rule 2: Eğer A Aα 1,..., A Aα n ve A β 1,...,A β m şeklinde kurallar varsa ve β i ler A ile başlamıyorsa ve n > 0 ise, bu kurallar A β 1 A,..., A β m A ve A α 1 A,..., A α n A ve A e kurallarıyla değiştirilir. A yeni nonterminaldir. Örnek: Önceki gramer i tanıyan DPDA M 4 = L(G )$ oluşturalım. M 4 = (K, {$}, V, Δ, p, {q $ }), K = {p, q, q id, q +, q *, q ), q (, q $ }, Δ=((p, e, e), (q, E)) ((q, a, e), (q a, e)) tüm a { $ } ((q a, e, a), (q, e)) tüm a ((q a, e, E), (q a, TE )) tüm a { $ } ((q +, e, E ), (q +, +TE )) ((q a, e, E ), (q a, e)) tüm a { ), $ } ((q a, e, T), (q a, FT )) tüm a { $ } ((q *, e, T ), (q *, *FT )) ((q a, e, T ), (q a, e)) tüm a { +, ), $ } ((q (, e, F), (q (, (E))) ((q id, e, F), (q id, ida)) ((q (, e, A), (q (, (E))) ((q a, e, A), (q a, e)) tüm a { +, *, ), $ } 12 Yrd.Doç.Dr.Hacer KARACAN
M 4 deterministik pushdown otomat ı G gramer i için bir parser dır. id * (id)$ giriş string i aşağıdaki tabloda görüldüğü gibi kabul edilir. 13 Yrd.Doç.Dr.Hacer KARACAN
G deki kurallar ile stack üzerinde nonterminal değiştirilen adımlar tabloda son sütunda numaralandırılmıştır. Sırayla bu kurallar uygulandığında id*(id)$ string inin leftmost derivation ı elde edilir. Oluşturulan parse yandadır. E TE FT E idt E id *FT E id *(E)T E id *(TE )T E id *(FT E )T E id *(idt E )T E id *(ide )T E id *(id)t E id *(id)e id *(id) Parse tree top-down ve left-first olarak oluşmuştur. Bottom-Up Parsing Context-free dillerin parse edilmesinde en iyi yol yoktur. Farklı gramer ler için farklı yöntemler vardır. 14 Yrd.Doç.Dr.Hacer KARACAN
Farklı bir yaklaşımda otomat ilk önce girişi okur ve derivation sonra yapılır. Sonuçta parse tree yapraklardan root node a doğru gerçekleşir. Bu yöntemler bottom-up olarak adlandırılırlar. G = (V,, R, S) bir CFG için M = (K,, Γ, Δ, p, F) bottom-up pushdown otomat ı oluşturalım. Burada K = {p, q}, Γ = V, F = {q} ve Δ aşağıdaki geçişlere sahip olsun. 1. ((p, a, e), (p, a)) tüm a için 2. ((p, a, α R ), (p, A)) tüm A α R için 3. ((p, e, S), (q, e)) Her transition bir transition sınıfını göstermektedir. Transition 1 input sembolleri stack a aktarır. Transition 2 stack ta kuralların sağ kısmının yerine sol kısmını değiştirir. Kuralların sağ kısmı ters sırada bulunmalıdır. Transition 3 ise sonuç durumuna geçerek çalışmayı sonlandırmayı sağlar. Örnek: Aritmetik deyimleri üreten gramer için bir bottom-up pushdown otomat oluşturalım. Kurallar aşağıdaki gibi olsun. E E + T (R1) E T (R2) T T * F (R3) T F (R4) F (E) (R5) F id (R6) M pushdown otomat ı için aşağıdaki geçişler oluşturulur. 15 Yrd.Doç.Dr.Hacer KARACAN
(p, a, e), (p, a) tüm a için (Δ0) (p, e, T + E), (p, E) (p, e, T), (p, E) (p, e, F * T), (p, T) (p, e, F), (p, T) (p, e, )E(), (p, F) (p, e, id), (p, F) (p, e, E), (q, e) (Δ1) (Δ2) (Δ3) (Δ4) (Δ5) (Δ6) (Δ7) id * (id) aşağıdaki gibi kabul edilir. M otomatı deterministik değildir. Çünkü Δ0 diğer tüm geçişlerle (Δ1 - Δ8) compatible dir. 16 Yrd.Doç.Dr.Hacer KARACAN
Herhangi bir anda M bir terminali stack a aktarabilir (1, 4, 5, 6 ve 10 adımlar) veya stack taki birkaç sembolü bir kuralın sağ kısmı olarak elde edebilir. Kuralın sağ kısmı olarak görülen string sol kısımla değiştirilerek indirgenir (Δ1 Δ6). İndirgeme yapılan adımlar ters sırada alınırsa rightmost derivation yapılır. İndirgeme yapılan adımların ters sırada alınmasıyla elde edilen rightmost derivation aşağıdaki gibidir. E T T * F T * (E) T * (T) T * (F) T * (id) F * (id) id * (id) 17 Yrd.Doç.Dr.Hacer KARACAN