Sözcüksel analizin kaba taslak anlatımı Özet Sözcüksel analizin kaba taslak anlatımı Girdi karakter dizisindeki(input string) sembolleri(token) tanımlar Sözcüksel analizde ele alınan konular İleriye bakmak(Lookahead) Belirsizlikler(Ambiguities) Sözcük belirleme(specify lexers) Düzgün ifadeler(düzgün ifadeler) Düzgün ifade örnekleri
Hatırlatma: Derleyicinin Yapısı Kaynak Sözcüksel Analiz Tokenlar Bugün başlangıç noktamız Sözdizimsel analiz Aradil (Interm. Dil) Optimizasyon Kod Üret. Makine Kodu
Ne yapmak istiyoruz? Örnek: Sözcüksel Analiz Ne yapmak istiyoruz? Örnek: if (i == j) z = 0; else z = 1; Girdi sadece bir dizi karakterden oluşmaktadır: \tif (i == j)\n\t\tz = 0;\n\telse\n\t\tz = 1; Amaç: Girdi karakter dizisini alt karakter dizilerine bölmektir Ve bunları görevlerine göre sınıflandırmaktır
Sembol-Token- Nedir? Sözcüksel analiz çıktısı bir dizi semboldür(token) Bir token yapısal bir kategoridir(syntactic category) Türkçe: isim, fiil, sıfat, … Programlama dilleri Dil: Identifier(belirtici), Integer(TamSayı), Keyword(AnahtarKelime), Whitespace, … Sözdizimsel analizci tokenlar arasındaki ayrımı kullanır: Belirticiler anahtar kelimelerden farklı işlenir
Tokenlar Bir dizi stringtir. Identifier: harfler ve rakamlardan oluşan ve harfle başlayan stringlerdir Integer: boş olmayan rakam stringidir Keyword: “else” , “if” , “begin”… Whitespace: boşluklar(blanks), yeni satır(newlines), ve tabler OpenPar: sol parantez
Sözcüksel Analizci: Uygulama Bir uygulama şunları yapmalıdır: Tokenlara karşılık gelen string alt kümelerini bulmalıdır Tokenın değerini veya lexeme döndürmelidir lexeme bir string parçasıdır.
Döndürülen Token-lexeme ikilileri: Örnek \tif (i == j)\n\t\tz = 0;\n\telse\n\t\tz = 1; Döndürülen Token-lexeme ikilileri: (Whitespace, “\t”) (Keyword, “if”) (OpenPar, “(“) (Identifier, “i”) (Relation, “==“) (Identifier, “j”) …
Sözcüksel analizci:Uygulama Sözdizimsel analize etkisi olmayan stringleri gözardı eder. Örnek: Whitespace, Açıklama Soru: Bütün boşluklar ve açıklamalar bu basamaktan önce silinirse ne olur?
Lookahead(İleri Bakma). İki önemli nokta: Amaç stringi parçalamaktır. Okuma soldan sağa yapılır ve bir defada bir token bulunur “Lookahead” bir tokenın nerede bittiği ve diğerinin nerede başladığına karar vermek için gereklidir. Basit örnekte bile lookahead konuları vardır i ve if = ve ==
Belirsizlikleri gidermek için yol gerekir Sonra Bir metot gerekir Tokenların stringlerini belirlemek için Belirsizlikleri gidermek için yol gerekir if i ve f? == ve = =?
Düzgün diller(regular languages) Tokenları belirtmek için farklı yaklaşımlar vardır düzgün diller en yaygın olanıdır Basit ve yararlı teorisi vardır Kolay anlaşılır Verimli uygulama yazılabilir
(S bu dilin alfabesidir) Diller Tanım. S bir dizi karakterdir. Bu S tanımlanan karakterlerden oluşan bir dizi string dili oluşturur (S bu dilin alfabesidir)
Örnek Diller alfabe= İngilizce karakterler Dil = İngilizce cümleler İngilizce karakterlerden oluşan her string İngilizce bir cümle değildir alfabe= ASCII Dil = C programları Not: ASCII karakterler İngilizce karakterlerden farklıdır.
Notasyon Diller bir dizi stringtir. Hangilerini kullanacağımızı belirtmenin bir yolu olmalıdır sözcüksel analiz için düzgün diller önemlidir, düzgün ifadelar kullanılarak ifade edilirler.
Düzgün ifadeler ve düzgün diller Her düzgün ifade bir düzgün dil için notasyon/gösterimdir (bir küme kelime) Eğer A bir düzgün ifadeyse L(A), A ile gösterilen dili belirtmek için kullanılır.
Atomik düzgün ifadeler Tek karakter: ‘c’ L(‘c’) = { “c” } (her c Є ) Arka arkaya Ekleme(Concatenation): AB (A ve B are düzgün ifade.) L(AB) = { ab | a Є L(A) ve b Є L(B) } Örnek: L(‘i’ ‘f’) = { “if” } ( ‘i’ ‘f’ ‘if’ olarak kısaltılacaktır )
Bileşik düzgün ifadeler Bileşim(Union) L(A | B) = { s | s Є L(A) or s Є L(B) } Örnekler: ‘if’ | ‘then‘ | ‘else’ = { “if”, “then”, “else”} ‘0’ | ‘1’ | … | ‘9’ = { “0”, “1”, …, “9” } Başka Bir Örnek: (‘0’ | ‘1’) (‘0’ | ‘1’) = { “00”, “01”, “10”, “11” }
Diğer bileşik düzgün ifadeler Şu ana kadar sonsuz diller için bir gösterim yapılmadı Tekraralama(Iteration): A* L(A*) = { “” } U L(A) U L(AA) U L(AAA) U … Örnekler: ‘0’* = { “”, “0”, “00”, “000”, …} ‘1’ ‘0’* = {1 ile başlayıp 0’lar ile devam eden stringler} Epsilon: L() = { “” }
Keyword: “else” or “if” or “begin” or … Örnek: Keyword Keyword: “else” or “if” or “begin” or … ‘else’ | ‘if’ | ‘begin’ | … (Hatırlatma: ‘else’ ‘e’ ‘l’ ‘s’ ‘e’ )
Örnek: Tam sayılar Integer: Boş olmayan rakamlar stringi digit = ‘0’ | ‘1’ | ‘2’ | ‘3’ | ‘4’ | ‘5’ | ‘6’ | ‘7’ | ‘8’ | ‘9’ number = digit digit* Kısaltma: A+ = A A*
Identifier: harfler ve rakamlardan oluşan, harfle başlayan stringler Örnek: Belirtici Identifier: harfler ve rakamlardan oluşan, harfle başlayan stringler letter = ‘A’ | … | ‘Z’ | ‘a’ | … | ‘z’ identifier = letter (letter | digit) * Soru: (letter* | digit*) aynı şeyi mi ifade eder?
(Burada küçük bir hata var mı?) Örnek: Whitespace Whitespace: boş olmayan boşluk, yeni satır ve tablerden oluşan stringler (‘ ‘ | ‘\t’ | ‘\n’)+ (Burada küçük bir hata var mı?)
number = ‘(‘ area ‘)’ exchange ‘-’ phone Örnek: Phone Numbers düzgün ifadeler aslında çok sık kullanılır! Örneğin (510) 643-1481 (telefon no) = { 0, 1, 2, 3, …, 9, (, ), - } area = digit3 exchange = digit3 phone = digit4 number = ‘(‘ area ‘)’ exchange ‘-’ phone
Örnek: Email Addresses Öreneğin zorhan@fatih.edu.tr = letters U { ., @ } name = letter+ address = name ‘@’ name (‘.’ name)*
Özet düzgün ifadeler pek çok faydalı dil tanımlarlar Bir sonraki adım: Bir string s ve bir düzgün ifade R verildiğinde sorusuna cevap bulmaktır Ancak sadece evet/hayır cevabı yeterli değildir! Bunun yerine: girdi parçalarına(lexeme) ayrılır Düzgün ifadeler bu amaç için kullanılacaktır
Taslak Sözcüksel yapıyı düzgün ifadeler kullanarak belirtmek Sonlu makinalar(Finite automata) Deterministik Sonlu makinalar (Deterministic Finite Automata (DFAler)) Deterministik olmayan Sonlu makinalar( Non-deterministic Finite Automata (NFAler)) düzgün ifadelerin uygulaması Düzgün İfadeler => NFA => DFA => Tablolar
Süzgün ifadeler => sözcüksel tanımlama. (1) Bir küme token seçin Number, Keyword, Identifier, ... Her bir token için bir R.E. yazın Number = digit+ Keyword = ‘if’ | ‘else’ | … Identifier = letter (letter | digit)* OpenPar = ‘(‘ …
düzgün ifadeler => sözcüksel tanımlama. (2) R’yi bütün tokenları kapsayacak şekilde yazın R = Keyword | Identifier | Number | … = R1 | R2 | R3 | … Doğru: If s Є L(R) s bir tokenı gösteren stringtir Dahası s Є L(Ri) (herhangi bir “i” için) Bu “i” bulunan tokenın hangisi olduğunu gösterir
düzgün ifadeler => sözcüksel tanımlama. (3) Girdi şu olsun: x1…xn (x1 ... xn dilin alfabesindeki karakterlerdir) 1 i n için aşağıdakini kontrol edin x1…xi L(R) ? Aşağıdaki ifadenin doğru olması gerekir: x1…xi L(Rj) (i ve j’nin değerleri için) Girdiden x1…xi‘yi silip 4. basamağa geri dönün
R = Whitespace | Integer | Identifier | ‘+’ Örnek R = Whitespace | Integer | Identifier | ‘+’ “f +3 +g” stringini çözümleyin “f” R’a uyar, hatta Identifier’a uyar “+“ R ’a uyar, hatta ‘+’ ’a uyar … token-lexeme ikilileri ise (Identifier, “f”), (‘+’, “+”), (Integer, “3”) (Whitespace, “ “), (‘+’, “+”), (Identifier, “g”) olur Whitespace tokenlardan kurtulmak istiyoruz Whitespace ’a uyan bulununca eşlemeye devam edin
Belirsizlikler (1) Algoritmada belirsizlikler vardır Örnek: R = Whitespace | Integer | Identifier | ‘+’ “foo+3” çözümleyin “f” R’a uyar, hatta Identifier’a uyar Ama aynı zamanda “fo” R ’a uyar, ve “foo” R ’a uyar, ama “foo+” uymaz Eğer Hem x1…xi L(R) ve hem de x1…xK L(R) doğru ise ne kadar girdi parçası kullanılır? “Maximal munch(en büyük lokma)” kuralı: R’a uyan mümkün olan en uzun stringi seçin
Daha Başka Belirsizlikler R = Whitespace | ‘new’ | Integer | Identifier “new foo” stringini çözümleyin “new” R’a uyar, hatta ‘new’ e uyar Aynı zamanda Identifier’a da uyar, hangisini seçeceğiz? Genelde, eğer x1…xi L(Rj) ve x1…xi L(Rk) ise Kural: Önce yazılanı kullanmaktır (Yani j < k ise j seçilir) Dolayısıyla ‘new’ Identifier’dan önce yazılmalıdır
Hataları ele alma R = Whitespace | Integer | Identifier | ‘+’ “=56” : çözümleyin Hiçbir önek(prefix) R’a uymamaktadır: ne “=“, ne “=5”, ne de “=56” Problem: İşin içinden çıkılamadı denemez stuck … Çözüm: Son kural olarak bütün uygun olmayan stringlere uyacak bir kural eklenir Lexer araçları şu şekilde bir gösterime izin verir: R = R1 | ... | Rn | Error Token Error diğer tokenlardan hiçbirine uygunluk çıkmazsa kullanılır
Özet düzgün ifadeler string kalıplarının gösterimi için kısa ve öz bir gösterim sağlar sözcüksel analizde kullanım için bazı ufak eklentiler yapmak gerekir Belirsizlikleri çözme ve Hataları ele alma gibi Bilinen güzel algoritmalar vardır (biraz sonra…) Sonuca ulaşmak için girdi üzerinden bir geçişe ihtiyacı vardır Karakter başı bir iki işlem gerekir (tablodan bakma-table lookup)
Sonlu Makine-Finite Automata(FA) düzgün ifadeler = şartnameler FA = uygulama Bir FA şunlardan oluşur Bir girdi alfabesi Bir durum(state) kümesi S Bir başlangıç durumu(start state) n Bir kabul edilen(accepting states) durumlar kümesi F S Bir geçişler(transitions) kümesi durum girdi durum
s1 durumunda “a” girdisiyle s2 durumuna git FA Geçiş s1 a s2 Okunuşu s1 durumunda “a” girdisiyle s2 durumuna git Eğer girdi biterse veya uygun geçiş yoksa Eğer kabul edilen durumlardan birindeysek=>kabul/ accept Değilse=> red/reject
FA Durum Şekilleri Bir durum Başlangıç durumu Kabul durumu a Geçiş
Basit Bir Örnek Sadece “1” kabul eden FA Bir FA verilen bir string için başlangıç durumdan başlayıp stringin karakterlerine göre bir dizi geçişle kabul durumlarından birine ulaşabiliyorsa bu stringi kabul eder. 1
Herhangi bir sayıda 1’i tek bir 0’ın izlediği stringleri kabul eden FA Diğer bir örnek Herhangi bir sayıda 1’i tek bir 0’ın izlediği stringleri kabul eden FA alfabe: {0,1} “1110” kabul edilir ancak “110…” edilmez 1
ve başka bir örnek alfabe{0,1} Bu FA hangi dili tanır? 1 1
FA’nın işlemi tam olarak girdi ile tanımlanmamıştır ve başka bir örnek Alfabe hala { 0, 1 } FA’nın işlemi tam olarak girdi ile tanımlanmamıştır “11” girdisi ile FA herhangi bir durumda olabilir 1
Diğer bir geçiş türü: -moves/hareketleri Epsilon hareketleri Diğer bir geçiş türü: -moves/hareketleri A B Makine A durumundan B durumuna bir girdi okumadan geçebilir
Deterministik ve deterministik olmayan FA Deterministik FA (DFA) Bir durumda bir girdi için tek bir geçiş -hareketi yok Deterministik olmayan FA (NFA) Verilen bir durumda bir girdi için birden fazla geçiş olabilir -hareketi vardır FA’nın sonlu bir hafızası vardır Sadece bulunduğu durumu kodlaması yeterlidir
Bir DFA durum şeklinde sadece bir yol izleyebilir FA’nın çalışması Bir DFA durum şeklinde sadece bir yol izleyebilir Bu tamamen girdi ile belirlenir NFA’ler seçim yapabilir -hareketi kullanıp kullanmama Girdi için muhtemel geçişlerden hangisni kullanma
Bir NFA birden fazla durumda olabilir NFA’lerde kabul etme Bir NFA birden fazla durumda olabilir 1 Girdi: 1 1 Kural: Son durumlardan/kabul durumlarından birine ulaşabiliyorsa girdi NFA tarafından kabul edilir
NFA’ler ve DFA’ler aynı dil kümelerini tanırlar (düzgün diller) NFA ve DFA (1) NFA’ler ve DFA’ler aynı dil kümelerini tanırlar (düzgün diller) DFA’lerin uygulaması ve yazılımı daha kolaydır Seçim yapmak gerekmemektedir
Verilen bir dil için NFA DFA’den daha basit olabilir NFA ve DFA (2) Verilen bir dil için NFA DFA’den daha basit olabilir 1 NFA 1 DFA DFA, NFA’e göre üssel olarak büyüyebilir
düzgün ifadelerden FA’lere Üst düzey gösterim NFA Düzgün İfadeler DFA sözcüksel şartname DFA’in tablo olarak uygulaması
düzgün ifadelerden NFA’lere (1) Her türlü düzgün ifade için, bir NFA tanımlayalım Gösterim: A düzgün ifadesi için NFA A a a
düzgün ifadelerden NFA’lere(2) AB A B A | B A B
düzgün ifadelerden NFA’lere(3) A
Örnek Düzgün ifade -> NFA dönüşümü (1 | 0)*1 NFA A H 1 C E B G 1 I J D F
DFA’in tablo olarak uygulaması Bir sonraki basamak NFA Düzgün İfadeler DFA sözcüksel şartname DFA’in tablo olarak uygulaması
DFA’e şu geçişler eklenir S a S’ bunun için şart: NFA DFA. Hile NFA benzetimi yapın DFA’in her bir durumu = NFA’in boş olmayan alt durum kümeleri Başlangıç durumu = NFA’in başlangıç durumundan -hareketleriyle ulaşılabilecek durumlar DFA’e şu geçişler eklenir S a S’ bunun için şart: S’, NFA’de a girdisini S durumunda gördüğümüzde ulaşılabilecek durumlar kümesi olmalıdır. -hareketleri gözönünen alınır
NFA -> DFA Örnek 1 1 1 1 1 C E A B G H I J D F G H I J D F FGABCDHI 1 ABCDHI 1 1 EJGABCDHI
Bir NFA herhangi bir anda bir çok durumda bulunabilir NFA DFA. Önemli Bir NFA herhangi bir anda bir çok durumda bulunabilir Kaç farklı durum vardır ? Eğer N durum varsa, NFA bu N durumun bir alt kümesinde bulunur Kaç tane boş olmayan alt küme vardır? 2N - 1
Bir DFA 2D(boyutlu) tablo ile gösterilebilir: T Uygulama Bir DFA 2D(boyutlu) tablo ile gösterilebilir: T Birinci boyut durumlardır Diğer boyut girdi sembolleridir Her Si a Sk geçişi için T[i,a] = k yazılır DFA “çalışması” Durum Si ve girdi a ise, T[i,a] = k okunur ve Sk durumuna gidilir Çok etkindir
Tablo Uygulaması: DFA T 1 S 1 1 U 1 S T U
Uygulama (Devam.) NFA -> DFA flex veya jlex gibi araçlarda önemlidir Ancak, DFA’ler çok büyük olabilir Pratikte, flex benzeri araçlar NFA ve DFA gösterimlerinde yer için hızdan taviz verir.