Bir kaç günün özeti

Son bir kaç gündür. Flex ve Bison ile alakalı örnekler bulup onları çözdüm. Örnekleri kendimce geliştirmeye çalıştım. Yaptığım çalışmaları gün gün klasörledim. Yazdığım kodları o günün klasörüne koydum. Biraz önce artık bir şeyler de yazayım diyip ne yaptığıma bakınca 3-5 kere hesap makinesi yazdığımı gördüm. Aslında biraz kendi etrafımda dolaşmışım. Pek ilerlediğim söylenemez.

Örnek 1

Eylül 12'de başarısız bir kaç hesap makinesi denemesinde bulunmuşum. (Onları paylaşmayacağım.) Sonrasında daha basit yapılara (çok basit yapılara) yönelmeyi düşünmüş olmalıyım ki; şöyle bir şey yapmışım.

A ->  ( A )
A ->   B
A ->  epsilon

// B' de hertürlü bir string olabilir. Resmi olamayan şekillerle şöyle gösterilebilir.
B -> [a-z]+
Bu gramer yapısına uyan bazı sözcükler şöyle:
((((((A))))))
(((omer)))
((A))
((((selam))))
((((((((()))))))))
()


Dosyaları koyunca herşey açık olacak. Ama şu kurala bir değinmem gerekiyor.
rules.y da tanımlanan şöyle bir kural var.

program: program s NL
    | s  {printf("Correct Syntax.\n");}
    ;

Yacc başlangıç kuralı bu, en başta bu kural çalışıyor. Buradaki program non-terminali kendini çağırarak bir döngü oluşturuyor. Ve bu döngü sayesinde birden çok satır girdiyi işleyebiliyor. Onun yerine program: s NL; olsaydı sadece bir kere çalıştırıp bırakacaktı.

tokens.l

%{
        #include "y.tab.h"
%}

%%

[ \t]  /* ignore */
\(      { printf("LP\n"); return LP;}
\)      { printf("RP\n"); return RP;}
[a-z]+  { printf("A\n"); return ALPHA;}
\n      { return NL;}
.

%%

rules.y

%{

#include<stdio.h>
int yylex();
void yyerror(char*);

%}

%token ALPHA LP RP NL

%%
program: program s NL
       | s              {printf("Correct syntax\n");}
       ;


s: LP s RP
 | ALPHA
 |
 ;

%%
int main(){
        yyparse();
        return 0;
}

void yyerror(char *s){
        fprintf(stderr, "error: %s\n" ,s);
}

Örnek 2 - Mantıksal Hesap Makinesi

Bir önceki örneği kafamda tasarlayıp yaptıktan sonra, aklıma yine bir hesap makinesi fikri geldi. Bu tam sayılar üzerinde , and, or, xor, not gibi mantıksal operatorleri çalıştırabileceğim bir hesap makinesi olacaktı. İlk denemelerim pek başarılı olmadı. Bugün bitirebildim.
Üzerine şunları söyleyebilirim. Bisondaki öncelik kurallarıyla alakalı bir örnek yapmış oldum. Sembol tabloları hakkında biraz daha fikir sahibi oldum .
Yaptığım örnekte, 26 lık bir dizi oluşturarak. a-z ye gelebilecek değişken isimlerini eşledim. Bu dizi her bir değişkenin değerini tam sayi olarak tutuyor.
Geçen yazıdaki aldığım hesap makinesi örneğinden tek farkı '+' '-' '/' '*' gibi operatorler yerine '&' '|' '!' gibi operatorleri kullanmamdı.

Örnek 3 - Fonksiyonlu Hesap Makinesi

Bu hesap makinesi örneğini bir kitaptan aldım. Çoğu kısmını anladım ama hala aklımda bir kaç soru işareti var. En önemli sorularda biri şöyle: YYSTYPE değişkeni nasıl kullanılıyor ?
İlk halinde YYSTYPE integer olarak seçilmiş. Bu değişken türünde bison bir stack tutuyor ve stack e erişmek için kullandığımız $$ = $1 - $3 gibi komutları stackten okuyup dönderiyor. Ama ben hertürlü değişkeni saklamak için bu stacki kullanacağım. Ama C programlama dili öyle bir dil değil. İşte bu yüzden adamlar YYSTYPE yerine bir uniontanımlayabilirsiniz demiş.
Kitaptaki hesap makinesinde şöyle bir union tanımlanmış. (Bisonda derledikten sonra, header dosyasında şöyle gözüküyor. )

union YYSTYPE{
    double dval;
    struct symtab* symp;
}

Union'daki struct'in olayi da şöyle:

struct symtab{
    char* name;
   double value;
   double (*funcptr)();
}

YYSTYPE ilk halinden başka bir şeye çevrildiğinde, bazı token ve non-terminaler için type tanımlanması gerekiyor. Kısaca:

%token <dval> NUMBER         /* token */
...

%type <dval> expression      /* non-terminal*/
Olayın lex tarafında da bir tokenin değerini stack'e koymak için:

([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) {
                yylval.dval = atof(yytext);
                return NUMBER;
        }

Üstte hertürlü sayi için (ondalik, bilimsel gösterim, negatif, pozitif) tanımlanmış bir regex bulunuyor. Action kısmında, geçerli olan metini (yytext) float'a çevirip onun yylval in dval kısmına eşitliyor.
Açıkcası bu örnek biraz karışıktı. Bunun gibi bir şeyi yazmam, 2 gün sürebilir.

Sonuç

Sanırım, buralarda bir kaç tur daha atıp, lex ve yacc biraz daha iyi öğreneceğim. Böyle örnekler çözünde, neyin nasıl olduğunu anlıyor, nasıl olacağını da biraz kestirebiliyorum. Zor olacak.
İlk haftanın sonunda, bütün kitabı onu bunu şunu kapatsam , bir hesap makinesi yazarım. Ortalama bir hesap makinesi.
Bu hızla gidersem 3 aya kadar yapabilirim diye düşünüyorum. Bakalım.

Yorumlar

Bu blogdaki popüler yayınlar

NFA, DFA, Regex, CFG, PDA

Lex ve Yacc-2

Lex ve Yacc