Sözcüksel Çözümleme/Analiz
(Lexical Analysis)
http://www.fatih.edu.tr/~zorhan/bilm204/bilm204.html
Bir Derleyicinin Genel Yapısı
1. Sözcüksel Çözümleme/Analiz
(Lexical Analysis)
2. Gramer İncelemesi veya Sözdizimsel Analiz
(Parsing)
3. Anlamsal Analiz (Semantic Analysis)
4. Optimizasyon
5. Kod Üretme (Code Generation)
İlk üç madde insanların dil anlama yöntemine benzer
şekilde anlaşılabilir.
2
Sözcüksel Analiz
• Sözcüksel Analiz işlemi kaynak programı sözcüklere
(words), ya da başka bir deyişle sembollere (tokens)
ayırır.
if x == y then z = 1; else z = 2;
• Tokenlarımız şunlar olur:
if, x, ==, y, then, z, =, 1, ;, else, z, =, 2, ;
3
Sözdizimsel Analiz
• Sözcükler anlaşıldıktan sonra, sıra cümle yapısını anlamaya
gelir.
• Sözdizimsel Analiz, cümlenin şekilsel olarak doğru olup
olmadığını anlamak için kullanılır.
4
Programların Sözdizimsel Analizi
• Örneğin:
If x == y then z = 1; else z = 2;
x
==
ilişki
if-ilişki
y
z
=
1
beyan
thenbeyan
if then else cümleciği
z
= 2
beyan
elsebeyan
5
Anlamsal Analiz: Semantic Analysis
• Cümle yapısı anlaşıldıktan sonra, şimdi “anlamın” ne
olduğunu çözmeye çalışabiliriz.
– Ancak derleyiciler için anlamı çözmek çok zordur.
• Derleyiciler tutarsızlıkları yakalamak için sınırlı bir
analiz yaparlar.
6
Anlamsal Analiz Örneği
• Derleyiciler değişken bağlamanın(variable bindings)
yanında pek çok anlamsal kontrol de yaparlar.
• Örnek:
Ali left her homework at home.
• Tip uyuşmazlığı(“type mismatch”): her ve Ali
arasında; bu iki sözcük farklı kişiler olmalı
7
Optimizasyon
• İngilizce için tam karşılığı olmamakla birlikte
redaksiyona(editing) benzemektedir.
• Programları otomatik olarak değiştirerek
– Daha hızlı çalışmasını
– Daha az bellek kaplamasını ve
– Genel olarak kaynak kullanımında tutumlu davranmayı
sağlamaktadır.
8
Optimizasyon Örneği
X = Y * 0 ifadesi X = 0 şeklinde yazılabilir.
9
Günümüzde Derleyiciler
• Genel olarak bütün derleyiciler bu yapıya uygunluk
gösterir.
• FORTRAN’dan bu yana oranlar değişmiştir.
– Önce: sözcüksel analiz, sözdizimsel analiz daha karmaşıktı
ve pahalıydı.
– Bugün: optimizasyon diğer safhalara göre daha önemlidir;
sözcüksel analiz, sözdizimsel analiz daha ucuzdur.
10
Derleyicilerdeki Yönelimler
• Optimizasyonu hız için kullanmak çok gerekli
değildir. Ancak:
– Bilimsel programlarda
– İleri işlemcilerde
– Küçük cihazlarda (hız = daha uzun pil ömrü) gerekebilir.
11
Biraz Daha Detay…
• 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/tokens)
– Düzgün/Düzenli ifadeler
– Düzgün/Düzenli ifade örnekleri
12
Hatırlatma: Derleyicinin Yapısı (Anlamsal
Analiz Safhası Gösterilmemiştir !)
Kaynak
Sözcüksel
Analiz
Tokenlar
Sözdizimsel
analiz
Bugün başlangıç noktamız
Optimizasyon
Aradil
(Interm.
Dil)
Kod
Üret.
Makine
Kodu
13
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.
14
Sembol (Token) Nedir?
• Sözcüksel analiz çıktısı bir dizi semboldür(token)
• Bir token yapısal bir kategoridir.
– Türkçe:
isim, fiil, sıfat, …
– Programlama dilleri:
Identifier(belirtici), Integer(TamSayı), Keyword(AnahtarKelime),
Whitespace, …
• Sözdizimsel analiz tokenlar arasındaki ayrımı kullanır:
– Belirticiler anahtar kelimelerden farklı işlenir.
15
Tokenlar
• Bir 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 tab ler
• OpenPar: sol parantez
16
Sözcüksel Analiz: Uygulama
•
Bir uygulama şunları yapmalıdır:
1. Tokenlara karşılık gelen string alt kümelerini bulmalıdır.
2. AyrıcaTokenın değerini (lexeme) döndürmelidir.
17
Ö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”)
…
18
Sözcüksel Analiz:Uygulama
• Sözdizimsel analize etkisi olmayan stringleri
gözardı eder.
• Örnek: Whitespace, Açıklama
19
Lookahead (İleri Bakma)
•
İki önemli nokta:
1. Amaç stringi parçalamaktır. Okuma soldan sağa yapılır ve
bir defada bir token bulunur.
2. “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 ==
20
Düzgün/Düzenli Diller (Regular Languages)
• Tokenları belirtmek için farklı yaklaşımlar vardır.
• Düzgün diller en yaygın olanıdır.
21
Diller
Tanım. S bir dizi karakterdir ve içindeki karakterler
belirli kurallarla bir dil oluşturur.
(S bu dilin alfabesidir.)
22
Örnek Diller
• alfabe= İngilizce
karakterler
• Dil = İngilizce cümleler
• alfabe= ASCII
karakterleri
• Dil = C programları
• İngilizce karakterlerden
oluşan her string
İngilizce bir cümle
değildir.
23
Düzgün İfadeler ve Düzgün Diller
• Her düzgün ifade bir düzgün dil için
notasyon/gösterimdir.
• Eğer A bir düzgün ifadeyse L(A), A ile gösterilen
dili belirtmek için kullanılır.
24
Düzgün İfadeler ve Düzgün Diller (Devam)
• Atomik düzgün ifadeler tek bir karakterden oluşur.
Tek karakter: ‘c’
L(‘c’) = { “c” } (her c Є S)
• Arka arkaya Ekleme(Concatenation): AB (A ve B
düzgün ifadeler olsun.)
L(AB) = { ab | a Є L(A) ve b Є L(B) }
• Örnek: L(‘i’ ‘f’) = { “if” }
( ‘i’ ‘f’ ‘if’ olarak kısaltılacaktır )
25
Düzgün İfadeler ve Düzgün Diller (Devam)
• 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” }
26
Diğer Bileşik Düzgün İfadeler
• Tekrarlama (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() = { “” }
27
Örnek: Keyword
– Keyword: “else” or “if” or “begin” or …
‘else’ | ‘if’ | ‘begin’ | …
(Hatırlatma: ‘else’  ‘e’ ‘l’ ‘s’ ‘e’ )
28
Ö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*
29
Örnek: Belirtici
Identifier: harfler ve rakamlardan oluşan, harfle
başlayan stringler.
letter = ‘A’ | … | ‘Z’ | ‘a’ | … | ‘z’
identifier = letter (letter | digit) *
30
Örnek: Whitespace
Whitespace: boş olmayan boşluk, yeni satır ve
tab lerden oluşan stringler
(‘ ‘ | ‘\t’ | ‘\n’)+
31
Örnek: Telefon Numaraları
• Düzgün ifadeler aslında çok sık kullanılır!
• Örneğin (510) 643-1481 (telefon no)
S
= { 0, 1, 2, 3, …, 9, (, ), - }
area
= digit3
exchange = digit3
phone
= digit4
number = ‘(‘ area ‘)’ exchange ‘-’ phone
32
Örnek: E-posta Adresleri
• Örneğin: [email protected]
harf = {A|B … a|b …}
S = harf U { ., @ }
isim= harf+
adres= [email protected] isim(‘.’ isim)+
33
Ö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
s  L(R) ?
sorusuna cevap bulmaktır
• Ancak sadece evet/hayır cevabı yeterli değildir!
• Düzgün ifadeler bu amaç için kullanılacaktır.
34
Düzgün İfadeler => Sözcüksel Tanımlama. (1)
1. Bir küme token seçin
•
Number, Keyword, Identifier, ...
2. Her bir token için bir düzgün ifade yazın
•
•
•
•
•
Number = digit+
Keyword = ‘if’ | ‘else’ | …
Identifier = letter (letter | digit)*
OpenPar = ‘(‘
…
35
Düzgün İfadeler => Sözcüksel Tanımlama. (2)
3. R dilini bütün tokenları kapsayacak şekilde yazın.
R = Keyword | Identifier | Number | …
= R1
| R2
| R3
|…
If s Є L(R)  s bir tokenın lexeme değeridir.
–
–
Dahası s Є L(Ri) (belirli bir “i” için)
Bu “i” bulunan tokenın hangisi olduğunu gösterir.
36
Örnek
R = Whitespace | Integer | Identifier | ‘+’
• “f +3 +g” stringini çözümleyin
–
–
–
–
“f” Identifier’a dolayısıyla R’ye uyar
“+“ “+” ya dolayısıyla R’ye uyar
…
token-lexeme ikilileri ise
(Identifier, “f”), (‘+’, “+”), (Integer, “3”)
(Whitespace, “ “), (‘+’, “+”), (Identifier, “g”) olur
37
Belirsizlikler (1)
• Algoritmada belirsizlikler vardır.
• Örnek:
R = Whitespace | Integer | Identifier | ‘+’
• “foo+3” çözümleyin
– “f” Identifier’a uyar
– Ama aynı zamanda “fo” Identifier ’a uyar, hatta “foo” da Identifier’a
uyar, ama “foo+” Identifier’a 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
38
Daha Başka Belirsizlikler
R = Whitespace | ‘new’ | Integer | Identifier
• “new foo” stringini çözümleyin
– “new” ‘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
39
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 …
• Çö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.
40
Özet (1)
A compiler is a translator whose source language is a highlevel language and whose object language is close to the
machine language of an actual computer. The typical
compiler consists of several phases each of which passes its
output to the next phase.
The lexical phase (scanner) groups characters into lexical
units or tokens. The input to the lexical phase is a character
stream. The output is a stream of tokens. Regular
expressions are used to define the tokens recognized by a
scanner (or lexical analyzer). The scanner is implemented as
a finite state machine. Lex and Flex are tools for generating
scanners: programs which recognize lexical patterns in text.
Flex is a faster version of Lex.
Özet (2)
The parser groups tokens into syntactical units. The
output of the parser is a parse tree representation of the
program. Context-free grammars are used to define the
program structure recognized by a parser. The parser is
implemented as a push-down automata.
Yacc and Bison are tools for generating parsers: programs
which recognize the grammatical structure of programs.
Bison is a faster version of Yacc.
Download

Lecture2