flex
Sözcüksel Analiz İçin Bir Araç
1
Sözcüksel ve Sözdizimsel Analiz
Girdi
Akımı
Sözcüksel Analizci
(Lexer)
Token
Akımı
Sözdizimsel Analizci
(Parser)
Parse
Ağacı
• Sözcüksel Analizci (Lexical Analyzer - Lexer):
Girdi akımını tarayarak karakter dizisini token’lara
çevirir. flex bu amaçla kullanılan bir araçtır.
• Sözdizimsel Analizci (Syntax Analyzer – Parser):
Token’ları okuyarak, dilin gramer kurallarına göre
onları dil yapılarına çevirir. bison bu amaçla
kullanılan bir araçtır.
2
Giriş
• flex:
– Düzgün ifade koleksiyonlarını okuyarak, onları
sözcüksel analiz yapacak C veya C++
programlarını yazmada kullanır.
• bison:
– flex programının çıktısını kullanır ve bu çıktıyı
dilin düzgün ifade kurallarını kullanarak parse
etmeye (ayrıştırmaya) çalışır.
3
flex ve bison İlişkisi
4
flex
• flex ile bir takım düzenli ifadeleri ve her birine
karşılık gelen aksiyonları tanımlarız.
• Bir flex programın kabaca içeriği:
%{
Global C, C++ değişkenleri
Kütüphane ekleme işlemleri
%}
Tanımlar
%%
Düzgün ifadeler ve ilişkili aksiyonlar (kurallar)
%%
C, C++ ana (main) programı ve diğer fonksiyonlar
5
Kolay Bir flex Programı (ornek0.lex)
(emacs, vi, nano vb. editörler ile oluşturulabilir.)
%{
#include <stdio.h> /* printf icin gerekli */
%}
%%
.|\n
%%
printf("%s",yytext);
$ flex ornek0.lex
$ gcc -o ornek0.x lex.yy.c –lfl
$ ls
ornek0.x
ornek0.lex
lex.yy.c
Flex, uyuşan token
değerini (lexeme)
yytext değişkeni
içinde tutar.
6
Kolay Bir flex Programı (ornek0.lex)
test0.txt isimli giriş dosyasının içeriği şöyle olsun:
ali
Veli
$ ./ornek0.x < test0.txt
ali
Veli
Giriş dosyasının içeriğini aynen geri döndürür.
7
Örnek flex Programı (ornek1.lex)
%%
zippy printf("I RECOGNIZED ZIPPY");
%%
test1.txt isimli giriş dosyasının içeriği şöyle olsun:
zippy
ali zip
veli and zippy here
Herhangi bir kuralla
zipzippy
eşleşmeyen karakter
ZIP
$ ./ornek1.x < test1.txt
I RECOGNIZED ZIPPY
ali zip
veli and I RECOGNIZED ZIPPY here
zipI RECOGNIZED ZIPPY
ZIP
dizisi grubu için
varsayılan kural bu
lexeme değerini
standart çıktı olan
ekrana yönlendirmektir.
8
ornek2.lex
%%
zip
printf("ZIP");
zippy printf("ZIPPY");
%%
$ ./ornek2.x < test1.txt
ZIPPY
ali ZIP
veli and ZIPPY here
ZIPZIPPY
ZIP
flex en uzun düzgün ifadeyi bulur.
9
ornek3.lex
%%
monday|tuesday|wednesday|thursday|friday|
saturday|sunday printf("<%s is a day.>",yytext);
%%
test3.txt şöyle olsun:
today is wednesday september 27
$ ./ornek3.x < test3.txt
today is <wednesday is a day.> september 27
10
Örüntü Tasarımı
. Enter (new line) dışında her türlü karakteri karşılar
(matches).
* Öncesindeki düzgün ifadenin 0 veya daha fazla
tekrarlarını karşılar.
+ Öncesindeki düzgün ifadenin 1 veya daha fazla
tekrarlarını karşılar.
? Öncesindeki düzgün ifadenin 0 veya 1 kopyasını karşılar.
| Veya – arkasındaki veya önündeki örüntüyü karşılar.
^ Satırın başını karşılar.
$ Satırın sonunu karşılar.
/ Öncesi ve sonrasındaki ifade varsa, önceki ifadeyi
karşılar.
11
Örüntü Tasarımı
[]
Braketler içindeki herhangi bir karakteri karşılar. İlk
karakter ^ ise, braketler dışındaki her türlü karakteri karşılar.
Aralık belirtimi için - kullanılabilir.
""
Tırnaklar içinde ne varsa onu karşılar.
()
Grup içini karşılar.
{}
İçindekileri (değişken kombinasyonları) karşılar.
12
flex deki Düzgün İfadeler
a matches (karşılar) a
abc matches abc
[abc] matches a, b veya c
[a-f] matches a, b, c, d, e, veya f
[0-9] matches herhangi bir rakam
X+ matches 1 veya daha fazla X
X* matches 0 veya daha fazla X
[0-9]+ matches herhangi bir sayı
(…) gruplama demektir
| veya demektir
(a|b|c)* eşittir [a-c]*
13
flex deki Düzgün İfadeler
X? X opsiyonel (0 veya 1 oluşum)
if(def)? matches if veya ifdef (eşittir if|ifdef)
[A-Za-z] matches herhangi bir alfabe karakteri
. matches enter dışındaki her türlü karakter
\. matches . (nokta) karakteri
\n matches enter (new line)
\t matches tab
\\ matches \ (ters bölü) karakteri
[ \t] matches ya boşluk ya da tab
[^a-d] matches a,b,c,d dışındaki her karakter
14
Düzgün İfade Örnekleri
• Reel sayılar, örn., 0. 27, 2.10, .17, 34
[0-9]*(\.)?[0-9]+
• Opsiyonel işaret karakteri eklemek için:
[+-]?[0-9]*(\.)?[0-9]+
15
Biraz Daha Kompleks Bir Program (ornek4.lex)
%%
[\t ]+ ; /* hicbirsey yapma */
monday|tuesday|wednesday|thursday|friday|
saturday|sunday printf("%s is a day.",yytext);
[a-zA-Z]+ printf("<%s is not a day.>",yytext);
%%
16
ornek5.lex
%%
[\t ]+ ; /* hicbirsey yapma */
Monday|Tuesday|Wednesday|Thursday|Friday
printf("%s is a week day.",yytext);
Saturday|Sunday printf("%s is a weekend.",yytext);
[a-zA-Z]+ printf("%s is not a day.",yytext);
%%
17
Tanımlar Kısmının Kullanımı
%%
[+-]?[0-9]*(\.)?[0-9]+ printf("FLOAT");
%%
Bunu şöyle de yazabiliriz: (digit tanımlaması yaparak)
digit [0-9]
%%
[+-]?{digit}*(\.)?{digit}+
%%
printf("FLOAT");
input: ab7.3c--5.4.3+d++5
output: abFLOATc-FLOATFLOAT+d+FLOAT
18
Değişken Deklarasyonu
%{
#include <stdlib.h> /* atof icin gerekli */
float val;
%}
digit [0-9]
sign [+-]
%%
{sign}?{digit}*(\.)?{digit}+
{val=atof(yytext);
printf(">%f<",val);}
%%
Input
=>
ali-7.8veli
=>
ali--07.8veli =>
+3.7.5
=>
Output
ali>-7.800000<veli
ali->-7.800000<veli
>3.700000<>0.500000<
19
Başka Bir Örnek
/* buyukharflerdenolusankelimeleriekranabas */
%%
[A-Z]+[ \t\n\.\,]
printf("%s",yytext);
.
;
/* hicbirsey yapma */
%%
flex, büyük harflerden oluşan sonrasında da boşluk, tab, enter,
nokta veya virgülden oluşan kelimeleri ekrana basar.
Input
Ali VELI A7, X. 12
HAMI BEY a
Output
VELI X.
HAMI BEY
20
Tanım İçinde Tanım Kullanımı
/* tanım içinde tanım */
alphabetic [A-Za-z]
digit [0-9]
alphanumeric ({alphabetic}|{digit})
%%
{alphabetic}{alphanumeric}* printf("Değişken");
\, printf("Virgül");
\{ printf("Sol süslü parantez");
\:\= printf("Atama");
%%
21
Kullanıcı Kodları Bölümü
• Bu bölümde istediğiniz C, C++ kodunu
kullanabilirsiniz. Tek gereken satır:
int main(){yylex();return 0;}
• flex yylex() fonksiyonunu kendisi oluşturur ve
sizin için bütün işi yapar.
• Buradaki fonksiyonlar kurallar bölümünde
çağrılabilir.
22
Kural Sırası
Birden fazla düzgün ifade input dosyasında bir
kelime karşılarsa, ilk tanımlanan kural kullanılır.
%%
for printf("FOR");
[a-z]+ printf("IDENTIFIER");
%%
Aşağıdaki input için
for count := 1 to 10
output şöyle olur:
FOR IDENTIFIER := 1 IDENTIFIER 10
23
Kural Sırası
Eğer sırayı değiştirirsek
%%
[a-z]+ printf("IDENTIFIER");
for printf("FOR");
%%
Aynı input için output:
IDENTIFIER IDENTIFIER := 1 IDENTIFIER 10
24
Sayı Tanıma (ornek6.lex)
%%
[\t ]+ ; /* Boşlukları gözardı et*/
[+-]?[0-9]*(\.)?[0-9]+ printf(" %s:number",yytext);
[a-zA-Z]+ printf(" %s:NOT number",yytext);
%%
int main()
{
yylex();
return 0;
}
25
Kelimeleri Sayma (ornek7.lex)
%{
int char_count=0;
int word_count=0;
int line_count=0;
%}
word
eol
%%
{word}
{eol}
.
%%
yyleng match edilen karakter sayısını verir.
[^ \t\n]+
\n
{word_count++; char_count+=yyleng;}
{char_count++; line_count++;}
char_count++;
int main()
{
yylex();
printf("line_count = %d , word_count = %d, char_count = %d\n",
line_count, word_count, char_count);
return 0;
26
}
Kelimeleri Sayma (Devam)
test7.txt şöyle olsun:
how many words
and how many lines
are there
in this file
$ ./ornek7.x < test7.txt
line_count = 5, word_count = 12,char_count = 58
27
Download

Lecture3